Compare commits
35 commits
Author | SHA1 | Date | |
---|---|---|---|
DataHoarder | ba11f91599 | ||
DataHoarder | 03a8d373b7 | ||
DataHoarder | 8294d09f7f | ||
DataHoarder | c2f4ea84d2 | ||
DataHoarder | 68745685f4 | ||
DataHoarder | 70b76cc688 | ||
DataHoarder | 36183648ff | ||
DataHoarder | 24a644245e | ||
DataHoarder | 50e084c919 | ||
DataHoarder | 4ca37a9ff3 | ||
DataHoarder | d4fe18abce | ||
DataHoarder | 0f8ce49da1 | ||
DataHoarder | 2ace9b3ecb | ||
DataHoarder | 109921d57b | ||
DataHoarder | eec1c7d041 | ||
DataHoarder | bb7e91682e | ||
DataHoarder | cef0bc38e6 | ||
DataHoarder | abddc2592b | ||
5d6d836ee5 | |||
c86990a999 | |||
c9085ac04a | |||
ae873e47cb | |||
1588be3a83 | |||
ce8b0e1e01 | |||
7f49d68da8 | |||
45d20bd214 | |||
725b18406a | |||
9c33501311 | |||
5f3e5a29b8 | |||
d94f668213 | |||
7a71687a9b | |||
a22f899f54 | |||
460c0ce76b | |||
8249006191 | |||
8d488b44ea |
17
.drone.yml
Normal file
17
.drone.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: default
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: debian:bullseye
|
||||
commands:
|
||||
- DEBIAN_FRONTEND=noninteractive apt update
|
||||
- DEBIAN_FRONTEND=noninteractive apt install -y g++ gcc autoconf automake make libtool-bin
|
||||
- autoreconf -fi
|
||||
- ./configure --prefix /usr
|
||||
- make -j$(nproc)
|
||||
- make install
|
||||
|
||||
...
|
66
README.md
66
README.md
|
@ -1 +1,67 @@
|
|||
ALAC
|
||||
====
|
||||
|
||||
This repository is a clone of the Apple Lossless Audio Codec (ALAC) repository at http://alac.macosforge.org with added files to enable it to be built using GNU `autotools`. Use it to build and install the ALAC library `libalac`.
|
||||
|
||||
The added files are based on work done by [Tiancheng "Timothy" Gu](https://github.com/TimothyGu) in his repository https://github.com/TimothyGu/alac with some changes. Many thanks to him for his work. This respository is bare-bones – for Visual Studio or Debian packaging support or for `man` pages, please go to Timothy's repository.
|
||||
|
||||
**Note:** In the rest of the note, a command prefixed with `#` means that it must be executed in superuser mode. The `$` prefix means it should be executed in regular user mode.
|
||||
|
||||
Install Build Tools
|
||||
---
|
||||
Building `libalac` requires a number of tools, such a the compiler and linker, `git` and more. Ensure they are already in place by running the following command. If the tools are already in place, it'll do no harm.
|
||||
```
|
||||
# apt get update
|
||||
# apt-get install build-essential git autoconf automake libtool
|
||||
```
|
||||
Download, Build, Install
|
||||
---
|
||||
|
||||
To download, build and install `libalac` do the following:
|
||||
|
||||
* Clone the repository and `cd` into the folder:
|
||||
```
|
||||
$ git clone https://git.gammaspectra.live/S.O.N.G/alac.git
|
||||
$ cd alac
|
||||
```
|
||||
* Configure the build and make the library:
|
||||
```
|
||||
$ autoreconf -fi
|
||||
$ ./configure
|
||||
$ make
|
||||
```
|
||||
The `autoconfigure` command may take a long time. You may get a warning which you can ignore:
|
||||
```
|
||||
aclocal: warning: couldn't open directory 'm4': No such file or directory
|
||||
```
|
||||
|
||||
* Install the library:
|
||||
```
|
||||
# make install
|
||||
```
|
||||
Make it Available
|
||||
---
|
||||
To make the library visible during compilation, you need to tell `ld` about it. Be careful here – if you are on FreeBSD, the Linux command will mess up your system. On Linux, use the following command:
|
||||
```
|
||||
# ldconfig
|
||||
```
|
||||
|
||||
Using the library
|
||||
---
|
||||
|
||||
The library can be found and linked to via `pkg-config` – the module name is `alac`.
|
||||
|
||||
Thus:
|
||||
```
|
||||
PKG_CHECK_MODULES([ALAC], [alac], [LIBS="${ALAC_LIBS} ${LIBS}"])
|
||||
```
|
||||
should work in a `configure.ac` file. If you are using `AC_CHECK_LIB`, something like this will work:
|
||||
```
|
||||
AC_CHECK_LIB([alac], [BitBufferInit], , AC_MSG_ERROR(Apple ALAC Decoder support requires the alac library!))
|
||||
```
|
||||
|
||||
On FreeBSD you must add the location of the `alac.pc` file to the `PKG_CONFIG_PATH`, if it exists, and define it otherwise. Here is what you do if it doesn't already exist:
|
||||
```
|
||||
$ PKG_CONFIG_PATH="/usr/local/lib/pkgconfig"
|
||||
$ export PKG_CONFIG_PATH
|
||||
```
|
||||
|
|
|
@ -37,6 +37,8 @@ void BitBufferInit( BitBuffer * bits, uint8_t * buffer, uint32_t byteSize )
|
|||
bits->byteSize = byteSize;
|
||||
}
|
||||
|
||||
#define AssertBufferReadBounds(b, n) RequireAction( b->end >= (b->cur + ((b->bitIndex + n) / 8 + ((b->bitIndex + n) % 8 > 0))), return 0; );
|
||||
|
||||
// BitBufferRead
|
||||
//
|
||||
uint32_t BitBufferRead( BitBuffer * bits, uint8_t numBits )
|
||||
|
@ -45,6 +47,8 @@ uint32_t BitBufferRead( BitBuffer * bits, uint8_t numBits )
|
|||
|
||||
//Assert( numBits <= 16 );
|
||||
|
||||
AssertBufferReadBounds(bits, numBits)
|
||||
|
||||
returnBits = ((uint32_t)bits->cur[0] << 16) | ((uint32_t)bits->cur[1] << 8) | ((uint32_t)bits->cur[2]);
|
||||
returnBits = returnBits << bits->bitIndex;
|
||||
returnBits &= 0x00FFFFFF;
|
||||
|
@ -55,7 +59,7 @@ uint32_t BitBufferRead( BitBuffer * bits, uint8_t numBits )
|
|||
|
||||
bits->cur += (bits->bitIndex >> 3);
|
||||
bits->bitIndex &= 7;
|
||||
|
||||
|
||||
//Assert( bits->cur <= bits->end );
|
||||
|
||||
return returnBits;
|
||||
|
@ -69,6 +73,8 @@ uint8_t BitBufferReadSmall( BitBuffer * bits, uint8_t numBits )
|
|||
uint16_t returnBits;
|
||||
|
||||
//Assert( numBits <= 8 );
|
||||
|
||||
AssertBufferReadBounds(bits, numBits)
|
||||
|
||||
returnBits = (bits->cur[0] << 8) | bits->cur[1];
|
||||
returnBits = returnBits << bits->bitIndex;
|
||||
|
@ -92,6 +98,8 @@ uint8_t BitBufferReadOne( BitBuffer * bits )
|
|||
{
|
||||
uint8_t returnBits;
|
||||
|
||||
AssertBufferReadBounds(bits, 8)
|
||||
|
||||
returnBits = (bits->cur[0] >> (7 - bits->bitIndex)) & 1;
|
||||
|
||||
bits->bitIndex++;
|
||||
|
|
|
@ -128,8 +128,13 @@ int32_t ALACDecoder::Init( void * inMagicCookie, uint32_t inMagicCookieSize )
|
|||
theConfig.sampleRate = Swap32BtoN(((ALACSpecificConfig *)theActualCookie)->sampleRate);
|
||||
|
||||
mConfig = theConfig;
|
||||
|
||||
|
||||
//sanity checks
|
||||
RequireAction( mConfig.compatibleVersion <= kALACVersion, return kALAC_ParamError; );
|
||||
RequireAction( mConfig.bitDepth == 16 || mConfig.bitDepth == 20 || mConfig.bitDepth == 24 || mConfig.bitDepth == 32, return kALAC_ParamError; );
|
||||
RequireAction( mConfig.frameLength > 0 && mConfig.frameLength <= 16384, return kALAC_ParamError; );
|
||||
RequireAction( mConfig.sampleRate > 0 && mConfig.sampleRate <= 384000, return kALAC_ParamError; );
|
||||
RequireAction( mConfig.numChannels > 0 && mConfig.numChannels < kALACMaxChannels, return kALAC_ParamError; );
|
||||
|
||||
// allocate mix buffers
|
||||
mMixBufferU = (int32_t *) calloc( mConfig.frameLength * sizeof(int32_t), 1 );
|
||||
|
@ -251,6 +256,8 @@ int32_t ALACDecoder::Decode( BitBuffer * bits, uint8_t * sampleBuffer, uint32_t
|
|||
{
|
||||
numSamples = BitBufferRead( bits, 16 ) << 16;
|
||||
numSamples |= BitBufferRead( bits, 16 );
|
||||
|
||||
RequireAction( numSamples <= mConfig.frameLength, status = kALAC_ParamError; goto Exit; );
|
||||
}
|
||||
|
||||
if ( escapeFlag == 0 )
|
||||
|
@ -402,6 +409,8 @@ int32_t ALACDecoder::Decode( BitBuffer * bits, uint8_t * sampleBuffer, uint32_t
|
|||
{
|
||||
numSamples = BitBufferRead( bits, 16 ) << 16;
|
||||
numSamples |= BitBufferRead( bits, 16 );
|
||||
|
||||
RequireAction( numSamples <= mConfig.frameLength, status = kALAC_ParamError; goto Exit; );
|
||||
}
|
||||
|
||||
if ( escapeFlag == 0 )
|
||||
|
|
|
@ -27,7 +27,9 @@ libalac_la_SOURCES = \
|
|||
dp_dec.c \
|
||||
dp_enc.c \
|
||||
matrix_dec.c \
|
||||
matrix_enc.c
|
||||
matrix_enc.c \
|
||||
libalac_encoder.cpp \
|
||||
libalac_decoder.cpp
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = alac.pc
|
||||
|
|
45
codec/libalac.h
Normal file
45
codec/libalac.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
|
||||
#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;
|
||||
int magic_cookie_size;
|
||||
int frames_per_packet;
|
||||
} alac_encoder;
|
||||
|
||||
alac_encoder alac_encoder_new(int sampleRate, int channels, int bitDepth, int fastMode);
|
||||
int alac_encoder_get_magic_cookie(alac_encoder* encoder, unsigned char * output);
|
||||
int alac_encoder_write(alac_encoder* encoder, const unsigned char * input, int input_size, unsigned char * output);
|
||||
void alac_encoder_delete(alac_encoder* encoder);
|
||||
|
||||
typedef struct {
|
||||
void *ptr;
|
||||
int sample_rate;
|
||||
int channels;
|
||||
int bit_depth;
|
||||
int frames_per_packet;
|
||||
int input_max_packet_size;
|
||||
int output_packet_size;
|
||||
|
||||
} alac_decoder;
|
||||
|
||||
typedef struct {
|
||||
int input_bytes_used;
|
||||
int output_bytes;
|
||||
|
||||
} alac_decoder_read_result;
|
||||
|
||||
alac_decoder alac_decoder_new(const unsigned char* magicCookie, int magicCookieSize);
|
||||
alac_decoder_read_result alac_decoder_read(alac_decoder* decoder, const unsigned char * input, int input_size, unsigned char * output);
|
||||
void alac_decoder_delete(alac_decoder* decoder);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
68
codec/libalac_decoder.cpp
Normal file
68
codec/libalac_decoder.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
#include "libalac.h"
|
||||
#include "ALACDecoder.h"
|
||||
#include "ALACBitUtilities.h"
|
||||
|
||||
enum
|
||||
{
|
||||
kTestFormatFlag_16BitSourceData = 1,
|
||||
kTestFormatFlag_20BitSourceData = 2,
|
||||
kTestFormatFlag_24BitSourceData = 3,
|
||||
kTestFormatFlag_32BitSourceData = 4
|
||||
};
|
||||
|
||||
alac_decoder alac_decoder_new(const unsigned char* magicCookie, int magicCookieSize) {
|
||||
alac_decoder decoder;
|
||||
decoder.ptr = nullptr;
|
||||
|
||||
|
||||
|
||||
auto d = new ALACDecoder();
|
||||
if(d->Init((void *) magicCookie, magicCookieSize) != ALAC_noErr){
|
||||
delete d;
|
||||
return decoder;
|
||||
}
|
||||
|
||||
decoder.ptr = d;
|
||||
decoder.sample_rate = d->mConfig.sampleRate;
|
||||
decoder.channels = d->mConfig.numChannels;
|
||||
decoder.bit_depth = d->mConfig.bitDepth;
|
||||
decoder.frames_per_packet = d->mConfig.frameLength;
|
||||
|
||||
decoder.input_max_packet_size = decoder.channels * (decoder.bit_depth >> 3) * decoder.frames_per_packet + kALACMaxEscapeHeaderBytes;
|
||||
decoder.output_packet_size = decoder.channels * (decoder.bit_depth >> 3) * decoder.frames_per_packet;
|
||||
|
||||
return decoder;
|
||||
}
|
||||
|
||||
alac_decoder_read_result alac_decoder_read(alac_decoder* decoder, const unsigned char * input, int input_size, unsigned char * output){
|
||||
if(decoder->ptr == nullptr){
|
||||
return {-1, -1};
|
||||
}
|
||||
|
||||
auto d = reinterpret_cast<ALACDecoder*>(decoder->ptr);
|
||||
|
||||
if(input_size > decoder->input_max_packet_size){
|
||||
return {-1, -1};
|
||||
}
|
||||
|
||||
|
||||
|
||||
BitBuffer inputBuffer;
|
||||
BitBufferInit(&inputBuffer, const_cast<uint8_t*>(input), input_size);
|
||||
|
||||
uint32_t ioNumSamples = input_size;
|
||||
if(d->Decode(&inputBuffer, output, decoder->frames_per_packet, decoder->channels, &ioNumSamples) != ALAC_noErr){
|
||||
return {-1, -1};
|
||||
}
|
||||
|
||||
|
||||
return {static_cast<int>(BitBufferGetPosition(&inputBuffer) / 8), static_cast<int>(decoder->channels * ioNumSamples * (decoder->bit_depth >> 3))};
|
||||
}
|
||||
|
||||
void alac_decoder_delete(alac_decoder* decoder){
|
||||
if(decoder->ptr == nullptr){
|
||||
return;
|
||||
}
|
||||
delete reinterpret_cast<ALACDecoder*>(decoder->ptr);
|
||||
decoder->ptr = nullptr;
|
||||
}
|
156
codec/libalac_encoder.cpp
Normal file
156
codec/libalac_encoder.cpp
Normal file
|
@ -0,0 +1,156 @@
|
|||
#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;
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
bin_PROGRAMS = alacconvert$(EXEEXT)
|
||||
|
||||
alacconvert_CPPFLAGS = -Wno-multichar
|
||||
alacconvert_CPPFLAGS = -Wno-multichar -I../codec
|
||||
alacconvert_LDADD = ../codec/libalac.la
|
||||
alacconvert_SOURCES = \
|
||||
main.cpp \
|
||||
|
|
Loading…
Reference in a new issue