/***************************************************************************
* Copyright (C) 2006-2021 by Ilya Kotov *
* forkotov02@ya.ru *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
/* The code is based on MOC by Damian Pietras <daper@daper.net>
and libxmms-flac written by Josh Coalson. */
#include <taglib/tag.h>
#include <taglib/fileref.h>
#include <taglib/flacfile.h>
#include <taglib/xiphcomment.h>
#include <taglib/tmap.h>
#include <taglib/id3v2header.h>
#include <taglib/tfilestream.h>
#include <taglib/id3v2framefactory.h>
#include <QObject>
#include <QFile>
#include <QIODevice>
#include <QRegularExpression>
#include <FLAC/all.h>
#include <stdint.h>
#include <qmmp/cueparser.h>
#include "decoder_flac.h"
#define BITRATE_CALC_TIME_MS 2000
static size_t pack_pcm_signed (FLAC__byte *output,
const FLAC__int32 * const input[],
unsigned samples,
unsigned channels, unsigned bps)
{
unsigned channel = 0;
uint8_t *data8 = (uint8_t *) output;
uint16_t *data16 = (uint16_t *) output;
uint32_t *data32 = (uint32_t *) output;
for(unsigned sample = 0; sample < samples; sample++)
{
for (channel = 0; channel < channels; channel++)
{
switch (bps)
{
case 8:
*data8 = input[channel][sample] & 0xff;
data8++;
break;
case 16:
*data16 = input[channel][sample] & 0xffffff;
data16++;
break;
case 24:
*data32 = (input[channel][sample] << 8) & 0xffffff00;
data32++;
break;
case 32:
*data32 = input[channel][sample];
data32++;
break;
}
}
}
if(bps == 24) // we encode to 32-bit words
bps = 32;
return samples * channels * bps / 8;
}
static int flac_decode (void *client_data, unsigned char *buf, int buf_len)
{
flac_data *data = static_cast<flac_data *>(client_data);
unsigned to_copy;
if (!data->sample_buffer_fill)
{
if (FLAC__stream_decoder_get_state(data->decoder)
== FLAC__STREAM_DECODER_END_OF_STREAM)
{
return 0;
}
if (!FLAC__stream_decoder_process_single(
data->decoder))
{
return 0;
}
}
to_copy = qMin((unsigned)buf_len, data->sample_buffer_fill);
memcpy (buf, data->sample_buffer, to_copy);
memmove (data->sample_buffer,
data->sample_buffer + to_copy,
data->sample_buffer_fill - to_copy);
data->sample_buffer_fill -= to_copy;
return to_copy;
}
static FLAC__StreamDecoderReadStatus flac_callback_read (const FLAC__StreamDecoder*,
FLAC__byte buffer[],
size_t *bytes,
void *client_data)
{
flac_data *data = static_cast<flac_data *>(client_data);
qint64 res = data->input->read((char *)buffer, *bytes);
if (res > 0)
{
*bytes = res;
data->read_bytes += res;
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
if (res == 0)
{
*bytes = res;
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
}
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
}
static FLAC__StreamDecoderWriteStatus flac_callback_write (const FLAC__StreamDecoder *d,
const FLAC__Frame *frame,
const FLAC__int32* const buffer[],
void *client_data)
{
flac_data *data = static_cast<flac_data *>(client_data);