[PD-cvs] externals/august/readanysf~/src Fifo.cpp, NONE, 1.1 Input.cpp, NONE, 1.1 InputFile.cpp, NONE, 1.1 InputStream.cpp, NONE, 1.1 Makefile.am, NONE, 1.1 Makefile.in, NONE, 1.1 ReadFlac.cpp, NONE, 1.1 ReadFlac.cpp.seekable, NONE, 1.1 ReadMad.cpp, NONE, 1.1 ReadRaw.cpp, NONE, 1.1 ReadVorbis.cpp, NONE, 1.1 Readsf.cpp, NONE, 1.1 config.h.in, NONE, 1.1 main.cpp, NONE, 1.1 simple.pd, NONE, 1.1

B. Bogart bbogart at users.sourceforge.net
Sat Aug 13 03:17:01 CEST 2005


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~. at pd_suffix@

readanysf__ at 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__ at 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~. at pd_suffix@$(EXEEXT)
PROGRAMS = $(bin_PROGRAMS)

am_readanysf__ at pd_suffix@_OBJECTS = Fifo.$(OBJEXT) Input.$(OBJEXT) \
	InputFile.$(OBJEXT) InputStream.$(OBJEXT) ReadRaw.$(OBJEXT) \
	Readsf.$(OBJEXT) main.$(OBJEXT) ReadMad.$(OBJEXT) \
	ReadVorbis.$(OBJEXT) ReadFlac.$(OBJEXT)
readanysf__ at pd_suffix@_OBJECTS = $(am_readanysf__ at pd_suffix@_OBJECTS)
readanysf__ at pd_suffix@_DEPENDENCIES =
readanysf__ at 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 at 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__ at pd_suffix@_SOURCES)
DIST_COMMON = Makefile.am Makefile.in
SOURCES = $(readanysf__ at 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~. at pd_suffix@$(EXEEXT): $(readanysf__ at pd_suffix@_OBJECTS) $(readanysf__ at pd_suffix@_DEPENDENCIES) 
	@rm -f readanysf~. at pd_suffix@$(EXEEXT)
	$(CXXLINK) $(readanysf__ at pd_suffix@_LDFLAGS) $(readanysf__ at pd_suffix@_OBJECTS) $(readanysf__ at pd_suffix@_LDADD) $(LIBS)

mostlyclean-compile:
	-rm -f *.$(OBJEXT) core *.core

distclean-compile:
	-rm -f *.tab.c

@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/Fifo.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/Input.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/InputFile.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/InputStream.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ReadFlac.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ReadMad.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ReadRaw.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ReadVorbis.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/Readsf.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/main.Po at 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,  &current_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~. at pd_suffix@

readanysf__ at 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__ at 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);
}





More information about the Pd-cvs mailing list