151 lines
4.5 KiB
C++
151 lines
4.5 KiB
C++
|
#include "flactomp3.h"
|
||
|
|
||
|
constexpr uint16_t flacBlockMaxSize = 4096;
|
||
|
|
||
|
FLACtoMP3::FLACtoMP3(uint8_t size) :
|
||
|
inPath(),
|
||
|
outPath(),
|
||
|
decoder(FLAC__stream_decoder_new()),
|
||
|
encoder(lame_init()),
|
||
|
statusFLAC(),
|
||
|
output(),
|
||
|
pcmCounter(0),
|
||
|
pcmSize(size * flacBlockMaxSize),
|
||
|
pcm(new int16_t[pcmSize * 2]),
|
||
|
mp3(new uint8_t[pcmSize])
|
||
|
{
|
||
|
}
|
||
|
|
||
|
FLACtoMP3::~FLACtoMP3() {
|
||
|
lame_close(encoder);
|
||
|
FLAC__stream_decoder_delete(decoder);
|
||
|
delete[] pcm;
|
||
|
delete[] mp3;
|
||
|
}
|
||
|
|
||
|
void FLACtoMP3::run() {
|
||
|
FLAC__bool ok = FLAC__stream_decoder_process_until_end_of_stream(decoder);
|
||
|
std::cout << "decoding: ";
|
||
|
if (ok)
|
||
|
std::cout << "succeeded";
|
||
|
else
|
||
|
std::cout << "FAILED";
|
||
|
|
||
|
std::cout << std::endl;
|
||
|
std::cout << " state: " << FLAC__StreamDecoderStateString[FLAC__stream_decoder_get_state(decoder)] << std::endl;
|
||
|
|
||
|
flush();
|
||
|
int nwrite = lame_encode_flush(encoder, mp3, pcmSize);
|
||
|
output.write((char*)mp3, nwrite);
|
||
|
|
||
|
// // 7. Write INFO tag (OPTIONAL)
|
||
|
// // lame_mp3_tags_fid(lame, mp3);
|
||
|
output.close();
|
||
|
}
|
||
|
|
||
|
void FLACtoMP3::setInputFile(const std::string& path) {
|
||
|
if (inPath.size() > 0)
|
||
|
throw 1;
|
||
|
|
||
|
inPath = path;
|
||
|
|
||
|
FLAC__stream_decoder_set_md5_checking(decoder, true);
|
||
|
statusFLAC = FLAC__stream_decoder_init_file(decoder, path.c_str(), write, metadata, error, this);
|
||
|
}
|
||
|
|
||
|
void FLACtoMP3::setOutputFile(const std::string& path) {
|
||
|
if (outPath.size() > 0)
|
||
|
throw 2;
|
||
|
|
||
|
outPath = path;
|
||
|
|
||
|
// 3. Do some settings (OPTIONAL)
|
||
|
lame_set_in_samplerate(encoder, 44100);
|
||
|
lame_set_VBR(encoder, vbr_default);
|
||
|
lame_set_VBR_quality(encoder, 2);
|
||
|
|
||
|
// 4. Initialize parameters
|
||
|
int ret = lame_init_params(encoder);
|
||
|
if (ret < 0) {
|
||
|
std::cout << "Error occurred during parameters initializing. Code = " << ret << std::endl;
|
||
|
throw 3;
|
||
|
}
|
||
|
|
||
|
output.open(path, std::ios::out | std::ios::binary);
|
||
|
}
|
||
|
|
||
|
void FLACtoMP3::decodeFrame(const int32_t * const buffer[], uint32_t size) {
|
||
|
for (size_t i = 0; i < size; ++i) {
|
||
|
pcm[2 * pcmCounter] = (int16_t)buffer[0][i];
|
||
|
pcm[2 * pcmCounter + 1] = (int16_t)buffer[1][i];
|
||
|
++pcmCounter;
|
||
|
}
|
||
|
|
||
|
if (pcmCounter == pcmSize)
|
||
|
flush();
|
||
|
}
|
||
|
|
||
|
void FLACtoMP3::flush() {
|
||
|
int nwrite = lame_encode_buffer_interleaved(
|
||
|
encoder,
|
||
|
pcm,
|
||
|
pcmCounter,
|
||
|
mp3,
|
||
|
pcmSize
|
||
|
);
|
||
|
output.write((char*)mp3, nwrite);
|
||
|
pcmCounter = 0;
|
||
|
}
|
||
|
|
||
|
void FLACtoMP3::metadata(const FLAC__StreamDecoder* decoder, const FLAC__StreamMetadata* metadata, void* client_data) {
|
||
|
|
||
|
}
|
||
|
|
||
|
FLAC__StreamDecoderWriteStatus FLACtoMP3::write(
|
||
|
const FLAC__StreamDecoder* decoder,
|
||
|
const FLAC__Frame* frame,
|
||
|
const FLAC__int32 * const buffer[],
|
||
|
void* client_data
|
||
|
){
|
||
|
FLACtoMP3* self = static_cast<FLACtoMP3*>(client_data);
|
||
|
self->decodeFrame(buffer, frame->header.blocksize);
|
||
|
|
||
|
// if (decoded->totalSamples == 0) {
|
||
|
// std::cout << "ERROR: this example only works for FLAC files that have a total_samples count in STREAMINFO" << std::endl;
|
||
|
// return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||
|
// }
|
||
|
// if (decoded->channels != 2 || decoded->depth != 16) {
|
||
|
// std::cout << "ERROR: this example only supports 16bit stereo streams" << std::endl;
|
||
|
// return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||
|
// }
|
||
|
if (frame->header.channels != 2) {
|
||
|
std::cout << "ERROR: This frame contains " << frame->header.channels << " channels (should be 2)" << std::endl;
|
||
|
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||
|
}
|
||
|
if (buffer[0] == NULL) {
|
||
|
std::cout << "ERROR: buffer [0] is NULL" << std::endl;
|
||
|
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||
|
}
|
||
|
if (buffer[1] == NULL) {
|
||
|
std::cout << "ERROR: buffer [1] is NULL" << std::endl;
|
||
|
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||
|
}
|
||
|
|
||
|
// /* write WAVE header before we write the first frame */
|
||
|
// if (frame->header.number.sample_number == 0)
|
||
|
// decoded->writeWaveHeader();
|
||
|
//
|
||
|
// /* write decoded PCM samples */
|
||
|
// for (size_t i = 0; i < frame->header.blocksize; i++) {
|
||
|
// decoded->write((uint16_t)buffer[0][i]);
|
||
|
// decoded->write((uint16_t)buffer[1][i]);
|
||
|
// }
|
||
|
|
||
|
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||
|
}
|
||
|
|
||
|
void FLACtoMP3::error(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErrorStatus status, void* client_data) {
|
||
|
(void)decoder, (void)client_data;
|
||
|
std::cout << "Got error callback: " << FLAC__StreamDecoderErrorStatusString[status] << std::endl;
|
||
|
}
|