Update of /cvsroot/pure-data/externals/august/readanysf~/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26207/src
Added Files: Fifo.cpp Input.cpp InputFile.cpp InputStream.cpp Makefile.am Makefile.in ReadFlac.cpp ReadFlac.cpp.seekable ReadMad.cpp ReadRaw.cpp ReadVorbis.cpp Readsf.cpp config.h.in main.cpp simple.pd Log Message: Initial commit of readanysf~ 0.13.1 for August
--- NEW FILE: ReadMad.cpp --- /* * readanysf~ external for pd. * * Copyright (C) 2003 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 * * ReadMad.cpp || much code studied from Andy Lo-A-Foe <www.alsaplayer.org> */ #ifdef READ_MAD
//#include <m_pd.h> #include "ReadMad.h"
#include <iostream> using namespace std;
#define mad_f_tofloat(x) ((float) ((x) / (float) (1L << MAD_F_FRACBITS)))
ReadMad::ReadMad (Input * input) { in = input; bytes_avail = 0; // IMPORTANT!!! //map_offset = 0; // do we need this? bitrate = 0; samplesperframe = 0; samplestotal = 0; time = 0; nr_frames = 0; lengthinseconds = 0.0; }
ReadMad::~ReadMad () { if (mad_init) { mad_synth_finish (&synth); mad_frame_finish (&frame); mad_stream_finish (&stream); mad_init = 0; } }
bool ReadMad::fill_buffer (long newoffset) { size_t bytes_read; if (!seekable) return false; if ( in->SeekSet( offset + newoffset ) == -1 ) return false; bytes_read = in->Read( (void *)mad_map, MAD_BUFSIZE ); if (bytes_read == 0) { //cout << "ReadMad:: fillbuf offset, got zero on read, EOF?" << endl; return 0; } if (bytes_read < 0 ) { //cout << "ReadMad:: fillbuf offset got -1 on read, ERROR?" << endl; return 0; } bytes_avail = bytes_read; return true; //map_offset = newoffset; }
bool ReadMad::fill_buffer () { size_t bytes_read, br; memmove (mad_map, mad_map + MAD_BUFSIZE - bytes_avail, bytes_avail); br = bytes_read = MAD_BUFSIZE - bytes_avail; bytes_read = in->Read ((void *) (mad_map + bytes_avail), bytes_read); if (bytes_read == 0) { //cout << "ReadMad:: got zero on read, EOF? br=%d",br); return 0; } if (bytes_read < 0 ) { //cout << "ReadMad:: got -1 on read, ERROR?" << endl; return 0; } //map_offset += (MAD_BUFSIZE - bytes_avail); bytes_avail += bytes_read; return 1; }
int ReadMad::Decode (float *buffer, int size) { struct mad_pcm *pcm; mad_fixed_t const *left_ch; mad_fixed_t const *right_ch; int nsamples; int nchannels; bool ret =1; //if (MAD_BUFSIZE > size) //return false;
if (bytes_avail < 3072) { //cout << "Filling buffer = %d,%d", bytes_avail,map_offset + MAD_BUFSIZE - bytes_avail); ret = fill_buffer (); // map_offset + MAD_BUFSIZE - bytes_avail);
if ( ret == 0 && in->get_recover() ) { // got EOF on stream, but we want to recover nsamples = 0; while (nsamples < size/2) buffer[nsamples++] = 0.0; return nsamples; } mad_stream_buffer (&stream, mad_map, bytes_avail); }
if (mad_frame_decode (&frame, &stream) == -1) { if (!MAD_RECOVERABLE (stream.error)) { mad_frame_mute (&frame); return 0; } else { if ( !ret ) { // error or EOF // not if stream input goes down, fill buffer with // cout << "ReadMad:: seems we have end of file" << endl; return 0; } // cout << "ReadMad::MAD error: (not fatal)" << endl; } }
mad_synth_frame (&synth, &frame); { pcm = &synth.pcm; nsamples = pcm->length; nchannels = pcm->channels; left_ch = pcm->samples[0]; right_ch = pcm->samples[1]; int x = 0; while (nsamples--) { buffer[x++] = mad_f_tofloat (*(left_ch++)); if (nchannels == 2) buffer[x++] = mad_f_tofloat (*(right_ch++)); } }
bytes_avail = stream.bufend - stream.next_frame; //if (pcm->length != 1152) //cout << " %d", pcm->length); return pcm->length * nchannels; }
ssize_t ReadMad::find_initial_frame (uint8_t * buf, int size) { uint8_t *data = buf; int ext_header = 0; int pos = 0; ssize_t header_size = 0; while (pos < (size - 10)) { if (pos == 0 && data[pos] == 0x0d && data[pos + 1] == 0x0a) pos += 2; if (data[pos] == 0xff && (data[pos + 1] == 0xfb || data[pos + 1] == 0xfa || data[pos + 1] == 0xf3 || data[pos + 1] == 0xe2 || data[pos + 1] == 0xe3)) { //error("found header at %d", pos); return pos; } if (pos == 0 && data[pos] == 0x0d && data[pos + 1] == 0x0a) { return -1; // Let MAD figure this out } if (pos == 0 && (data[pos] == 'I' && data[pos + 1] == 'D' && data[pos + 2] == '3')) { header_size = (data[pos + 6] << 21) + (data[pos + 7] << 14) + (data[pos + 8] << 7) + data[pos + 9]; /* syncsafe integer */ if (data[pos + 5] & 0x10) { ext_header = 1; header_size += 10; /* 10 byte extended header */ }
header_size += 10;
if (header_size > MAD_BUFSIZE) { //cout << "Header larger than 32K (%d)", header_size); return header_size; } return header_size; } else if (data[pos] == 'R' && data[pos + 1] == 'I' && data[pos + 2] == 'F' && data[pos + 3] == 'F') { pos += 4; //error("Found a RIFF header" << endl; while (pos < size) { if (data[pos] == 'd' && data[pos + 1] == 'a' && data[pos + 2] == 't' && data[pos + 3] == 'a') { pos += 8; /* skip 'data' and ignore size */ return pos; } else pos++; } cout << "MAD debug: invalid header" << endl; return -1; } else if (pos == 0 && data[pos] == 'T' && data[pos + 1] == 'A' && data[pos + 2] == 'G') { return 128; /* TAG is fixed 128 bytes, we assume! */ } else { pos++; } } cout << "MAD debug: potential problem file or unhandled info block" << endl; //cout << "next 4 bytes = %x %x %x %x (index = %d, size = %d)", //data[header_size], data[header_size + 1], //data[header_size + 2], data[header_size + 3], //header_size, size); return -1; }
bool ReadMad::Initialize () {
if (in->get_format () == FORMAT_HTTP_MP3) seekable = 0; else seekable = 1; //assume seekable if its a file mad_synth_init (&synth); mad_stream_init (&stream); mad_frame_init (&frame); memset (&xing, 0, sizeof (struct xing)); xing_init (&xing); mad_init = 1;
fill_buffer (); offset = find_initial_frame (mad_map, bytes_avail < MAD_BUFSIZE ? bytes_avail : MAD_BUFSIZE);
if (offset < 0) { offset = 0; for (int i=0; i < 10; i++) { // lets try this a coupla times to sync on a proper header fill_buffer(); offset = find_initial_frame (mad_map, bytes_avail < MAD_BUFSIZE ? bytes_avail : MAD_BUFSIZE); if ( offset > 0) { //cout << "ReadMad:: found Header on %d try\n", i); break; } } if ( offset < 0 ) { cout << "ReadMad::mad_open() couldn't find valid MPEG header\n" << endl; return false; } }
if (offset > bytes_avail) { //cout << "ReadMad:: offset > bytes_avail " << endl; if ( !fill_buffer() ) { cout << "ReadMad::couldn't read from InputFIFO, bailing..." << endl; return 0; } mad_stream_buffer (&stream, mad_map, bytes_avail); } else { //cout << "ReadMad:: not sure why we are here, offset = %d, bytes_avail = %d", offset, bytes_avail); mad_stream_buffer (&stream, mad_map + offset, bytes_avail - offset); bytes_avail -= offset; }
if ((mad_frame_decode (&frame, &stream) != 0)) { //error("MAD error: %s", error_str(data->stream.error, data->str)); switch (stream.error) { case MAD_ERROR_BUFLEN: cout << "MAD_ERROR_BUFLEN" << endl; return false; //return 0; case MAD_ERROR_LOSTSYNC: if (mad_header_decode (&frame.header, &stream) == -1) { cout << "ReadMad::Invalid header (" << in->get_filename () << ")" << endl; } mad_stream_buffer (&stream, stream.this_frame, bytes_avail - (stream.this_frame - mad_map)); bytes_avail -= (stream.this_frame - mad_map); //cout << "avail = %d", data->bytes_avail); mad_frame_decode (&frame, &stream); break; case MAD_ERROR_BADBITALLOC: cout << "MAD_ERROR_BADBITALLOC" << endl; return false; //return 0; case MAD_ERROR_BADCRC: cout << "MAD_ERROR_BADCRC" << endl; //error_str( stream.error, str)); case 0x232: case 0x235: break; default: cout << "ReadMad:: no valid frame found at start" << endl; //cout << "No valid frame found at start (pos: %d, error: 0x%x --> %x %x %x %x) (%s)", offset, stream.error, stream.this_frame[0], stream.this_frame[1], stream.this_frame[2], stream.this_frame[3], in->get_filename ()); return false; //return 0; } } if (stream.error != MAD_ERROR_LOSTSYNC) if (xing_parse (&xing, stream.anc_ptr, stream.anc_bitlen) == 0) { // We use the xing data later on }
num_channels = (frame.header.mode == MAD_MODE_SINGLE_CHANNEL) ? 1 : 2; samplerate = (double) frame.header.samplerate; bitrate = frame.header.bitrate; mad_synth_frame (&synth, &frame);
/* Calculate some values */ bytes_avail = stream.bufend - stream.next_frame; if (seekable) { int64_t lframes;
long oldpos = in->SeekCur (0); in->SeekEnd (0);
filesize = in->SeekCur (0); filesize -= offset;
in->SeekSet (oldpos); if (bitrate) lengthinseconds = (float) ((filesize * 8) / (bitrate)); else lengthinseconds = 0.0; time = (long) lengthinseconds;
samplesperframe = 32 * MAD_NSBSAMPLES (&frame.header); samplestotal = (long) (samplerate * (time + 1)); lframes = samplestotal / samplesperframe; nr_frames = xing.frames ? xing.frames : (int) lframes; }
mad_init = 1;
if (xing.frames) { //cout << "xing.frames " << xing.frames << endl; seekable = 1; }
return true; //return 1; }
bool ReadMad::Rewind () { if (in == NULL) return false; if (!seekable) return true; seek_bytes (0); return true; }
bool ReadMad::PCM_seek (long position) { long byte_offset; if (!seekable) return false; byte_offset = (long) (((double) position / (double) samplestotal) * filesize); seek_bytes (byte_offset); return true; }
bool ReadMad::TIME_seek (double seconds) { //double time = ( filesize * 8) / (bitrate); long byte_offset; if (!seekable) return false; byte_offset = (int) ((seconds / (double) time) * filesize); seek_bytes (byte_offset); return true; }
void ReadMad::seek_bytes (long byte_offset) { struct mad_header header; int skip; mad_header_init (&header);
bytes_avail = 0; skip = 0; //The total size in bytes for any given frame can be calculated with the following formula: //FrameSize = 144 * BitRate / (SampleRate + Padding). // 417.96 bytes: 144 * 128000 / (44100 + 0) if (byte_offset > 4 * 418){ skip = 3; } //(seekpos / song length) * (filelength).
//cout << "byte_offset %ld, position %ld, samplestotal %ld, filesize %ld", // byte_offset, position, samplestotal, filesize); fill_buffer ( byte_offset ); mad_stream_buffer (&stream, mad_map, bytes_avail); skip++; while (skip--) { mad_frame_decode (&frame, &stream); if (skip == 0) mad_synth_frame (&synth, &frame); } bytes_avail = stream.bufend - stream.next_frame; return; }
// /////////////// xing stuff
void ReadMad::xing_init (struct xing *xing) { xing->flags = 0; }
/* * NAME: xing->parse() * DESCRIPTION: parse a Xing VBR header */ int ReadMad::xing_parse (struct xing *xing, struct mad_bitptr ptr, unsigned int bitlen) { if (bitlen < 64 || mad_bit_read (&ptr, 32) != XING_MAGIC) goto fail;
xing->flags = mad_bit_read (&ptr, 32); bitlen -= 64;
if (xing->flags & XING_FRAMES) { if (bitlen < 32) goto fail;
xing->frames = mad_bit_read (&ptr, 32); bitlen -= 32; }
if (xing->flags & XING_BYTES) { if (bitlen < 32) goto fail;
xing->bytes = mad_bit_read (&ptr, 32); bitlen -= 32; }
if (xing->flags & XING_TOC) { int i;
if (bitlen < 800) goto fail;
for (i = 0; i < 100; ++i) xing->toc[i] = mad_bit_read (&ptr, 8);
bitlen -= 800; }
if (xing->flags & XING_SCALE) { if (bitlen < 32) goto fail;
xing->scale = mad_bit_read (&ptr, 32); bitlen -= 32; }
return 0;
fail: xing->flags = 0; return -1; }
#endif
--- NEW FILE: main.cpp --- /* * 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 * * main.cpp */
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <unistd.h>
#include "main.h"
readanysf::readanysf () { fifo = new Fifo (FIFOSIZE); request = R_NOTHING; state = STATE_IDLE; loop = false; eof = true; format = -1; readsf = NULL; in = NULL; floatmsg = 0.0; cachemsg = 0.0; outtick = 1000; counttick = 0; lengthinseconds = 0.0; sendout = false; src_buffer = (float *) malloc ((Blocksize ()) * 2 * FLOATSIZE);
src_mode = SRC_SINC_FASTEST; src_state = NULL; src_data.input_frames = 0;
AddInAnything (); // add one inlet for any message AddOutSignal ("audio out Left"); AddOutSignal ("audio out Right"); AddOutAnything (); // add one float outlet (has index 2)
FLEXT_ADDMETHOD_ (0, "start", m_start); FLEXT_ADDMETHOD_ (0, "play", m_start); FLEXT_ADDMETHOD_ (0, "pause", m_pause); FLEXT_ADDMETHOD_ (0, "stop", m_stop); FLEXT_ADDMETHOD_ (0, "open", m_open); FLEXT_ADDMETHOD_ (0, "reopen", m_reopen);
FLEXT_ADDMETHOD_ (0, "loop", m_loop_f); FLEXT_ADDMETHOD_ (0, "recover", m_recover); FLEXT_ADDMETHOD_ (0, "set_tick", m_set_tick); FLEXT_ADDMETHOD_ (0, "pcm_seek", m_pcm_seek); FLEXT_ADDMETHOD_ (0, "time_seek", m_time_seek);
FLEXT_ADDMETHOD_ (0, "speed", m_src_factor); //FLEXT_ADDBANG(0,m_bang); FLEXT_CALLMETHOD (m_child); //post("Blocksize = %d", Blocksize()); }
readanysf::~readanysf () {
setSys (STATE_IDLE, R_QUIT); cond.Signal (); if (readsf != NULL) delete (readsf); if (fifo != NULL) delete (fifo); if (in != NULL) delete (in);
}
void readanysf::m_bang () { ToOutBang (2); }
void readanysf::m_loop_f (float f) { if (f == 0.0) { post ("readanysf~:: looping Off"); varmutex.Lock (); loop = false; varmutex.Unlock (); return; } else { post ("readanysf~:: looping On"); varmutex.Lock (); loop = true; varmutex.Unlock (); return; } }
void readanysf::m_recover (float f) { if (f == 0.0) { //dangerous!!!! post ("readanysf~:: stream recover Off"); varmutex.Lock (); if (in != NULL) in->set_recover(false); varmutex.Unlock (); return; } else { post ("readanysf~:: stream recover On"); varmutex.Lock (); if (in != NULL) in->set_recover(true); varmutex.Unlock (); return; } }
void readanysf::m_start () { int st = getState(); if ( st == STATE_STARTUP ) { post("readanysf~:: still starting up....wait a bit please"); m_bang(); return; }
if ( st != STATE_STREAM ) { varmutex.Lock (); eof = false; pcmseek = 0; timeseek = 0.0; //if ( st != STATE_IDLE ) // floatmsg = 0.0; varmutex.Unlock ();
bzero ((void *) src_buffer, sizeof (src_buffer)); if ( readsf == NULL ) { // nothing is opened, lets open it //setSys (STATE_IDLE, R_OPEN); post ("readanysf~:: first select a file."); m_bang(); } else { setSys (STATE_STREAM, R_PROCESS); } } else { post ("readanysf~:: already playing"); } cond.Signal (); return; }
void readanysf::m_time_seek (float f) {
if (f > 0.0) { varmutex.Lock (); timeseek = (double) f; varmutex.Unlock (); setRequest (R_PROCESS); } cond.Signal (); }
void readanysf::m_pcm_seek (int i) {
if (i > 0) { varmutex.Lock (); pcmseek = (long) i; varmutex.Unlock (); setRequest (R_PROCESS); } cond.Signal (); }
void readanysf::m_set_tick (int i) { varmutex.Lock (); if (i > 1) outtick = i; varmutex.Unlock (); }
void readanysf::m_stop () {
setSys (STATE_IDLE, R_STOP); varmutex.Lock (); floatmsg = 0.0; bzero ((void *) src_buffer, sizeof (src_buffer)); varmutex.Unlock (); cond.Signal (); }
void readanysf::m_pause () { setState (STATE_IDLE); cond.Signal (); }
void readanysf::m_open (t_symbol * s) { //cond.Signal(); sprintf (filename, GetString (s)); if (getRequest () != R_OPEN) { //post ("readanysf~:: opening..."); setSys (STATE_IDLE, R_OPEN); varmutex.Lock (); floatmsg = 0.0; pcmseek = 0; timeseek = 0.0; format = -1; varmutex.Unlock ();
ToOutFloat (2, 0.0 ); // send a 0.0 to float output // we are at the beginning of the file
} else { // kill old file ??? post ("readanysf~:: still initailizing old file, please be patient"); } cond.Signal ();
}
void readanysf::m_reopen ( ) { int st = getState(); int rq = getRequest (); post ("readanysf~:: reopening..."); if ( rq == R_NOTHING && filename[0] != 0 ) { setSys (STATE_IDLE, R_OPEN); varmutex.Lock (); floatmsg = 0.0; pcmseek = 0; timeseek = 0.0; format = -1; varmutex.Unlock (); ToOutFloat (2, 0.0 ); // send a 0.0 to float output // we are at the beginning of the file cond.Signal (); } else { setSys (STATE_IDLE, R_PROCESS); cond.Signal (); } }
void readanysf::m_src_factor (float f) { if (src_is_valid_ratio (f)) { varmutex.Lock (); src_factor = (double) f; varmutex.Unlock (); } }
void readanysf::FillFifo () { int ret, wret;
if (readsf == NULL || in == NULL) return; varmutex.Lock (); if (pcmseek) { //post("readanysf~:: seeking.."); if (readsf->PCM_seek (pcmseek)) { floatmsg = pcmseek / samplerate; fifo->Flush (); //setRequest( R_PROCESS ); } pcmseek = 0; } if (timeseek != 0.0) { if (readsf->TIME_seek (timeseek)) { floatmsg = timeseek; fifo->Flush (); //setRequest( R_PROCESS ); } timeseek = 0.0; } varmutex.Unlock ();
while (fifo->FreeSpace () > INOUTSIZE) { // leave enough space for odd chunks
ret = readsf->Decode (read_buffer, READBUFFER);
varmutex.Lock (); cachemsg = in->get_cachesize (); // we should fix this - this is only a relative position // we need to account for FIFO size
floatmsg += (float) (ret / num_channels / samplerate);
varmutex.Unlock ();
if (ret > 0) { wret = fifo->Write ((void *) read_buffer, ret * FLOATSIZE); } else { //post("eof, %d", ret); readsf->Rewind (); //post("Rewound the file"); varmutex.Lock (); floatmsg = 0.0; if (!loop) { //state = STATE_IDLE; //this is premature. we check for eof in m_signal routine eof = true; varmutex.Unlock (); setRequest (R_NOTHING); break; } //else { //post("Should loop here"); //setSys (STATE_STREAM, R_PROCESS); //} varmutex.Unlock ();
} } }
void readanysf::m_child () { int req;
while ((req = getRequest ()) != R_QUIT) { switch (req) {
case R_STOP: if (readsf != NULL) { //post("Trying to kill the readsf"); delete (readsf); readsf = NULL; //post("killed it"); } if (in != NULL) { delete (in); in = NULL; } fifo->Flush (); setSys (STATE_IDLE, R_NOTHING); break;
case R_OPEN: if (readsf != NULL && in != NULL && strcmp (filename, in->get_filename ()) == 0) { // all is well here, we are just opening the same file again // this happens when you open a file , hit play and then try to // open it again post("opening file again..."); fifo->Flush (); readsf->Rewind(); setSys (STATE_IDLE, R_PROCESS); } else { // Set state to STARTUP at begingin of open and make sure to set // it to IDLE or NOTHING after succesfully opening; setState( STATE_STARTUP ); if (readsf != NULL) { delete (readsf); readsf = NULL; } if (in != NULL) { delete (in); in = NULL; } //check if its a stream or file; if ( strcmp( "http://").. if (!strncasecmp (filename, "http://", 7)) { in = new InputStream (); post("Opening stream: %s", filename); } else { in = new InputFile (); post("Opening file: %s", filename); } //if ( in != NULL ) format = in->Open (filename); switch (format) { case FORMAT_WAVE: case FORMAT_AIFF: case FORMAT_NEXT: readsf = new ReadRaw (in); break; #ifdef READ_MAD case FORMAT_HTTP_MP3: case FORMAT_MAD: readsf = new ReadMad (in); break; #endif #ifdef READ_VORBIS case FORMAT_VORBIS: case FORMAT_HTTP_VORBIS: readsf = new ReadVorbis (in); break; #endif #ifdef READ_FLAC case FORMAT_FLAC: //post("readanysf~:: trying to make a ReadFLAC"); readsf = new ReadFlac (in); break; #endif default: // probably got here 'cause we opend a stream and didn't connect // InputStream will then return a -1 on Open m_bang(); break; } fifo->Flush (); if (format >= 0 && readsf != NULL) { if (readsf->Initialize ()) { //post("readanysf~:: successfully initialized, format = %d", format); varmutex.Lock (); num_channels = readsf->get_channels (); samplerate = readsf->get_samplerate (); if (num_channels > 2) num_channels = 2; src_factor = Samplerate() / samplerate; if (!src_is_valid_ratio (src_factor) ) src_factor = 1.0; lengthinseconds = readsf->get_lengthinseconds(); sendout = true; varmutex.Unlock(); setSys (STATE_IDLE, R_PROCESS); fifo->Flush (); } else { post("Readanysf:: Couldn't initialize the file/stream!!!, sucks for you dude"); if (readsf != NULL) // safe without locking ??? delete (readsf); if ( in != NULL) // es bueno aqui? delete (in); setSys (STATE_IDLE, R_NOTHING); readsf = NULL; in = NULL; // muy importante varmutex.Lock (); filename[0] = 0; varmutex.Unlock (); m_bang (); } } else { // not a recognized file type post ("file not recognized, format = %d", format); setSys (STATE_IDLE, R_NOTHING); m_bang (); } } break; case R_PROCESS: FillFifo (); //take care of mutex locking in FillFifo routine case R_NOTHING: default: cond.Wait (); } } return; }
int readanysf::m_resample (int frames) { unsigned int size, out_gen;
if (src_factor == 1.0) { size = frames * num_channels * FLOATSIZE; fifo->Read ((void *) src_buffer, size); return size / FLOATSIZE; }
if (src_channels != num_channels) { src_state = src_delete (src_state); src_state = src_new (src_mode, num_channels, &src_error); src_channels = num_channels; }
src_data.output_frames = frames; out_gen = 0;
while (src_data.output_frames > 0) { if (src_data.input_frames <= 0) { if (src_factor > 1.0) size = frames * num_channels * FLOATSIZE; else size = 1024 * num_channels * FLOATSIZE; fifo->Read ((void *) pd_buffer, size); src_data.data_in = pd_buffer; src_data.data_out = src_buffer; src_data.input_frames = size / FLOATSIZE / num_channels; }
src_data.src_ratio = src_factor; if ((src_error = src_process (src_state, &src_data))) { post ("readanysf~:: SRC error: %s", src_strerror (src_error)); return 0; } else { if (src_data.output_frames_gen == 0) { break; } src_data.data_in += src_data.input_frames_used * num_channels; src_data.input_frames -= src_data.input_frames_used; src_data.output_frames -= src_data.output_frames_gen; out_gen += src_data.output_frames_gen; } } //if (out_gen != frames) { //post("outgen %d, frames %d", out_gen, frames); //}
return out_gen * num_channels; }
FLEXT_NEW_DSP ("readanysf~", readanysf)
void readanysf::m_signal (int n, float *const *in, float *const *out) { float *outs1 = out[0]; float *outs2 = out[1]; t_atom lst[2];
varmutex.Lock (); if (counttick++ > outtick) { SetString (lst[0], "cache"); SetFloat (lst[1], cachemsg); ToOutAnything (2, GetSymbol (lst[0]), 2, lst + 1); counttick = 0; } varmutex.Unlock ();
if (getState () == STATE_STREAM) { varmutex.Lock (); int ch = num_channels; int size = m_resample (n); bool endoffile = eof; int fmt = format;
if (counttick == 0) { //lock it here? //ToOutFloat (2, floatmsg - (FIFOSECONDS / ch)); ToOutFloat ( 2, floatmsg ); } varmutex.Unlock ();
if (size < n * ch) { if (endoffile) // we should do a mutex here!!! { fifo->Flush (); if (fmt >= FORMAT_HTTP_MP3) { post("-------------------> End of Stream"); setSys (STATE_IDLE, R_STOP); cond.Signal (); } else { setSys (STATE_IDLE, R_PROCESS); } m_bang (); // bang out at end of file } else { //post("not EOF, but buffer is empty"); } //if not eof, buffer is stuck somehow so lets keep crunching. //in any case fill from size returned to the end with zeros for (int x = size; x < (n * ch); x += ch) { *outs1++ = 0.0; *outs2++ = 0.0; } }
if (fifo->FreeSpace () > INOUTSIZE) { if (getRequest () == R_PROCESS && !endoffile) { cond.Signal (); // tell the child that the fifo is hungry } }
if (ch > 1) { for (int x = 0; x < size; x += 2) { *outs1++ = src_buffer[x]; *outs2++ = src_buffer[x + 1]; } } else { //mono for (int x = 0; x < size; x++) { *outs1++ = src_buffer[x]; *outs2++ = src_buffer[x]; } }
} else { // we're not streaming. just zero out the audio outlets varmutex.Lock (); if (sendout) { SetString (lst[0], "length"); SetFloat (lst[1], lengthinseconds); ToOutAnything (2, GetSymbol (lst[0]), 2, lst + 1); SetString (lst[0], "rate"); SetFloat (lst[1], (float) samplerate); ToOutAnything (2, GetSymbol (lst[0]), 2, lst + 1); sendout = false; } varmutex.Unlock ();
while (n--) { *outs1++ = 0.0; *outs2++ = 0.0; } } }
int readanysf::getState () { int i; sysmut.Lock (); i = state; sysmut.Unlock (); return i; }
int readanysf::getRequest () { int i; sysmut.Lock (); i = request; sysmut.Unlock (); return i; }
void readanysf::setSys (int sys, int req) { sysmut.Lock (); state = sys; request = req; sysmut.Unlock (); return; }
void readanysf::setState (int i) { sysmut.Lock (); state = i; sysmut.Unlock (); return; }
void readanysf::setRequest (int i) { sysmut.Lock (); request = i; sysmut.Unlock (); return; }
--- NEW FILE: Fifo.cpp --- #include <stdio.h> #include "Fifo.h"
Fifo::Fifo () { astate = 0; // not allocated buffer = NULL; totsize = 0; datasize = 0; start = 0; pthread_mutex_init (&mut, 0); }
Fifo::Fifo (unsigned int size) { buffer = new char[size]; if (buffer != NULL) { astate = 1; totsize = size; datasize = 0; start = 0; } else { astate = 0; totsize = 0; datasize = 0; start = 0; } pthread_mutex_init (&mut, 0); }
Fifo::~Fifo () { pthread_mutex_lock (&mut); if (astate) delete buffer; pthread_mutex_unlock (&mut); }
void Fifo::Flush () { pthread_mutex_lock (&mut); astate = 1; //totsize = size; datasize = 0; start = 0; pthread_mutex_unlock (&mut); //for (int x =0; x < sizeof(buffer); x++) { // buffer[x] = 0; //} }
int Fifo::ReAlloc (unsigned int size) { pthread_mutex_lock (&mut); if (astate) delete buffer; buffer = new char[size]; if (buffer != NULL) { astate = 1; totsize = size; datasize = 0; start = 0; pthread_mutex_unlock (&mut); } else { astate = 0; totsize = 0; datasize = 0; start = 0; pthread_mutex_unlock (&mut); return -1; } return 0; }
void * Fifo::Read (void *buf, unsigned int &len) { pthread_mutex_lock (&mut); if (len > datasize) len = datasize; unsigned int rest; if (len > (totsize - start)) rest = len - (totsize - start); else rest = 0; unsigned int first = len - rest; memcpy (buf, buffer + start, first); memcpy ((char *) buf + first, buffer, rest); datasize -= len; start += len; if (start >= totsize) start = rest; //if (datasize == 0) printf("in fifo READ, data is zero\n"); pthread_mutex_unlock (&mut); return buf; }
int Fifo::Write (void *buf, unsigned int len) { pthread_mutex_lock (&mut); unsigned int end; end = start + datasize; if (end > totsize) end = end - totsize; if (len > (totsize - datasize)) { pthread_mutex_unlock (&mut); return -1; } unsigned int rest; if ((len + end) > totsize) rest = (len + end) - totsize; else rest = 0; unsigned int first = len - rest; memcpy (buffer + end, buf, first); memcpy (buffer, (char *) buf + first, rest);
datasize += len; //if (datasize == 0) printf("in fifo WRITE, data is zero\n"); pthread_mutex_unlock (&mut); return len; }
unsigned int Fifo::FreeSpace (void) { // do we need locks here? int x; pthread_mutex_lock (&mut); x = totsize - datasize; pthread_mutex_unlock (&mut); return x; }
unsigned int Fifo::UsedSpace (void) { int x; pthread_mutex_lock (&mut); x = datasize; pthread_mutex_unlock (&mut); return x; }
--- NEW FILE: config.h.in --- /* config.h.in. Generated automatically from configure.in by autoheader. */
--- NEW FILE: Makefile.in --- # Makefile.in generated by automake 1.6.3 from Makefile.am. # @configure_input@
# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 # Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE.
@SET_MAKE@ SHELL = @SHELL@
srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@
bindir = @bindir@ sbindir = @sbindir@ libexecdir = @libexecdir@ datadir = @datadir@ sysconfdir = @sysconfdir@ sharedstatedir = @sharedstatedir@ localstatedir = @localstatedir@ libdir = @libdir@ infodir = @infodir@ mandir = @mandir@ includedir = @includedir@ oldincludedir = /usr/include pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = ..
ACLOCAL = @ACLOCAL@ AUTOCONF = @AUTOCONF@ AUTOMAKE = @AUTOMAKE@ AUTOHEADER = @AUTOHEADER@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_HEADER = $(INSTALL_DATA) transform = @program_transform_name@ NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : host_alias = @host_alias@ host_triplet = @host@
EXEEXT = @EXEEXT@ OBJEXT = @OBJEXT@ PATH_SEPARATOR = @PATH_SEPARATOR@ AMTAR = @AMTAR@ AWK = @AWK@ CPP = @CPP@ CXX = @CXX@ DEPDIR = @DEPDIR@ FLC_CFLAGS = @FLC_CFLAGS@ FLC_LIBS = @FLC_LIBS@ FLEXT_CFLAGS = @FLEXT_CFLAGS@ FLEXT_LIBS = @FLEXT_LIBS@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ MAD_CFLAGS = @MAD_CFLAGS@ MAD_LIBS = @MAD_LIBS@ PACKAGE = @PACKAGE@ PTHREAD_LIBS = @PTHREAD_LIBS@ SRC_LIBS = @SRC_LIBS@ STRIP = @STRIP@ VERSION = @VERSION@ VORBIS_CFLAGS = @VORBIS_CFLAGS@ VORBIS_LIBS = @VORBIS_LIBS@ am__include = @am__include@ am__quote = @am__quote@ install_sh = @install_sh@ pd_suffix = @pd_suffix@
INCLUDES = \ -I/usr/local/include/ -I/usr/local/lib/pd/flext/ -I../include/
CFLAGS = \ @FLEXT_CFLAGS@ @VORBIS_CFLAGS@ @MAD_CFLAGS@ @FLC_CFLAGS@
CXXFLAGS = \ @FLEXT_CFLAGS@ @VORBIS_CFLAGS@ @MAD_CFLAGS@ @FLC_CFLAGS@
bin_PROGRAMS = readanysf~.@pd_suffix@
readanysf__@pd_suffix@_SOURCES = \ Fifo.cpp\ Input.cpp\ InputFile.cpp\ InputStream.cpp\ ReadRaw.cpp\ Readsf.cpp\ main.cpp\ ReadMad.cpp\ ReadVorbis.cpp \ ReadFlac.cpp
#readanysf__pd_linux_LDFLAGS = -L/usr/local/lib/pd/flext/
#### IMPORTANT!!! FLEXT_LIBS HAS TO CUM FIRST readanysf__@pd_suffix@_LDADD = \ @FLEXT_LIBS@ @PTHREAD_LIBS@ @SRC_LIBS@ @FLEXT_LIBS@ @VORBIS_LIBS@ @MAD_LIBS@ @FLC_LIBS@
subdir = src mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = bin_PROGRAMS = readanysf~.@pd_suffix@$(EXEEXT) PROGRAMS = $(bin_PROGRAMS)
am_readanysf__@pd_suffix@_OBJECTS = Fifo.$(OBJEXT) Input.$(OBJEXT) \ InputFile.$(OBJEXT) InputStream.$(OBJEXT) ReadRaw.$(OBJEXT) \ Readsf.$(OBJEXT) main.$(OBJEXT) ReadMad.$(OBJEXT) \ ReadVorbis.$(OBJEXT) ReadFlac.$(OBJEXT) readanysf__@pd_suffix@_OBJECTS = $(am_readanysf__@pd_suffix@_OBJECTS) readanysf__@pd_suffix@_DEPENDENCIES = readanysf__@pd_suffix@_LDFLAGS =
DEFS = @DEFS@ DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/Fifo.Po ./$(DEPDIR)/Input.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/InputFile.Po ./$(DEPDIR)/InputStream.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/ReadFlac.Po ./$(DEPDIR)/ReadMad.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/ReadRaw.Po ./$(DEPDIR)/ReadVorbis.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/Readsf.Po ./$(DEPDIR)/main.Po CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ DIST_SOURCES = $(readanysf__@pd_suffix@_SOURCES) DIST_COMMON = Makefile.am Makefile.in SOURCES = $(readanysf__@pd_suffix@_SOURCES)
all: all-am
.SUFFIXES: .SUFFIXES: .cpp .o .obj $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) cd $(top_srcdir) && \ $(AUTOMAKE) --foreign src/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) $(mkinstalldirs) $(DESTDIR)$(bindir) @list='$(bin_PROGRAMS)'; for p in $$list; do \ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ if test -f $$p \ ; then \ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f"; \ $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f; \ else :; fi; \ done
uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; for p in $$list; do \ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ rm -f $(DESTDIR)$(bindir)/$$f; \ done
clean-binPROGRAMS: -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) readanysf~.@pd_suffix@$(EXEEXT): $(readanysf__@pd_suffix@_OBJECTS) $(readanysf__@pd_suffix@_DEPENDENCIES) @rm -f readanysf~.@pd_suffix@$(EXEEXT) $(CXXLINK) $(readanysf__@pd_suffix@_LDFLAGS) $(readanysf__@pd_suffix@_OBJECTS) $(readanysf__@pd_suffix@_LDADD) $(LIBS)
mostlyclean-compile: -rm -f *.$(OBJEXT) core *.core
distclean-compile: -rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Fifo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Input.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InputFile.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InputStream.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ReadFlac.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ReadMad.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ReadRaw.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ReadVorbis.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Readsf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
distclean-depend: -rm -rf ./$(DEPDIR)
.cpp.o: @AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ @AMDEP_TRUE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<
.cpp.obj: @AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ @AMDEP_TRUE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ $(CXXCOMPILE) -c -o $@ `cygpath -w $<` CXXDEPMODE = @CXXDEPMODE@ uninstall-info-am:
ETAGS = etags ETAGSFLAGS =
tags: TAGS
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(ETAGS_ARGS)$$tags$$unique" \ || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique
GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here
distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
top_distdir = .. distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
distdir: $(DISTFILES) @list='$(DISTFILES)'; for file in $$list; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkinstalldirs) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS)
installdirs: $(mkinstalldirs) $(DESTDIR)$(bindir)
install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am
install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic:
clean-generic:
distclean-generic: -rm -f Makefile $(CONFIG_CLEAN_FILES)
maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am
clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
distclean: distclean-am
distclean-am: clean-am distclean-compile distclean-depend \ distclean-generic distclean-tags
dvi: dvi-am
dvi-am:
info: info-am
info-am:
install-data-am:
install-exec-am: install-binPROGRAMS
install-info: install-info-am
install-man:
installcheck-am:
maintainer-clean: maintainer-clean-am
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic
uninstall-am: uninstall-binPROGRAMS uninstall-info-am
.PHONY: GTAGS all all-am check check-am clean clean-binPROGRAMS \ clean-generic distclean distclean-compile distclean-depend \ distclean-generic distclean-tags distdir dvi dvi-am info \ info-am install install-am install-binPROGRAMS install-data \ install-data-am install-exec install-exec-am install-info \ install-info-am install-man install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic tags uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-info-am
# Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT:
--- NEW FILE: Input.cpp --- #include "Input.h" #include <iostream.h>
Input::Input () { fd = 0; format = -1; verbosity = 1; recover=false; }
Input::~Input () { }
int Input::Open (const char *pathname) { return -1; }
int Input::Close () { return -1; }
int Input::Read (void *buf, unsigned int count) { return -1; }
long Input::SeekSet (long offset) { return -1; }
long Input::SeekCur (long offset) { return -1; }
long Input::SeekEnd (long offset) { return -1; } float Input::get_cachesize () { return 0.0; }
--- NEW FILE: Readsf.cpp --- /* * readanysf~ external for pd. * * Copyright (C) 2003 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 * * Readsf.cpp */
#include "Readsf.h"
Readsf::Readsf( ) { }
Readsf::Readsf( Input *input ) { in = input; num_channels = 1; samplerate = 44100; lengthinseconds =0; } Readsf::~Readsf() {
}
int Readsf::Decode(float *buffer, int size) { if (CHUNKSIZE > (unsigned int)size) return 0; for(unsigned int c=0;c< CHUNKSIZE;c++) { buffer[c] = 0.0; } return CHUNKSIZE; }
bool Readsf::Initialize() { //printf( "%s\n", filename); return false; } bool Readsf::Rewind() { return false; }
bool Readsf::PCM_seek(long bytes) { return false; }
bool Readsf::TIME_seek(double seconds) { return false; }
--- NEW FILE: InputStream.cpp --- #include "InputStream.h" #include <iostream> // cout, cerr #include <string> // strcpy, etc.
using namespace std;
int receive (int fd, unsigned char *rcvbuffer, int size) { fd_set set; struct timeval tv; int ret = -1; int selret = -1; tv.tv_sec = 1; tv.tv_usec = 500; FD_ZERO(&set); FD_SET(fd, &set);
selret= select(fd +1, &set, NULL, NULL, &tv); if ( selret > 0 ) { // we can now be certain that ret will return something. ret = recv (fd, rcvbuffer, size, 0); if (ret < 0 ) { cerr << "InputStream:: receive error" << endl; return -1; } return ret; } else if ( selret == -1 ){ cerr << "InputStream:: receive: select timed out, returned "<< selret << endl; return -1; } // return zero...means keep on selecting return 0; }
void * fill_infifo (void *zz) { int ret, wret, last_type, last_state; unsigned char tmp[SOCKET_READSIZE]; InputStream *instream = (InputStream *) zz; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &last_type); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_state);
pthread_mutex_lock (instream->get_mutex ()); instream->set_threaded(true); pthread_cond_signal (instream->get_condition ()); pthread_mutex_unlock (instream->get_mutex ()); //cout << "signalled parent thread" << endl; while ( 1 ) { while (instream->get_fifo()->FreeSpace() > SOCKET_READSIZE + 576) { // it's possible to hang here, watch this if ( instream->get_quit() ) break; ret = receive (instream->get_fd() , tmp, SOCKET_READSIZE); if (ret > 0){ wret = instream->get_fifo()->Write ((void *) tmp, ret * sizeof (unsigned char)); } else if ( ret == -1){ // got -1 on recieve. ...this means select failed and there is no data cerr << "InputStream:: fill_infifo: select failed, our socket must have died" << endl; if ( instream->get_recover() ) { cout << "InputStream:: try to reconnect to server..." << endl; if ( instream->socket_connect () < 0 ) { cout << "InputStream:: tried to recover stream but socket connect failed" <<endl; break; } } else { break; } } else { // got 0?? on recieve. ...select timed out, cause there wasn't any data //cerr << "InputStream: fill_infifo: select timed out, no data. ret = " << ret << endl; // keep on truckin' until we get a select and recv that sticks } } if ( instream->get_quit() ) break; //cerr << "InputStream: fifo is full" << endl; pthread_mutex_lock (instream->get_mutex ()); pthread_cond_wait (instream->get_condition (), instream->get_mutex ()); pthread_mutex_unlock (instream->get_mutex ());
} instream->set_threaded(false); return NULL; }
InputStream::InputStream () { fd = 0; format = -1; threaded = false; port = 0; infifo = new Fifo( STREAM_FIFOSIZE ); quit = false; recover = false; verbosity = 1; pthread_mutex_init(&mut, 0); pthread_cond_init(&cond, 0); }
InputStream::~InputStream () { quit = true; void *status;
if (threaded ) { //cout << "canceling thread" << endl; pthread_cond_signal ( &cond ); //pthread_cancel( childthread ); pthread_join( childthread, &status); threaded = -1; //cout << "thread canceled" << endl; } delete infifo; }
// Open() returns the file type, either WAV, MP3, OGG, etc. see input.h // this is a blocking call, in order to use the open command we need // to figure out the format (ogg, mp3, etc). this has to block.
int InputStream::Open (const char *pathname) { int rettype, thret; filename = pathname; if (verbosity > 1) cout << "trying to open a socket connection" << endl; SetUrl (pathname);
rettype = socket_connect( ); //hostname, mountpoint, port ); if (rettype < 0) { // couldn't connect or got a bad filetype cerr << "InputStream:: Couldn't connect or got a bad filetype" <<endl; return -1; } // start thread here to fill infifo //cout << "creating thread" << endl; thret = pthread_create(&childthread, NULL, fill_infifo, (void *)this); if ( thret!= 0 ) return -1; //wait for thread to be created. pthread_mutex_lock( &mut ); while ( !threaded ) pthread_cond_wait( &cond, &mut ); pthread_mutex_unlock( &mut ); //cout << "threaded = " << threaded << "rettype = " << rettype << endl;
while ( get_fifo()->UsedSpace () < (unsigned int)(STREAM_FIFOSIZE / 2) ) { usleep(100); // we need to wait here for some of the input buffer to fill. //cout << "waiting for HTTP buffer to fill " << get_fifo()->UsedSpace () <<endl; } /* if ( rettype == FORMAT_HTTP_VORBIS) { cout << "---------->Lets try to flush fifo and fill again" <<endl; get_fifo()->Flush(); pthread_cond_signal ( &cond ); while ( get_fifo()->UsedSpace () < (unsigned int)(8500*2) ) { usleep(1000); // we need to wait here for some of the input buffer to fill. cout << "waiting for HTTP buffer to fill " << get_fifo()->UsedSpace () <<endl; } }*/ return rettype; }
int InputStream::Close () { // returns zero on success, or -1 if an error occurred return sys_closesocket (fd); }
int InputStream::Read (void *buf, unsigned int count) { //if (quit) return -1; // return negative if the childthread exits //and sets quit true infifo->Read( buf , count); pthread_cond_signal ( &cond ); return count; }
long InputStream::SeekSet (long offset) { return -1; }
long InputStream::SeekCur (long offset) { return -1; }
long InputStream::SeekEnd (long offset) { return -1; }
int InputStream::get_line( char * str, int sock, int maxget) { int i = 0; while(i < maxget - 1) {
if ( recv(sock, str + i, 1, 0) <= 0 ) { cerr << "InputStream : could not read from socket" << endl; sys_closesocket(sock); return (-1); } if ( str[i] == '\n' ) break; if( str[i] == 0x0A) /* leave at end of line */ break; if ( str[i] != '\r' ) i++; } str[i] = '\0'; return i; }
// connect to shoutcast server int InputStream::socket_connect ( ) { struct sockaddr_in server; struct hostent *hp; int flags; // variables used for communication with server string strtmp; // tmp string for manipulating server strings string line, parsed; // string for parsing x-audicast vars char strret[STRBUF_SIZE]; // returned string from server
fd_set fdset; struct timeval tv; int relocate = false; std::string::size_type ret;
fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (fd < 0) { if (verbosity > 0) cerr << "InputStream: internal error while attempting to open socket" << endl; return (-1); }
//connect socket using hostname server.sin_family = AF_INET; hp = gethostbyname (hostname.c_str ());
if (hp == NULL) { if (verbosity > 0) cerr << "InputStream:: bad host?" << endl; sys_closesocket (fd); return (-1); }
memcpy ((char *) &server.sin_addr, (char *) hp->h_addr, hp->h_length); // assign client port number server.sin_port = htons ((unsigned short) port);
flags = fcntl( fd, F_GETFL, 0); fcntl( fd, F_SETFL, FNDELAY); // make this socket's calls non-blocking // fcntl( fd, F_SETFL, flags | O_NONBLOCK);
if (connect( fd, (struct sockaddr *) &server, sizeof(server) ) == -1 && errno != EINPROGRESS) { /* * If non-blocking connect() couldn't finish, it returns * EINPROGRESS. That's OK, we'll take care of it a little * later, in the select(). But if some other error code was * returned there's a real problem... */ sys_closesocket (fd); return(-1);
} else { //cout << " error is EINPROGRESS " << endl; FD_ZERO (&fdset); FD_SET (fd, &fdset); tv.tv_sec = 1; /* seconds */ tv.tv_usec = 0; /* microseconds */
// you want to do the select on the WRITEablity of the socket, HTTP expects a get // command, so make sure to pass args to both read and write fdset switch (select( fd+1 , &fdset, &fdset, NULL, &tv) ) { /* * select() will return when the socket is ready for action, * or when there is an error, or the when timeout specified * using tval is exceeded without anything becoming ready. */
case 0: // timeout //do whatever you do when you couldn't connect cout << "InputStream:: connect timed out, bailing..." <<endl; sys_closesocket (fd); return (-1); break; case -1: // error cout << "InputStream:: connection error, bailing..." <<endl; sys_closesocket (fd); return (-1); break; default: // your file descriptor is ready... fcntl( fd, F_SETFL, flags); break; } }
// build up stuff we need to send to server // should change it to send GET and then read the header until // it recieves "\n\n", and then parse the header strtmp = "GET /" + mountpoint + " HTTP/1.0 \r\nHost: " + hostname + "\r\nUser-Agent: Readanysf~ 0.5\r\nAccept: */*\r\n\r\n"; if (verbosity > 2) cout << "sending...." << strtmp << endl; if (send (fd, strtmp.c_str (), strtmp.length (), 0) < 0) { if (verbosity > 0) cerr << "InputStream:: could not contact server... " << endl; return (-1); }
get_line( strret , fd , STRBUF_SIZE ) ; strtmp = strret; //cout << strtmp << endl;
ret = strtmp.find ("HTTP", 0); if (ret != string::npos) { /* seems to be IceCast server */ ret = strtmp.find ("302", 0); if (ret != string::npos) { if (verbosity > 0) cerr << "InputStream::need to relocate...not implemented yet, bailing" << endl; relocate = true; return (-1); } ret = strtmp.find ("200", 0); if (ret == string::npos) { if (verbosity > 0) cerr << "InputStream : cannot connect to the (default) stream" << endl; sys_closesocket (fd); return (-1); } if (verbosity > 2) cerr << "everything seems to be fine, now lets parse the server strings" << endl;
// go through header 10 times, line by line. this should be enough. // we only need the Content-Type for checking if it's mp3 or vorbis for (int i = 0; i < 10; i++) { get_line( strret , fd , STRBUF_SIZE ) ; line = strret; //cout << " Got line: " << line << endl; // we could probable parse the Server flag for icecast 1 // or 2 // server type, but that is more trouble than what its // worth parsed = ParseHttp (line, "Server"); if (!parsed.empty ()) if (verbosity > 1) cout << "server" << parsed << endl; parsed = ParseHttp (line, "Content-Type"); if (!parsed.empty ()) { std::string::size_type n; if (verbosity > 1) cout << "Content-Type " << parsed << endl; n = parsed.find ("ogg"); if (n != string::npos) { if (verbosity > 1) cout << "we have an ogg vorbis stream" << endl; format = FORMAT_HTTP_VORBIS; break; // found what we were looking for } n = parsed.find ("mpeg"); if (n != string::npos){ if (verbosity > 1) cout << "we have an Mp3 stream" << endl; format = FORMAT_HTTP_MP3; break; // found what we were looking for } } }
} else { //cout << "not HTTP, could be ICY for shoutcast" << endl; ret = strtmp.find ("ICY 200 OK", 0); if (ret != string::npos) { /* seems to be IceCast server */ // we are only interested in mp3 or ogg content type cout << "we have an ICY Mp3 stream" << endl; format = FORMAT_HTTP_MP3;
} else { cout << "Neither a Shoutcast or Icecast stream, hafta bail." << endl; return -1; } }
return (format); }
// parses string "str" for the item "parse", if found return the part of // "str" after the ":" ex.
string InputStream::ParseHttp (string str, string parse) { std::string::size_type ret;
ret = str.find (parse, 0); if (ret != string::npos) { return str.substr (parse.length () + 1, str.length () - parse.length ()); } return ""; }
int InputStream::SetUrl (const char *url) { string strtmp = url; std::string::size_type p1, p2, tmp;
tmp = strtmp.find ("http://"); if (tmp < 0 || tmp > strtmp.length ()) return 0;
tmp = tmp + 7; strtmp = strtmp.substr (tmp, strtmp.length () - tmp);
p2 = strtmp.find ("/", 0); if (p2 < 0 || p2 > strtmp.length ()) { p2 = strtmp.length(); //cout << "didn't find the / in the url" <<endl; p1 = strtmp.find (":"); if (p1 < 0 || p1 > strtmp.length ()) { port = 80; // set port to default 80 hostname = strtmp; mountpoint = " "; // send blank mntpoint } else { // found the ":", setting port number port = atoi (strtmp.substr (p1 + 1, p2 - p1 -1).c_str ()); hostname = strtmp.substr (0, p1); mountpoint = " "; // send blank mntpoint } return 1; // didn't find the / in the URL } p1 = strtmp.find (":"); if (p1 < 0 || p1 > strtmp.length ()) { // didn't find a ":", that // // means there's no port port = 80; // set port to default 8000 hostname = strtmp.substr (0, p2); mountpoint = strtmp.substr (p2 + 1, strtmp.length () - p2); if (verbosity > 1) cerr << "port is: default " << port << endl; } else { // found the ":", setting port number port = atoi (strtmp.substr (p1 + 1, p2 - p1 - 1).c_str ()); hostname = strtmp.substr (0, p1); mountpoint = strtmp.substr (p2 + 1, strtmp.length () - p2); }
if (verbosity > 2 ) { cout << "port: " << port << endl; cout << "hostname: " << hostname << endl; cout << "mount: " << mountpoint << endl; } return 1; }
float InputStream::get_cachesize() { return (float)infifo->UsedSpace(); } // ~ parsed = ParseHttp( line, "x-audiocast-location" ) ; // ~ if ( !parsed.empty()) cout << parsed << endl; // ~ parsed = ParseHttp( line, "x-audiocast-admin" ) ; // ~ if ( !parsed.empty()) cout << parsed << endl; // ~ parsed = ParseHttp( line, "x-audiocast-server-url" ) ; // ~ if ( !parsed.empty()) cout << parsed << endl; // ~ parsed = ParseHttp( line, "x-audiocast-mount" ) ; // ~ if ( !parsed.empty()) cout << parsed << endl; // ~ parsed = ParseHttp( line, "x-audiocast-name" ) ; // ~ if ( !parsed.empty()) cout << parsed << endl; // ~ parsed = ParseHttp( line, "x-audiocast-description" ) ; // ~ if ( !parsed.empty()) cout << parsed << endl; // ~ parsed = ParseHttp( line, "x-audiocast-url:http" ) ; // ~ if ( !parsed.empty()) cout << parsed << endl; // ~ parsed = ParseHttp( line, "x-audiocast-genre" ) ; // ~ if ( !parsed.empty()) cout << parsed << endl; // ~ parsed = ParseHttp( line, "x-audiocast-bitrate" ) ; // ~ if ( !parsed.empty()) cout << parsed << endl; // ~ parsed = ParseHttp( line, "x-audiocast-public" ) ; // ~ if ( !parsed.empty()) cout << parsed << endl;
--- NEW FILE: ReadVorbis.cpp --- /* * readanysf~ external for pd. * * Copyright (C) 2003 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 * * ReadVorbis.cpp || much code (C) by Olaf Matthes * http://www.akustische-kunst.org/puredata/shout/shout.html */
#ifdef READ_VORBIS
#include "ReadVorbis.h" //#include <m_pd.h>
#include <iostream> using namespace std;
ReadVorbis::ReadVorbis( Input *input) { in = input; seekable = false; callbacks.read_func = read_func; callbacks.seek_func = seek_func; callbacks.close_func = close_func; callbacks.tell_func = tell_func; }
ReadVorbis::~ReadVorbis(){
if ( ov_clear(&vf) != 0) cout << "ReadVorbis::couldn't deconstruct the vorbis file reader" << endl; //if (fp != NULL) { //don't know why, but this will cause a segfault // fclose(fp); //} }
bool ReadVorbis::Initialize( ) {
vorbis_info *vi;
if ( in == NULL ) { return 0; } if ( in->get_format() == FORMAT_HTTP_VORBIS ) { seekable = false; } else seekable = true;
int err = ov_open_callbacks( (void *)in, &vf, NULL, 0, callbacks); if( err < 0 ) { cout << "ReadVorbis:: does not appear to be an Ogg bitstream.\n" << endl; switch (err) { case OV_EREAD: cout << "ReadVorbis:: read from media retuned an error" << endl; break; case OV_ENOTVORBIS: cout << "ReadVorbis:: bistream is not vorbis data" << endl; break; case OV_EVERSION: cout << "ReadVorbis:: vorbis version mismatch" << endl; break; case OV_EBADHEADER: cout << "ReadVorbis:: invalid vorbis btistream header" << endl; break; case OV_EFAULT: cout << "ReadVorbis:: internal logic fault" << endl; break; default: cout << "ReadVorbis:: general error on ov_open_callbacks" << endl; break; } return false; }
vi=ov_info(&vf,-1); samplerate = (double)vi->rate; num_channels = vi->channels; if ( in->get_format() == FORMAT_HTTP_VORBIS ) lengthinseconds = 0.0; else lengthinseconds = (double)ov_time_total(&vf, -1); //cout << "ReadVorbis: opening url: [%s] %ld (Hz), %d chan(s)", // fullurl, vi->rate, vi->channels);
return true; }
int ReadVorbis::Decode(float *buffer, int size) { long ret = 0; int current_section; float **buftmp; int x=0; if (CHUNKSIZE > (unsigned int)size) return 0;
ret = ov_read_float(&vf, &buftmp , CHUNKSIZE, ¤t_section); if (ret == 0 ) { // This means it is a definite end of file, lets return zero here. return 0; } else if (ret <= 0) { switch (ret) { case OV_HOLE: cout << "ReadVorbis:: there was an interruption in the data. " << endl; cout << "one of: garbage between pages, loss of sync followed" << " by recapture, or a corrupt page" << endl; break; case OV_EBADLINK: cout << "ReadVorbis:: an invalid stream section was supplied " << "to libvorbisfile, or the requested link is corrupt" << endl; break; default: cout << "ReadVorbis:: unknown error on ov_read_float" << endl; break; }
for(int j = 0; j < 1024; j++) { buffer[x++] = 0.0; } return 512;
} else {
// we should check here to see if ret is larger than size! for(int j = 0; j < ret; j++) { buffer[x++] = buftmp[0][j]; if (num_channels == 2) buffer[x++] = buftmp[1][j]; } } //cout << "x %d", x); return x; //ret;
}
size_t ReadVorbis::read_func(void *ptr, size_t size, size_t nmemb, void *datasource) {
Input * tmpin = ( Input *)datasource; unsigned int get = size*nmemb; size_t ret; // cout << "ReadVorbis:: calling read function" << endl;
ret = tmpin->Read( ptr, get);
//cout << "read from fifo, get %d, ret %d, size %d, nmemb %d", //get, ret,size,nmemb );
return ret;//size*nmemb; }
int ReadVorbis::seek_func(void *datasource, ogg_int64_t offset, int whence) { // InputStream will always return -1 Input * tmpin = ( Input *)datasource; switch ( whence ) { case SEEK_SET: return tmpin->SeekSet( offset ); break; case SEEK_CUR: return tmpin->SeekCur( offset ); break; case SEEK_END: return tmpin->SeekEnd( offset ); break; default: return -1; break; }
}
int ReadVorbis::close_func(void *datasource) {
cout << "ReadVorbis:: calling close function" << endl; //ov_clear(&vf); //return tmpin->Close(); return 0; }
long ReadVorbis::tell_func(void *datasource) { // InputStream will always return -1 Input * tmpin = ( Input *)datasource; return tmpin->SeekCur( 0 );
}
bool ReadVorbis::Rewind() { ov_pcm_seek(&vf, 0); return true; // need to return true here for fill_buffer of main.cpp }
bool ReadVorbis::PCM_seek(long bytes) { int ret = ov_pcm_seek(&vf, bytes); if ( ret == 0) return true; else { switch (ret) { case OV_ENOSEEK: cout << "ReadVorbis:: stream not seekable" << endl; break; case OV_EINVAL: ret = ov_pcm_seek(&vf, 0); if (ret == 0) return true; else cout << "ReadVorbis:: invalid argument" << endl; break; case OV_EREAD: cout << "ReadVorbis:: read returned an error" << endl; break; case OV_EOF: cout << "ReadVorbis:: End of File" << endl; break; case OV_EBADLINK: cout << "ReadVorbis:: invalid stream section" << endl; break; default: cout << "ReadVorbis:: some other seek error PCM_seek" << endl; break; } return false; } }
bool ReadVorbis::TIME_seek(double seconds) { int ret = ov_time_seek(&vf, seconds); if ( ret == 0) return true; else { switch (ret) { case OV_ENOSEEK: cout << "ReadVorbis:: stream not seekable" << endl; break; case OV_EINVAL: cout << "ReadVorbis:: invalid argument" << endl; break; case OV_EREAD: cout << "ReadVorbis:: read returned an error" << endl; break; case OV_EOF: cout << "ReadVorbis:: End of File" << endl; break; case OV_EBADLINK: cout << "ReadVorbis:: invalid stream section" << endl; break; default: cout << "ReadVorbis:: some other seek error Time_seek" << endl; break; } return false; } }
#endif
--- NEW FILE: InputFile.cpp --- #include "InputFile.h" #include <iostream.h>
InputFile::InputFile () { fd = 0; format = -1; recover = false; }
InputFile::~InputFile () { }
// returns the file type, either WAV, MP3, OGG, etc. see input.h int InputFile::Open (const char *pathname) { char buf[18]; filename = pathname;
fd = open (pathname, O_RDONLY);
if (fd == -1) { // error opening the file, no dice return -1; }
int bytesread = read (fd, buf, 16);
if (bytesread < 4) { // fill is too fucking small dude close (fd); return -1; }
if (!strncmp (buf, ".snd", 4)) { //rewind the stream if ((lseek (fd, 0, SEEK_SET)) == -1) return -1; return format = FORMAT_NEXT; //, bigendian = 1; } else if (!strncmp (buf, "dns.", 4)) { //rewind the stream if ((lseek (fd, 0, SEEK_SET)) == -1) return -1; return format = FORMAT_NEXT; //, bigendian = 0; } else if (!strncmp (buf, "RIFF", 4)) { if (bytesread < 12 || strncmp (buf + 8, "WAVE", 4)) { cout << "bad header ?" << endl; return -1; } //rewind the stream if ((lseek (fd, 0, SEEK_SET)) == -1) return -1; return format = FORMAT_WAVE; //, bigendian = 0; } else if (!strncmp (buf, "FORM", 4)) { if (bytesread < 12 || strncmp (buf + 8, "AIFF", 4)) return -1; //goto badheader; //rewind the stream if ((lseek (fd, 0, SEEK_SET)) == -1) return -1; return format = FORMAT_AIFF; //, bigendian = 1; }
else if (!strncmp (buf, "OggS", 4)) { //rewind the stream if ((lseek (fd, 0, SEEK_SET)) == -1) return -1; #ifdef READ_VORBIS return format = FORMAT_VORBIS; #else return -1; #endif }
else if (!strncmp (buf, "ID3", 3)) { //rewind the stream if ((lseek (fd, 0, SEEK_SET)) == -1) return -1; #ifdef READ_MAD return format = FORMAT_MAD; #else return -1; #endif }
else if (!strncasecmp (buf, "FLAC", 4)) { // } else if( !strncasecmp(thefile+strlen(thefile)-4,".fla",4) ) { //rewind the stream if ((lseek (fd, 0, SEEK_SET)) == -1) return -1; #ifdef READ_FLAC return format = FORMAT_FLAC; #else return -1; #endif } else { unsigned int sync; sync = (unsigned char) buf[0]; sync = sync << 3; sync |= ((unsigned char) buf[1] & 0xE0) >> 5; if (sync == 0x7FF) { //rewind the stream if ((lseek (fd, 0, SEEK_SET)) == -1) return -1; #ifdef READ_MAD return format = FORMAT_MAD; #else return -1; #endif } else if (!strncasecmp (pathname + strlen (pathname) - 4, ".mp3", 4)) { //trust that its mp3 //rewind the stream if ((lseek (fd, 0, SEEK_SET)) == -1) return -1; cout << "doesnt seem like its an mp3, but if you say so" << endl; #ifdef READ_MAD return format = FORMAT_MAD; #else return -1; #endif } }
return -1;
}
int InputFile::Close () { return close (fd); }
int InputFile::Read (void *buf, unsigned int count) { return read (fd, buf, count); }
long InputFile::SeekSet (long offset) { return lseek (fd, offset, SEEK_SET); }
long InputFile::SeekCur (long offset) { return lseek (fd, offset, SEEK_CUR); }
long InputFile::SeekEnd (long offset) { return lseek (fd, offset, SEEK_END); }
--- NEW FILE: Makefile.am ---
INCLUDES =\ -I/usr/local/include/ -I/usr/local/lib/pd/flext/ -I../include/
CFLAGS = \ @FLEXT_CFLAGS@ @VORBIS_CFLAGS@ @MAD_CFLAGS@ @FLC_CFLAGS@
CXXFLAGS = \ @FLEXT_CFLAGS@ @VORBIS_CFLAGS@ @MAD_CFLAGS@ @FLC_CFLAGS@
bin_PROGRAMS = readanysf~.@pd_suffix@
readanysf__@pd_suffix@_SOURCES = \ Fifo.cpp\ Input.cpp\ InputFile.cpp\ InputStream.cpp\ ReadRaw.cpp\ Readsf.cpp\ main.cpp\ ReadMad.cpp\ ReadVorbis.cpp \ ReadFlac.cpp
#readanysf__pd_linux_LDFLAGS = -L/usr/local/lib/pd/flext/
#### IMPORTANT!!! FLEXT_LIBS HAS TO CUM FIRST readanysf__@pd_suffix@_LDADD = \ @FLEXT_LIBS@ @PTHREAD_LIBS@ @SRC_LIBS@ @FLEXT_LIBS@ @VORBIS_LIBS@ @MAD_LIBS@ @FLC_LIBS@
--- NEW FILE: simple.pd --- #N canvas 119 113 595 349 10; #X obj 150 223 dac~; #X msg 149 123 play; #X msg 232 123 stop; #X msg 187 123 pause; #X obj 29 25 hsl 100 15 0 15 0 0 empty empty empty -2 -6 0 8 -44926 -1 -1 661 1; #X floatatom 95 40 5 0 0 0 - - -; #X msg 26 45 speed $1; #X msg 170 41 loop $1; #X obj 170 25 tgl 15 0 empty empty empty 0 -6 0 8 -44926 -1 -1 0 1 ; #X obj 214 282 nbx 4 10 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 10 -241291 -1 -1 172.072 256; #X obj 260 271 nbx 6 10 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 10 -260818 -1 -1 0 256; #X obj 307 255 nbx 5 10 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 10 -260241 -1 -1 44100 256; #X obj 353 242 nbx 7 12 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 10 -259729 -1 -1 34273 256; #X msg 21 269 ; pd dsp 1; #X obj 21 244 loadbang; #X obj 149 180 readanysf~; #X obj 53 163 r rany; #X obj 26 72 s rany; #X obj 170 67 s rany; #X msg 253 50 recover 1; #N canvas 381 279 570 425 testfiles 0; #X msg 308 151 open Schnucki.wav; #X msg 42 111 open http://fro.at:8008/24k; #X msg 308 132 open Schnucki.ogg; #X msg 308 112 open Schnucki.mp3; #X obj 43 372 s rany; #X msg 42 131 open http://66.28.68.70:8000/; #X msg 43 151 open http://212.23.57.33:8010; #X msg 308 172 open Schnucki.fla; #X msg 309 191 open Schnucki.aif; #X text 301 85 some test files; #X text 42 87 open some test streams; #X connect 0 0 4 0; #X connect 1 0 4 0; #X connect 2 0 4 0; #X connect 3 0 4 0; #X connect 5 0 4 0; #X connect 6 0 4 0; #X connect 7 0 4 0; #X connect 8 0 4 0; #X restore 389 31 pd testfiles; #N canvas 0 22 450 300 testseek 0; #X msg 145 167 pcm_seek $1; #X floatatom 145 147 5 0 0 0 - - -; #X obj 145 192 s rany; #X floatatom 149 60 5 0 0 0 - - -; #X obj 149 99 s rany; #X msg 149 77 time_seek $1; #X obj 184 147 * 44100; #X msg 145 126 13; #X msg 149 41 13; #X obj 204 124 f; #X obj 208 102 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 -1; #X floatatom 240 100 5 0 0 0 - - -; #X msg 268 130 81; #X msg 268 155 19; #X connect 0 0 2 0; #X connect 1 0 6 0; #X connect 3 0 5 0; #X connect 5 0 4 0; #X connect 6 0 0 0; #X connect 7 0 1 0; #X connect 8 0 3 0; #X connect 9 0 6 0; #X connect 10 0 9 0; #X connect 11 0 9 1; #X connect 12 0 1 0; #X connect 13 0 1 0; #X restore 390 61 pd testseek; #X obj 400 264 bng 15 250 50 0 empty empty empty 0 -6 0 8 -258699 -1 -1; #X obj 214 223 route float length rate cache bang; #X msg 413 163 open $1; #X obj 413 142 openpanel; #X obj 413 123 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 -1; #X text 409 103 Open a File on disk; #X connect 1 0 15 0; #X connect 2 0 15 0; #X connect 3 0 15 0; #X connect 4 0 5 0; #X connect 4 0 6 0; #X connect 6 0 17 0; #X connect 7 0 18 0; #X connect 8 0 7 0; #X connect 14 0 13 0; #X connect 15 0 0 0; #X connect 15 1 0 1; #X connect 15 2 23 0; #X connect 16 0 15 0; #X connect 19 0 18 0; #X connect 23 0 9 0; #X connect 23 1 10 0; #X connect 23 2 11 0; #X connect 23 3 12 0; #X connect 23 4 22 0; #X connect 24 0 15 0; #X connect 25 0 24 0; #X connect 26 0 25 0;
--- NEW FILE: ReadFlac.cpp.seekable --- /* * 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
--- NEW FILE: ReadFlac.cpp --- /* * 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() { 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__stream_decoder_new(); if(decoder == 0) return false;
FLAC__stream_decoder_set_read_callback(decoder, readCallback_); FLAC__stream_decoder_set_write_callback(decoder, writeCallback_);
FLAC__stream_decoder_set_metadata_callback(decoder, metadataCallback_); FLAC__stream_decoder_set_error_callback(decoder, errorCallback_); FLAC__stream_decoder_set_client_data(decoder, this);
if(FLAC__stream_decoder_init(decoder) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA ) { cleanup(); return false; } if(!FLAC__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;
//while (samples_in_reservoir < 576) { //if (samples_in_reservoir < 576) { if(FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_END_OF_STREAM) { cout << "FLAC: end of file" << endl; return 0; } else if(!FLAC__stream_decoder_process_single(decoder)) {
//ErrorCheck( FLAC__stream_decoder_get_state(decoder) ); //ErrorCheck( FLAC__stream_decoder_finish(decoder) ); //ErrorCheck( FLAC__stream_decoder_init(decoder) ); //FLAC__stream_decoder_reset(decoder); //FLAC__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() {
cleanup(); Initialize(); samples_in_reservoir = 0; //ErrorCheck( FLAC__stream_decoder_get_state(decoder) ); //FLAC__stream_decoder_seek_absolute(decoder, 0); return true; }
bool ReadFlac::PCM_seek(long bytes) { cout << "ReadFlac:: no seeking on flac files, sorry" << endl; return false; }
bool ReadFlac::TIME_seek(double seconds) { cout << "ReadFlac:: no seeking on flac files, sorry" << endl; return false; }
void ReadFlac::cleanup() { if(decoder) { FLAC__stream_decoder_finish(decoder); FLAC__stream_decoder_delete(decoder); decoder = NULL; } }
FLAC__StreamDecoderReadStatus ReadFlac::readCallback_(const FLAC__StreamDecoder *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__STREAM_DECODER_READ_STATUS_END_OF_STREAM ; } else { return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE ; } }
FLAC__StreamDecoderWriteStatus ReadFlac::writeCallback_(const FLAC__StreamDecoder *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__StreamDecoder *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__StreamDecoder *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__stream_decoder_reset(instance->decoder); FLAC__stream_decoder_flush(instance->decoder); //instance->abort_flag = true; } }
void ReadFlac::ErrorCheck(int state) { switch (state) {
case FLAC__STREAM_DECODER_END_OF_STREAM : cout << "END_OF_STREAM " << endl; break; case FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR : cout << "MEMORY_ALLOCATION_ERROR " << endl; break; case FLAC__STREAM_DECODER_READ_FRAME : cout << "READ_FRAME " << endl; break; case FLAC__STREAM_DECODER_INVALID_CALLBACK : cout << "INVALID_CALLBACK " << endl; break; case FLAC__STREAM_DECODER_UNINITIALIZED : cout << "UNINITIALIZED " << endl; break; case FLAC__STREAM_DECODER_ABORTED : cout << "ABORTED " << endl; default: cout << "OK" << endl; break; } }
#endif
--- NEW FILE: ReadRaw.cpp --- /* * readanysf~ external for pd. * * Copyright (C) 2003 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 * * ReadRaw.cpp || code here was kindly 'borrowed' from d_soundfile.c from * puredata source code by Miller Puckette */
#include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <iostream>
#include "ReadRaw.h" #include <m_pd.h>
//# define _F_FRACBITS 28 //# define do_f_fromint(x) ((x) << _F_FRACBITS) #define SCALE (1./(1024. * 1024. * 1024. * 2.))
using namespace std;
int ambigendian(void) { unsigned short s = 1; unsigned char c = *(char *)(&s); return (c==0); }
static unsigned int swap4 (unsigned int n, int doit) { if (doit) return (((n & 0xff) << 24) | ((n & 0xff00) << 8) | ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24)); else return (n); }
static unsigned short swap2 (unsigned int n, int doit) { if (doit) return (((n & 0xff) << 8) | ((n & 0xff00) >> 8)); else return (n); }
#define ULPOW2TO31 ((unsigned int)0x80000000) #define DPOW2TO31 ((double)2147483648.0) /* 2^31 */
static double myUlongToDouble (unsigned int ul) { double val; if (ul & ULPOW2TO31) val = DPOW2TO31 + (ul & (~ULPOW2TO31)); else val = ul; return val; }
static double ieee_80_to_double (unsigned char *p) { unsigned char sign; short lexp = 0; unsigned int mant1 = 0; unsigned int mant0 = 0; double val; lexp = *p++; lexp <<= 8; lexp |= *p++; sign = (lexp & 0x8000) ? 1 : 0; lexp &= 0x7FFF; mant1 = *p++; mant1 <<= 8; mant1 |= *p++; mant1 <<= 8; mant1 |= *p++; mant1 <<= 8; mant1 |= *p++; mant0 = *p++; mant0 <<= 8; mant0 |= *p++; mant0 <<= 8; mant0 |= *p++; mant0 <<= 8; mant0 |= *p++; if (mant1 == 0 && mant0 == 0 && lexp == 0 && sign == 0) return 0.0; else { val = myUlongToDouble (mant0) * pow (2.0, -63.0); val += myUlongToDouble (mant1) * pow (2.0, -31.0); val *= pow (2.0, ((double) lexp) - 16383.0); return sign ? -val : val; } }
ReadRaw::ReadRaw () {
}
ReadRaw::ReadRaw (Input * input) { //char file; in = input; bigendian = ambigendian(); //bigendian = 0; }
ReadRaw::~ReadRaw () { if (in != NULL) in->Close (); }
bool ReadRaw::Initialize () { char buf[128]; int format, swap; //long bytelimit = 0x7fffffff;
if (in == NULL) { cout << "ReadRaw:: Input is NULL, this is bad, bailing...." << endl; //shouldn't ever happen, but just checking return false; //cout << "already opened, now closing file" << endl; }
int bytesread = in->Read (buf, READHDRSIZE);
if (bytesread < 4) { cout << "ReadRaw:: bytesread is < 4, this is bad, bailing...." << endl; return false; } format = in->get_format (); // we know the format already
if (format == FORMAT_NEXT){ /* nextstep header */
//unsigned int param; bigendian = 1; swap = (bigendian != ambigendian());
if (bytesread < (int) sizeof (t_nextstep)) { cout << "ReadRaw:: bytesread < sizeof(nextstep), this is bad, bailing...."<< endl; return false; } num_channels = swap4 (((t_nextstep *) buf)->ns_nchans, swap); format = swap4 (((t_nextstep *) buf)->ns_format, swap); samplerate = (double) swap4( ((t_nextstep *) buf)->ns_sr, swap );
headersize = swap4 (((t_nextstep *) buf)->ns_onset, swap); if (format == NS_FORMAT_LINEAR_16) bytespersamp = 2; else if (format == NS_FORMAT_LINEAR_24) bytespersamp = 3; else if (format == NS_FORMAT_FLOAT) bytespersamp = 4; else return false;
//bytelimit = 0x7fffffff;
} else if (format == FORMAT_WAVE) { /* wave header */
/* This is awful. You have to skip over chunks, * except that if one happens to be a "fmt" chunk, you want to * find out the format from that one. The case where the * "fmt" chunk comes after the audio isn't handled. */
bigendian = 0; swap = (bigendian != ambigendian());
headersize = 12; if (bytesread < 20) { cout << "ReadRaw:: bytesread < 20, this is bad, bailing...." << endl; return false; } /* First we guess a number of channels, etc., in case there's * no "fmt" chunk to follow. */ num_channels = 1; bytespersamp = 2; /* copy the first chunk header to beginnning of buffer. */ memcpy (buf, buf + headersize, sizeof (t_wavechunk));
/* read chunks in loop until we get to the data chunk */ while (strncmp (((t_wavechunk *) buf)->wc_id, "data", 4)) { long chunksize = swap4 (((t_wavechunk *) buf)->wc_size, swap), seekto = headersize + chunksize + 8, seekout;
if (!strncmp(((t_wavechunk *) buf)->wc_id, "fmt ", 4)) { long commblockonset = headersize + 8; seekout = in->SeekSet ( commblockonset); if (seekout != commblockonset) { cout << "ReadRaw:: Seek prob, seekout != commblockonset" << endl; return false; } if ( in->Read ( buf, sizeof (t_fmt) ) < (int) sizeof (t_fmt)) { cout << "ReadRaw:: Read prob, read < sizeopf(t_fmt)" << endl; return false; } num_channels = swap2 (((t_fmt *) buf)->f_nchannels, swap); samplerate = (double) swap2 (((t_fmt *) buf)->f_samplespersec, swap); int sampsize = swap2 (((t_fmt *) buf)->f_nbitspersample, swap); if (sampsize == 16) bytespersamp = 2; else if (sampsize == 24) bytespersamp = 3; else if (sampsize == 32) bytespersamp = 4; else { cout << "ReadRaw:: bytespersamp is not supported, samplesize= "<< sampsize << endl; //return false; } } seekout = in->SeekSet ( seekto ); if (seekout != seekto) { cout << "ReadRaw:: Seek prob, seekout != seekto"<< endl; return false; } if ( in->Read ( buf, sizeof (t_wavechunk) ) < (int) sizeof (t_wavechunk)) { cout << "ReadRaw:: Read prob, read < sizeof(wavechunk)" << endl; return false; } /* cout << "new chunk %c %c %c %c at %d", * ((t_wavechunk *)buf)->wc_id[0], * ((t_wavechunk *)buf)->wc_id[1], * ((t_wavechunk *)buf)->wc_id[2], * ((t_wavechunk *)buf)->wc_id[3], seekto); */ headersize = seekto; } //bytelimit = swap4 (((t_wavechunk *) buf)->wc_size, swap); headersize += 8; } else { /* AIFF. same as WAVE; actually predates it. Disgusting. */ bigendian = 1; swap = (bigendian != ambigendian());
headersize = 12; if (bytesread < 20) return false; /* First we guess a number of channels, etc., in case there's * no COMM block to follow. */ num_channels = 1; bytespersamp = 2; /* copy the first chunk header to beginnning of buffer. */ memcpy (buf, buf + headersize, sizeof (t_datachunk)); /* read chunks in loop until we get to the data chunk */ while (strncmp (((t_datachunk *) buf)->dc_id, "SSND", 4)) { long chunksize = swap4 (((t_datachunk *) buf)->dc_size, swap), seekto = headersize + chunksize + 8, seekout;
if (!strncmp (((t_datachunk *) buf)->dc_id, "COMM", 4)) { long commblockonset = headersize + 8; seekout = in->SeekSet ( commblockonset ); if (seekout != commblockonset) return false; if ( in->Read (buf, sizeof (t_comm)) < (int) sizeof (t_comm)) return false; num_channels = swap2 (((t_comm *) buf)->c_nchannels, swap); samplerate = ieee_80_to_double (((t_comm *) buf)->c_samprate); format = swap2 (((t_comm *) buf)->c_bitspersamp, swap); if (format == 16) bytespersamp = 2; else if (format == 24) bytespersamp = 3; else return false; } seekout = in->SeekSet ( seekto ); if (seekout != seekto) return false; if ( in->Read (buf, sizeof (t_datachunk)) < (int) sizeof (t_datachunk)) return false; headersize = seekto; } //bytelimit = swap4 (((t_datachunk *) buf)->dc_size, bigendian); headersize += 8; }
//cout << "ReadRaw:: [%s] %1.0lf (Hz), %d chan(s), bps %d",in->get_filename(), // samplerate, num_channels, bytespersamp); //cout << " headersize = %d", headersize);
long tmp = in->SeekEnd(0); // get filesize if (tmp == -1) post ("couldn't seek on file"); lengthinseconds = (float) ((tmp - headersize) / bytespersamp / samplerate / num_channels);
/* seek past header and any sample frames to skip */ if ( ( in->SeekSet( headersize ) ) != -1 ) { return true; } else { cout << "ReadRaw:: strange, wasn't able to seek on the file" << endl; return false; } }
bool ReadRaw::Rewind () { if ( ( in->SeekSet( headersize ) ) != -1 ) return true; else return false; }
int ReadRaw::Decode (float *buffer, int size) { int ret, x = 0;; int chunk = WAVCHUNKSIZE * bytespersamp * num_channels; int bytesperframe = bytespersamp * num_channels; unsigned char *sp; float ftmp;
if (chunk > size) return 0; ret = in->Read ( data, chunk ); ret = ret * bytespersamp; if (bytespersamp == 2) {
for (int j = 0; j < ret; j += bytespersamp) { sp = (unsigned char *) &data[j]; if (bigendian) ftmp = SCALE * ((sp[0] << 24) | (sp[1] << 16)); else ftmp = SCALE * ((sp[1] << 24) | (sp[0] << 16)); buffer[x++] = ftmp; //if (num_channels == 1) buffer[x++] = ftmp; sp += bytesperframe; }
} else if (bytespersamp == 3) {
for (int j = 0; j < ret; j += bytespersamp) { sp = (unsigned char *) &data[j]; if (bigendian) ftmp = SCALE * ((sp[0] << 24) | (sp[1] << 16) | (sp[2] << 8)); else ftmp = SCALE * ((sp[2] << 24) | (sp[1] << 16) | (sp[0] << 8)); buffer[x++] = ftmp; //if (num_channels == 1) buffer[x++] = ftmp; sp += bytesperframe; }
} else if (bytespersamp == 4) {
for (int j = 0; j < ret; j += bytespersamp) { sp = (unsigned char *) &data[j]; if (bigendian) ftmp = (float) ((sp[0] << 24) | (sp[1] << 16) | (sp[2] << 8) | sp[3]); else ftmp = (float) ((sp[3] << 24) | (sp[2] << 16) | (sp[1] << 8) | sp[0]); buffer[x++] = ftmp; //if (num_channels == 1) buffer[x++] = ftmp; sp += bytesperframe; }
}
return x / 2; //num_channels; //always two }
bool ReadRaw::PCM_seek (long frames) { if (frames > (long) (lengthinseconds * samplerate)) return false; if ( in->SeekSet ( headersize + (frames * num_channels * bytespersamp ) ) != -1 ) return true; else { cout << "ReadRaw:: fuck, no seeking!!" << endl; return false; } }
bool ReadRaw::TIME_seek (double seconds) { long frames = (long) (seconds * samplerate); return PCM_seek (frames); }