2005-06-02 18:16:43 +00:00
|
|
|
//
|
2007-02-24 20:36:27 +00:00
|
|
|
// FlacDecoder.m
|
2005-06-02 18:16:43 +00:00
|
|
|
// zyVorbis
|
|
|
|
//
|
|
|
|
// Created by Vincent Spader on 1/25/05.
|
2005-07-02 21:02:06 +00:00
|
|
|
// Copyright 2005 Vincent Spader All rights reserved.
|
2005-06-02 18:16:43 +00:00
|
|
|
//
|
|
|
|
|
2007-02-24 20:36:27 +00:00
|
|
|
#import "FlacDecoder.h"
|
2005-06-02 18:16:43 +00:00
|
|
|
|
2013-10-11 12:03:55 +00:00
|
|
|
#import "Logging.h"
|
2005-06-02 18:16:43 +00:00
|
|
|
|
2007-02-24 20:36:27 +00:00
|
|
|
@implementation FlacDecoder
|
2005-06-02 18:16:43 +00:00
|
|
|
|
2007-11-24 20:16:27 +00:00
|
|
|
FLAC__StreamDecoderReadStatus ReadCallback(const FLAC__StreamDecoder *decoder, FLAC__byte blockBuffer[], size_t *bytes, void *client_data)
|
2007-03-04 21:32:03 +00:00
|
|
|
{
|
2016-05-05 20:05:39 +00:00
|
|
|
FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data;
|
2013-10-11 12:03:55 +00:00
|
|
|
long bytesRead = [[flacDecoder source] read:blockBuffer amount:*bytes];
|
2007-03-04 21:32:03 +00:00
|
|
|
|
2013-10-11 12:03:55 +00:00
|
|
|
if(bytesRead < 0) {
|
|
|
|
*bytes = 0;
|
2007-03-04 21:32:03 +00:00
|
|
|
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
|
|
|
|
}
|
2013-10-11 12:03:55 +00:00
|
|
|
else if(bytesRead == 0) {
|
|
|
|
*bytes = 0;
|
2007-03-04 21:32:03 +00:00
|
|
|
[flacDecoder setEndOfStream:YES];
|
|
|
|
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
|
|
|
|
}
|
|
|
|
else {
|
2013-10-11 12:03:55 +00:00
|
|
|
*bytes = bytesRead;
|
2007-03-04 21:32:03 +00:00
|
|
|
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FLAC__StreamDecoderSeekStatus SeekCallback(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
|
|
|
|
{
|
2016-05-05 20:05:39 +00:00
|
|
|
FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data;
|
2007-03-04 21:32:03 +00:00
|
|
|
|
|
|
|
if(![[flacDecoder source] seek:absolute_byte_offset whence:SEEK_SET])
|
|
|
|
return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
|
|
|
|
else
|
|
|
|
return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
FLAC__StreamDecoderTellStatus TellCallback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
|
|
|
|
{
|
2016-05-05 20:05:39 +00:00
|
|
|
FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data;
|
2007-03-04 21:32:03 +00:00
|
|
|
|
|
|
|
off_t pos;
|
|
|
|
if((pos = [[flacDecoder source] tell]) < 0)
|
|
|
|
return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
|
|
|
|
else {
|
|
|
|
*absolute_byte_offset = (FLAC__uint64)pos;
|
|
|
|
return FLAC__STREAM_DECODER_TELL_STATUS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FLAC__bool EOFCallback(const FLAC__StreamDecoder *decoder, void *client_data)
|
|
|
|
{
|
2016-05-05 20:05:39 +00:00
|
|
|
FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data;
|
2007-03-04 21:32:03 +00:00
|
|
|
|
|
|
|
return (FLAC__bool)[flacDecoder endOfStream];
|
|
|
|
}
|
|
|
|
|
|
|
|
FLAC__StreamDecoderLengthStatus LengthCallback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
|
|
|
|
{
|
2016-05-05 20:05:39 +00:00
|
|
|
FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data;
|
2007-03-04 21:32:03 +00:00
|
|
|
|
|
|
|
if ([[flacDecoder source] seekable]) {
|
|
|
|
long currentPos = [[flacDecoder source] tell];
|
|
|
|
|
|
|
|
[[flacDecoder source] seek:0 whence:SEEK_END];
|
|
|
|
*stream_length = [[flacDecoder source] tell];
|
|
|
|
|
|
|
|
[[flacDecoder source] seek:currentPos whence:SEEK_SET];
|
|
|
|
|
|
|
|
return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*stream_length = 0;
|
|
|
|
return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-24 20:16:27 +00:00
|
|
|
FLAC__StreamDecoderWriteStatus WriteCallback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const sampleblockBuffer[], void *client_data)
|
2005-06-02 18:16:43 +00:00
|
|
|
{
|
2016-05-05 20:05:39 +00:00
|
|
|
FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data;
|
2005-06-02 18:16:43 +00:00
|
|
|
|
2007-11-24 20:16:27 +00:00
|
|
|
void *blockBuffer = [flacDecoder blockBuffer];
|
2007-02-27 23:56:52 +00:00
|
|
|
|
|
|
|
int8_t *alias8;
|
|
|
|
int16_t *alias16;
|
|
|
|
int32_t *alias32;
|
|
|
|
int sample, channel;
|
|
|
|
int32_t audioSample;
|
|
|
|
|
|
|
|
switch(frame->header.bits_per_sample) {
|
|
|
|
case 8:
|
|
|
|
// Interleave the audio (no need for byte swapping)
|
2007-11-24 20:16:27 +00:00
|
|
|
alias8 = blockBuffer;
|
2007-02-27 23:56:52 +00:00
|
|
|
for(sample = 0; sample < frame->header.blocksize; ++sample) {
|
|
|
|
for(channel = 0; channel < frame->header.channels; ++channel) {
|
2007-11-24 20:16:27 +00:00
|
|
|
*alias8++ = (int8_t)sampleblockBuffer[channel][sample];
|
2007-02-27 23:56:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 16:
|
|
|
|
// Interleave the audio, converting to big endian byte order
|
2007-11-24 20:16:27 +00:00
|
|
|
alias16 = blockBuffer;
|
2007-02-27 23:56:52 +00:00
|
|
|
for(sample = 0; sample < frame->header.blocksize; ++sample) {
|
|
|
|
for(channel = 0; channel < frame->header.channels; ++channel) {
|
2007-11-24 20:16:27 +00:00
|
|
|
*alias16++ = (int16_t)OSSwapHostToBigInt16((int16_t)sampleblockBuffer[channel][sample]);
|
2007-02-27 23:56:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 24:
|
|
|
|
// Interleave the audio (no need for byte swapping)
|
2007-11-24 20:16:27 +00:00
|
|
|
alias8 = blockBuffer;
|
2007-02-27 23:56:52 +00:00
|
|
|
for(sample = 0; sample < frame->header.blocksize; ++sample) {
|
|
|
|
for(channel = 0; channel < frame->header.channels; ++channel) {
|
2007-11-24 20:16:27 +00:00
|
|
|
audioSample = sampleblockBuffer[channel][sample];
|
2007-02-27 23:56:52 +00:00
|
|
|
*alias8++ = (int8_t)(audioSample >> 16);
|
|
|
|
*alias8++ = (int8_t)(audioSample >> 8);
|
|
|
|
*alias8++ = (int8_t)audioSample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 32:
|
|
|
|
// Interleave the audio, converting to big endian byte order
|
2007-11-24 20:16:27 +00:00
|
|
|
alias32 = blockBuffer;
|
2007-02-27 23:56:52 +00:00
|
|
|
for(sample = 0; sample < frame->header.blocksize; ++sample) {
|
|
|
|
for(channel = 0; channel < frame->header.channels; ++channel) {
|
2007-11-24 20:16:27 +00:00
|
|
|
*alias32++ = OSSwapHostToBigInt32(sampleblockBuffer[channel][sample]);
|
2007-02-27 23:56:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
2013-10-11 12:03:55 +00:00
|
|
|
ALog(@"Error, unsupported sample size.");
|
2005-06-02 18:16:43 +00:00
|
|
|
}
|
2007-02-27 23:56:52 +00:00
|
|
|
|
2007-11-24 20:16:27 +00:00
|
|
|
[flacDecoder setBlockBufferFrames:frame->header.blocksize];
|
2005-06-02 18:16:43 +00:00
|
|
|
|
|
|
|
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2013-10-11 14:25:41 +00:00
|
|
|
// This callback is only called for STREAMINFO blocks
|
2007-03-04 21:32:03 +00:00
|
|
|
void MetadataCallback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
|
2005-06-02 18:16:43 +00:00
|
|
|
{
|
2013-10-11 14:25:41 +00:00
|
|
|
// Some flacs observed in the wild have multiple STREAMINFO metadata blocks,
|
|
|
|
// of which only first one has sane values, so only use values from the first STREAMINFO
|
|
|
|
// to determine stream format (this seems to be consistent with flac spec: http://flac.sourceforge.net/format.html)
|
2016-05-05 20:05:39 +00:00
|
|
|
FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data;
|
2005-06-02 18:16:43 +00:00
|
|
|
|
2013-10-11 14:25:41 +00:00
|
|
|
if (!flacDecoder->hasStreamInfo) {
|
|
|
|
flacDecoder->channels = metadata->data.stream_info.channels;
|
|
|
|
flacDecoder->frequency = metadata->data.stream_info.sample_rate;
|
|
|
|
flacDecoder->bitsPerSample = metadata->data.stream_info.bits_per_sample;
|
2005-06-02 18:16:43 +00:00
|
|
|
|
2013-10-11 14:25:41 +00:00
|
|
|
flacDecoder->totalFrames = metadata->data.stream_info.total_samples;
|
2007-03-04 21:32:03 +00:00
|
|
|
|
2013-10-11 14:25:41 +00:00
|
|
|
[flacDecoder willChangeValueForKey:@"properties"];
|
|
|
|
[flacDecoder didChangeValueForKey:@"properties"];
|
|
|
|
|
|
|
|
flacDecoder->hasStreamInfo = YES;
|
|
|
|
}
|
2005-06-02 18:16:43 +00:00
|
|
|
}
|
|
|
|
|
2007-03-04 21:32:03 +00:00
|
|
|
void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
|
2005-06-02 18:16:43 +00:00
|
|
|
{
|
2007-02-24 20:36:27 +00:00
|
|
|
//Do nothing?
|
2005-06-02 18:16:43 +00:00
|
|
|
}
|
|
|
|
|
2007-03-04 21:32:03 +00:00
|
|
|
- (BOOL)open:(id<CogSource>)s
|
2005-06-02 18:16:43 +00:00
|
|
|
{
|
2007-03-04 21:32:03 +00:00
|
|
|
[self setSource:s];
|
2005-06-02 18:16:43 +00:00
|
|
|
|
2007-03-04 21:32:03 +00:00
|
|
|
decoder = FLAC__stream_decoder_new();
|
2005-06-02 18:16:43 +00:00
|
|
|
if (decoder == NULL)
|
|
|
|
return NO;
|
|
|
|
|
2007-03-04 21:32:03 +00:00
|
|
|
if (FLAC__stream_decoder_init_stream(decoder,
|
|
|
|
ReadCallback,
|
|
|
|
([source seekable] ? SeekCallback : NULL),
|
|
|
|
([source seekable] ? TellCallback : NULL),
|
|
|
|
([source seekable] ? LengthCallback : NULL),
|
|
|
|
([source seekable] ? EOFCallback : NULL),
|
|
|
|
WriteCallback,
|
|
|
|
MetadataCallback,
|
|
|
|
ErrorCallback,
|
2016-05-05 20:05:39 +00:00
|
|
|
(__bridge void *)(self)
|
2007-03-04 21:32:03 +00:00
|
|
|
) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
|
|
|
|
{
|
2005-06-02 18:16:43 +00:00
|
|
|
return NO;
|
2007-03-04 21:32:03 +00:00
|
|
|
}
|
2005-06-02 18:16:43 +00:00
|
|
|
|
2007-03-04 21:32:03 +00:00
|
|
|
FLAC__stream_decoder_process_until_end_of_metadata(decoder);
|
2005-06-02 18:16:43 +00:00
|
|
|
|
2007-11-24 20:16:27 +00:00
|
|
|
blockBuffer = malloc(SAMPLE_blockBuffer_SIZE);
|
2007-02-27 23:56:52 +00:00
|
|
|
|
2005-06-02 18:16:43 +00:00
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2007-11-24 20:16:27 +00:00
|
|
|
- (int)readAudio:(void *)buffer frames:(UInt32)frames
|
2005-06-02 18:16:43 +00:00
|
|
|
{
|
2007-11-24 20:16:27 +00:00
|
|
|
int framesRead = 0;
|
|
|
|
int bytesPerFrame = (bitsPerSample/8) * channels;
|
|
|
|
while (framesRead < frames)
|
|
|
|
{
|
|
|
|
if (blockBufferFrames == 0)
|
|
|
|
{
|
|
|
|
if (FLAC__stream_decoder_get_state (decoder) == FLAC__STREAM_DECODER_END_OF_STREAM)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
FLAC__stream_decoder_process_single(decoder);
|
|
|
|
}
|
2007-11-04 03:08:41 +00:00
|
|
|
|
2007-11-24 20:16:27 +00:00
|
|
|
int framesToRead = blockBufferFrames;
|
|
|
|
if (blockBufferFrames > frames)
|
2005-06-02 18:16:43 +00:00
|
|
|
{
|
2007-11-24 20:16:27 +00:00
|
|
|
framesToRead = frames;
|
2005-06-02 18:16:43 +00:00
|
|
|
}
|
|
|
|
|
2007-11-24 20:16:27 +00:00
|
|
|
memcpy(((uint8_t *)buffer) + (framesRead * bytesPerFrame), (uint8_t *)blockBuffer, framesToRead * bytesPerFrame);
|
|
|
|
|
2008-01-23 02:45:57 +00:00
|
|
|
frames -= framesToRead;
|
2007-11-24 20:16:27 +00:00
|
|
|
framesRead += framesToRead;
|
|
|
|
blockBufferFrames -= framesToRead;
|
|
|
|
|
|
|
|
if (blockBufferFrames > 0)
|
|
|
|
{
|
|
|
|
memmove((uint8_t *)blockBuffer, ((uint8_t *)blockBuffer) + (framesToRead * bytesPerFrame), blockBufferFrames * bytesPerFrame);
|
|
|
|
}
|
|
|
|
}
|
2005-06-02 18:16:43 +00:00
|
|
|
|
2007-11-24 20:16:27 +00:00
|
|
|
return framesRead;
|
2005-06-02 18:16:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)close
|
|
|
|
{
|
|
|
|
if (decoder)
|
|
|
|
{
|
2007-03-04 21:32:03 +00:00
|
|
|
FLAC__stream_decoder_finish(decoder);
|
|
|
|
FLAC__stream_decoder_delete(decoder);
|
2005-06-02 18:16:43 +00:00
|
|
|
}
|
2007-11-24 20:16:27 +00:00
|
|
|
if (blockBuffer)
|
2007-02-27 23:56:52 +00:00
|
|
|
{
|
2007-11-24 20:16:27 +00:00
|
|
|
free(blockBuffer);
|
2007-02-27 23:56:52 +00:00
|
|
|
}
|
|
|
|
|
2005-06-02 18:16:43 +00:00
|
|
|
decoder = NULL;
|
2007-11-24 20:16:27 +00:00
|
|
|
blockBuffer = NULL;
|
2005-06-02 18:16:43 +00:00
|
|
|
}
|
|
|
|
|
2016-06-19 19:57:18 +00:00
|
|
|
- (void)dealloc
|
|
|
|
{
|
|
|
|
[self close];
|
|
|
|
}
|
|
|
|
|
2007-11-24 20:16:27 +00:00
|
|
|
- (long)seek:(long)sample
|
2005-06-02 18:16:43 +00:00
|
|
|
{
|
2014-03-26 09:46:36 +00:00
|
|
|
if (!FLAC__stream_decoder_seek_absolute(decoder, sample))
|
|
|
|
return -1;
|
2005-06-05 18:52:35 +00:00
|
|
|
|
2007-11-24 20:16:27 +00:00
|
|
|
return sample;
|
2005-06-02 18:16:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//bs methods
|
2007-11-24 20:16:27 +00:00
|
|
|
- (char *)blockBuffer
|
2005-06-02 18:16:43 +00:00
|
|
|
{
|
2007-11-24 20:16:27 +00:00
|
|
|
return blockBuffer;
|
2005-06-02 18:16:43 +00:00
|
|
|
}
|
2007-11-24 20:16:27 +00:00
|
|
|
- (int)blockBufferFrames
|
2005-06-02 18:16:43 +00:00
|
|
|
{
|
2007-11-24 20:16:27 +00:00
|
|
|
return blockBufferFrames;
|
2005-06-02 18:16:43 +00:00
|
|
|
}
|
2007-11-24 20:16:27 +00:00
|
|
|
- (void)setBlockBufferFrames:(int)frames
|
2005-06-02 18:16:43 +00:00
|
|
|
{
|
2007-11-24 20:16:27 +00:00
|
|
|
blockBufferFrames = frames;
|
2005-06-02 18:16:43 +00:00
|
|
|
}
|
|
|
|
|
2007-03-04 21:32:03 +00:00
|
|
|
- (FLAC__StreamDecoder *)decoder
|
2005-06-02 18:16:43 +00:00
|
|
|
{
|
|
|
|
return decoder;
|
|
|
|
}
|
|
|
|
|
2007-03-04 21:32:03 +00:00
|
|
|
- (void)setSource:(id<CogSource>)s
|
|
|
|
{
|
|
|
|
source = s;
|
|
|
|
}
|
|
|
|
- (id<CogSource>)source
|
|
|
|
{
|
|
|
|
return source;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setEndOfStream:(BOOL)eos
|
|
|
|
{
|
|
|
|
endOfStream = eos;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)endOfStream
|
|
|
|
{
|
|
|
|
return endOfStream;
|
|
|
|
}
|
|
|
|
|
2007-02-24 20:36:27 +00:00
|
|
|
- (NSDictionary *)properties
|
|
|
|
{
|
|
|
|
return [NSDictionary dictionaryWithObjectsAndKeys:
|
|
|
|
[NSNumber numberWithInt:channels],@"channels",
|
|
|
|
[NSNumber numberWithInt:bitsPerSample],@"bitsPerSample",
|
|
|
|
[NSNumber numberWithFloat:frequency],@"sampleRate",
|
2007-11-24 20:16:27 +00:00
|
|
|
[NSNumber numberWithDouble:totalFrames],@"totalFrames",
|
2007-05-27 15:11:30 +00:00
|
|
|
[NSNumber numberWithBool:[source seekable]], @"seekable",
|
2007-02-27 23:56:52 +00:00
|
|
|
@"big",@"endian",
|
2007-02-24 20:36:27 +00:00
|
|
|
nil];
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *)fileTypes
|
|
|
|
{
|
2007-10-14 18:39:58 +00:00
|
|
|
return [NSArray arrayWithObjects:@"flac", nil];
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *)mimeTypes
|
|
|
|
{
|
|
|
|
return [NSArray arrayWithObjects:@"audio/x-flac", nil];
|
2007-02-24 20:36:27 +00:00
|
|
|
}
|
|
|
|
|
Implemented support for multiple decoders per file name extension, with a floating point priority control per interface. In the event that more than one input is registered to a given extension, and we match that extension, it will be passed off to an instance of the multi-decoder wrapper, which will try opening the file with all of the decoders in order of priority, until either one of them accepts it, or all of them have failed. This paves the way for adding a VGMSTREAM input, so I can give it a very low priority, since it has several formats that are verified by file name extension only. All current inputs have been given a priority of 1.0, except for CoreAudio, which was given a priority of 0.5, because it contains an MP3 and AC3 decoders that I'd rather not use if I don't have to.
2013-10-21 17:54:11 +00:00
|
|
|
+ (float)priority
|
|
|
|
{
|
|
|
|
return 1.0;
|
|
|
|
}
|
|
|
|
|
2005-06-02 18:16:43 +00:00
|
|
|
@end
|