[PD-cvs] externals/tb/sndfiler/src Makefile, NONE, 1.1 Makefile.pd_main, NONE, 1.1 sndfiler.c, NONE, 1.1

Georg Holzmann grholzi at users.sourceforge.net
Sun Nov 20 22:54:43 CET 2005


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

Added Files:
	Makefile Makefile.pd_main sndfiler.c 
Log Message:
also works with pd_main now - additional threaded resize method


--- NEW FILE: sndfiler.c ---
/*
 *
 * threaded soundfiler based on libsndfile
 * Copyright (C) 2005, Tim Blechmann
 *           (C) 2005, Georg Holzmann <grh at mur.at>
 *
 * 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.
 */

/* 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"

/* forward declaration */
struct _garray
{
    t_gobj x_gobj;
    t_scalar *x_scalar;     /* scalar "containing" the array */
    t_glist *x_glist;       /* containing glist */
    t_symbol *x_name;       /* unexpanded name (possibly with leading '$') */
    t_symbol *x_realname;   /* expanded name (symbol we're bound to) */
    char x_usedindsp;       /* true if some DSP routine is using this */
    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 <string.h>

/* for alloca */
#ifdef MSW
#include <malloc.h>
#else
#include "alloca.h"
#endif

#if (_POSIX_MEMLOCK - 0) >=  200112L
#include <sys/mman.h>
#endif /* _POSIX_MEMLOCK */


/************ forward declarations **************/

#ifdef UNIX
/* real-time flag, true if priority boosted */
extern int sys_hipriority;
#endif

/* get a garray's "array" structure. */
t_array *h_garray_getarray(t_garray *x)
{
    int zonset, ztype;
    t_symbol *zarraytype;
    t_scalar *sc = x->x_scalar;
    t_symbol *templatesym = sc->sc_template;
    t_template *_template = template_findbyname(templatesym);
    if (!_template)
    {
        error("array: couldn't find template %s", templatesym->s_name);
        return (0);
    }
    if (!template_find_field(_template, gensym("z"), 
        &zonset, &ztype, &zarraytype))
    {
        error("array: template %s has no 'z' field", templatesym->s_name);
        return (0);
    }
    if (ztype != DT_ARRAY)
    {
        error("array: template %s, 'z' field is not an array",
               templatesym->s_name);
        return (0);
    }
    return (sc->sc_vec[zonset].w_array);
}


/************ sndfiler **************/

static t_class *sndfiler_class;

typedef struct _sndfiler
{
    t_object x_obj;
    t_canvas *x_canvas;
} t_sndfiler;

typedef struct _sfprocess
{
    void* padding;
    /* callback function */
    void (* process) (t_sndfiler *, int, t_atom *);
    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 i, j;
    int channel_count;
    t_float** helper_arrays;

    t_symbol* file;
    t_garray ** arrays;

    SNDFILE* sndfile;
    SF_INFO info;
  
    if (argc < 2)
    {
        pd_error(x, "usage: read soundfile array1 array2 ...");
        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;
        }
    }
  
    post("sndfiler: loading file ...");

    sndfile = sf_open(file->s_name, SFM_READ, &info);

    if (sndfile)
    {
        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, info.channels);

            for (j = 0; j != info.channels; ++j)
            {
                if (j < channel_count)
                {
                    helper_arrays[j][i] = item[j];
                }
            }
        }

#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 = h_garray_getarray(garray);
        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;
}

static void sndfiler_t_resize(t_sndfiler * y, int argc, t_atom* argv);

/* syntax:
 * resize table size
 * */
static void sndfiler_resize(t_sndfiler * x, t_symbol *s, int argc, t_atom* argv)
{
    t_sfprocess * process = getbytes(sizeof(t_sfprocess));

    process->process = &sndfiler_t_resize;
    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 void sndfiler_t_resize(t_sndfiler *y, int argc, t_atom *argv)
{
    int was, elemsize;       /* array contains was elements of size elemsize */
    t_float * vec;           /* old array */ 
    t_glist *gl;
    int n;                   /* resize of n elements */
    char *nvec;              /* new array */ 

    t_garray * x = (t_garray *)pd_findbyclass(argv[0].a_w.w_symbol, garray_class);
    t_array *data = h_garray_getarray(x);

    if (!(x))
    {
        pd_error(y, "%s: no such table", argv[0].a_w.w_symbol->s_name);
        goto usage;
    }
    
    vec = (t_float*) data->a_vec;
    was = data->a_n;

    if ((argv+1)->a_type == A_FLOAT)
        n = (int) (argv+1)->a_w.w_float;
    else
        goto usage;

    if (n == was) return;

    if (n < 1) n = 1;
    elemsize = template_findbyname(data->a_templatesym)->t_n * sizeof(t_word);

#if (_POSIX_MEMLOCK - 0) >=  200112L
    munlockall();
#endif

    if (was > n)
        nvec = (char*)copybytes(data->a_vec, was * elemsize);
    else
    {
        nvec = getbytes(n * elemsize);
        memcpy (nvec, data->a_vec, was * elemsize);

        /* LATER should check t_resizebytes result */
        memset(nvec + was*elemsize, 0, (n - was) * elemsize);
    }
  
    if (!nvec)
    {
        pd_error(x, "array resize failed: out of memory");

#if (_POSIX_MEMLOCK - 0) >=  200112L
        mlockall(MCL_FUTURE);
#endif

        return;
    }

    /* TB: we'll have to be sure that no one is accessing the array */
    sys_lock();

#ifdef GARRAY_THREAD_LOCK
    garray_lock(x);
#endif

    data->a_vec = nvec;
    data->a_n = n;

#ifdef GARRAY_THREAD_LOCK
    garray_unlock(x);
#endif
    
    if (x->x_usedindsp) canvas_update_dsp();
    sys_unlock();

    /* if this is the only array in the graph,
       reset the graph's coordinates */
    gl = x->x_glist;
    if (gl->gl_list == &x->x_gobj && !x->x_gobj.g_next)
    {
        vmess(&gl->gl_pd, gensym("bounds"), "ffff",
            0., gl->gl_y1, (double)(n > 1 ? n-1 : 1), gl->gl_y2);
        /* close any dialogs that might have the wrong info now... */
        gfxstub_deleteforkey(gl);
    }
    else garray_redraw(x);

    freebytes (vec, was * elemsize);

#if (_POSIX_MEMLOCK - 0) >= 200112L
    mlockall(MCL_FUTURE);
#endif

    sys_lock();
    outlet_float(y->x_obj.ob_outlet, (float)atom_getintarg(1,argc,argv)); 
    sys_unlock();
  
    return;
  
    usage:
        pd_error(x, "usage: resize tablename size");
}

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);
    class_addmethod(sndfiler_class, (t_method)sndfiler_resize,
                    gensym("resize"), A_GIMME, 0);

