cog/Plugins/Flac/FlacDecoder.m

319 lines
7.9 KiB
Objective-C

//
// FlacDecoder.m
// zyVorbis
//
// Created by Vincent Spader on 1/25/05.
// Copyright 2005 Vincent Spader All rights reserved.
//
#import "FlacDecoder.h"
@implementation FlacDecoder
FLAC__StreamDecoderReadStatus ReadCallback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
{
FlacDecoder *flacDecoder = (FlacDecoder *)client_data;
*bytes = [[flacDecoder source] read:buffer amount:*bytes];
if(*bytes < 0) {
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
}
else if(*bytes == 0) {
[flacDecoder setEndOfStream:YES];
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
}
else {
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
}
FLAC__StreamDecoderSeekStatus SeekCallback(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
{
FlacDecoder *flacDecoder = (FlacDecoder *)client_data;
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)
{
FlacDecoder *flacDecoder = (FlacDecoder *)client_data;
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)
{
FlacDecoder *flacDecoder = (FlacDecoder *)client_data;
return (FLAC__bool)[flacDecoder endOfStream];
}
FLAC__StreamDecoderLengthStatus LengthCallback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
{
FlacDecoder *flacDecoder = (FlacDecoder *)client_data;
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;
}
}
FLAC__StreamDecoderWriteStatus WriteCallback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const sampleBuffer[], void *client_data)
{
FlacDecoder *flacDecoder = (FlacDecoder *)client_data;
void *buffer = [flacDecoder buffer];
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)
alias8 = buffer;
for(sample = 0; sample < frame->header.blocksize; ++sample) {
for(channel = 0; channel < frame->header.channels; ++channel) {
*alias8++ = (int8_t)sampleBuffer[channel][sample];
}
}
break;
case 16:
// Interleave the audio, converting to big endian byte order
alias16 = buffer;
for(sample = 0; sample < frame->header.blocksize; ++sample) {
for(channel = 0; channel < frame->header.channels; ++channel) {
*alias16++ = (int16_t)OSSwapHostToBigInt16((int16_t)sampleBuffer[channel][sample]);
}
}
break;
case 24:
// Interleave the audio (no need for byte swapping)
alias8 = buffer;
for(sample = 0; sample < frame->header.blocksize; ++sample) {
for(channel = 0; channel < frame->header.channels; ++channel) {
audioSample = sampleBuffer[channel][sample];
*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
alias32 = buffer;
for(sample = 0; sample < frame->header.blocksize; ++sample) {
for(channel = 0; channel < frame->header.channels; ++channel) {
*alias32++ = OSSwapHostToBigInt32(sampleBuffer[channel][sample]);
}
}
default:
NSLog(@"Error, unsupported sample size.");
}
[flacDecoder setBufferAmount:frame->header.blocksize * frame->header.channels * (frame->header.bits_per_sample/8)];
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
void MetadataCallback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
{
FlacDecoder *flacDecoder = (FlacDecoder *)client_data;
flacDecoder->channels = metadata->data.stream_info.channels;
flacDecoder->frequency = metadata->data.stream_info.sample_rate;
flacDecoder->bitsPerSample = metadata->data.stream_info.bits_per_sample;
flacDecoder->length = ((double)metadata->data.stream_info.total_samples*1000.0)/flacDecoder->frequency;
[flacDecoder willChangeValueForKey:@"properties"];
[flacDecoder didChangeValueForKey:@"properties"];
}
void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
{
//Do nothing?
}
- (BOOL)open:(id<CogSource>)s
{
[self setSource:s];
decoder = FLAC__stream_decoder_new();
if (decoder == NULL)
return NO;
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,
self
) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
{
return NO;
}
FLAC__stream_decoder_process_until_end_of_metadata(decoder);
buffer = malloc(SAMPLE_BUFFER_SIZE);
return YES;
}
- (int)fillBuffer:(void *)buf ofSize:(UInt32)size
{
int count;
int numread;
if (bufferAmount == 0)
{
if (FLAC__stream_decoder_get_state (decoder) == FLAC__STREAM_DECODER_END_OF_STREAM)
{
return 0;
}
FLAC__stream_decoder_process_single(decoder);
}
count = bufferAmount;
if (bufferAmount > size)
{
count = size;
}
memcpy(buf, buffer, count);
bufferAmount -= count;
if (bufferAmount > 0)
memmove((char *)buffer, &((char *)buffer)[count], bufferAmount);
if (count < size)
numread = [self fillBuffer:(&((char *)buf)[count]) ofSize:(size - count)];
else
numread = 0;
return count + numread;
}
- (void)close
{
if (decoder)
{
FLAC__stream_decoder_finish(decoder);
FLAC__stream_decoder_delete(decoder);
}
if (buffer)
{
free(buffer);
}
[self setSource:nil];
decoder = NULL;
buffer = NULL;
}
- (double)seekToTime:(double)milliseconds
{
FLAC__stream_decoder_seek_absolute(decoder, frequency * ((double)milliseconds/1000.0));
return milliseconds;
}
//bs methods
- (char *)buffer
{
return buffer;
}
- (int)bufferAmount
{
return bufferAmount;
}
- (void)setBufferAmount:(int)amount
{
bufferAmount = amount;
}
- (FLAC__StreamDecoder *)decoder
{
return decoder;
}
- (void)setSource:(id<CogSource>)s
{
[s retain];
[source release];
source = s;
}
- (id<CogSource>)source
{
return source;
}
- (void)setEndOfStream:(BOOL)eos
{
endOfStream = eos;
}
- (BOOL)endOfStream
{
return endOfStream;
}
- (NSDictionary *)properties
{
return [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:channels],@"channels",
[NSNumber numberWithInt:bitsPerSample],@"bitsPerSample",
[NSNumber numberWithFloat:frequency],@"sampleRate",
[NSNumber numberWithDouble:length],@"length",
[NSNumber numberWithBool:[source seekable]], @"seekable",
@"big",@"endian",
nil];
}
+ (NSArray *)fileTypes
{
return [NSArray arrayWithObjects:@"flac", nil];
}
+ (NSArray *)mimeTypes
{
return [NSArray arrayWithObjects:@"audio/x-flac", nil];
}
@end