aboutsummaryrefslogtreecommitdiff
path: root/src/ReadFlac.cpp.seekable
diff options
context:
space:
mode:
Diffstat (limited to 'src/ReadFlac.cpp.seekable')
-rw-r--r--src/ReadFlac.cpp.seekable398
1 files changed, 398 insertions, 0 deletions
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 <m_pd.h>
+#include "ReadFlac.h"
+#include <iostream>
+
+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