DataHoarder
36183648ff
All checks were successful
continuous-integration/drone/push Build is passing
156 lines
4.6 KiB
C++
156 lines
4.6 KiB
C++
#include "libalac.h"
|
|
#include "ALACEncoder.h"
|
|
#include "ALACBitUtilities.h"
|
|
|
|
enum
|
|
{
|
|
kTestFormatFlag_16BitSourceData = 1,
|
|
kTestFormatFlag_20BitSourceData = 2,
|
|
kTestFormatFlag_24BitSourceData = 3,
|
|
kTestFormatFlag_32BitSourceData = 4
|
|
};
|
|
|
|
alac_encoder alac_encoder_new(int sampleRate, int channels, int bitDepth, int fastMode) {
|
|
alac_encoder encoder;
|
|
encoder.ptr = nullptr;
|
|
encoder.sample_rate = sampleRate;
|
|
encoder.channels = channels;
|
|
encoder.bit_depth = bitDepth;
|
|
encoder.input_packet_size = 0;
|
|
encoder.output_max_packet_size = 0;
|
|
encoder.magic_cookie_size = 0;
|
|
encoder.frames_per_packet = 0;
|
|
|
|
AudioFormatDescription d;
|
|
d.mFormatID = kALACFormatAppleLossless;
|
|
d.mSampleRate = static_cast<alac_float64_t>(sampleRate);
|
|
|
|
switch (bitDepth) {
|
|
//TODO: hmm, source bit data?
|
|
case 16:
|
|
d.mFormatFlags = kTestFormatFlag_16BitSourceData;
|
|
break;
|
|
case 20:
|
|
d.mFormatFlags = kTestFormatFlag_20BitSourceData;
|
|
break;
|
|
case 24:
|
|
d.mFormatFlags = kTestFormatFlag_24BitSourceData;
|
|
break;
|
|
case 32:
|
|
d.mFormatFlags = kTestFormatFlag_32BitSourceData;
|
|
break;
|
|
default:
|
|
return encoder;
|
|
}
|
|
|
|
if (channels > kALACMaxChannels) {
|
|
return encoder;
|
|
}
|
|
|
|
d.mFramesPerPacket = kALACDefaultFramesPerPacket;
|
|
d.mChannelsPerFrame = channels;
|
|
d.mBytesPerPacket = 0;
|
|
d.mBytesPerFrame = 0;
|
|
d.mBitsPerChannel = 0;
|
|
d.mReserved = 0;
|
|
|
|
auto e = new ALACEncoder();
|
|
|
|
e->SetFrameSize(d.mFramesPerPacket);
|
|
e->SetFastMode(fastMode != 0);
|
|
if(e->InitializeEncoder(d) != ALAC_noErr){
|
|
delete e;
|
|
return encoder;
|
|
}
|
|
|
|
|
|
encoder.ptr = e;
|
|
encoder.input_packet_size = channels * (bitDepth >> 3) * d.mFramesPerPacket;
|
|
encoder.output_max_packet_size = encoder.input_packet_size + kALACMaxEscapeHeaderBytes;
|
|
encoder.magic_cookie_size = e->GetMagicCookieSize(channels);
|
|
encoder.frames_per_packet = d.mFramesPerPacket;
|
|
|
|
return encoder;
|
|
}
|
|
|
|
int alac_encoder_get_magic_cookie(alac_encoder* encoder, unsigned char * output) {
|
|
if (encoder->ptr == nullptr) {
|
|
return -1;
|
|
}
|
|
|
|
|
|
auto e = reinterpret_cast<ALACEncoder*>(encoder->ptr);
|
|
|
|
|
|
uint32_t ioSize = encoder->magic_cookie_size;
|
|
e->GetMagicCookie(output, &ioSize);
|
|
|
|
return ioSize;
|
|
}
|
|
|
|
int alac_encoder_write(alac_encoder* encoder, const unsigned char * input, int input_size, unsigned char * output){
|
|
if(encoder->ptr == nullptr){
|
|
return -1;
|
|
}
|
|
|
|
auto e = reinterpret_cast<ALACEncoder*>(encoder->ptr);
|
|
|
|
AudioFormatDescription outputFormat;
|
|
outputFormat.mFormatID = kALACFormatAppleLossless;
|
|
outputFormat.mSampleRate = static_cast<alac_float64_t>(encoder->sample_rate);
|
|
outputFormat.mFramesPerPacket = kALACDefaultFramesPerPacket;
|
|
outputFormat.mChannelsPerFrame = encoder->channels;
|
|
outputFormat.mBytesPerPacket = 0;
|
|
outputFormat.mBytesPerFrame = 0;
|
|
outputFormat.mBitsPerChannel = 0;
|
|
outputFormat.mReserved = 0;
|
|
|
|
AudioFormatDescription inputFormat;
|
|
inputFormat.mFormatID = kALACFormatLinearPCM;
|
|
inputFormat.mSampleRate = static_cast<alac_float64_t>(encoder->sample_rate);
|
|
inputFormat.mFramesPerPacket = 1;
|
|
inputFormat.mChannelsPerFrame = encoder->channels;
|
|
inputFormat.mBitsPerChannel = encoder->bit_depth;
|
|
inputFormat.mBytesPerFrame = (inputFormat.mBitsPerChannel >> 3) * inputFormat.mChannelsPerFrame;
|
|
inputFormat.mBytesPerPacket = inputFormat.mFramesPerPacket * inputFormat.mBytesPerFrame;
|
|
inputFormat.mFormatFlags = kALACFormatFlagIsSignedInteger | kALACFormatFlagIsPacked; //little endian
|
|
inputFormat.mReserved = 0;
|
|
|
|
|
|
switch (encoder->bit_depth) {
|
|
//TODO: hmm, source bit data?
|
|
case 16:
|
|
outputFormat.mFormatFlags = kTestFormatFlag_16BitSourceData;
|
|
break;
|
|
case 20:
|
|
outputFormat.mFormatFlags = kTestFormatFlag_20BitSourceData;
|
|
break;
|
|
case 24:
|
|
outputFormat.mFormatFlags = kTestFormatFlag_24BitSourceData;
|
|
break;
|
|
case 32:
|
|
outputFormat.mFormatFlags = kTestFormatFlag_32BitSourceData;
|
|
break;
|
|
}
|
|
|
|
if(input_size > encoder->input_packet_size){
|
|
return -1;
|
|
}
|
|
|
|
int32_t ioNumBytes = input_size;
|
|
if(e->Encode(inputFormat, outputFormat, const_cast<unsigned char *>(input), output, &ioNumBytes) != ALAC_noErr){
|
|
return -1;
|
|
}
|
|
|
|
|
|
return ioNumBytes;
|
|
|
|
}
|
|
|
|
void alac_encoder_delete(alac_encoder* encoder){
|
|
if(encoder->ptr == nullptr){
|
|
return;
|
|
}
|
|
delete reinterpret_cast<ALACEncoder*>(encoder->ptr);
|
|
encoder->ptr = nullptr;
|
|
} |