[PD-cvs] externals/tb/sndfiler makefile, NONE, 1.1 sndfiler-help.pd, NONE, 1.1 sndfiler.c, NONE, 1.1

Tim Blechmann timblech at users.sourceforge.net
Sat Sep 10 17:47:25 CEST 2005


Update of /cvsroot/pure-data/externals/tb/sndfiler
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27313

Added Files:
	makefile sndfiler-help.pd sndfiler.c 
Log Message:
libsndfile base soundfiler.
- supports only read command
- no resize / nframe flags


--- NEW FILE: sndfiler.c ---
/* 
 * 
 * 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 <sys/mman.h>
#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();
}



--- NEW FILE: sndfiler-help.pd ---
#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;

--- NEW FILE: makefile ---
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





More information about the Pd-cvs mailing list