aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Bogart <bbogart@users.sourceforge.net>2005-08-13 01:16:59 +0000
committerB. Bogart <bbogart@users.sourceforge.net>2005-08-13 01:16:59 +0000
commit5e05f47d61ebad8aee6c3831912b21ad5dcc36e3 (patch)
treeb8793d1908e5c2ce256e886357cbcb86e1b768b9
Initial commit of readanysf~ 0.13.1 for Augustsvn2git-root
svn path=/trunk/externals/august/readanysf~/; revision=3426
-rw-r--r--include/Fifo.h31
-rw-r--r--include/Input.h56
-rw-r--r--include/InputFile.h29
-rw-r--r--include/InputStream.h83
-rw-r--r--include/Makefile223
-rw-r--r--include/Makefile.am21
-rw-r--r--include/Makefile.in223
-rw-r--r--include/ReadFlac.h88
-rw-r--r--include/ReadFlac.h.seekable93
-rw-r--r--include/ReadMad.h125
-rw-r--r--include/ReadRaw.h154
-rw-r--r--include/ReadVorbis.h99
-rw-r--r--include/Readsf.h62
-rw-r--r--include/generic.h48
-rw-r--r--include/main.h158
-rw-r--r--include/stamp-h2.in0
-rw-r--r--src/Fifo.cpp152
-rw-r--r--src/Input.cpp56
-rw-r--r--src/InputFile.cpp172
-rw-r--r--src/InputStream.cpp473
-rw-r--r--src/Makefile.am30
-rw-r--r--src/Makefile.in374
-rw-r--r--src/ReadFlac.cpp288
-rw-r--r--src/ReadFlac.cpp.seekable398
-rw-r--r--src/ReadMad.cpp474
-rw-r--r--src/ReadRaw.cpp394
-rw-r--r--src/ReadVorbis.cpp272
-rw-r--r--src/Readsf.cpp65
-rw-r--r--src/config.h.in1
-rw-r--r--src/main.cpp664
-rw-r--r--src/simple.pd107
31 files changed, 5413 insertions, 0 deletions
diff --git a/include/Fifo.h b/include/Fifo.h
new file mode 100644
index 0000000..c060079
--- /dev/null
+++ b/include/Fifo.h
@@ -0,0 +1,31 @@
+#ifndef _FIFO_H_
+#define _FIFO_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include <memory.h>
+#include <pthread.h>
+
+class Fifo
+{
+ public:
+ Fifo();
+ Fifo(unsigned int size);
+ ~Fifo();
+ void Flush();
+ int IsAlloc(void) { return astate; }
+ int ReAlloc(unsigned int size);
+ void * Read(void *buf, unsigned int &len);
+ int Write(void *buf, unsigned int len);
+ unsigned int FreeSpace(void);
+ unsigned int UsedSpace(void);
+ private:
+ char *buffer;
+ unsigned int astate;
+ unsigned int totsize, start, datasize;
+ pthread_mutex_t mut;
+};
+#endif
diff --git a/include/Input.h b/include/Input.h
new file mode 100644
index 0000000..960bbb0
--- /dev/null
+++ b/include/Input.h
@@ -0,0 +1,56 @@
+#ifndef _INPUT_H_
+#define _INPUT_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h> // open
+#include <sys/stat.h> // open
+#include <fcntl.h> // open
+#include <unistd.h> // read
+#include <netdb.h> // for gethostbyname
+#include <sys/socket.h> // socket
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+#include <string> // save filename
+using namespace std;
+#include "generic.h"
+
+class Input {
+ public:
+ Input();
+ virtual ~ Input();
+
+ virtual int Open(const char *pathname); // open file or stream and return formt
+ virtual int Close(); // close or disconnect
+ virtual int Read(void *buf, unsigned int count); //read into buf count times.
+
+ virtual long SeekSet(long offset); // lseek using SEEK_SET
+ virtual long SeekCur(long offset); // lseek using SEEK_CUR
+ virtual long SeekEnd(long offset); // lseek using SEEK_END
+ //int getEof() { return eof(fd); }
+ virtual float get_cachesize(); // return amount of buffer that is used. 0.0 for InputFile
+
+ virtual bool get_recover( ) { return recover; }
+ void set_recover( bool x) { recover =x;}
+
+
+ void SetVerbosity(int d) { verbosity = d; } // set debug level 0-3 protected:
+ int get_fd() { return fd;}
+ int get_format() { return format;}
+ const char * get_filename() { return filename.c_str(); }
+
+ protected:
+ int fd; //file descriptor for files and sockets
+ int format; //what format? OGG,MP3,NEXT etc. see defines above
+ int verbosity; //how much debugging/info to print
+ //we need to be able to set this dynamically for http
+ bool recover; // whether to recover connections on the net
+ string filename; // store the path/filename of what is opened for reading
+};
+#endif
diff --git a/include/InputFile.h b/include/InputFile.h
new file mode 100644
index 0000000..35f180c
--- /dev/null
+++ b/include/InputFile.h
@@ -0,0 +1,29 @@
+#ifndef _INPUTFILE_H_
+#define _INPUTFILE_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include "Input.h"
+
+class InputFile : public Input {
+ public:
+ InputFile();
+ virtual ~InputFile();
+
+ virtual int Open( const char *pathname );
+ virtual int Close();
+ virtual int Read( void *buf, unsigned int count );
+
+ virtual long SeekSet ( long offset );
+ virtual long SeekCur ( long offset );
+ virtual long SeekEnd ( long offset );
+ virtual float get_cachesize() { return 0.0; };
+ virtual bool get_recover( ) { return false; }
+ private:
+
+
+};
+#endif
diff --git a/include/InputStream.h b/include/InputStream.h
new file mode 100644
index 0000000..704fed1
--- /dev/null
+++ b/include/InputStream.h
@@ -0,0 +1,83 @@
+#ifndef _INPUTSTREAM_H_
+#define _INPUTSTREAM_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "Input.h"
+#include "Fifo.h"
+
+#include <string>
+#include <pthread.h>
+#include <dlfcn.h>
+
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#ifdef UNIX
+#include <sys/time.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#define SOCKET_ERROR -1
+#else
+#include <winsock.h>
+#endif
+
+using namespace std;
+
+class InputStream : public Input {
+ public:
+ InputStream ();
+ virtual ~InputStream();
+
+ virtual int Open( const char *pathname );
+ virtual int Close();
+ virtual int Read( void *buf, unsigned int count );
+
+ virtual long SeekSet ( long offset );
+ virtual long SeekCur ( long offset );
+ virtual long SeekEnd ( long offset );
+ virtual float get_cachesize();
+ virtual bool get_recover( ) { return recover; }
+
+ pthread_mutex_t *get_mutex() { return &mut;}
+ pthread_cond_t *get_condition(){ return &cond;}
+
+ void set_threaded( bool b ) { threaded = b;}
+
+ Fifo * get_fifo() { return infifo;}
+ bool get_quit() { return quit;}
+
+ int socket_connect ( );
+
+ private:
+ //int socket_connect (string hostname, string mountpoint, int portno);
+ //int socket_connect (char *hostname, char *mountpoint, int portno);
+ // connects to socket and checks for ice or shout
+ // returns type of stream(ogg, mp3) or -1 for failure
+
+ string ParseHttp( string str, string parse ); // parse x-audio* vars from icecast
+ int SetUrl (const char *url); // breaks http://server:port/mount down to hostname,port,mountpoint
+ // return 1 for success, 0 for failure
+
+ int get_line( char * str, int sock, int maxget);
+
+ Fifo *infifo; // fifo for thread buffering
+ string hostname; // hostname of URL
+ string mountpoint; // mountpoint for Icecast URL
+ int port; // port number URL
+ bool threaded; // if thread is running or not, true if running
+ bool quit; // if we should quit thread or not
+
+ pthread_mutex_t mut;
+ pthread_cond_t cond;
+ pthread_t childthread;
+
+};
+#endif
diff --git a/include/Makefile b/include/Makefile
new file mode 100644
index 0000000..6db9da2
--- /dev/null
+++ b/include/Makefile
@@ -0,0 +1,223 @@
+# Generated automatically from Makefile.in by configure.
+# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999, 2001 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.
+
+
+SHELL = /bin/sh
+
+srcdir = .
+top_srcdir = ..
+prefix = /usr/local
+exec_prefix = ${prefix}
+
+bindir = ${exec_prefix}/bin
+sbindir = ${exec_prefix}/sbin
+libexecdir = ${exec_prefix}/libexec
+datadir = ${prefix}/share
+sysconfdir = ${prefix}/etc
+sharedstatedir = ${prefix}/com
+localstatedir = ${prefix}/var
+libdir = ${exec_prefix}/lib
+infodir = ${prefix}/info
+mandir = ${prefix}/man
+includedir = ${prefix}/include
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/readanysf
+pkglibdir = $(libdir)/readanysf
+pkgincludedir = $(includedir)/readanysf
+
+top_builddir = ..
+
+ACLOCAL = aclocal-1.4
+AUTOCONF = autoconf
+AUTOMAKE = automake-1.4
+AUTOHEADER = autoheader
+
+INSTALL = /bin/install -c
+INSTALL_PROGRAM = ${INSTALL} $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_SCRIPT = ${INSTALL_PROGRAM}
+transform = s,x,x,
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = i686-pc-linux-gnu
+host_triplet = i686-pc-linux-gnu
+AS = @AS@
+CC = gcc
+CXX = g++
+DLLTOOL = @DLLTOOL@
+ECHO = echo
+EXEEXT =
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LN_S = ln -s
+MAKEINFO = makeinfo
+NO_PREFIX_PACKAGE_DATA_DIR = share/readanysf
+NO_PREFIX_PACKAGE_DOC_DIR = doc/readanysf
+NO_PREFIX_PACKAGE_HELP_DIR = share/readanysf/help
+NO_PREFIX_PACKAGE_MENU_DIR = share/readanysf
+NO_PREFIX_PACKAGE_PIXMAPS_DIR = share/readanysf/pixmaps
+OBJDUMP = @OBJDUMP@
+OBJEXT = o
+PACKAGE = readanysf
+PACKAGE_DATA_DIR = /usr/local/share/readanysf
+PACKAGE_DOC_DIR = /usr/local/doc/readanysf
+PACKAGE_HELP_DIR = /usr/local/share/readanysf/help
+PACKAGE_MENU_DIR = /usr/local/share/readanysf
+PACKAGE_PIXMAPS_DIR = /usr/local/share/readanysf/pixmaps
+RANLIB = ranlib
+STRIP = strip
+VERSION = 0.13
+
+readanysf_includedir = $(pkgincludedir)
+
+readanysf_include_DATA = Fifo.h Input.h InputFile.h InputStream.h Readsf.h ReadRaw.h generic.h main.h ReadMad.h ReadVorbis.h
+
+
+EXTRA_DIST = $(readanysf_include_DATA)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+DATA = $(readanysf_include_DATA)
+
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+install-readanysf_includeDATA: $(readanysf_include_DATA)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(readanysf_includedir)
+ @list='$(readanysf_include_DATA)'; for p in $$list; do \
+ if test -f $(srcdir)/$$p; then \
+ echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(readanysf_includedir)/$$p"; \
+ $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(readanysf_includedir)/$$p; \
+ else if test -f $$p; then \
+ echo " $(INSTALL_DATA) $$p $(DESTDIR)$(readanysf_includedir)/$$p"; \
+ $(INSTALL_DATA) $$p $(DESTDIR)$(readanysf_includedir)/$$p; \
+ fi; fi; \
+ done
+
+uninstall-readanysf_includeDATA:
+ @$(NORMAL_UNINSTALL)
+ list='$(readanysf_include_DATA)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(readanysf_includedir)/$$p; \
+ done
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = include
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu include/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am: install-readanysf_includeDATA
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-readanysf_includeDATA
+uninstall: uninstall-am
+all-am: Makefile $(DATA)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(readanysf_includedir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-generic clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: uninstall-readanysf_includeDATA install-readanysf_includeDATA \
+tags distdir info-am info dvi-am dvi check check-am installcheck-am \
+installcheck install-exec-am install-exec install-data-am install-data \
+install-am install uninstall-am uninstall all-redirect all-am all \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# 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:
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..f82066e
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,21 @@
+## Process this file with automake to produce Makefile.in
+
+## Created by Anjuta - will be overwritten
+## If you don't want it to overwrite it,
+## Please disable it in the Anjuta project configuration
+
+readanysf_includedir = $(pkgincludedir)
+
+readanysf_include_DATA = \
+ Fifo.h\
+ Input.h\
+ InputFile.h\
+ InputStream.h\
+ Readsf.h\
+ ReadRaw.h\
+ generic.h\
+ main.h\
+ ReadMad.h\
+ ReadVorbis.h
+
+EXTRA_DIST = $(readanysf_include_DATA)
diff --git a/include/Makefile.in b/include/Makefile.in
new file mode 100644
index 0000000..607c754
--- /dev/null
+++ b/include/Makefile.in
@@ -0,0 +1,223 @@
+# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999, 2001 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.
+
+
+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
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AS = @AS@
+CC = @CC@
+CXX = @CXX@
+DLLTOOL = @DLLTOOL@
+ECHO = @ECHO@
+EXEEXT = @EXEEXT@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+NO_PREFIX_PACKAGE_DATA_DIR = @NO_PREFIX_PACKAGE_DATA_DIR@
+NO_PREFIX_PACKAGE_DOC_DIR = @NO_PREFIX_PACKAGE_DOC_DIR@
+NO_PREFIX_PACKAGE_HELP_DIR = @NO_PREFIX_PACKAGE_HELP_DIR@
+NO_PREFIX_PACKAGE_MENU_DIR = @NO_PREFIX_PACKAGE_MENU_DIR@
+NO_PREFIX_PACKAGE_PIXMAPS_DIR = @NO_PREFIX_PACKAGE_PIXMAPS_DIR@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_DATA_DIR = @PACKAGE_DATA_DIR@
+PACKAGE_DOC_DIR = @PACKAGE_DOC_DIR@
+PACKAGE_HELP_DIR = @PACKAGE_HELP_DIR@
+PACKAGE_MENU_DIR = @PACKAGE_MENU_DIR@
+PACKAGE_PIXMAPS_DIR = @PACKAGE_PIXMAPS_DIR@
+RANLIB = @RANLIB@
+STRIP = @STRIP@
+VERSION = @VERSION@
+
+readanysf_includedir = $(pkgincludedir)
+
+readanysf_include_DATA = Fifo.h Input.h InputFile.h InputStream.h Readsf.h ReadRaw.h generic.h main.h ReadMad.h ReadVorbis.h
+
+
+EXTRA_DIST = $(readanysf_include_DATA)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+DATA = $(readanysf_include_DATA)
+
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+install-readanysf_includeDATA: $(readanysf_include_DATA)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(readanysf_includedir)
+ @list='$(readanysf_include_DATA)'; for p in $$list; do \
+ if test -f $(srcdir)/$$p; then \
+ echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(readanysf_includedir)/$$p"; \
+ $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(readanysf_includedir)/$$p; \
+ else if test -f $$p; then \
+ echo " $(INSTALL_DATA) $$p $(DESTDIR)$(readanysf_includedir)/$$p"; \
+ $(INSTALL_DATA) $$p $(DESTDIR)$(readanysf_includedir)/$$p; \
+ fi; fi; \
+ done
+
+uninstall-readanysf_includeDATA:
+ @$(NORMAL_UNINSTALL)
+ list='$(readanysf_include_DATA)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(readanysf_includedir)/$$p; \
+ done
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = include
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu include/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am: install-readanysf_includeDATA
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-readanysf_includeDATA
+uninstall: uninstall-am
+all-am: Makefile $(DATA)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(readanysf_includedir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-generic clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: uninstall-readanysf_includeDATA install-readanysf_includeDATA \
+tags distdir info-am info dvi-am dvi check check-am installcheck-am \
+installcheck install-exec-am install-exec install-data-am install-data \
+install-am install uninstall-am uninstall all-redirect all-am all \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# 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:
diff --git a/include/ReadFlac.h b/include/ReadFlac.h
new file mode 100644
index 0000000..0d75e60
--- /dev/null
+++ b/include/ReadFlac.h
@@ -0,0 +1,88 @@
+/*
+ * 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.h
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef READ_FLAC
+
+#ifndef _READFLAC_H
+#define _READFLAC_H
+
+extern "C" {
+#include "FLAC/stream_decoder.h"
+};
+
+#include "Readsf.h"
+#include "generic.h"
+
+class ReadFlac : public Readsf {
+ public:
+ ReadFlac( Input *input);
+ virtual ~ReadFlac();
+ virtual bool Initialize();
+ virtual int Decode(float *buffer, int size);
+ virtual bool Rewind();
+ virtual bool PCM_seek(long bytes);
+ virtual bool TIME_seek(double seconds);
+
+ protected:
+ bool needs_seek;
+ FLAC__uint64 seek_sample;
+ unsigned samples_in_reservoir;
+ bool abort_flag;
+ FLAC__StreamDecoder *decoder;
+ FLAC__StreamMetadata streaminfo;
+ FLAC__int16 reservoir[FLAC__MAX_BLOCK_SIZE * 2 * 2]; // *2 for max channels, another *2 for overflow
+ //unsigned char output[576 * 2 * (16/8)]; // *2 for max channels, (16/8) for max bytes per sample
+
+ unsigned lengthInMsec() { return (unsigned)((FLAC__uint64)1000 * streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate); }
+ private:
+ void ErrorCheck(int state);
+ long filelength;
+ void cleanup();
+
+
+
+ static FLAC__StreamDecoderReadStatus readCallback_(const FLAC__StreamDecoder *decoder,
+ FLAC__byte buffer[],
+ unsigned *bytes,
+ void *client_data);
+
+ static FLAC__StreamDecoderWriteStatus writeCallback_(const FLAC__StreamDecoder *decoder,
+ const FLAC__Frame *frame,
+ const FLAC__int32 * const buffer[],
+ void *client_data);
+
+
+ static FLAC__bool eofCallback_(const FLAC__StreamDecoder *decoder, void *client_data);
+
+ static void metadataCallback_(const FLAC__StreamDecoder *decoder,
+ const FLAC__StreamMetadata *metadata,
+ void *client_data);
+ static void errorCallback_(const FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderErrorStatus status,
+ void *client_data);
+};
+
+#endif
+#endif //#ifdef READ_FLAC
diff --git a/include/ReadFlac.h.seekable b/include/ReadFlac.h.seekable
new file mode 100644
index 0000000..c4cdfcf
--- /dev/null
+++ b/include/ReadFlac.h.seekable
@@ -0,0 +1,93 @@
+/*
+ * 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.h
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef READ_FLAC
+
+#ifndef _READFLAC_H
+#define _READFLAC_H
+
+extern "C" {
+#include "FLAC/seekable_stream_decoder.h"
+};
+
+#include "Readsf.h"
+#include "generic.h"
+
+class ReadFlac : public Readsf {
+ public:
+ ReadFlac( Input *input);
+ virtual ~ReadFlac();
+ virtual bool Initialize();
+ virtual int Decode(float *buffer, int size);
+ virtual bool Rewind();
+ virtual bool PCM_seek(long bytes);
+ virtual bool TIME_seek(double seconds);
+
+ protected:
+ bool needs_seek;
+ FLAC__uint64 seek_sample;
+ unsigned samples_in_reservoir;
+ bool abort_flag;
+ FLAC__SeekableStreamDecoder *decoder;
+ FLAC__StreamMetadata streaminfo;
+ FLAC__int16 reservoir[FLAC__MAX_BLOCK_SIZE * 2 * 2]; // *2 for max channels, another *2 for overflow
+ //unsigned char output[576 * 2 * (16/8)]; // *2 for max channels, (16/8) for max bytes per sample
+
+ unsigned lengthInMsec() { return (unsigned)((FLAC__uint64)1000 * streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate); }
+ private:
+ void ErrorCheck(int state);
+ long filelength;
+ void cleanup();
+
+
+
+ static FLAC__SeekableStreamDecoderReadStatus readCallback_(const FLAC__SeekableStreamDecoder *decoder,
+ FLAC__byte buffer[],
+ unsigned *bytes,
+ void *client_data);
+ static FLAC__SeekableStreamDecoderSeekStatus seekCallback_(const FLAC__SeekableStreamDecoder *decoder,
+ FLAC__uint64 absolute_byte_offset,
+ void *client_data);
+ static FLAC__SeekableStreamDecoderTellStatus tellCallback_(const FLAC__SeekableStreamDecoder *decoder,
+ FLAC__uint64 *absolute_byte_offset,
+ void *client_data);
+ static FLAC__SeekableStreamDecoderLengthStatus lengthCallback_(const FLAC__SeekableStreamDecoder *decoder,
+ FLAC__uint64 *stream_length,
+ void *client_data);
+ static FLAC__bool eofCallback_(const FLAC__SeekableStreamDecoder *decoder, void *client_data);
+ static FLAC__StreamDecoderWriteStatus writeCallback_(const FLAC__SeekableStreamDecoder *decoder,
+ const FLAC__Frame *frame,
+ const FLAC__int32 * const buffer[],
+ void *client_data);
+ static void metadataCallback_(const FLAC__SeekableStreamDecoder *decoder,
+ const FLAC__StreamMetadata *metadata,
+ void *client_data);
+ static void errorCallback_(const FLAC__SeekableStreamDecoder *decoder,
+ FLAC__StreamDecoderErrorStatus status,
+ void *client_data);
+};
+
+#endif
+#endif //#ifdef READ_FLAC
diff --git a/include/ReadMad.h b/include/ReadMad.h
new file mode 100644
index 0000000..bf0bc27
--- /dev/null
+++ b/include/ReadMad.h
@@ -0,0 +1,125 @@
+/*
+ * 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 HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#ifdef READ_MAD
+
+#ifndef _READMAD_H_
+#define _READMAD_H_
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+
+#define MAD_BUFSIZE (4 * 1024)
+#define XING_MAGIC (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g')
+
+extern "C" {
+#include <mad.h>
+}
+
+//#include "xing.h"
+#include "Readsf.h"
+#include "Input.h"
+
+
+#define FRAME_RESERVE 2000
+
+
+struct xing {
+ long flags; /* valid fields (see below) */
+ unsigned long frames; /* total number of frames */
+ unsigned long bytes; /* total number of bytes */
+ unsigned char toc[100]; /* 100-point seek table */
+ long scale; /* ?? */
+};
+
+enum {
+ XING_FRAMES = 0x00000001L,
+ XING_BYTES = 0x00000002L,
+ XING_TOC = 0x00000004L,
+ XING_SCALE = 0x00000008L
+};
+
+# define xing_finish(xing) /* nothing */
+
+
+class ReadMad : public Readsf {
+
+ private:
+ //FILE *mad_fd;
+ uint8_t mad_map[MAD_BUFSIZE];
+ long map_offset;
+ int bytes_avail;
+
+ struct mad_synth synth;
+ struct mad_stream stream;
+ struct mad_frame frame;
+ mad_timer_t timer;
+ struct xing xing;
+
+ int mad_init;
+ ssize_t offset;
+ ssize_t filesize;
+ // int samplerate;
+ int bitrate;
+ int samplesperframe;
+ long samplestotal;
+ long time;
+ int seekable;
+ int nr_frames;
+
+ //float my_scale(mad_fixed_t sample);
+ bool fill_buffer( );
+ bool fill_buffer( long newoffset );
+ int mad_frame_seek( int frame );
+ ssize_t find_initial_frame(uint8_t *buf, int size);
+ void seek_bytes(long byte_offset);
+
+ void xing_init(struct xing *);
+ int xing_parse(struct xing *, struct mad_bitptr, unsigned int);
+
+ public:
+ ReadMad();
+ ReadMad( Input *input );
+ virtual ~ReadMad();
+ virtual bool Initialize();
+ virtual int Decode(float *buffer, int size);
+ virtual bool Rewind();
+ virtual bool PCM_seek(long bytes);
+ virtual bool TIME_seek(double seconds);
+};
+
+#endif
+#endif //ifdef READ_MAD
diff --git a/include/ReadRaw.h b/include/ReadRaw.h
new file mode 100644
index 0000000..9906ecf
--- /dev/null
+++ b/include/ReadRaw.h
@@ -0,0 +1,154 @@
+/*
+ * 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.h
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#ifndef _READRAW_H_
+#define _READRAW_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "Readsf.h"
+
+typedef struct _nextstep
+{
+ char ns_fileid[4]; /* magic number '.snd' if file is big-endian */
+ unsigned int ns_onset; /* byte offset of first sample */
+ unsigned int ns_length; /* length of sound in bytes */
+ unsigned int ns_format; /* format; see below */
+ unsigned int ns_sr; /* sample rate */
+ unsigned int ns_nchans; /* number of channels */
+ char ns_info[4]; /* comment */
+} t_nextstep;
+
+typedef struct _wave
+{
+ char w_fileid[4]; /* chunk id 'RIFF' */
+ unsigned int w_chunksize; /* chunk size */
+ char w_waveid[4]; /* wave chunk id 'WAVE' */
+ char w_fmtid[4]; /* format chunk id 'fmt ' */
+ unsigned int w_fmtchunksize; /* format chunk size */
+ unsigned short w_fmttag; /* format tag, 1 for PCM */
+ unsigned short w_nchannels; /* number of channels */
+ unsigned int w_samplespersec; /* sample rate in hz */
+ unsigned int w_navgbytespersec; /* average bytes per second */
+ unsigned short w_nblockalign; /* number of bytes per frame */
+ unsigned short w_nbitspersample; /* number of bits in a sample */
+ char w_datachunkid[4]; /* data chunk id 'data' */
+ unsigned int w_datachunksize; /* length of data chunk */
+} t_wave;
+
+typedef struct _fmt /* format chunk */
+{
+ unsigned short f_fmttag; /* format tag, 1 for PCM */
+ unsigned short f_nchannels; /* number of channels */
+ unsigned int f_samplespersec; /* sample rate in hz */
+ unsigned int f_navgbytespersec; /* average bytes per second */
+ unsigned short f_nblockalign; /* number of bytes per frame */
+ unsigned short f_nbitspersample; /* number of bits in a sample */
+} t_fmt;
+
+typedef struct _wavechunk /* ... and the last two items */
+{
+ char wc_id[4]; /* data chunk id, e.g., 'data' or 'fmt ' */
+ unsigned int wc_size; /* length of data chunk */
+} t_wavechunk;
+
+/* the AIFF header. I'm assuming AIFC is compatible but don't really know
+ that. */
+
+typedef struct _datachunk
+{
+ char dc_id[4]; /* data chunk id 'SSND' */
+ unsigned int dc_size; /* length of data chunk */
+} t_datachunk;
+
+typedef struct _comm
+{
+ unsigned short c_nchannels; /* number of channels */
+ unsigned short c_nframeshi; /* # of sample frames (hi) */
+ unsigned short c_nframeslo; /* # of sample frames (lo) */
+ unsigned short c_bitspersamp; /* bits per sample */
+ unsigned char c_samprate[10]; /* sample rate, 80-bit float! */
+} t_comm;
+
+ /* this version is more convenient for writing them out: */
+typedef struct _aiff
+{
+ char a_fileid[4]; /* chunk id 'FORM' */
+ unsigned int a_chunksize; /* chunk size */
+ char a_aiffid[4]; /* aiff chunk id 'AIFF' */
+ char a_fmtid[4]; /* format chunk id 'COMM' */
+ unsigned int a_fmtchunksize; /* format chunk size, 18 */
+ unsigned short a_nchannels; /* number of channels */
+ unsigned short a_nframeshi; /* # of sample frames (hi) */
+ unsigned short a_nframeslo; /* # of sample frames (lo) */
+ unsigned short a_bitspersamp; /* bits per sample */
+ unsigned char a_samprate[10]; /* sample rate, 80-bit float! */
+} t_aiff;
+
+
+#define NS_FORMAT_LINEAR_16 3
+#define NS_FORMAT_LINEAR_24 4
+#define NS_FORMAT_FLOAT 6
+#define SCALE (1./(1024. * 1024. * 1024. * 2.))
+
+
+#define AIFFHDRSIZE 38 /* probably not what sizeof() gives */
+#define AIFFPLUS (AIFFHDRSIZE + 8) /* header size including first chunk hdr */
+
+#define WHDR1 sizeof(t_nextstep)
+#define WHDR2 (sizeof(t_wave) > WHDR1 ? sizeof (t_wave) : WHDR1)
+#define WRITEHDRSIZE (AIFFPLUS > WHDR2 ? AIFFPLUS : WHDR2)
+
+#define READHDRSIZE (16 > WHDR2 + 2 ? 16 : WHDR2 + 2)
+
+
+class ReadRaw : public Readsf {
+ private:
+
+ long ret;
+ unsigned char data[WAVCHUNKSIZE * 4 * 2]; //WAVCHUNKSIZE * bytespersamp * num_channels;
+
+ int headersize;
+ int bytespersamp;
+ int bigendian;
+ public:
+ ReadRaw ( );
+ ReadRaw( Input *input );
+ virtual ~ReadRaw();
+ virtual bool Initialize();
+ virtual int Decode(float *buffer,int size);
+ virtual bool Rewind();
+ virtual bool PCM_seek(long bytes);
+ virtual bool TIME_seek(double seconds);
+};
+
+
+
+
+
+#endif
diff --git a/include/ReadVorbis.h b/include/ReadVorbis.h
new file mode 100644
index 0000000..bf42a23
--- /dev/null
+++ b/include/ReadVorbis.h
@@ -0,0 +1,99 @@
+/*
+ * 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
+ *
+ * ReadVorbisUrl.h
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef READ_VORBIS
+
+#ifndef _READVORBISURL_H_
+#define _READVORBISURL_H_
+
+#include "Readsf.h"
+#include "generic.h"
+
+extern "C" {
+#include <vorbis/codec.h>
+#include <vorbis/vorbisfile.h>
+}
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+
+//#include <stdlib.h>
+//#include <math.h>
+
+#ifdef NT
+#include <io.h> /* for 'write' in pute-function only */
+#include <winsock.h>
+#include <winbase.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <unistd.h>
+#define SOCKET_ERROR -1
+#endif
+
+
+
+//#define VSTREAM_FIFOSIZE (32 * 1024)
+//#define VSTREAM_BUFFERSIZE (4 * 1024)
+//#define VSOCKET_READSIZE 1024
+//#define STRBUF_SIZE 1024
+
+
+class ReadVorbis : public Readsf {
+ private:
+
+ OggVorbis_File vf;
+ ov_callbacks callbacks;
+
+ static size_t read_func(void *ptr, size_t size, size_t nmemb, void *datasource);
+ static int seek_func(void *datasource, ogg_int64_t offset, int whence);
+ static int close_func(void *datasource);
+ static long tell_func(void *datasource);
+ bool seekable;
+
+ public:
+ ReadVorbis( Input *input );
+ virtual ~ReadVorbis();
+ virtual bool Initialize();
+ virtual int Decode(float *buffer, int size);
+ virtual bool Rewind();
+ virtual bool PCM_seek(long bytes);
+ virtual bool TIME_seek(double seconds);
+ bool is_seekable() { return seekable;};
+
+};
+
+#endif
+#endif //ifdef READVORBIS
diff --git a/include/Readsf.h b/include/Readsf.h
new file mode 100644
index 0000000..ea09384
--- /dev/null
+++ b/include/Readsf.h
@@ -0,0 +1,62 @@
+/*
+ * 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.h
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef _READSF_H_
+#define _READSF_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "Input.h"
+
+class Readsf {
+
+private:
+
+
+ public:
+ Readsf();
+ Readsf( Input *input );
+
+ virtual ~Readsf();
+ virtual bool Initialize();
+ virtual int Decode(float *buffer, int size);
+ virtual bool Rewind();
+ virtual bool PCM_seek(long bytes);
+ virtual bool TIME_seek(double seconds);
+ double get_samplerate() { return samplerate;}
+ int get_channels() { return num_channels;}
+ float get_lengthinseconds() { return lengthinseconds; }
+
+ protected:
+ Input *in;
+ double samplerate;
+ int num_channels;
+ float lengthinseconds;
+ bool eof;
+};
+
+#endif
diff --git a/include/generic.h b/include/generic.h
new file mode 100644
index 0000000..c165f2f
--- /dev/null
+++ b/include/generic.h
@@ -0,0 +1,48 @@
+#ifndef _GENERIC_H_
+#define _GENERIC_H_
+
+
+#define FLOATSIZE sizeof(float)
+#define SHORTSIZE sizeof(short)
+#define CHUNKSIZE 4096*FLOATSIZE
+#define WAVCHUNKSIZE 1024
+//#define MAD_CHUNKSIZE 2016*FLOATSIZE //576
+#define INOUTSIZE (CHUNKSIZE*4)+1
+
+#define FIFOSIZE (CHUNKSIZE*16)
+#define FIFOSECONDS (FIFOSIZE/FLOATSIZE/44100) //assume samplerate
+#define READBUFFER (1024*16)
+
+#define R_NOTHING 0
+#define R_OPEN 1
+#define R_CLOSE 2
+#define R_QUIT 3
+#define R_PROCESS 4
+#define R_STOP 5
+
+#define STATE_IDLE 0
+#define STATE_STARTUP 1
+#define STATE_STREAM 2
+#define STATE_IDLE_CLOSED 3
+
+#define FORMAT_WAVE 0
+#define FORMAT_AIFF 1
+#define FORMAT_NEXT 2
+#define FORMAT_VORBIS 3
+#define FORMAT_MAD 4
+#define FORMAT_FLAC 5
+#define FORMAT_HTTP_MP3 6
+#define FORMAT_HTTP_VORBIS 7
+
+
+
+#define STREAM_FIFOSIZE (32 * 1152)
+#define SOCKET_READSIZE 1024 //1152/4
+#define sys_closesocket close // windows uses sys_closesocket
+#define STRBUF_SIZE 1024
+
+//#define STREAM_BUFFERSIZE (4 * 1152)
+//#define FRAME_RESERVE 2000
+//#define STRDUP strdup
+
+#endif
diff --git a/include/main.h b/include/main.h
new file mode 100644
index 0000000..ea1093f
--- /dev/null
+++ b/include/main.h
@@ -0,0 +1,158 @@
+/*
+ * 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
+ *
+ * main.h
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include <flext.h>
+#include <stdio.h>
+
+
+extern "C" {
+#include <samplerate.h> //libsamplerate
+}
+
+#include "Readsf.h"
+#include "ReadRaw.h"
+#ifdef READ_VORBIS
+#include "ReadVorbis.h"
+#endif
+#ifdef READ_MAD
+#include "ReadMad.h"
+#endif
+#ifdef READ_MAD_URL
+#include "ReadMadUrl.h"
+#endif
+#ifdef READ_FLAC
+#include "ReadFlac.h"
+#endif
+
+#include "Fifo.h"
+#include "generic.h"
+#include "Input.h"
+#include "InputFile.h"
+#include "InputStream.h"
+
+// check for appropriate flext version
+#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 400)
+#error You need at least flext version 0.4.0
+#endif
+
+
+class readanysf: public flext_dsp
+{
+ // obligatory flext header (class name,base class name)
+ FLEXT_HEADER(readanysf, flext_dsp)
+
+public:
+
+ readanysf();
+ ~readanysf();
+
+
+protected:
+ // here we declare the virtual DSP function
+ virtual void m_signal(int n, float *const *in, float *const *out);
+
+ void m_open(t_symbol *s); // open file Input; set req = R_OPEN
+ void m_reopen(); // re open a file Input; set req = R_OPEN
+ void m_start(); // set state = S_PROCESS
+ void m_pause(); // set state = S_IDLE
+ void m_stop(); // set state = S_STATE; cond.signal();
+
+ void m_child();
+ void FillFifo();
+
+ //void m_loop_s(t_symbol *s);
+ void m_recover(float f);
+ void m_loop_f(float f);
+ void m_set_tick(int i);
+ void m_pcm_seek(int i);
+ void m_time_seek(float f);
+ void m_src_factor(float f);
+
+ void m_bang();
+
+ int m_resample(int frames);
+
+ int getState();
+ int getRequest();
+ void setState(int i);
+ void setRequest(int i);
+ void setSys(int state, int request);
+private:
+ FLEXT_CALLBACK_S(m_open)
+ FLEXT_CALLBACK(m_reopen)
+
+
+ FLEXT_CALLBACK_F(m_loop_f)
+ FLEXT_CALLBACK_F(m_recover)
+ FLEXT_CALLBACK_I(m_set_tick)
+ FLEXT_CALLBACK(m_start)
+ FLEXT_CALLBACK(m_pause)
+ FLEXT_CALLBACK(m_stop)
+
+ FLEXT_CALLBACK_I(m_pcm_seek)
+ FLEXT_CALLBACK_F(m_time_seek)
+
+ FLEXT_CALLBACK_F(m_src_factor)
+
+ FLEXT_THREAD(m_child)
+ FLEXT_CALLBACK(m_bang)
+
+
+ Readsf *readsf;
+ ThrCond cond;
+ ThrMutex sysmut;
+ ThrMutex varmutex;
+ Fifo *fifo;
+ Input *in;
+ int format;
+ int outtick, counttick;
+ int fifosecondsize;
+
+ volatile int state, request;
+ volatile bool loop, eof, quit, sendout;
+ volatile float floatmsg, cachemsg, lengthinseconds;
+
+ char filename[1024];
+ int num_channels;
+ double samplerate;
+
+ volatile long pcmseek;
+ volatile double timeseek;
+
+ float read_buffer[READBUFFER];
+ float pd_buffer[1024*2*FLOATSIZE];
+
+ ///Secret Rabbit Code stuff
+ int src_channels;
+ float *src_buffer;
+ SRC_STATE * src_state;
+ SRC_DATA src_data;
+ double src_factor;
+ int src_error;
+ int src_mode;
+};
diff --git a/include/stamp-h2.in b/include/stamp-h2.in
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/include/stamp-h2.in
diff --git a/src/Fifo.cpp b/src/Fifo.cpp
new file mode 100644
index 0000000..c5f0853
--- /dev/null
+++ b/src/Fifo.cpp
@@ -0,0 +1,152 @@
+#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;
+}
diff --git a/src/Input.cpp b/src/Input.cpp
new file mode 100644
index 0000000..549528d
--- /dev/null
+++ b/src/Input.cpp
@@ -0,0 +1,56 @@
+#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;
+}
diff --git a/src/InputFile.cpp b/src/InputFile.cpp
new file mode 100644
index 0000000..73b5c2b
--- /dev/null
+++ b/src/InputFile.cpp
@@ -0,0 +1,172 @@
+#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);
+}
diff --git a/src/InputStream.cpp b/src/InputStream.cpp
new file mode 100644
index 0000000..8b6a331
--- /dev/null
+++ b/src/InputStream.cpp
@@ -0,0 +1,473 @@
+#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;
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..5b47170
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,30 @@
+
+INCLUDES =\
+ -I/usr/local/include/ -I/usr/local/lib/pd/flext/ -I../include/
+
+CFLAGS = \
+ @FLEXT_CFLAGS@ @VORBIS_CFLAGS@ @MAD_CFLAGS@ @FLC_CFLAGS@
+
+CXXFLAGS = \
+ @FLEXT_CFLAGS@ @VORBIS_CFLAGS@ @MAD_CFLAGS@ @FLC_CFLAGS@
+
+bin_PROGRAMS = readanysf~.@pd_suffix@
+
+readanysf__@pd_suffix@_SOURCES = \
+ Fifo.cpp\
+ Input.cpp\
+ InputFile.cpp\
+ InputStream.cpp\
+ ReadRaw.cpp\
+ Readsf.cpp\
+ main.cpp\
+ ReadMad.cpp\
+ ReadVorbis.cpp \
+ ReadFlac.cpp
+
+#readanysf__pd_linux_LDFLAGS = -L/usr/local/lib/pd/flext/
+
+#### IMPORTANT!!! FLEXT_LIBS HAS TO CUM FIRST
+readanysf__@pd_suffix@_LDADD = \
+ @FLEXT_LIBS@ @PTHREAD_LIBS@ @SRC_LIBS@ @FLEXT_LIBS@ @VORBIS_LIBS@ @MAD_LIBS@ @FLC_LIBS@
+
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..323545c
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,374 @@
+# Makefile.in generated by automake 1.6.3 from Makefile.am.
+# @configure_input@
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = @program_transform_name@
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+
+EXEEXT = @EXEEXT@
+OBJEXT = @OBJEXT@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+AMTAR = @AMTAR@
+AWK = @AWK@
+CPP = @CPP@
+CXX = @CXX@
+DEPDIR = @DEPDIR@
+FLC_CFLAGS = @FLC_CFLAGS@
+FLC_LIBS = @FLC_LIBS@
+FLEXT_CFLAGS = @FLEXT_CFLAGS@
+FLEXT_LIBS = @FLEXT_LIBS@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+MAD_CFLAGS = @MAD_CFLAGS@
+MAD_LIBS = @MAD_LIBS@
+PACKAGE = @PACKAGE@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+SRC_LIBS = @SRC_LIBS@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VORBIS_CFLAGS = @VORBIS_CFLAGS@
+VORBIS_LIBS = @VORBIS_LIBS@
+am__include = @am__include@
+am__quote = @am__quote@
+install_sh = @install_sh@
+pd_suffix = @pd_suffix@
+
+INCLUDES = \
+ -I/usr/local/include/ -I/usr/local/lib/pd/flext/ -I../include/
+
+
+CFLAGS = \
+ @FLEXT_CFLAGS@ @VORBIS_CFLAGS@ @MAD_CFLAGS@ @FLC_CFLAGS@
+
+
+CXXFLAGS = \
+ @FLEXT_CFLAGS@ @VORBIS_CFLAGS@ @MAD_CFLAGS@ @FLC_CFLAGS@
+
+
+bin_PROGRAMS = readanysf~.@pd_suffix@
+
+readanysf__@pd_suffix@_SOURCES = \
+ Fifo.cpp\
+ Input.cpp\
+ InputFile.cpp\
+ InputStream.cpp\
+ ReadRaw.cpp\
+ Readsf.cpp\
+ main.cpp\
+ ReadMad.cpp\
+ ReadVorbis.cpp \
+ ReadFlac.cpp
+
+
+#readanysf__pd_linux_LDFLAGS = -L/usr/local/lib/pd/flext/
+
+#### IMPORTANT!!! FLEXT_LIBS HAS TO CUM FIRST
+readanysf__@pd_suffix@_LDADD = \
+ @FLEXT_LIBS@ @PTHREAD_LIBS@ @SRC_LIBS@ @FLEXT_LIBS@ @VORBIS_LIBS@ @MAD_LIBS@ @FLC_LIBS@
+
+subdir = src
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+bin_PROGRAMS = readanysf~.@pd_suffix@$(EXEEXT)
+PROGRAMS = $(bin_PROGRAMS)
+
+am_readanysf__@pd_suffix@_OBJECTS = Fifo.$(OBJEXT) Input.$(OBJEXT) \
+ InputFile.$(OBJEXT) InputStream.$(OBJEXT) ReadRaw.$(OBJEXT) \
+ Readsf.$(OBJEXT) main.$(OBJEXT) ReadMad.$(OBJEXT) \
+ ReadVorbis.$(OBJEXT) ReadFlac.$(OBJEXT)
+readanysf__@pd_suffix@_OBJECTS = $(am_readanysf__@pd_suffix@_OBJECTS)
+readanysf__@pd_suffix@_DEPENDENCIES =
+readanysf__@pd_suffix@_LDFLAGS =
+
+DEFS = @DEFS@
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/Fifo.Po ./$(DEPDIR)/Input.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/InputFile.Po ./$(DEPDIR)/InputStream.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ReadFlac.Po ./$(DEPDIR)/ReadMad.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ReadRaw.Po ./$(DEPDIR)/ReadVorbis.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/Readsf.Po ./$(DEPDIR)/main.Po
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
+ -o $@
+DIST_SOURCES = $(readanysf__@pd_suffix@_SOURCES)
+DIST_COMMON = Makefile.am Makefile.in
+SOURCES = $(readanysf__@pd_suffix@_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .o .obj
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(bindir)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f"; \
+ $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f $(DESTDIR)$(bindir)/$$f"; \
+ rm -f $(DESTDIR)$(bindir)/$$f; \
+ done
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+readanysf~.@pd_suffix@$(EXEEXT): $(readanysf__@pd_suffix@_OBJECTS) $(readanysf__@pd_suffix@_DEPENDENCIES)
+ @rm -f readanysf~.@pd_suffix@$(EXEEXT)
+ $(CXXLINK) $(readanysf__@pd_suffix@_LDFLAGS) $(readanysf__@pd_suffix@_OBJECTS) $(readanysf__@pd_suffix@_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Fifo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Input.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InputFile.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InputStream.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ReadFlac.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ReadMad.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ReadRaw.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ReadVorbis.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Readsf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+
+distclean-depend:
+ -rm -rf ./$(DEPDIR)
+
+.cpp.o:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<
+
+.cpp.obj:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(CXXCOMPILE) -c -o $@ `cygpath -w $<`
+CXXDEPMODE = @CXXDEPMODE@
+uninstall-info-am:
+
+ETAGS = etags
+ETAGSFLAGS =
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$tags$$unique" \
+ || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @list='$(DISTFILES)'; for file in $$list; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkinstalldirs) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(bindir)
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+ distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+uninstall-am: uninstall-binPROGRAMS uninstall-info-am
+
+.PHONY: GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic distclean distclean-compile distclean-depend \
+ distclean-generic distclean-tags distdir dvi dvi-am info \
+ info-am install install-am install-binPROGRAMS install-data \
+ install-data-am install-exec install-exec-am install-info \
+ install-info-am install-man install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic tags uninstall uninstall-am \
+ uninstall-binPROGRAMS uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/ReadFlac.cpp b/src/ReadFlac.cpp
new file mode 100644
index 0000000..3ecba75
--- /dev/null
+++ b/src/ReadFlac.cpp
@@ -0,0 +1,288 @@
+/*
+ * 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
diff --git a/src/ReadFlac.cpp.seekable b/src/ReadFlac.cpp.seekable
new file mode 100644
index 0000000..17992b9
--- /dev/null
+++ b/src/ReadFlac.cpp.seekable
@@ -0,0 +1,398 @@
+/*
+ * readanysf~ external for pd.
+ *
+ * Copyright (C) 2003,2004 August Black
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ReadFlac.cpp
+ *
+ * much of the code comes from FLAC input plugin for Winamp3
+ * distributed with the flac source under the GPL
+ * Copyright (C) 2000,2001,2002,2003 Josh Coalson
+ */
+
+#ifdef READ_FLAC
+
+//#include <m_pd.h>
+#include "ReadFlac.h"
+#include <iostream>
+
+extern "C" {
+#include "FLAC/metadata.h"
+};
+
+using namespace std;
+
+ReadFlac::ReadFlac( Input *input ) {
+ in=input;
+ needs_seek = false;
+ seek_sample = 0;
+ samples_in_reservoir =0;
+ abort_flag = false;
+ decoder = NULL;
+ filelength = 0;
+}
+
+ReadFlac::~ReadFlac() {
+ cout << "exiting FLAC ..." << endl;
+ //exit(1);
+ cleanup();
+}
+
+bool ReadFlac::Initialize( ) {
+
+
+ //@@@ to be really "clean" we should go through the reader instead of directly to the file...
+ if(!FLAC__metadata_get_streaminfo(in->get_filename(), &streaminfo)) {
+ cout << "what the fuck" << endl;
+ return 1;
+ }
+
+ //length_msec = lengthInMsec();
+ /*cout << "FLAC:<%ihz:%ibps:%dch>",
+ streaminfo.data.stream_info.sample_rate,
+ streaminfo.data.stream_info.bits_per_sample,
+ streaminfo.data.stream_info.channels); //@@@ fix later
+ */
+
+ samplerate = (double)streaminfo.data.stream_info.sample_rate;
+ num_channels = streaminfo.data.stream_info.channels;
+ lengthinseconds = streaminfo.data.stream_info.total_samples/samplerate;
+
+ filelength = in->SeekEnd(0);
+ filelength = in->SeekCur(0);
+ in->SeekSet(0);
+
+ decoder = FLAC__seekable_stream_decoder_new();
+ if(decoder == 0)
+ return false;
+ FLAC__seekable_stream_decoder_set_md5_checking(decoder, false);
+ FLAC__seekable_stream_decoder_set_read_callback(decoder, readCallback_);
+ FLAC__seekable_stream_decoder_set_seek_callback(decoder, seekCallback_);
+ FLAC__seekable_stream_decoder_set_tell_callback(decoder, tellCallback_);
+ FLAC__seekable_stream_decoder_set_length_callback(decoder, lengthCallback_);
+ FLAC__seekable_stream_decoder_set_eof_callback(decoder, eofCallback_);
+ FLAC__seekable_stream_decoder_set_write_callback(decoder, writeCallback_);
+ FLAC__seekable_stream_decoder_set_metadata_callback(decoder, metadataCallback_);
+ FLAC__seekable_stream_decoder_set_error_callback(decoder, errorCallback_);
+ FLAC__seekable_stream_decoder_set_client_data(decoder, this);
+
+ if(FLAC__seekable_stream_decoder_init(decoder) != FLAC__SEEKABLE_STREAM_DECODER_OK) {
+ cleanup();
+ return false;
+ }
+ if(!FLAC__seekable_stream_decoder_process_until_end_of_metadata(decoder)) {
+ cleanup();
+ return false;
+ }
+
+ return true;
+}
+
+
+
+int ReadFlac::Decode(float *buffer, int size) {
+
+ if(decoder == NULL)
+ return 0;
+
+ if(needs_seek) {
+ FLAC__seekable_stream_decoder_seek_absolute(decoder, seek_sample);
+ //cout << "seeking " << seek_sample << " samples" << endl;
+ needs_seek = false;
+ }
+
+ //while (samples_in_reservoir < 576) {
+ //if (samples_in_reservoir < 576) {
+ if(FLAC__seekable_stream_decoder_get_state(decoder) == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) {
+ cout << "FLAC: end of file" << endl;
+ return 0;
+ } else if(!FLAC__seekable_stream_decoder_process_single(decoder)) {
+
+ //ErrorCheck( FLAC__seekable_stream_decoder_get_state(decoder) );
+ //ErrorCheck( FLAC__seekable_stream_decoder_finish(decoder) );
+ //ErrorCheck( FLAC__seekable_stream_decoder_init(decoder) );
+ //FLAC__seekable_stream_decoder_reset(decoder);
+ //FLAC__seekable_stream_decoder_flush(decoder);
+ cout << "FLAC: no process single " << endl;
+ //break;
+ //exit(1);
+ //return 0;
+ //return samples_in_reservoir;
+ }
+ //}
+
+ int n = samples_in_reservoir; // > 576 ? samples_in_reservoir: 576;
+ const unsigned channels = streaminfo.data.stream_info.channels;
+
+ if(samples_in_reservoir == 0) {
+ //cout << "FLAC: reservoir is empty" << endl;
+ return 0;
+ } else {
+
+ //const unsigned bits_per_sample = streaminfo.data.stream_info.bits_per_sample;
+ //const unsigned bytes_per_sample = (bits_per_sample+7)/8;
+ //const unsigned sample_rate = streaminfo.data.stream_info.sample_rate;
+ unsigned i;
+ //16 > WHDR2 + 2 ? 16 : WHDR2 + 2
+
+ //unsigned delta;
+
+
+ for(i = 0; i < n*channels; i++)
+ buffer[i] = (float) ( reservoir[i]/ 32768.0 );
+
+
+ samples_in_reservoir = 0;
+
+ //const int bytes = n * channels * bytes_per_sample;
+ }
+
+ //if(eof)
+ //return 0;
+
+ return n*channels; //1;
+}
+
+bool ReadFlac::Rewind() {
+ needs_seek = true;
+ seek_sample = 0;
+ samples_in_reservoir = 0;
+ //ErrorCheck( FLAC__seekable_stream_decoder_get_state(decoder) );
+ //FLAC__seekable_stream_decoder_seek_absolute(decoder, 0);
+ return true;
+}
+
+bool ReadFlac::PCM_seek(long bytes) {
+
+ if ( bytes < (long) streaminfo.data.stream_info.total_samples ) {
+ needs_seek = true;
+ //bool ret = FLAC__seekable_stream_decoder_seek_absolute(decoder, bytes);
+ //if (ret) {
+ //samples_in_reservoir = 0;
+ //FLAC__seekable_stream_decoder_flush(decoder);
+ //cout << "successfull seeking" << endl;
+ //return true;
+ // }else {
+ //cout << "UNsuccessfull seeking" << endl;
+ //return false;
+ //}
+ seek_sample = bytes;
+ return true;
+ } else {
+ cout << " GOT HERE " << endl;
+ return false;
+ }
+}
+
+bool ReadFlac::TIME_seek(double seconds) {
+
+ //lengthInMsec();
+ if ( seconds < lengthinseconds ) {
+ //cout << "FLAC: time seek" << endl;
+ needs_seek = true;
+ seek_sample = (FLAC__uint64)(seconds * streaminfo.data.stream_info.sample_rate);
+ return true;
+ } else {
+
+ return false;
+ }
+
+}
+
+
+void ReadFlac::cleanup()
+{
+ if(decoder) {
+ FLAC__seekable_stream_decoder_finish(decoder);
+ FLAC__seekable_stream_decoder_delete(decoder);
+ decoder = NULL;
+ }
+}
+
+FLAC__SeekableStreamDecoderReadStatus ReadFlac::readCallback_(const FLAC__SeekableStreamDecoder *decoder,
+ FLAC__byte buffer[],
+ unsigned *bytes,
+ void *client_data) {
+ ReadFlac *instance = (ReadFlac*)client_data;
+ *bytes = instance->in->Read( (char *)buffer, *bytes);
+ if (*bytes == 0) {
+ cout << "FLAC: read returned 0" << endl;
+ return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
+ } else {
+ return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
+ }
+}
+
+FLAC__SeekableStreamDecoderSeekStatus ReadFlac::seekCallback_(const FLAC__SeekableStreamDecoder *decoder,
+ FLAC__uint64 absolute_byte_offset,
+ void *client_data) {
+
+ //if (!client_data)
+ //return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
+
+ ReadFlac *instance = (ReadFlac*)client_data;
+ //if (!instance)
+ //return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
+
+ instance->ErrorCheck( FLAC__seekable_stream_decoder_get_state(decoder) );
+
+ //if (absolute_byte_offset < 0)
+ //absolute_byte_offset = 0;
+ long pos = instance->in->SeekSet( (long)absolute_byte_offset ) ;
+ if ( pos == -1 ) {
+ cout << "COULD NOT seek " << absolute_byte_offset << " bytes" << endl;
+ return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
+ } else {
+ //cout << "seeked %ld bytes", pos);
+ return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
+ }
+}
+
+
+FLAC__SeekableStreamDecoderTellStatus ReadFlac::tellCallback_(const FLAC__SeekableStreamDecoder *decoder,
+ FLAC__uint64 *absolute_byte_offset,
+ void *client_data) {
+ ReadFlac *instance = (ReadFlac*)client_data;
+
+ long pos = instance->in->SeekCur( *absolute_byte_offset );
+ if ( pos != -1 ) {
+ *absolute_byte_offset = pos;
+ //cout << "FLAC: tell is ok" << endl;
+ return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
+ } else {
+ cout << "FLAC: tell is NOT ok" << endl;
+ return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR;
+ }
+}
+
+FLAC__SeekableStreamDecoderLengthStatus ReadFlac::lengthCallback_(const FLAC__SeekableStreamDecoder *decoder,
+ FLAC__uint64 *stream_length,
+ void *client_data) {
+ ReadFlac *instance = (ReadFlac*)client_data;
+ *stream_length = (FLAC__uint64)instance->filelength;
+ return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
+}
+
+FLAC__bool ReadFlac::eofCallback_(const FLAC__SeekableStreamDecoder *decoder,
+ void *client_data) {
+ ReadFlac *instance = (ReadFlac*)client_data;
+ long pos = instance->in->SeekCur(0);
+ if ( pos == instance->filelength ) {
+ //instance->in->SeekSet(pos);
+ cout << "FLAC: eofCallback: it is EOF" << endl;
+ //exit(1);
+ return 1;
+ } else {
+ //post ("FLAC: eofCallback: not eof %ld, filelength %ld", pos, instance->filelength);
+ //instance->in->SeekSet(pos);
+ return 0;
+ }
+}
+
+FLAC__StreamDecoderWriteStatus ReadFlac::writeCallback_(const FLAC__SeekableStreamDecoder *decoder,
+ const FLAC__Frame *frame,
+ const FLAC__int32 * const buffer[],
+ void *client_data) {
+ ReadFlac *instance = (ReadFlac*)client_data;
+ //const unsigned bps = instance->streaminfo.data.stream_info.bits_per_sample;
+ const unsigned channels = instance->streaminfo.data.stream_info.channels;
+ const unsigned wide_samples = frame->header.blocksize;
+ unsigned wide_sample, sample, channel;
+
+ (void)decoder;
+
+ if(instance->abort_flag) {
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+ //cout << "FLAC: blocksize = " << wide_samples << endl;
+ for(sample = instance->samples_in_reservoir*channels, wide_sample = 0;
+ wide_sample < wide_samples; wide_sample++)
+ for(channel = 0; channel < channels; channel++, sample++)
+ instance->reservoir[sample] = (FLAC__int16)buffer[channel][wide_sample];
+
+ instance->samples_in_reservoir += wide_samples;
+
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void ReadFlac::metadataCallback_(const FLAC__SeekableStreamDecoder *decoder,
+ const FLAC__StreamMetadata *metadata,
+ void *client_data) {
+ ReadFlac *instance = (ReadFlac*)client_data;
+ (void)decoder;
+
+ //cout << "FLAC: metadata callback" << endl;
+ if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+ instance->streaminfo = *metadata;
+
+ if(instance->streaminfo.data.stream_info.bits_per_sample != 16) {
+ cout << "\nFLAC: bps is not 16 ..Aboorting ...\n" << endl;
+ instance->abort_flag = true;
+ //exit(1);
+ return;
+ }
+ }
+}
+
+void ReadFlac::errorCallback_(const FLAC__SeekableStreamDecoder *decoder,
+ FLAC__StreamDecoderErrorStatus status,
+ void *client_data) {
+ ReadFlac *instance = (ReadFlac*)client_data;
+ (void)decoder;
+ if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC) {
+ cout << "FLAC: error callback - lost sync, trying reset,flush" << endl;
+ FLAC__seekable_stream_decoder_reset(instance->decoder);
+ FLAC__seekable_stream_decoder_flush(instance->decoder);
+ //instance->abort_flag = true;
+ }
+}
+
+void ReadFlac::ErrorCheck(int state) {
+ switch (state) {
+ case FLAC__SEEKABLE_STREAM_DECODER_SEEKING:
+ //cout << "SEEKING " << endl;
+ break;
+ case FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM :
+ cout << "END_OF_STREAM " << endl;
+ break;
+ case FLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR :
+ cout << "MEMORY_ALLOCATION_ERROR " << endl;
+ break;
+ case FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR :
+ cout << "STREAM_DECODER_ERROR " << endl;
+ break;
+ case FLAC__SEEKABLE_STREAM_DECODER_READ_ERROR :
+ cout << "READ_ERROR " << endl;
+ break;
+ case FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR :
+ cout << "SEEK_ERROR " << endl;
+ break;
+ case FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK :
+ cout << "INVALID_CALLBACK " << endl;
+ break;
+ case FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED :
+ cout << "UNINITIALIZED " << endl;
+ break;
+ case FLAC__SEEKABLE_STREAM_DECODER_OK :
+ default:
+ cout << "OK" << endl;
+ break;
+ }
+}
+
+
+#endif
diff --git a/src/ReadMad.cpp b/src/ReadMad.cpp
new file mode 100644
index 0000000..694e044
--- /dev/null
+++ b/src/ReadMad.cpp
@@ -0,0 +1,474 @@
+/*
+ * 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
diff --git a/src/ReadRaw.cpp b/src/ReadRaw.cpp
new file mode 100644
index 0000000..30d86e8
--- /dev/null
+++ b/src/ReadRaw.cpp
@@ -0,0 +1,394 @@
+/*
+ * 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);
+}
diff --git a/src/ReadVorbis.cpp b/src/ReadVorbis.cpp
new file mode 100644
index 0000000..500486c
--- /dev/null
+++ b/src/ReadVorbis.cpp
@@ -0,0 +1,272 @@
+/*
+ * 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
diff --git a/src/Readsf.cpp b/src/Readsf.cpp
new file mode 100644
index 0000000..e62196b
--- /dev/null
+++ b/src/Readsf.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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;
+}
diff --git a/src/config.h.in b/src/config.h.in
new file mode 100644
index 0000000..61025bc
--- /dev/null
+++ b/src/config.h.in
@@ -0,0 +1 @@
+/* config.h.in. Generated automatically from configure.in by autoheader. */
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..abc55a2
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,664 @@
+/*
+ * 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;
+}
diff --git a/src/simple.pd b/src/simple.pd
new file mode 100644
index 0000000..e5fae3a
--- /dev/null
+++ b/src/simple.pd
@@ -0,0 +1,107 @@
+#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;