diff options
author | B. Bogart <bbogart@users.sourceforge.net> | 2005-08-13 01:16:59 +0000 |
---|---|---|
committer | B. Bogart <bbogart@users.sourceforge.net> | 2005-08-13 01:16:59 +0000 |
commit | 5e05f47d61ebad8aee6c3831912b21ad5dcc36e3 (patch) | |
tree | b8793d1908e5c2ce256e886357cbcb86e1b768b9 |
Initial commit of readanysf~ 0.13.1 for Augustsvn2git-root
svn path=/trunk/externals/august/readanysf~/; revision=3426
-rw-r--r-- | include/Fifo.h | 31 | ||||
-rw-r--r-- | include/Input.h | 56 | ||||
-rw-r--r-- | include/InputFile.h | 29 | ||||
-rw-r--r-- | include/InputStream.h | 83 | ||||
-rw-r--r-- | include/Makefile | 223 | ||||
-rw-r--r-- | include/Makefile.am | 21 | ||||
-rw-r--r-- | include/Makefile.in | 223 | ||||
-rw-r--r-- | include/ReadFlac.h | 88 | ||||
-rw-r--r-- | include/ReadFlac.h.seekable | 93 | ||||
-rw-r--r-- | include/ReadMad.h | 125 | ||||
-rw-r--r-- | include/ReadRaw.h | 154 | ||||
-rw-r--r-- | include/ReadVorbis.h | 99 | ||||
-rw-r--r-- | include/Readsf.h | 62 | ||||
-rw-r--r-- | include/generic.h | 48 | ||||
-rw-r--r-- | include/main.h | 158 | ||||
-rw-r--r-- | include/stamp-h2.in | 0 | ||||
-rw-r--r-- | src/Fifo.cpp | 152 | ||||
-rw-r--r-- | src/Input.cpp | 56 | ||||
-rw-r--r-- | src/InputFile.cpp | 172 | ||||
-rw-r--r-- | src/InputStream.cpp | 473 | ||||
-rw-r--r-- | src/Makefile.am | 30 | ||||
-rw-r--r-- | src/Makefile.in | 374 | ||||
-rw-r--r-- | src/ReadFlac.cpp | 288 | ||||
-rw-r--r-- | src/ReadFlac.cpp.seekable | 398 | ||||
-rw-r--r-- | src/ReadMad.cpp | 474 | ||||
-rw-r--r-- | src/ReadRaw.cpp | 394 | ||||
-rw-r--r-- | src/ReadVorbis.cpp | 272 | ||||
-rw-r--r-- | src/Readsf.cpp | 65 | ||||
-rw-r--r-- | src/config.h.in | 1 | ||||
-rw-r--r-- | src/main.cpp | 664 | ||||
-rw-r--r-- | src/simple.pd | 107 |
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, ¤t_section); + if (ret == 0 ) { + // This means it is a definite end of file, lets return zero here. + return 0; + } else if (ret <= 0) { + switch (ret) { + case OV_HOLE: + cout << "ReadVorbis:: there was an interruption in the data. " << endl; + cout << "one of: garbage between pages, loss of sync followed" << + " by recapture, or a corrupt page" << endl; + break; + case OV_EBADLINK: + cout << "ReadVorbis:: an invalid stream section was supplied " << + "to libvorbisfile, or the requested link is corrupt" << endl; + break; + default: + cout << "ReadVorbis:: unknown error on ov_read_float" << endl; + break; + } + + for(int j = 0; j < 1024; j++) { + buffer[x++] = 0.0; + } + return 512; + + } else { + + // we should check here to see if ret is larger than size! + for(int j = 0; j < ret; j++) { + buffer[x++] = buftmp[0][j]; + if (num_channels == 2) + buffer[x++] = buftmp[1][j]; + } + } + //cout << "x %d", x); + return x; //ret; + +} + +size_t ReadVorbis::read_func(void *ptr, size_t size, size_t nmemb, void *datasource) { + + Input * tmpin = ( Input *)datasource; + unsigned int get = size*nmemb; + size_t ret; + // cout << "ReadVorbis:: calling read function" << endl; + + ret = tmpin->Read( ptr, get); + + //cout << "read from fifo, get %d, ret %d, size %d, nmemb %d", + //get, ret,size,nmemb ); + + return ret;//size*nmemb; +} + +int ReadVorbis::seek_func(void *datasource, ogg_int64_t offset, int whence) { + // InputStream will always return -1 + Input * tmpin = ( Input *)datasource; + switch ( whence ) { + case SEEK_SET: + return tmpin->SeekSet( offset ); + break; + case SEEK_CUR: + return tmpin->SeekCur( offset ); + break; + case SEEK_END: + return tmpin->SeekEnd( offset ); + break; + default: + return -1; + break; + } + +} + +int ReadVorbis::close_func(void *datasource) { + + cout << "ReadVorbis:: calling close function" << endl; + //ov_clear(&vf); + //return tmpin->Close(); + return 0; +} + +long ReadVorbis::tell_func(void *datasource) { + // InputStream will always return -1 + Input * tmpin = ( Input *)datasource; + return tmpin->SeekCur( 0 ); + +} + +bool ReadVorbis::Rewind() { + ov_pcm_seek(&vf, 0); + return true; // need to return true here for fill_buffer of main.cpp +} + +bool ReadVorbis::PCM_seek(long bytes) { + int ret = ov_pcm_seek(&vf, bytes); + if ( ret == 0) + return true; + else { + switch (ret) { + case OV_ENOSEEK: + cout << "ReadVorbis:: stream not seekable" << endl; + break; + case OV_EINVAL: + ret = ov_pcm_seek(&vf, 0); + if (ret == 0) + return true; + else + cout << "ReadVorbis:: invalid argument" << endl; + + break; + case OV_EREAD: + cout << "ReadVorbis:: read returned an error" << endl; + break; + case OV_EOF: + cout << "ReadVorbis:: End of File" << endl; + break; + case OV_EBADLINK: + cout << "ReadVorbis:: invalid stream section" << endl; + break; + default: + cout << "ReadVorbis:: some other seek error PCM_seek" << endl; + break; + } + return false; + } +} + +bool ReadVorbis::TIME_seek(double seconds) { + int ret = ov_time_seek(&vf, seconds); + if ( ret == 0) + return true; + else { + switch (ret) { + case OV_ENOSEEK: + cout << "ReadVorbis:: stream not seekable" << endl; + break; + case OV_EINVAL: + cout << "ReadVorbis:: invalid argument" << endl; + break; + case OV_EREAD: + cout << "ReadVorbis:: read returned an error" << endl; + break; + case OV_EOF: + cout << "ReadVorbis:: End of File" << endl; + break; + case OV_EBADLINK: + cout << "ReadVorbis:: invalid stream section" << endl; + break; + default: + cout << "ReadVorbis:: some other seek error Time_seek" << endl; + break; + } + return false; + } +} + + + + +#endif 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; |