#ifdef USE_PD_MAIN
    // needed to start thread callback system
    threadlib_setup();
#endif
  
    // starts helper thread
    sndfiler_start_thread();
}

--- NEW FILE: Makefile.pd_main ---
# ----------------------------------------------------------

# adjust the next pathes to your system:

# this should point to the directory which contains
# m_pd.h and g_canvas.h
PD_SCR = /home/holzi/pd-0.39-1/src
#PD_SCR = c:/pd/src

# this is the pd directory, usually /usr/lib/pd
# or c:/pd etc.
PD_PATH = /usr/lib/pd
#PD_PATH = c:/pd

# path of sndfile.h from libsndfile, usually it's in
# /usr/include and so detected automatically
SNDFILE_SRC = /usr/include

# the directory, where libsndfile is located
# (in linux it' normally not necessary, in windows it's
# normally in c:/windwos/system or so)
SNDFILE_PATH = c:/windows/system

# path to threadlib.h
THREADLIB_SRC = /home/Georg/pd-cvs/externals/grh/threadlib/src
#THREADLIB_SRC = c:/Georg/pd-cvs/externals/grh/threadlib/src

# path to threadlib.pd_linux/dll/pd_darwin
# (usually path/to/pd/extra)
THREADLIB_PATH = $(PD_PATH)/extra

# ----------------------------------------------------------

NAME=sndfiler

CC = gcc
LD = gcc
INCLUDE= -I. -I$(PD_SCR) -I$(SNDFILE_SRC) -I$(THREADLIB_SRC)
CC_FLAGS = -DPD -DUSE_PD_MAIN -O3 -funroll-loops \
           -Wall -W -Wshadow -Wno-parentheses -Wno-switch \
           -Wno-unused -fomit-frame-pointer
LD_FLAGS = --export-dynamic -shared -o

current:
	@echo ----------------------------
	@echo  USAGE:
	@echo     linux:   make pd_linux
	@echo     windows: make pd_win
	@echo     darwin:  make pd_darwin
	@echo ----------------------------

# ----------------------- LINUX i386 -----------------------

pd_linux: $(NAME).pd_linux

.SUFFIXES: .pd_linux

CC_UNIX = -DUNIX -fPIC -pthread
LIB_UNIX = -lc -lm -lsndfile $(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)
	strip --strip-unneeded $*.pd_linux
	chmod 755 $*.pd_linux
	@test -d ../bin || mkdir -p ../bin
	cp $*.pd_linux ../bin
	rm -f $*.o

# ------------------------ WIN MinGW -----------------------

pd_win: $(NAME).dll

.SUFFIXES: .dll

CC_WIN = -DMSW -mms-bitfields
LIB_WIN = $(PD_PATH)/bin/pd.dll \
          $(SNDFILE_PATH)/pthreadGC.dll \
          $(SNDFILE_PATH)/libsndfile.dll \
          $(THREADLIB_PATH)/threadlib.dll

.c.dll:
	$(CC) $(CC_WIN) $(CC_FLAGS) $(INCLUDE) -o $*.o -c $*.c
	$(LD) $(LD_FLAGS) $*.dll $*.o $(LIB_WIN)
	strip --strip-unneeded $*.dll
	chmod 755 $*.dll
	@test -d ../bin || mkdir -p ../bin
	cp $*.dll ../bin
	rm -f $*.o

# ----------------------- Mac OSX -----------------------

pd_darwin: $(NAME).pd_darwin

.SUFFIXES: .pd_darwin

CC_DARWIN = -pthread
LD_DARWIN = -bundle -undefined suppress -flat_namespace \
            -bundle_loader $(PD_PATH)/bin/pd --export-dynamic

.c.pd_darwin:
	$(CC) $(CC_FLAGS) $(CC_DARWIN) $(INCLUDE) -o $*.o -c $*.c
	$(LD) $(LD_DARWIN) $*.pd_linux $*.o $(LIB)
	chmod 755 $*.pd_darwin
	@test -d ../bin || mkdir -p ../bin
	cp $*.pd_darwin ../bin
	rm -f $*.o

# ----------------------------------------------------------

clean:
	rm -f *.o *.pd_darwin *.pd_linux *.dll

install:
	install ../bin/$(NAME).* $(PD_PATH)/extra
	install ../doc/*.pd $(PD_PATH)/doc/5.reference

--- 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_darwin *.pd_linux *.dll so_locations





More information about the Pd-cvs mailing list