From 5e05f47d61ebad8aee6c3831912b21ad5dcc36e3 Mon Sep 17 00:00:00 2001 From: "B. Bogart" Date: Sat, 13 Aug 2005 01:16:59 +0000 Subject: Initial commit of readanysf~ 0.13.1 for August svn path=/trunk/externals/august/readanysf~/; revision=3426 --- src/ReadFlac.cpp.seekable | 398 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 398 insertions(+) create mode 100644 src/ReadFlac.cpp.seekable (limited to 'src/ReadFlac.cpp.seekable') diff --git a/src/ReadFlac.cpp.seekable b/src/ReadFlac.cpp.seekable new file mode 100644 index 0000000..17992b9 --- /dev/null +++ b/src/ReadFlac.cpp.seekable @@ -0,0 +1,398 @@ +/* + * readanysf~ external for pd. + * + * Copyright (C) 2003,2004 August Black + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ReadFlac.cpp + * + * much of the code comes from FLAC input plugin for Winamp3 + * distributed with the flac source under the GPL + * Copyright (C) 2000,2001,2002,2003 Josh Coalson + */ + +#ifdef READ_FLAC + +//#include +#include "ReadFlac.h" +#include + +extern "C" { +#include "FLAC/metadata.h" +}; + +using namespace std; + +ReadFlac::ReadFlac( Input *input ) { + in=input; + needs_seek = false; + seek_sample = 0; + samples_in_reservoir =0; + abort_flag = false; + decoder = NULL; + filelength = 0; +} + +ReadFlac::~ReadFlac() { + cout << "exiting FLAC ..." << endl; + //exit(1); + cleanup(); +} + +bool ReadFlac::Initialize( ) { + + + //@@@ to be really "clean" we should go through the reader instead of directly to the file... + if(!FLAC__metadata_get_streaminfo(in->get_filename(), &streaminfo)) { + cout << "what the fuck" << endl; + return 1; + } + + //length_msec = lengthInMsec(); + /*cout << "FLAC:<%ihz:%ibps:%dch>", + streaminfo.data.stream_info.sample_rate, + streaminfo.data.stream_info.bits_per_sample, + streaminfo.data.stream_info.channels); //@@@ fix later + */ + + samplerate = (double)streaminfo.data.stream_info.sample_rate; + num_channels = streaminfo.data.stream_info.channels; + lengthinseconds = streaminfo.data.stream_info.total_samples/samplerate; + + filelength = in->SeekEnd(0); + filelength = in->SeekCur(0); + in->SeekSet(0); + + decoder = FLAC__seekable_stream_decoder_new(); + if(decoder == 0) + return false; + FLAC__seekable_stream_decoder_set_md5_checking(decoder, false); + FLAC__seekable_stream_decoder_set_read_callback(decoder, readCallback_); + FLAC__seekable_stream_decoder_set_seek_callback(decoder, seekCallback_); + FLAC__seekable_stream_decoder_set_tell_callback(decoder, tellCallback_); + FLAC__seekable_stream_decoder_set_length_callback(decoder, lengthCallback_); + FLAC__seekable_stream_decoder_set_eof_callback(decoder, eofCallback_); + FLAC__seekable_stream_decoder_set_write_callback(decoder, writeCallback_); + FLAC__seekable_stream_decoder_set_metadata_callback(decoder, metadataCallback_); + FLAC__seekable_stream_decoder_set_error_callback(decoder, errorCallback_); + FLAC__seekable_stream_decoder_set_client_data(decoder, this); + + if(FLAC__seekable_stream_decoder_init(decoder) != FLAC__SEEKABLE_STREAM_DECODER_OK) { + cleanup(); + return false; + } + if(!FLAC__seekable_stream_decoder_process_until_end_of_metadata(decoder)) { + cleanup(); + return false; + } + + return true; +} + + + +int ReadFlac::Decode(float *buffer, int size) { + + if(decoder == NULL) + return 0; + + if(needs_seek) { + FLAC__seekable_stream_decoder_seek_absolute(decoder, seek_sample); + //cout << "seeking " << seek_sample << " samples" << endl; + needs_seek = false; + } + + //while (samples_in_reservoir < 576) { + //if (samples_in_reservoir < 576) { + if(FLAC__seekable_stream_decoder_get_state(decoder) == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) { + cout << "FLAC: end of file" << endl; + return 0; + } else if(!FLAC__seekable_stream_decoder_process_single(decoder)) { + + //ErrorCheck( FLAC__seekable_stream_decoder_get_state(decoder) ); + //ErrorCheck( FLAC__seekable_stream_decoder_finish(decoder) ); + //ErrorCheck( FLAC__seekable_stream_decoder_init(decoder) ); + //FLAC__seekable_stream_decoder_reset(decoder); + //FLAC__seekable_stream_decoder_flush(decoder); + cout << "FLAC: no process single " << endl; + //break; + //exit(1); + //return 0; + //return samples_in_reservoir; + } + //} + + int n = samples_in_reservoir; // > 576 ? samples_in_reservoir: 576; + const unsigned channels = streaminfo.data.stream_info.channels; + + if(samples_in_reservoir == 0) { + //cout << "FLAC: reservoir is empty" << endl; + return 0; + } else { + + //const unsigned bits_per_sample = streaminfo.data.stream_info.bits_per_sample; + //const unsigned bytes_per_sample = (bits_per_sample+7)/8; + //const unsigned sample_rate = streaminfo.data.stream_info.sample_rate; + unsigned i; + //16 > WHDR2 + 2 ? 16 : WHDR2 + 2 + + //unsigned delta; + + + for(i = 0; i < n*channels; i++) + buffer[i] = (float) ( reservoir[i]/ 32768.0 ); + + + samples_in_reservoir = 0; + + //const int bytes = n * channels * bytes_per_sample; + } + + //if(eof) + //return 0; + + return n*channels; //1; +} + +bool ReadFlac::Rewind() { + needs_seek = true; + seek_sample = 0; + samples_in_reservoir = 0; + //ErrorCheck( FLAC__seekable_stream_decoder_get_state(decoder) ); + //FLAC__seekable_stream_decoder_seek_absolute(decoder, 0); + return true; +} + +bool ReadFlac::PCM_seek(long bytes) { + + if ( bytes < (long) streaminfo.data.stream_info.total_samples ) { + needs_seek = true; + //bool ret = FLAC__seekable_stream_decoder_seek_absolute(decoder, bytes); + //if (ret) { + //samples_in_reservoir = 0; + //FLAC__seekable_stream_decoder_flush(decoder); + //cout << "successfull seeking" << endl; + //return true; + // }else { + //cout << "UNsuccessfull seeking" << endl; + //return false; + //} + seek_sample = bytes; + return true; + } else { + cout << " GOT HERE " << endl; + return false; + } +} + +bool ReadFlac::TIME_seek(double seconds) { + + //lengthInMsec(); + if ( seconds < lengthinseconds ) { + //cout << "FLAC: time seek" << endl; + needs_seek = true; + seek_sample = (FLAC__uint64)(seconds * streaminfo.data.stream_info.sample_rate); + return true; + } else { + + return false; + } + +} + + +void ReadFlac::cleanup() +{ + if(decoder) { + FLAC__seekable_stream_decoder_finish(decoder); + FLAC__seekable_stream_decoder_delete(decoder); + decoder = NULL; + } +} + +FLAC__SeekableStreamDecoderReadStatus ReadFlac::readCallback_(const FLAC__SeekableStreamDecoder *decoder, + FLAC__byte buffer[], + unsigned *bytes, + void *client_data) { + ReadFlac *instance = (ReadFlac*)client_data; + *bytes = instance->in->Read( (char *)buffer, *bytes); + if (*bytes == 0) { + cout << "FLAC: read returned 0" << endl; + return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; + } else { + return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK; + } +} + +FLAC__SeekableStreamDecoderSeekStatus ReadFlac::seekCallback_(const FLAC__SeekableStreamDecoder *decoder, + FLAC__uint64 absolute_byte_offset, + void *client_data) { + + //if (!client_data) + //return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR; + + ReadFlac *instance = (ReadFlac*)client_data; + //if (!instance) + //return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR; + + instance->ErrorCheck( FLAC__seekable_stream_decoder_get_state(decoder) ); + + //if (absolute_byte_offset < 0) + //absolute_byte_offset = 0; + long pos = instance->in->SeekSet( (long)absolute_byte_offset ) ; + if ( pos == -1 ) { + cout << "COULD NOT seek " << absolute_byte_offset << " bytes" << endl; + return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR; + } else { + //cout << "seeked %ld bytes", pos); + return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK; + } +} + + +FLAC__SeekableStreamDecoderTellStatus ReadFlac::tellCallback_(const FLAC__SeekableStreamDecoder *decoder, + FLAC__uint64 *absolute_byte_offset, + void *client_data) { + ReadFlac *instance = (ReadFlac*)client_data; + + long pos = instance->in->SeekCur( *absolute_byte_offset ); + if ( pos != -1 ) { + *absolute_byte_offset = pos; + //cout << "FLAC: tell is ok" << endl; + return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK; + } else { + cout << "FLAC: tell is NOT ok" << endl; + return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR; + } +} + +FLAC__SeekableStreamDecoderLengthStatus ReadFlac::lengthCallback_(const FLAC__SeekableStreamDecoder *decoder, + FLAC__uint64 *stream_length, + void *client_data) { + ReadFlac *instance = (ReadFlac*)client_data; + *stream_length = (FLAC__uint64)instance->filelength; + return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK; +} + +FLAC__bool ReadFlac::eofCallback_(const FLAC__SeekableStreamDecoder *decoder, + void *client_data) { + ReadFlac *instance = (ReadFlac*)client_data; + long pos = instance->in->SeekCur(0); + if ( pos == instance->filelength ) { + //instance->in->SeekSet(pos); + cout << "FLAC: eofCallback: it is EOF" << endl; + //exit(1); + return 1; + } else { + //post ("FLAC: eofCallback: not eof %ld, filelength %ld", pos, instance->filelength); + //instance->in->SeekSet(pos); + return 0; + } +} + +FLAC__StreamDecoderWriteStatus ReadFlac::writeCallback_(const FLAC__SeekableStreamDecoder *decoder, + const FLAC__Frame *frame, + const FLAC__int32 * const buffer[], + void *client_data) { + ReadFlac *instance = (ReadFlac*)client_data; + //const unsigned bps = instance->streaminfo.data.stream_info.bits_per_sample; + const unsigned channels = instance->streaminfo.data.stream_info.channels; + const unsigned wide_samples = frame->header.blocksize; + unsigned wide_sample, sample, channel; + + (void)decoder; + + if(instance->abort_flag) { + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + //cout << "FLAC: blocksize = " << wide_samples << endl; + for(sample = instance->samples_in_reservoir*channels, wide_sample = 0; + wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + instance->reservoir[sample] = (FLAC__int16)buffer[channel][wide_sample]; + + instance->samples_in_reservoir += wide_samples; + + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +void ReadFlac::metadataCallback_(const FLAC__SeekableStreamDecoder *decoder, + const FLAC__StreamMetadata *metadata, + void *client_data) { + ReadFlac *instance = (ReadFlac*)client_data; + (void)decoder; + + //cout << "FLAC: metadata callback" << endl; + if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { + instance->streaminfo = *metadata; + + if(instance->streaminfo.data.stream_info.bits_per_sample != 16) { + cout << "\nFLAC: bps is not 16 ..Aboorting ...\n" << endl; + instance->abort_flag = true; + //exit(1); + return; + } + } +} + +void ReadFlac::errorCallback_(const FLAC__SeekableStreamDecoder *decoder, + FLAC__StreamDecoderErrorStatus status, + void *client_data) { + ReadFlac *instance = (ReadFlac*)client_data; + (void)decoder; + if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC) { + cout << "FLAC: error callback - lost sync, trying reset,flush" << endl; + FLAC__seekable_stream_decoder_reset(instance->decoder); + FLAC__seekable_stream_decoder_flush(instance->decoder); + //instance->abort_flag = true; + } +} + +void ReadFlac::ErrorCheck(int state) { + switch (state) { + case FLAC__SEEKABLE_STREAM_DECODER_SEEKING: + //cout << "SEEKING " << endl; + break; + case FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM : + cout << "END_OF_STREAM " << endl; + break; + case FLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR : + cout << "MEMORY_ALLOCATION_ERROR " << endl; + break; + case FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR : + cout << "STREAM_DECODER_ERROR " << endl; + break; + case FLAC__SEEKABLE_STREAM_DECODER_READ_ERROR : + cout << "READ_ERROR " << endl; + break; + case FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR : + cout << "SEEK_ERROR " << endl; + break; + case FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK : + cout << "INVALID_CALLBACK " << endl; + break; + case FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED : + cout << "UNINITIALIZED " << endl; + break; + case FLAC__SEEKABLE_STREAM_DECODER_OK : + default: + cout << "OK" << endl; + break; + } +} + + +#endif -- cgit v1.2.1