From 10dee9a91925645cd9e3bb14e5ef31e8a338949e Mon Sep 17 00:00:00 2001 From: Georg Holzmann Date: Wed, 1 Feb 2006 09:01:28 +0000 Subject: now possible to read ogg file (using libvorbisfile) svn path=/trunk/externals/tb/; revision=4531 --- sndfiler/src/Makefile | 9 +- sndfiler/src/Makefile.pd_main | 14 ++- sndfiler/src/file_input.c | 253 ++++++++++++++++++++++++++++++++++++++++++ sndfiler/src/file_input.h | 66 +++++++++++ sndfiler/src/sndfiler.c | 170 +++++----------------------- sndfiler/src/sndfiler.h | 87 +++++++++++++++ 6 files changed, 451 insertions(+), 148 deletions(-) create mode 100644 sndfiler/src/file_input.c create mode 100644 sndfiler/src/file_input.h create mode 100755 sndfiler/src/sndfiler.h diff --git a/sndfiler/src/Makefile b/sndfiler/src/Makefile index 2b17d1c..b8f1c8a 100755 --- a/sndfiler/src/Makefile +++ b/sndfiler/src/Makefile @@ -2,6 +2,8 @@ NAME=sndfiler CSYM=sndfiler +OBJ=sndfiler.o file_input.o + current: pd_linux # ----------------------- NT ----------------------- @@ -65,13 +67,14 @@ LINUXCFLAGS = -DPD -O3 -fPIC -funroll-loops -fomit-frame-pointer \ -Wall -W -Wshadow -Wstrict-prototypes -Werror \ -Wno-unused -Wno-parentheses -Wno-switch -LINUXINCLUDE = -I/home/tim/pd/devel_0_39/src +LINUXINCLUDE = -I../../../../pd/src LSTRIP = strip --strip-unneeded -R .note -R .comment .c.pd_linux: - cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c - cc -Wl,-export_dynamic --shared -o $*.pd_linux $*.o -lm -lsndfile + cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o sndfiler.o -c sndfiler.c + cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o file_input.o -c file_input.c + cc -Wl,-export_dynamic --shared -o $*.pd_linux $(OBJ) -lm -lsndfile -lvorbisfile # $(LSTRIP) $*.pd_linux rm -f $*.o diff --git a/sndfiler/src/Makefile.pd_main b/sndfiler/src/Makefile.pd_main index f5a70e5..29bde80 100755 --- a/sndfiler/src/Makefile.pd_main +++ b/sndfiler/src/Makefile.pd_main @@ -41,6 +41,8 @@ CC_FLAGS = -DPD -DUSE_PD_MAIN -O3 -funroll-loops \ -Wno-unused -fomit-frame-pointer LD_FLAGS = --export-dynamic -shared -o +OBJ=sndfiler.o file_input.o + current: @echo ---------------------------- @echo USAGE: @@ -56,11 +58,12 @@ pd_linux: $(NAME).pd_linux .SUFFIXES: .pd_linux CC_UNIX = -DUNIX -fPIC -pthread -LIB_UNIX = -lc -lm -lsndfile $(THREADLIB_PATH)/threadlib.pd_linux +LIB_UNIX = -lc -lm -lsndfile -lvorbisfile $(THREADLIB_PATH)/threadlib.pd_linux .c.pd_linux: - $(CC) $(CC_UNIX) $(CC_FLAGS) $(INCLUDE) -o $*.o -c $*.c - $(LD) $(LD_FLAGS) $*.pd_linux $*.o $(LIB_UNIX) + $(CC) $(CC_UNIX) $(CC_FLAGS) $(INCLUDE) -o sndfiler.o -c sndfiler.c + $(CC) $(CC_UNIX) $(CC_FLAGS) $(INCLUDE) -o file_input.o -c file_input.c + $(LD) $(LD_FLAGS) $*.pd_linux $(OBJ) $(LIB_UNIX) strip --strip-unneeded $*.pd_linux chmod 755 $*.pd_linux @test -d ../bin || mkdir -p ../bin @@ -97,11 +100,12 @@ pd_darwin: $(NAME).pd_darwin CC_DARWIN = -pthread LD_DARWIN = -bundle -undefined suppress -flat_namespace \ -bundle_loader $(PD_PATH)/bin/pd --export-dynamic \ - -L/sw/lib -L/opt/local/lib -lsndfile \ + -L/sw/lib -L/opt/local/lib -lsndfile -lvorbisfile \ $(THREADLIB_PATH)/threadlib.pd_darwin .c.pd_darwin: - $(CC) $(CC_FLAGS) $(CC_DARWIN) $(INCLUDE) -o $*.o -c $*.c + $(CC) $(CC_UNIX) $(CC_FLAGS) $(INCLUDE) -o sndfiler.o -c sndfiler.c + $(CC) $(CC_UNIX) $(CC_FLAGS) $(INCLUDE) -o file_input.o -c file_input.c $(LD) $(LD_DARWIN) -o $*.pd_darwin $*.o $(LIB) chmod 755 $*.pd_darwin @test -d ../bin || mkdir -p ../bin diff --git a/sndfiler/src/file_input.c b/sndfiler/src/file_input.c new file mode 100644 index 0000000..79ad27e --- /dev/null +++ b/sndfiler/src/file_input.c @@ -0,0 +1,253 @@ +/* + * threaded soundfiler for PD + * Copyright (C) 2005, Georg Holzmann + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "sndfiler.h" +#include "file_input.h" + +int check_fileformat(t_symbol* file) +{ + FILE *fp = NULL; + OggVorbis_File vorbisfile; + + // partially opens a vorbis file to test for Vorbis-ness + if( !(fp = fopen(file->s_name, "r")) ) + return -1; + + if( ov_test(fp, &vorbisfile, NULL, 0) < 0 ) + { + fclose(fp); + return USE_LIBSNDFILE; + } + + ov_clear(&vorbisfile); + return USE_LIBVORBISFILE; +} + +int read_libsndfile(t_float** helper_arrays, int channel_count, int seek, + int resize, int array_size, t_symbol* file) +{ + int arraysize = array_size; + int writesize = 0, i=0, j=0; + SNDFILE* sndfile; + SF_INFO info; + + sndfile = sf_open(file->s_name, SFM_READ, &info); + + if(!sndfile) + return -1; + + int pos = 0; + int maxchannels = (channel_count < info.channels) ? + channel_count : info.channels; + + t_float * item = alloca(maxchannels * sizeof(t_float)); + + // negative seek: offset from the end of the file + if(seek<0) + { + if(CHECK_SEEK(seek+info.frames, info.frames)) + pos = sf_seek(sndfile, seek, SEEK_END); + else pos = -1; + } + if(seek>0) + { + if(CHECK_SEEK(seek, info.frames)) + pos = sf_seek(sndfile, seek, SEEK_SET); + else pos = -1; + } + if(pos == -1) + { + sf_close(sndfile); + post("invalid seek in soundfile"); + return -1; + } + + if(resize) + { + writesize = (info.frames-pos); + arraysize = writesize; + } + else + writesize = (arraysize>(info.frames-pos)) ? + info.frames-pos : arraysize; + +#if (_POSIX_MEMLOCK - 0) >= 200112L + munlockall(); +#endif + + for (i = 0; i != channel_count; ++i) + { + helper_arrays[i] = getalignedbytes(arraysize * sizeof(t_float)); + } + + for (i = 0; i != writesize; ++i) + { + sf_read_float(sndfile, item, info.channels); + + for (j = 0; j != info.channels; ++j) + { + if (j < channel_count) + { + helper_arrays[j][i] = item[j]; + } + } + } + + // fill remaining elements with zero + if(!resize && (arraysize > (info.frames-pos))) + { + for (i = writesize; i != arraysize; ++i) + { + for (j = 0; j != info.channels; ++j) + { + if (j < channel_count) + { + helper_arrays[j][i] = 0; + } + } + } + } + +#if (_POSIX_MEMLOCK - 0) >= 200112L + mlockall(MCL_FUTURE); +#endif + + sf_close(sndfile); + return arraysize; +} + +int read_libvorbisfile(t_float** helper_arrays, int channel_count, int seek, + int resize, int array_size, t_symbol* file) +{ + int arraysize = array_size; + int writesize = 0, i=0, j=0; + int pos=0, maxchannels=0, frames=0, frames_read=0; + int current_section=0, finished=0; + float **buftmp = NULL; + FILE *fp = NULL; + OggVorbis_File vorbisfile; + vorbis_info *info; + + if( !(fp = fopen(file->s_name, "r")) ) + return -1; + + if( ov_open(fp, &vorbisfile, NULL, 0) < 0 ) + { + fclose(fp); + return -1; + } + + info = ov_info(&vorbisfile, -1); + frames = ov_pcm_total(&vorbisfile, -1); + if( !info || frames==OV_EINVAL ) + { + ov_clear(&vorbisfile); + post("failed to get info about vorbis file"); + return -1; + } + + maxchannels = (channel_count < info->channels) ? + channel_count : info->channels; + + // negative seek: offset from the end of the file + if(seek<0) + { + if(CHECK_SEEK(frames+seek, frames)) + { + int ret = ov_pcm_seek(&vorbisfile, frames+seek); + if(ret!=0) + pos =-1; + else + pos = frames+seek; + } + else pos = -1; + } + if(seek>0) + { + if(CHECK_SEEK(seek, frames)) + { + int ret = ov_pcm_seek(&vorbisfile, seek); + if(ret!=0) + pos =-1; + else + pos = seek; + } + else pos = -1; + } + if(pos == -1) + { + ov_clear(&vorbisfile); + post("invalid seek in vorbis file"); + return -1; + } + + if(resize) + { + writesize = (frames-pos); + arraysize = writesize; + } + else + writesize = (arraysize>(frames-pos)) ? + frames-pos : arraysize; + +#if (_POSIX_MEMLOCK - 0) >= 200112L + munlockall(); +#endif + + for (i = 0; i != channel_count; ++i) + { + helper_arrays[i] = getalignedbytes(arraysize * sizeof(t_float)); + } + + for (i = 0; i != writesize; ++i) + { + int ret = ov_read_float(&vorbisfile, &buftmp, 1, + ¤t_section); + if(ret!=1) + post("wrong return type while ogg decoding!"); + + for (j = 0; j != channel_count; ++j) + { + helper_arrays[j][i] = buftmp[j][0]; + } + } + + // fill remaining elements with zero + if(!resize && (arraysize > (frames-pos))) + { + for (i = writesize; i != arraysize; ++i) + { + for (j = 0; j != info->channels; ++j) + { + if (j < channel_count) + { + helper_arrays[j][i] = 0; + } + } + } + } + +#if (_POSIX_MEMLOCK - 0) >= 200112L + mlockall(MCL_FUTURE); +#endif + + ov_clear(&vorbisfile); + return arraysize; +} diff --git a/sndfiler/src/file_input.h b/sndfiler/src/file_input.h new file mode 100644 index 0000000..e5b5232 --- /dev/null +++ b/sndfiler/src/file_input.h @@ -0,0 +1,66 @@ +/* + * threaded soundfiler for PD + * Copyright (C) 2005, Georg Holzmann + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _FILE_INPUT__ +#define _FILE_INPUT__ + +#define USE_LIBSNDFILE 0 +#define USE_LIBVORBISFILE 1 + +//! returns 1 if s is in [0,c) +#define CHECK_SEEK(s, c) (s<0 ? 0 : (s>=c ? 0 : 1)) + +/*! + * checks which library to use + * + * @param file filename + * @return USE_LIBSNDFILE or USE_LIBVORBISFILE, -1 if there was an error + */ +int check_fileformat(t_symbol* file); + +/*! + * read audio data with libsndfile + * + * @param helper_arrays (unallocated) pointer to the data + * @param channel_count nr of channels + * @param seek frames to seek in file + * @param resize 1 if array should be resized + * @param array_size size of the array in samples + * @param file filename + * @return new arraysiize, -1 if there was a failure + */ +int read_libsndfile(t_float** helper_arrays, int channel_count, int seek, + int resize, int array_size, t_symbol* file); + +/*! + * read audio data with libvorbisfile + * + * @param helper_arrays (unallocated) pointer to the data + * @param channel_count nr of channels + * @param seek frames to seek in file + * @param resize 1 if array should be resized + * @param array_size size of the array in samples + * @param file filename + * @return new arraysiize, -1 if there was a failure + */ +int read_libvorbisfile(t_float** helper_arrays, int channel_count, int seek, + int resize, int array_size, t_symbol* file); + +#endif //_FILE_INPUT__ diff --git a/sndfiler/src/sndfiler.c b/sndfiler/src/sndfiler.c index 9bf6b65..4cd14d9 100755 --- a/sndfiler/src/sndfiler.c +++ b/sndfiler/src/sndfiler.c @@ -1,6 +1,6 @@ /* * - * threaded soundfiler based on libsndfile + * threaded soundfiler for pd * Copyright (C) 2005, Tim Blechmann * (C) 2005, Georg Holzmann * @@ -20,14 +20,18 @@ * Boston, MA 02111-1307, USA. */ -/* to be compatible with main pd */ -#ifdef USE_PD_MAIN +#include "sndfiler.h" +#include "file_input.h" + -#define getalignedbytes(a) getbytes(a) -#define freealignedbytes(a,b) freebytes(a,b) -#include "threadlib.h" +/************ forward declarations **************/ -/* forward declaration */ +#ifdef UNIX +/* real-time flag, true if priority boosted */ +extern int sys_hipriority; +#endif + +#ifdef USE_PD_MAIN struct _garray { t_gobj x_gobj; @@ -39,56 +43,6 @@ struct _garray char x_saveit; /* true if we should save this with parent */ char x_listviewing; /* true if list view window is open */ }; - -#else /* now for pd_devel */ - -#include "m_pd.h" -#include "m_fifo.h" - -#include "pthread.h" - -#endif /* USE_PD_MAIN */ - - -#include "g_canvas.h" -#include "sndfile.h" - -#include "stdlib.h" -#include "sched.h" /* for thread priority */ -#include -#include "semaphore.h" - -/* for alloca */ -#ifdef MSW -#include -#else -#include "alloca.h" -#endif - -#if (_POSIX_MEMLOCK - 0) >= 200112L -#include -#endif /* _POSIX_MEMLOCK */ - -#ifdef __APPLE__ -#include -#include -#include -#define SEM_T semaphore_t -#define SEM_INIT(s) (semaphore_create(mach_task_self(),&s,SYNC_POLICY_FIFO,0) == 0) -#define SEM_SIGNAL(s) semaphore_signal(s) -#define SEM_WAIT(s) semaphore_wait(s) -#else -#define SEM_T sem_t -#define SEM_INIT(s) (sem_init(&s,0,0) == 0) -#define SEM_SIGNAL(s) sem_post(&s) -#define SEM_WAIT(s) sem_wait(&s) -#endif - -/************ forward declarations **************/ - -#ifdef UNIX -/* real-time flag, true if priority boosted */ -extern int sys_hipriority; #endif /* get a garray's "array" structure. */ @@ -206,7 +160,7 @@ static void sndfiler_start_thread(void) /* 1mb of stack should be enough */ pthread_attr_setstacksize(&sf_attr,1048576); - + #ifdef UNIX if (sys_hipriority == 1/* && getuid() == 0 */) { @@ -252,18 +206,15 @@ static t_int sndfiler_synchonize(t_int * w); static void sndfiler_read_cb(t_sndfiler * x, int argc, t_atom* argv) { - int i, j; + int i, j, lib; int channel_count; t_float** helper_arrays; int resize = 0; - int seek = 0, arraysize = 0, writesize; + int seek = 0, arraysize = 0; t_symbol* file; t_garray ** arrays; - SNDFILE* sndfile; - SF_INFO info; - // parse flags while (argc > 0 && argv->a_type == A_SYMBOL && *argv->a_w.w_symbol->s_name == '-') @@ -276,9 +227,10 @@ static void sndfiler_read_cb(t_sndfiler * x, int argc, t_atom* argv) } else if (!strcmp(flag, "skip")) { - if (argc < 2 || argv[1].a_type != A_FLOAT || - ((seek = argv[1].a_w.w_float) == 0)) + if (argc < 2 || argv[1].a_type != A_FLOAT) goto usage; + else + seek = argv[1].a_w.w_float; argc -= 2; argv += 2; } else goto usage; @@ -323,85 +275,23 @@ static void sndfiler_read_cb(t_sndfiler * x, int argc, t_atom* argv) } arraysize = size; } - - sndfile = sf_open(file->s_name, SFM_READ, &info); - if (sndfile) + lib = check_fileformat(file); + if(lib == USE_LIBSNDFILE) + arraysize = read_libsndfile(helper_arrays, channel_count, seek, + resize, arraysize, file); + else if(lib == USE_LIBVORBISFILE) + arraysize = read_libvorbisfile(helper_arrays, channel_count, seek, + resize, arraysize, file); + else { - int pos = 0; - int maxchannels = (channel_count < info.channels) ? - channel_count : info.channels; + pd_error(x, "Error opening file"); + return; + } - t_float * item = alloca(maxchannels * sizeof(t_float)); - + if(arraysize > 0) + { t_int ** syncdata = getbytes(sizeof(t_int*) * 5); - - // negative seek: offset from the end of the file - if(seek<0) - { - pos = sf_seek(sndfile, seek, SEEK_END); - } - if(seek>0) - { - pos = sf_seek(sndfile, seek, SEEK_SET); - } - if(pos == -1) - { - pd_error(x, "invalid seek in soundfile"); - return; - } - - if(resize) - { - writesize = (info.frames-pos); - arraysize = writesize; - } - else - writesize = (arraysize>(info.frames-pos)) ? - info.frames-pos : arraysize; - -#if (_POSIX_MEMLOCK - 0) >= 200112L - munlockall(); -#endif - - for (i = 0; i != channel_count; ++i) - { - helper_arrays[i] = getalignedbytes(arraysize * sizeof(t_float)); - } - - for (i = 0; i != writesize; ++i) - { - sf_read_float(sndfile, item, info.channels); - - for (j = 0; j != info.channels; ++j) - { - if (j < channel_count) - { - helper_arrays[j][i] = item[j]; - } - } - } - - // fill remaining elements with zero - if(!resize && (arraysize>(info.frames-pos))) - { - for (i = writesize; i != arraysize; ++i) - { - for (j = 0; j != info.channels; ++j) - { - if (j < channel_count) - { - helper_arrays[j][i] = 0; - } - } - } - } - -#if (_POSIX_MEMLOCK - 0) >= 200112L - mlockall(MCL_FUTURE); -#endif - - sf_close(sndfile); syncdata[0] = (t_int*)arrays; syncdata[1] = (t_int*)helper_arrays; diff --git a/sndfiler/src/sndfiler.h b/sndfiler/src/sndfiler.h new file mode 100755 index 0000000..f5fbd2c --- /dev/null +++ b/sndfiler/src/sndfiler.h @@ -0,0 +1,87 @@ +/* + * + * threaded soundfiler for pd + * Copyright (C) 2005, Tim Blechmann + * (C) 2005, Georg Holzmann + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _SND_FILER__ +#define _SND_FILER__ + + +/* to be compatible with main pd */ +#ifdef USE_PD_MAIN + +#define getalignedbytes(a) getbytes(a) +#define freealignedbytes(a,b) freebytes(a,b) +#include "threadlib.h" + +#else /* now for pd_devel */ + +#include "m_pd.h" +#include "m_fifo.h" + +#include "pthread.h" + +#endif /* USE_PD_MAIN */ + + +#include "g_canvas.h" +#include "sndfile.h" +#include "vorbis/codec.h" +#include "vorbis/vorbisfile.h" + +#include "stdlib.h" +#include +#include "sched.h" /* for thread priority */ +#include +#include "semaphore.h" + +#ifdef MSW +#include +#include +#endif + +/* for alloca */ +#ifdef MSW +#include +#else +#include "alloca.h" +#endif + +#if (_POSIX_MEMLOCK - 0) >= 200112L +#include +#endif /* _POSIX_MEMLOCK */ + +#ifdef __APPLE__ +#include +#include +#include +#define SEM_T semaphore_t +#define SEM_INIT(s) (semaphore_create(mach_task_self(),&s,SYNC_POLICY_FIFO,0) == 0) +#define SEM_SIGNAL(s) semaphore_signal(s) +#define SEM_WAIT(s) semaphore_wait(s) +#else +#define SEM_T sem_t +#define SEM_INIT(s) (sem_init(&s,0,0) == 0) +#define SEM_SIGNAL(s) sem_post(&s) +#define SEM_WAIT(s) sem_wait(&s) +#endif + + +#endif // _SND_FILER__ -- cgit v1.2.1