From 1e17420038c1737ee6aabd4f9cc7dc833bb776f0 Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Sat, 10 Sep 2005 15:47:23 +0000 Subject: libsndfile base soundfiler. - supports only read command - no resize / nframe flags svn path=/trunk/externals/tb/; revision=3521 --- sndfiler/makefile | 94 ++++++++++++++ sndfiler/sndfiler-help.pd | 10 ++ sndfiler/sndfiler.c | 321 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 425 insertions(+) create mode 100644 sndfiler/makefile create mode 100644 sndfiler/sndfiler-help.pd create mode 100644 sndfiler/sndfiler.c diff --git a/sndfiler/makefile b/sndfiler/makefile new file mode 100644 index 0000000..f44a8da --- /dev/null +++ b/sndfiler/makefile @@ -0,0 +1,94 @@ +NAME=sndfiler +CSYM=sndfiler + +current: pd_linux + +# ----------------------- NT ----------------------- + +pd_nt: $(NAME).dll + +.SUFFIXES: .dll + +PDNTCFLAGS = /W3 /WX /DNT /DPD /nologo +VC="C:\Program Files\Microsoft Visual Studio\Vc98" + +PDNTINCLUDE = /I. /I..\..\src /I$(VC)\include + +PDNTLDIR = $(VC)\lib +PDNTLIB = $(PDNTLDIR)\libc.lib \ + $(PDNTLDIR)\oldnames.lib \ + $(PDNTLDIR)\kernel32.lib \ + ..\..\bin\pd.lib + +.c.dll: + cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c $*.c + link /dll /export:$(CSYM)_setup $*.obj $(PDNTLIB) + +# ----------------------- IRIX 5.x ----------------------- + +pd_irix5: $(NAME).pd_irix5 + +.SUFFIXES: .pd_irix5 + +SGICFLAGS5 = -o32 -DPD -DUNIX -DIRIX -O2 + +SGIINCLUDE = -I../../src + +.c.pd_irix5: + $(CC) $(SGICFLAGS5) $(SGIINCLUDE) -o $*.o -c $*.c + ld -elf -shared -rdata_shared -o $*.pd_irix5 $*.o + rm $*.o + +# ----------------------- IRIX 6.x ----------------------- + +pd_irix6: $(NAME).pd_irix6 + +.SUFFIXES: .pd_irix6 + +SGICFLAGS6 = -n32 -DPD -DUNIX -DIRIX -DN32 -woff 1080,1064,1185 \ + -OPT:roundoff=3 -OPT:IEEE_arithmetic=3 -OPT:cray_ivdep=true \ + -Ofast=ip32 + +.c.pd_irix6: + $(CC) $(SGICFLAGS6) $(SGIINCLUDE) -o $*.o -c $*.c + ld -n32 -IPA -shared -rdata_shared -o $*.pd_irix6 $*.o + rm $*.o + +# ----------------------- LINUX i386 ----------------------- + +pd_linux: $(NAME).pd_linux + +.SUFFIXES: .pd_linux + +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 + +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 +# $(LSTRIP) $*.pd_linux + rm -f $*.o + +# ----------------------- Mac OSX ----------------------- + +pd_darwin: $(NAME).pd_darwin + +.SUFFIXES: .pd_darwin + +DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \ + -Wno-unused -Wno-parentheses -Wno-switch + +.c.pd_darwin: + $(CC) $(DARWINCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c + $(CC) -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o + rm -f $*.o + +# ---------------------------------------------------------- + +clean: + rm -f *.o *.pd_* so_locations diff --git a/sndfiler/sndfiler-help.pd b/sndfiler/sndfiler-help.pd new file mode 100644 index 0000000..fe9de17 --- /dev/null +++ b/sndfiler/sndfiler-help.pd @@ -0,0 +1,10 @@ +#N canvas 0 0 450 300 10; +#X obj 36 103 sndfiler; +#X obj 294 87 table array; +#X msg 37 60 read \$1 array; +#X obj 38 33 openpanel; +#X obj 124 15 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X connect 2 0 0 0; +#X connect 3 0 2 0; +#X connect 4 0 3 0; diff --git a/sndfiler/sndfiler.c b/sndfiler/sndfiler.c new file mode 100644 index 0000000..29c692a --- /dev/null +++ b/sndfiler/sndfiler.c @@ -0,0 +1,321 @@ +/* + * + * soundfiler based on libsndfile + * Copyright (C) 2005 Tim Blechmann + * + * 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 "stdlib.h" +#include "m_pd.h" +#include "g_canvas.h" +#include "m_fifo.h" +#include "pthread.h" /* for helper thread */ +#include "sched.h" /* for thread priority */ +#include "alloca.h" + +#include "sndfile.h" + +#if (_POSIX_MEMLOCK - 0) >= 200112L +#include +#endif /* _POSIX_MEMLOCK */ + +static t_class *sndfiler_class; + + +typedef struct _sndfiler +{ + t_object x_obj; + t_canvas *x_canvas; +} t_sndfiler; + +typedef struct _sfprocess +{ + void* padding; + void (* process) (t_sndfiler *, + int, t_atom *); /* callback function */ + t_sndfiler * x; /* soundfiler */ + int argc; + t_atom * argv; +} t_sfprocess; + + +/* this is the queue for all soundfiler objects */ +typedef struct _sfqueue +{ + t_fifo* x_jobs; + + pthread_mutex_t mutex; + pthread_cond_t cond; +} t_sfqueue; + + +typedef struct _syncdata +{ + t_garray** arrays; + t_float** helper_arrays; + int argc; + t_int frames; +} t_syncdata; + + +static t_sfqueue sndfiler_queue; +static pthread_t sf_thread_id; /* id of soundfiler thread */ + + +static t_sndfiler *sndfiler_new(void) +{ + t_sndfiler *x = (t_sndfiler *)pd_new(sndfiler_class); + x->x_canvas = canvas_getcurrent(); + outlet_new(&x->x_obj, &s_float); + return (x); +} + + +/* global soundfiler thread ... sleeping until signaled */ +static void sndfiler_thread(void) +{ + while (1) + { + t_sfprocess * me; + pthread_cond_wait(&sndfiler_queue.cond, &sndfiler_queue.mutex); + + while (me = (t_sfprocess *)fifo_get(sndfiler_queue.x_jobs)) + { + (me->process)(me->x, me->argc, me->argv); + + /* freeing the argument vector */ + freebytes(me->argv, sizeof(t_atom) * me->argc); + freebytes(me, sizeof(t_sfprocess)); + } + } +} + +static void sndfiler_start_thread(void) +{ + pthread_attr_t sf_attr; + struct sched_param sf_param; + int status; + + //initialize queue + sndfiler_queue.x_jobs = fifo_init(); + pthread_mutex_init (&sndfiler_queue.mutex,NULL); + pthread_cond_init (&sndfiler_queue.cond,NULL); + + // initialize thread + pthread_attr_init(&sf_attr); + + sf_param.sched_priority=sched_get_priority_min(SCHED_OTHER); + pthread_attr_setschedparam(&sf_attr,&sf_param); + +#ifdef UNIX + if (sys_hipriority == 1/* && getuid() == 0 */) + { + sf_param.sched_priority=sched_get_priority_min(SCHED_RR); + pthread_attr_setschedpolicy(&sf_attr,SCHED_RR); + } +#endif /* UNIX */ + + //start thread + status = pthread_create(&sf_thread_id, &sf_attr, + (void *) sndfiler_thread,NULL); + if (status != 0) + error("Couldn't create sndfiler thread: %d",status); + else + post("global sndfiler thread launched, priority: %d", + sf_param.sched_priority); +} + + +static void sndfiler_read_cb(t_sndfiler * x, int argc, t_atom* argv); + + +/* syntax: + * read soundfile array0..n + * if the soundfile has less channels than arrays are given, these arrays are + * set to zero + * if there are too little arrays given, only the first n channels will be used + * */ + +static void sndfiler_read(t_sndfiler * x, t_symbol *s, int argc, t_atom* argv) +{ + t_sfprocess * process = getbytes(sizeof(t_sfprocess)); + + + process->process = &sndfiler_read_cb; + process->x = x; + process->argc = argc; + process->argv = (t_atom*) copybytes(argv, sizeof(t_atom) * argc); + + fifo_put(sndfiler_queue.x_jobs, process); + + pthread_cond_signal(&sndfiler_queue.cond); +} + +static t_int sndfiler_synchonize(t_int * w); + +static void sndfiler_read_cb(t_sndfiler * x, int argc, t_atom* argv) +{ + int resize = 0; + int frames = -1; + int i, j; + int counter=0; + int channel_count; + t_float** helper_arrays; + + t_symbol* file; + t_garray ** arrays; + + SNDFILE* sndfile; + SF_INFO info; + + if (argc < 2) + { + pd_error(x, "Invalid arguments"); + return; + } + + file = atom_getsymbolarg(0, argc, argv); + + channel_count = argc - 1; + helper_arrays = getbytes(channel_count * sizeof(t_float*)); + + arrays = getbytes(channel_count * sizeof(t_garray*)); + for (i = 0; i != channel_count; ++i) + { + t_garray * array = (t_garray *)pd_findbyclass(atom_getsymbolarg(i+1, argc, argv), garray_class); + + if (array) + arrays[i] = array; + else + { + pd_error(x, "%s: no such array", atom_getsymbolarg(i+1, argc, argv)->s_name); + return; + } + } + + sndfile = sf_open(file->s_name, SFM_READ, &info); + + if (sndfile) + { + int minchannels = (channel_count < info.channels) ? + channel_count : info.channels; + + int maxchannels = (channel_count < info.channels) ? + channel_count : info.channels; + + t_float * item = alloca(maxchannels * sizeof(t_float)); + + t_int ** syncdata = getbytes(sizeof(t_int*) * 5); + +#if (_POSIX_MEMLOCK - 0) >= 200112L + munlockall(); +#endif + + for (i = 0; i != channel_count; ++i) + { + helper_arrays[i] = getalignedbytes(info.frames * sizeof(t_float)); + } + + + for (i = 0; i != info.frames; ++i) + { + sf_read_float(sndfile, item, 1); + + for (j = 0; j != channel_count; ++j) + { + if (j < minchannels) + helper_arrays[j][i] = item[j]; + else + 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; + syncdata[2] = (t_int*)channel_count; + syncdata[3] = (t_int*)(long)info.frames; + syncdata[4] = (t_int*)x; + + sys_callback(sndfiler_synchonize, (t_int*)syncdata, 5); + } + else + { + pd_error(x, "Error opening file"); + } +} + + +static t_int sndfiler_synchonize(t_int * w) +{ + int i; + t_garray** arrays = (t_garray**) w[0]; + t_float** helper_arrays = (t_float**) w[1]; + t_int channel_count = (t_int)w[2]; + t_int frames = (t_int)w[3]; + t_sndfiler* x = (t_sndfiler*)w[4]; + + for (i = 0; i != channel_count; ++i) + { + t_garray * garray = arrays[i]; + t_array * array = garray->x_scalar->sc_vec[0].w_array; + t_glist * gl = garray->x_glist;; + + + freealignedbytes(array->a_vec, array->a_n); + array->a_vec = (char*)helper_arrays[i]; + array->a_n = frames; + + if (gl->gl_list == &garray->x_gobj && !garray->x_gobj.g_next) + { + vmess(&gl->gl_pd, gensym("bounds"), "ffff", + 0., gl->gl_y1, (double)(frames > 1 ? frames-1 : 1), gl->gl_y2); + /* close any dialogs that might have the wrong info now... */ + gfxstub_deleteforkey(gl); + } + else + garray_redraw(garray); + } + + free(arrays); + free(helper_arrays); + + canvas_update_dsp(); + + outlet_float(x->x_obj.ob_outlet, frames); + + return 0; +} + + +void sndfiler_setup(void) +{ + sndfiler_class = class_new(gensym("sndfiler"), (t_newmethod)sndfiler_new, + 0, sizeof(t_sndfiler), 0, 0); + class_addmethod(sndfiler_class, (t_method)sndfiler_read, + gensym("read"), A_GIMME, 0); + + sndfiler_start_thread(); +} + + -- cgit v1.2.1