Add C libalac interface for encoder
This commit is contained in:
parent
5d6d836ee5
commit
abddc2592b
|
@ -21,7 +21,7 @@ To download, build and install `libalac` do the following:
|
|||
|
||||
* Clone the repository and `cd` into the folder:
|
||||
```
|
||||
$ git clone https://github.com/mikebrady/alac.git
|
||||
$ git clone https://git.gammaspectra.live/S.O.N.G/alac.git
|
||||
$ cd alac
|
||||
```
|
||||
* Configure the build and make the library:
|
||||
|
|
|
@ -27,7 +27,8 @@ libalac_la_SOURCES = \
|
|||
dp_dec.c \
|
||||
dp_enc.c \
|
||||
matrix_dec.c \
|
||||
matrix_enc.c
|
||||
matrix_enc.c \
|
||||
libalac.cpp
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = alac.pc
|
||||
|
|
134
codec/libalac.cpp
Normal file
134
codec/libalac.cpp
Normal file
|
@ -0,0 +1,134 @@
|
|||
#include <vector>
|
||||
#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;
|
||||
|
||||
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;
|
||||
|
||||
return encoder;
|
||||
}
|
||||
|
||||
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 = outputFormat.mFramesPerPacket;
|
||||
inputFormat.mChannelsPerFrame = encoder->channels;
|
||||
inputFormat.mBitsPerChannel = encoder->bit_depth;
|
||||
inputFormat.mBytesPerPacket = inputFormat.mBytesPerFrame = inputFormat.mFramesPerPacket * (inputFormat.mBitsPerChannel >> 3) * inputFormat.mChannelsPerFrame;
|
||||
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;
|
||||
}
|
||||
|
||||
int32_t ioNumBytes = 0;
|
||||
|
||||
if(input_size > inputFormat.mBytesPerPacket){
|
||||
return -1;
|
||||
}
|
||||
|
||||
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){
|
||||
delete reinterpret_cast<ALACEncoder*>(encoder->ptr);
|
||||
encoder->ptr = nullptr;
|
||||
}
|
21
codec/libalac.h
Normal file
21
codec/libalac.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
void *ptr;
|
||||
int sample_rate;
|
||||
int channels;
|
||||
int bit_depth;
|
||||
int input_packet_size;
|
||||
int output_max_packet_size;
|
||||
} alac_encoder;
|
||||
|
||||
alac_encoder alac_encoder_new(int sampleRate, int channels, int bitDepth, int fastMode);
|
||||
int alac_encoder_write(alac_encoder* encoder, const unsigned char * input, int input_size, unsigned char * output);
|
||||
void alac_encoder_delete(alac_encoder* encoder);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Loading…
Reference in a new issue