aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorg Holzmann <grholzi@users.sourceforge.net>2005-11-20 21:29:12 +0000
committerGeorg Holzmann <grholzi@users.sourceforge.net>2005-11-20 21:29:12 +0000
commit171485daa08e97782c05b3ca7490e6e42b827197 (patch)
tree373ba2e33f38e4435a93f457aeddb85cd88744a6
parent3cef5d2ec589e3da66a66b27d7521af096bd9300 (diff)
version 0.1
svn path=/trunk/externals/grh/; revision=3989
-rwxr-xr-xthreadlib/INSTALL7
-rwxr-xr-xthreadlib/README29
-rwxr-xr-xthreadlib/doc/help-threadedsf.pd54
-rwxr-xr-xthreadlib/src/Makefile9
-rwxr-xr-xthreadlib/src/Makefile_darwin13
-rwxr-xr-xthreadlib/src/Makefile_mingw22
-rwxr-xr-xthreadlib/src/Makefile_msvc72
-rwxr-xr-xthreadlib/src/callbacks.c2
-rwxr-xr-xthreadlib/src/join.c12
-rwxr-xr-xthreadlib/src/sleep.c9
-rwxr-xr-xthreadlib/src/threadedsf.c1919
-rwxr-xr-xthreadlib/src/threadlib.c15
-rwxr-xr-xthreadlib/src/threadlib.h32
13 files changed, 152 insertions, 2043 deletions
diff --git a/threadlib/INSTALL b/threadlib/INSTALL
index 0aac333..35dd2f2 100755
--- a/threadlib/INSTALL
+++ b/threadlib/INSTALL
@@ -1,4 +1,9 @@
-threadlib installation
+threadlib binary:
+ get them on http://grh.mur.at/software/threadlib.html
+ and follow the instructions there
+
+
+threadlib compilation:
1) open the right makefile for your platform/compiler
diff --git a/threadlib/README b/threadlib/README
index 54850f1..e38f78b 100755
--- a/threadlib/README
+++ b/threadlib/README
@@ -1,23 +1,32 @@
threadlib
-PD library for threaded patching
+C and PD library for threaded patching and threaded PD externals
heavily based on pd_devel code by Tim Blechmann
(c) 2005, Georg Holzmann, <grh@mur.at>
http://grh.mur.at/software/threadlib.html
------------------------------------------------------------------------
-contents of threadlib:
- detach run part of the patch in a helper thread
- join synchronize messages to pd's main thread
- sleep blocks the system for a specific time
- threadedsf modified threaded soundfiler from pd_devel_0.38
+PD objects for threaded patching:
+- detach run part of the patch in a helper thread
+- join synchronize messages to pd's main thread
+- sleep blocks the system for a specific time
+- threadedsf modified threaded soundfiler from pd_devel_0.38
WARNING:
these objects (especially detach/join) are very experimental and may
crash your patches if you use them in the wrong way, because some
externals/internals are not threadsafe!
-REQUIREMENT: pd >= 0.39
+Features for PD external programmers:
+- lockfree FIFO from pd_devel
+- callback system like in pd_devel:
+ Instead of the idle callbacks, which are not really useable
+ in current main pd, it uses clock callbacks
+- USAGE: you have to link your externals against threadlib
+ (see sndfiler as an example)
+- ADVANTAGES: so it's possible to write threaded externals
+ for main and devel pd with the same source code
+ (using the lockfree FIFO and sys_callback)
Many thanks to Tim Blechmann for his code and help!
@@ -43,12 +52,6 @@ is also useful to place behind any threaded external calling the outlet
functions from the helper thread, to make sure the following messages
are being run in the main pd thread.
-threadedsf:
-This is the threaded soundfiler from pd devel 0.38 by Tim Blechmann,
-adapted to work with main pd >= 0.39.
-Instead of the idle callbacks, which are not really useable in current
-main pd, it uses clock-callbacks (and also the lockfree FIFO of pd devel).
-
!!! WARNING: !!!
detach/join provide the possibility of threaded patching.
beware of the risks:
diff --git a/threadlib/doc/help-threadedsf.pd b/threadlib/doc/help-threadedsf.pd
deleted file mode 100755
index 7d6ea64..0000000
--- a/threadlib/doc/help-threadedsf.pd
+++ /dev/null
@@ -1,54 +0,0 @@
-#N canvas 728 33 465 834 10;
-#X obj 29 23 cnv 15 404 54 empty empty empty 22 25 0 18 -1 -66577 0
-;
-#X obj 31 25 cnv 15 400 50 empty empty threadlib 22 25 0 18 -228992
--66577 0;
-#X text 314 35 help file of;
-#X text 27 765 =%)!(%= threadlib \, by Georg Holzmann <grh@mur.at>
-\, 2005;
-#X text 70 799 htttp://grh.mur.at/software/threadlib.html;
-#X text 100 711 see also:;
-#X text 55 782 heavily based on pd_devel code by Tim Blechmann;
-#X obj 180 711 detach;
-#X obj 237 711 join;
-#X text 292 51 ::: threadedsf :::;
-#X text 162 112 ::: THREADEDSF :::;
-#X text 106 152 A threaded soundfiler for main pd.;
-#X obj 274 191 soundfiler;
-#X obj 278 711 sleep;
-#X text 27 594 NOTE: this is the threaded soundfiler from pd devel
-0.38 by Tim Blechmann \, adapted to work with main pd >= 0.39. Instead
-of the idle callbacks \, which are not really useable in current main
-pd \, it uses clock-callbacks (ans also the lockfree FIFO of pd devel).
-;
-#X obj 70 512 threadedsf;
-#X obj 70 534 print THREADED_SF;
-#X obj 70 489 r \$0-tsf;
-#X text 101 191 USAGE: see help-file of;
-#X text 148 207 (same usage);
-#X obj 52 307 openpanel;
-#X msg 52 329 read -resize \$1 array1;
-#X obj 52 351 s \$0-tsf;
-#X obj 52 287 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
--1;
-#X obj 248 349 s \$0-tsf;
-#X obj 248 285 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
--1;
-#X msg 248 327 write -wave \$1 array1;
-#X obj 248 305 savepanel;
-#X obj 265 505 table array1;
-#X text 48 255 the same as with soundfiler:;
-#X text 73 286 <- read;
-#X text 271 284 <- write;
-#X obj 262 437 s \$0-tsf;
-#X text 46 409 additional: threaded resize->;
-#X msg 262 411 resize array1 4410;
-#X connect 15 0 16 0;
-#X connect 17 0 15 0;
-#X connect 20 0 21 0;
-#X connect 21 0 22 0;
-#X connect 23 0 20 0;
-#X connect 25 0 27 0;
-#X connect 26 0 24 0;
-#X connect 27 0 26 0;
-#X connect 34 0 32 0;
diff --git a/threadlib/src/Makefile b/threadlib/src/Makefile
index 0579345..fd635c6 100755
--- a/threadlib/src/Makefile
+++ b/threadlib/src/Makefile
@@ -3,7 +3,7 @@
# this should point to the directory which contains
# m_pd.h and g_canvas.h
-PDSCR=/home/holzi/pd-0.39-1test1/src
+PDSCR=/home/holzi/pd-0.39-1/src
# this is the pd directory, here the files will be
# installed
@@ -13,8 +13,8 @@ PDPATH=/usr/lib/pd
TARGET=threadlib.pd_linux
-OBJ=fifo.o callbacks.o threadlib.o sleep.o detach.o \
- join.o threadedsf.o
+OBJ=fifo.o callbacks.o threadlib.o \
+ sleep.o detach.o join.o
CC = gcc
LD = gcc
@@ -54,9 +54,6 @@ detach.o: threadlib.o fifo.o detach.c
join.o: threadlib.o callbacks.o join.c
$(CC) $(CC_FLAGS) $(INCLUDE) join.c
-threadedsf.o: threadlib.o callbacks.o threadedsf.c
- $(CC) $(CC_FLAGS) $(INCLUDE) threadedsf.c
-
# --------------------------------------------------
clean:
diff --git a/threadlib/src/Makefile_darwin b/threadlib/src/Makefile_darwin
index a254ff0..6c77444 100755
--- a/threadlib/src/Makefile_darwin
+++ b/threadlib/src/Makefile_darwin
@@ -11,10 +11,10 @@ PDPATH=/usr/lib/pd
# --------------------------------------------------
-TARGET=threadlib.pd_linux
+TARGET=threadlib.pd_darwin
-OBJ=fifo.o callbacks.o threadlib.o sleep.o detach.o \
- join.o threadedsf.o
+OBJ=fifo.o callbacks.o threadlib.o \
+ sleep.o detach.o join.o
CC = gcc
LD = gcc
@@ -28,9 +28,9 @@ LD_FLAGS = -bundle -bundle_loader $(PDPATH)/bin/pd \
# --------------------------------------------------
-all: pd_linux
+all: pd_darwin
-pd_linux: $(TARGET)
+pd_darwin: $(TARGET)
$(TARGET): $(OBJ)
$(LD) $(LD_FLAGS) $(TARGET) $(OBJ) $(LIB)
@@ -55,9 +55,6 @@ detach.o: threadlib.o fifo.o detach.c
join.o: threadlib.o callbacks.o join.c
$(CC) $(CC_FLAGS) $(INCLUDE) join.c
-threadedsf.o: threadlib.o callbacks.o threadedsf.c
- $(CC) $(CC_FLAGS) $(INCLUDE) threadedsf.c
-
# --------------------------------------------------
clean:
diff --git a/threadlib/src/Makefile_mingw b/threadlib/src/Makefile_mingw
index c110eec..21de955 100755
--- a/threadlib/src/Makefile_mingw
+++ b/threadlib/src/Makefile_mingw
@@ -11,25 +11,26 @@ PDPATH=c:/pd
# --------------------------------------------------
-TARGET=threadlib.pd_linux
+TARGET=threadlib.dll
-OBJ=fifo.o callbacks.o threadlib.o sleep.o detach.o \
- join.o threadedsf.o
+OBJ=fifo.o callbacks.o threadlib.o \
+ sleep.o detach.o join.o
CC = gcc
LD = gcc
-INCLUDE=-I$(PDSCR) -I.
-LIB=$(PD-PATH)/bin/pd.dll
-CC_FLAGS = -DPD -DWINDOWS -c -mms-bitfields \
+INCLUDE = -I$(PDSCR) -I.
+LIB = $(PDPATH)/bin/pd.dll \
+ c:/windows/system/pthreadGC.dll
+CC_FLAGS = -DPD -DMSW -c -mms-bitfields \
-Wall -Wno-parentheses -Wno-switch -O3 \
- -funroll-loops -fomit-frame-pointer -pthread
+ -funroll-loops -fomit-frame-pointer
LD_FLAGS = --export-dynamic -shared -o
# --------------------------------------------------
-all: pd_linux
+all: dll
-pd_linux: $(TARGET)
+dll: $(TARGET)
$(TARGET): $(OBJ)
$(LD) $(LD_FLAGS) $(TARGET) $(OBJ) $(LIB)
@@ -54,9 +55,6 @@ detach.o: threadlib.o fifo.o detach.c
join.o: threadlib.o callbacks.o join.c
$(CC) $(CC_FLAGS) $(INCLUDE) join.c
-threadedsf.o: threadlib.o callbacks.o threadedsf.c
- $(CC) $(CC_FLAGS) $(INCLUDE) threadedsf.c
-
# --------------------------------------------------
clean:
diff --git a/threadlib/src/Makefile_msvc b/threadlib/src/Makefile_msvc
new file mode 100755
index 0000000..0f651d7
--- /dev/null
+++ b/threadlib/src/Makefile_msvc
@@ -0,0 +1,72 @@
+# -------------------------------------------------
+# adjust the next 3 pathes to your system:
+
+# this should point to the directory which contains
+# m_pd.h and g_canvas.h
+PD_SCR = C:\pd\src
+
+# this is the pd directory, here the files will be
+# installed
+PD_PATH = C:\pd
+
+# path of the microsoft compiler
+VIS_CPP_PATH = "C:\Programme\Microsoft Visual Studio\Vc98"
+
+# --------------------------------------------------
+
+TARGET=threadlib.dll
+
+OBJ=fifo.obj callbacks.obj threadlib.obj \
+ sleep.obj detach.obj join.obj threadedsf.obj
+
+CC = cl.exe
+LD = link.exe
+INCLUDE = /I. /I$(PD_SCR) /I$(VIS_CPP_PATH)\include
+CC_FLAGS = /W3 /WX /DMSW /DPD /nologo /D_WINDOWS
+LD_FLAGS = /nologo /dll /export:threadlib_setup
+
+#LDIR = $(VIS_CPP_PATH)\lib
+LIB = /NODEFAULTLIB:libc /NODEFAULTLIB:oldnames \
+ /NODEFAULTLIB:kernel /NODEFAULTLIB:uuid \
+ $(VIS_CPP_PATH)\lib\libc.lib \
+ $(VIS_CPP_PATH)\lib\oldnames.lib \
+ $(VIS_CPP_PATH)\lib\kernel32.lib \
+ $(PD_PATH)\bin\pd.lib \
+ $(PD_PATH)\bin\pthreadVC.lib
+
+# --------------------------------------------------
+
+all: dll
+
+dll: $(TARGET)
+
+$(TARGET): $(OBJ)
+ $(LD) $(LD_FLAGS) /out:$(TARGET) $(OBJ) $(LIB)
+
+
+threadlib.obj: threadlib.h threadlib.c
+ $(CC) $(CC_FLAGS) $(INCLUDE) /c threadlib.c
+
+fifo.obj: threadlib.obj fifo.c
+ $(CC) $(CC_FLAGS) $(INCLUDE) /c fifo.c
+
+callbacks.obj: fifo.obj threadlib.obj callbacks.c
+ $(CC) $(CC_FLAGS) $(INCLUDE) /c callbacks.c
+
+sleep.obj: threadlib.obj sleep.c
+ $(CC) $(CC_FLAGS) $(INCLUDE) /c sleep.c
+
+detach.obj: threadlib.obj fifo.obj detach.c
+ $(CC) $(CC_FLAGS) $(INCLUDE) /c detach.c
+
+join.obj: threadlib.obj callbacks.obj join.c
+ $(CC) $(CC_FLAGS) $(INCLUDE) /c join.c
+
+# --------------------------------------------------
+
+clean:
+ del $(OBJ) $(TARGET) *.lib *.exp
+
+install:
+ copy $(TARGET) $(PD_PATH)\extra
+ copy help\*.pd $(PD_PATH)\doc\5.reference
diff --git a/threadlib/src/callbacks.c b/threadlib/src/callbacks.c
index 1385992..7bf4a19 100755
--- a/threadlib/src/callbacks.c
+++ b/threadlib/src/callbacks.c
@@ -41,7 +41,7 @@ void h_free_callbacks()
fifo_destroy(h_callback_fifo);
}
-void h_set_callback(t_int (*callback) (t_int* argv), t_int* argv, t_int argc)
+void sys_callback(t_int (*callback) (t_int* argv), t_int* argv, t_int argc)
{
t_sched_callback* new = (t_sched_callback*) getbytes
(sizeof(t_sched_callback));
diff --git a/threadlib/src/join.c b/threadlib/src/join.c
index 5e3f688..65c8092 100755
--- a/threadlib/src/join.c
+++ b/threadlib/src/join.c
@@ -49,7 +49,7 @@ static void join_bang(join_t * x)
t_int* argv = getbytes(sizeof(t_int*));
argv[0] = (t_int)x->x_outlet;
- h_set_callback(join_bang_callback, argv, 1);
+ sys_callback(join_bang_callback, argv, 1);
}
static t_int join_pointer_callback(t_int * argv)
@@ -64,7 +64,7 @@ static void join_pointer(join_t * x, t_gpointer * gp)
argv[0] = (t_int)x->x_outlet;
argv[1] = (t_int)gp;
- h_set_callback(join_pointer_callback, argv, 2);
+ sys_callback(join_pointer_callback, argv, 2);
}
static t_int join_float_callback(t_int * argv)
@@ -79,7 +79,7 @@ static void join_float(join_t * x, t_float f)
argv[0] = (t_int)x->x_outlet;
argv[1] = (t_int)f;
- h_set_callback(join_float_callback, argv, 2);
+ sys_callback(join_float_callback, argv, 2);
}
static t_int join_symbol_callback(t_int * argv)
@@ -94,7 +94,7 @@ static void join_symbol(join_t * x, t_symbol * s)
argv[0] = (t_int)x->x_outlet;
argv[1] = (t_int)s;
- h_set_callback(join_symbol_callback, argv, 2);
+ sys_callback(join_symbol_callback, argv, 2);
}
static t_int join_list_callback(t_int * argv)
@@ -113,7 +113,7 @@ static void join_list(join_t * x, t_symbol * s, int argc, t_atom* largv)
argv[1] = (t_int)argc;
argv[2] = (t_int)copied_argv;
- h_set_callback(join_list_callback, argv, 3);
+ sys_callback(join_list_callback, argv, 3);
}
static t_int join_anything_callback(t_int * argv)
@@ -144,7 +144,7 @@ static void join_anything(join_t * x, t_symbol * s, int argc, t_atom* largv)
argv[1] = (t_int)copied_argc;
argv[2] = (t_int)copied_argv;
- h_set_callback(join_anything_callback, argv, 3);
+ sys_callback(join_anything_callback, argv, 3);
}
void join_setup(void)
diff --git a/threadlib/src/sleep.c b/threadlib/src/sleep.c
index f800074..9f9eaab 100755
--- a/threadlib/src/sleep.c
+++ b/threadlib/src/sleep.c
@@ -21,7 +21,14 @@
*/
#include "threadlib.h"
+
+// include for sleep
+#ifdef MSW
+#include <windows.h>
+#define sleep(t) Sleep(1000*(t))
+#else
#include <unistd.h>
+#endif
static t_class *sleep_class;
@@ -41,9 +48,7 @@ static void sleep_float(t_sleep * x, t_float f)
static void *sleep_new(void)
{
t_sleep *x = (t_sleep *)pd_new(sleep_class);
-
x->x_outlet = outlet_new(&x->x_obj,&s_float);
-
return (void *)x;
}
diff --git a/threadlib/src/threadedsf.c b/threadlib/src/threadedsf.c
deleted file mode 100755
index c9d0b9f..0000000
--- a/threadlib/src/threadedsf.c
+++ /dev/null
@@ -1,1919 +0,0 @@
-/*
-*
-* threadedsf
-*
-* this is a little bit hacked version of the
-* threaded soundfiler of pd_devel_0.38 by Tim Blechmann
-*
-* (c) 2005, Georg Holzmann, <grh@mur.at>
-*/
-
-/* Copyright (c) 1997-1999 Miller Puckette.
-* For information on usage and redistribution, and for a DISCLAIMER OF ALL
-* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
-
-/* this file contains, first, a collection of soundfile access routines, a
-sort of soundfile library. Second, the "soundfiler" object is defined which
-uses the routines to read or write soundfiles, synchronously, from garrays.
-These operations are not to be done in "real time" as they may have to wait
-for disk accesses (even the write routine.) Finally, the realtime objects
-readsf~ and writesf~ are defined which confine disk operations to a separate
-thread so that they can be used in real time. The readsf~ and writesf~
-objects use Posix-like threads. */
-
-/* threaded soundfiler by Tim Blechmann */
-
-
-#include "threadlib.h"
-
-#ifndef MSW
-#include <unistd.h>
-#include <fcntl.h>
-#endif
-#ifdef MSW
-#include <io.h>
-#endif
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-#include "g_canvas.h"
-
-#define MAXSFCHANS 64
-
-
-// forward declarations
-
-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 */
-};
-
-t_array *garray_getarray(t_garray *x);
-int garray_ambigendian(void);
-
-
-
-/***************** soundfile header structures ************************/
-
-typedef unsigned short uint16;
-typedef unsigned int uint32; /* long isn't 32-bit on amd64 */
-
-#define FORMAT_WAVE 0
-#define FORMAT_AIFF 1
-#define FORMAT_NEXT 2
-
-/* the NeXTStep sound header structure; can be big or little endian */
-
-typedef struct _nextstep
-{
- char ns_fileid[4]; /* magic number '.snd' if file is big-endian */
- uint32 ns_onset; /* byte offset of first sample */
- uint32 ns_length; /* length of sound in bytes */
- uint32 ns_format; /* format; see below */
- uint32 ns_sr; /* sample rate */
- uint32 ns_nchans; /* number of channels */
- char ns_info[4]; /* comment */
-} t_nextstep;
-
-#define NS_FORMAT_LINEAR_16 3
-#define NS_FORMAT_LINEAR_24 4
-#define NS_FORMAT_FLOAT 6
-#define SCALE (1./(1024. * 1024. * 1024. * 2.))
-
-/* the WAVE header. All Wave files are little endian. We assume
- the "fmt" chunk comes first which is usually the case but perhaps not
- always; same for AIFF and the "COMM" chunk. */
-
-typedef struct _wave
-{
- char w_fileid[4]; /* chunk id 'RIFF' */
- uint32 w_chunksize; /* chunk size */
- char w_waveid[4]; /* wave chunk id 'WAVE' */
- char w_fmtid[4]; /* format chunk id 'fmt ' */
- uint32 w_fmtchunksize; /* format chunk size */
- uint16 w_fmttag; /* format tag (WAV_INT etc) */
- uint16 w_nchannels; /* number of channels */
- uint32 w_samplespersec; /* sample rate in hz */
- uint32 w_navgbytespersec; /* average bytes per second */
- uint16 w_nblockalign; /* number of bytes per frame */
- uint16 w_nbitspersample; /* number of bits in a sample */
- char w_datachunkid[4]; /* data chunk id 'data' */
- uint32 w_datachunksize; /* length of data chunk */
-} t_wave;
-
-typedef struct _fmt /* format chunk */
-{
- uint16 f_fmttag; /* format tag, 1 for PCM */
- uint16 f_nchannels; /* number of channels */
- uint32 f_samplespersec; /* sample rate in hz */
- uint32 f_navgbytespersec; /* average bytes per second */
- uint16 f_nblockalign; /* number of bytes per frame */
- uint16 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 ' */
- uint32 wc_size; /* length of data chunk */
-} t_wavechunk;
-
-#define WAV_INT 1
-#define WAV_FLOAT 3
-
-/* 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' */
- uint32 dc_size; /* length of data chunk */
-} t_datachunk;
-
-typedef struct _comm
-{
- uint16 c_nchannels; /* number of channels */
- uint16 c_nframeshi; /* # of sample frames (hi) */
- uint16 c_nframeslo; /* # of sample frames (lo) */
- uint16 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' */
- uint32 a_chunksize; /* chunk size */
- char a_aiffid[4]; /* aiff chunk id 'AIFF' */
- char a_fmtid[4]; /* format chunk id 'COMM' */
- uint32 a_fmtchunksize; /* format chunk size, 18 */
- uint16 a_nchannels; /* number of channels */
- uint16 a_nframeshi; /* # of sample frames (hi) */
- uint16 a_nframeslo; /* # of sample frames (lo) */
- uint16 a_bitspersamp; /* bits per sample */
- unsigned char a_samprate[10]; /* sample rate, 80-bit float! */
-} t_aiff;
-
-#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)
-
-#define OBUFSIZE MAXPDSTRING /* assume MAXPDSTRING is bigger than headers */
-
-#ifdef MSW
-#include <fcntl.h>
-#define BINCREATE _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY
-#else
-#define BINCREATE O_WRONLY | O_CREAT | O_TRUNC
-#endif
-
-/* this routine returns 1 if the high order byte comes at the lower
-address on our architecture (big-endianness.). It's 1 for Motorola,
-0 for Intel: */
-
-extern int garray_ambigendian(void);
-
-/* byte swappers */
-
-static uint32 swap4(uint32 n, int doit)
-{
- if (doit)
- return (((n & 0xff) << 24) | ((n & 0xff00) << 8) |
- ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24));
- else return (n);
-}
-
-static uint16 swap2(uint32 n, int doit)
-{
- if (doit)
- return (((n & 0xff) << 8) | ((n & 0xff00) >> 8));
- else return (n);
-}
-
-static void swapstring(char *foo, int doit)
-{
- if (doit)
- {
- char a = foo[0], b = foo[1], c = foo[2], d = foo[3];
- foo[0] = d; foo[1] = c; foo[2] = b; foo[3] = a;
- }
-}
-
-/******************** soundfile access routines **********************/
-
-/* This routine opens a file, looks for either a nextstep or "wave" header,
-* seeks to end of it, and fills in bytes per sample and number of channels.
-* Only 2- and 3-byte fixed-point samples and 4-byte floating point samples
-* are supported. If "headersize" is nonzero, the
-* caller should supply the number of channels, endinanness, and bytes per
-* sample; the header is ignored. Otherwise, the routine tries to read the
-* header and fill in the properties.
-*/
-
-int open_soundfile(const char *dirname, const char *filename, int headersize,
- int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
- long skipframes)
-{
- char buf[OBUFSIZE], *bufptr;
- int fd, format, nchannels, bigendian, bytespersamp, swap, sysrtn;
- long bytelimit = 0x7fffffff;
- errno = 0;
- fd = open_via_path(dirname, filename,
- "", buf, &bufptr, MAXPDSTRING, 1);
- if (fd < 0)
- return (-1);
- if (headersize >= 0) /* header detection overridden */
- {
- bigendian = *p_bigendian;
- nchannels = *p_nchannels;
- bytespersamp = *p_bytespersamp;
- bytelimit = *p_bytelimit;
- }
- else
- {
- int bytesread = read(fd, buf, READHDRSIZE);
- int format;
- if (bytesread < 4)
- goto badheader;
- if (!strncmp(buf, ".snd", 4))
- format = FORMAT_NEXT, bigendian = 1;
- else if (!strncmp(buf, "dns.", 4))
- format = FORMAT_NEXT, bigendian = 0;
- else if (!strncmp(buf, "RIFF", 4))
- {
- if (bytesread < 12 || strncmp(buf + 8, "WAVE", 4))
- goto badheader;
- format = FORMAT_WAVE, bigendian = 0;
- }
- else if (!strncmp(buf, "FORM", 4))
- {
- if (bytesread < 12 || strncmp(buf + 8, "AIFF", 4))
- goto badheader;
- format = FORMAT_AIFF, bigendian = 1;
- }
- else
- goto badheader;
- swap = (bigendian != garray_ambigendian());
- if (format == FORMAT_NEXT) /* nextstep header */
- {
- uint32 param;
- if (bytesread < (int)sizeof(t_nextstep))
- goto badheader;
- nchannels = swap4(((t_nextstep *)buf)->ns_nchans, swap);
- format = swap4(((t_nextstep *)buf)->ns_format, 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 goto badheader;
- 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. */
- headersize = 12;
- if (bytesread < 20)
- goto badheader;
- /* First we guess a number of channels, etc., in case there's
- no "fmt" chunk to follow. */
- nchannels = 1;
- bytespersamp = 2;
- /* copy the first chunk header to beginnning of buffer. */
- memcpy(buf, buf + headersize, sizeof(t_wavechunk));
- /* post("chunk %c %c %c %c",
- ((t_wavechunk *)buf)->wc_id[0],
- ((t_wavechunk *)buf)->wc_id[1],
- ((t_wavechunk *)buf)->wc_id[2],
- ((t_wavechunk *)buf)->wc_id[3]); */
- /* 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 = lseek(fd, commblockonset, SEEK_SET);
- if (seekout != commblockonset)
- goto badheader;
- if (read(fd, buf, sizeof(t_fmt)) < (int) sizeof(t_fmt))
- goto badheader;
- nchannels = swap2(((t_fmt *)buf)->f_nchannels, swap);
- format = swap2(((t_fmt *)buf)->f_nbitspersample, swap);
- if (format == 16)
- bytespersamp = 2;
- else if (format == 24)
- bytespersamp = 3;
- else if (format == 32)
- bytespersamp = 4;
- else goto badheader;
- }
- seekout = lseek(fd, seekto, SEEK_SET);
- if (seekout != seekto)
- goto badheader;
- if (read(fd, buf, sizeof(t_wavechunk)) <
- (int) sizeof(t_wavechunk))
- goto badheader;
- /* post("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. */
- headersize = 12;
- if (bytesread < 20)
- goto badheader;
- /* First we guess a number of channels, etc., in case there's
- no COMM block to follow. */
- nchannels = 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;
- /* post("chunk %c %c %c %c seek %d",
- ((t_datachunk *)buf)->dc_id[0],
- ((t_datachunk *)buf)->dc_id[1],
- ((t_datachunk *)buf)->dc_id[2],
- ((t_datachunk *)buf)->dc_id[3], seekto); */
- if (!strncmp(((t_datachunk *)buf)->dc_id, "COMM", 4))
- {
- long commblockonset = headersize + 8;
- seekout = lseek(fd, commblockonset, SEEK_SET);
- if (seekout != commblockonset)
- goto badheader;
- if (read(fd, buf, sizeof(t_comm)) <
- (int) sizeof(t_comm))
- goto badheader;
- nchannels = swap2(((t_comm *)buf)->c_nchannels, swap);
- format = swap2(((t_comm *)buf)->c_bitspersamp, swap);
- if (format == 16)
- bytespersamp = 2;
- else if (format == 24)
- bytespersamp = 3;
- else goto badheader;
- }
- seekout = lseek(fd, seekto, SEEK_SET);
- if (seekout != seekto)
- goto badheader;
- if (read(fd, buf, sizeof(t_datachunk)) <
- (int) sizeof(t_datachunk))
- goto badheader;
- headersize = seekto;
- }
- bytelimit = swap4(((t_datachunk *)buf)->dc_size, swap);
- headersize += 8;
- }
- }
- /* seek past header and any sample frames to skip */
- sysrtn = lseek(fd, nchannels * bytespersamp * skipframes + headersize, 0);
- if (sysrtn != nchannels * bytespersamp * skipframes + headersize)
- return (-1);
- bytelimit -= nchannels * bytespersamp * skipframes;
- if (bytelimit < 0)
- bytelimit = 0;
- /* copy sample format back to caller */
- *p_bigendian = bigendian;
- *p_nchannels = nchannels;
- *p_bytespersamp = bytespersamp;
- *p_bytelimit = bytelimit;
- return (fd);
-badheader:
- /* the header wasn't recognized. We're threadable here so let's not
- print out the error... */
- errno = EIO;
- return (-1);
-}
-
-static void soundfile_xferin(int sfchannels, int nvecs, float **vecs,
- long itemsread, unsigned char *buf, int nitems, int bytespersamp,
- int bigendian)
-{
- int i, j;
- unsigned char *sp, *sp2;
- float *fp;
- int nchannels = (sfchannels < nvecs ? sfchannels : nvecs);
- int bytesperframe = bytespersamp * sfchannels;
- for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
- {
- if (bytespersamp == 2)
- {
- if (bigendian)
- {
- for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
- j < nitems; j++, sp2 += bytesperframe, fp++)
- *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16));
- }
- else
- {
- for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
- j < nitems; j++, sp2 += bytesperframe, fp++)
- *fp = SCALE * ((sp2[1] << 24) | (sp2[0] << 16));
- }
- }
- else if (bytespersamp == 3)
- {
- if (bigendian)
- {
- for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
- j < nitems; j++, sp2 += bytesperframe, fp++)
- *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16)
- | (sp2[2] << 8));
- }
- else
- {
- for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
- j < nitems; j++, sp2 += bytesperframe, fp++)
- *fp = SCALE * ((sp2[2] << 24) | (sp2[1] << 16)
- | (sp2[0] << 8));
- }
- }
- else if (bytespersamp == 4)
- {
- if (bigendian)
- {
- for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
- j < nitems; j++, sp2 += bytesperframe, fp++)
- *(long *)fp = ((sp2[0] << 24) | (sp2[1] << 16)
- | (sp2[2] << 8) | sp2[3]);
- }
- else
- {
- for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
- j < nitems; j++, sp2 += bytesperframe, fp++)
- *(long *)fp = ((sp2[3] << 24) | (sp2[2] << 16)
- | (sp2[1] << 8) | sp2[0]);
- }
- }
- }
- /* zero out other outputs */
- for (i = sfchannels; i < nvecs; i++)
- for (j = nitems, fp = vecs[i]; j--; )
- *fp++ = 0;
-
-}
-
- /* soundfiler_write ...
-
- usage: write [flags] filename table ...
- flags:
- -nframes <frames>
- -skip <frames>
- -bytes <bytes per sample>
- -normalize
- -nextstep
- -wave
- -big
- -little
- */
-
- /* the routine which actually does the work should LATER also be called
- from garray_write16. */
-
-
- /* Parse arguments for writing. The "obj" argument is only for flagging
- errors. For streaming to a file the "normalize", "onset" and "nframes"
- arguments shouldn't be set but the calling routine flags this. */
-
-static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv,
- t_symbol **p_filesym,
- int *p_filetype, int *p_bytespersamp, int *p_swap, int *p_bigendian,
- int *p_normalize, long *p_onset, long *p_nframes, float *p_rate)
-{
- int argc = *p_argc;
- t_atom *argv = *p_argv;
- int bytespersamp = 2, bigendian = 0,
- endianness = -1, swap, filetype = -1, normalize = 0;
- long onset = 0, nframes = 0x7fffffff;
- t_symbol *filesym;
- float rate = -1;
-
- while (argc > 0 && argv->a_type == A_SYMBOL &&
- *argv->a_w.w_symbol->s_name == '-')
- {
- char *flag = argv->a_w.w_symbol->s_name + 1;
- if (!strcmp(flag, "skip"))
- {
- if (argc < 2 || argv[1].a_type != A_FLOAT ||
- ((onset = argv[1].a_w.w_float) < 0))
- goto usage;
- argc -= 2; argv += 2;
- }
- else if (!strcmp(flag, "nframes"))
- {
- if (argc < 2 || argv[1].a_type != A_FLOAT ||
- ((nframes = argv[1].a_w.w_float) < 0))
- goto usage;
- argc -= 2; argv += 2;
- }
- else if (!strcmp(flag, "bytes"))
- {
- if (argc < 2 || argv[1].a_type != A_FLOAT ||
- ((bytespersamp = argv[1].a_w.w_float) < 2) ||
- bytespersamp > 4)
- goto usage;
- argc -= 2; argv += 2;
- }
- else if (!strcmp(flag, "normalize"))
- {
- normalize = 1;
- argc -= 1; argv += 1;
- }
- else if (!strcmp(flag, "wave"))
- {
- filetype = FORMAT_WAVE;
- argc -= 1; argv += 1;
- }
- else if (!strcmp(flag, "nextstep"))
- {
- filetype = FORMAT_NEXT;
- argc -= 1; argv += 1;
- }
- else if (!strcmp(flag, "aiff"))
- {
- filetype = FORMAT_AIFF;
- argc -= 1; argv += 1;
- }
- else if (!strcmp(flag, "big"))
- {
- endianness = 1;
- argc -= 1; argv += 1;
- }
- else if (!strcmp(flag, "little"))
- {
- endianness = 0;
- argc -= 1; argv += 1;
- }
- else if (!strcmp(flag, "r") || !strcmp(flag, "rate"))
- {
- if (argc < 2 || argv[1].a_type != A_FLOAT ||
- ((rate = argv[1].a_w.w_float) <= 0))
- goto usage;
- argc -= 2; argv += 2;
- }
- else goto usage;
- }
- if (!argc || argv->a_type != A_SYMBOL)
- goto usage;
- filesym = argv->a_w.w_symbol;
-
- /* check if format not specified and fill in */
- if (filetype < 0)
- {
- if (strlen(filesym->s_name) >= 5 &&
- (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".aif") ||
- !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".AIF")))
- filetype = FORMAT_AIFF;
- if (strlen(filesym->s_name) >= 6 &&
- (!strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".aiff") ||
- !strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".AIFF")))
- filetype = FORMAT_AIFF;
- if (strlen(filesym->s_name) >= 5 &&
- (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".snd") ||
- !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".SND")))
- filetype = FORMAT_NEXT;
- if (strlen(filesym->s_name) >= 4 &&
- (!strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".au") ||
- !strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".AU")))
- filetype = FORMAT_NEXT;
- if (filetype < 0)
- filetype = FORMAT_WAVE;
- }
- /* don't handle AIFF floating point samples */
- if (bytespersamp == 4)
- {
- if (filetype == FORMAT_AIFF)
- {
- pd_error(obj, "AIFF floating-point file format unavailable");
- goto usage;
- }
- }
- /* for WAVE force little endian; for nextstep use machine native */
- if (filetype == FORMAT_WAVE)
- {
- bigendian = 0;
- if (endianness == 1)
- pd_error(obj, "WAVE file forced to little endian");
- }
- else if (filetype == FORMAT_AIFF)
- {
- bigendian = 1;
- if (endianness == 0)
- pd_error(obj, "AIFF file forced to big endian");
- }
- else if (endianness == -1)
- {
- bigendian = garray_ambigendian();
- }
- else bigendian = endianness;
- swap = (bigendian != garray_ambigendian());
-
- argc--; argv++;
-
- *p_argc = argc;
- *p_argv = argv;
- *p_filesym = filesym;
- *p_filetype = filetype;
- *p_bytespersamp = bytespersamp;
- *p_swap = swap;
- *p_normalize = normalize;
- *p_onset = onset;
- *p_nframes = nframes;
- *p_bigendian = bigendian;
- *p_rate = rate;
- return (0);
-usage:
- return (-1);
-}
-
-static int create_soundfile(t_canvas *canvas, const char *filename,
- int filetype, int nframes, int bytespersamp,
- int bigendian, int nchannels, int swap, float samplerate)
-{
- char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING];
- char headerbuf[WRITEHDRSIZE];
- t_wave *wavehdr = (t_wave *)headerbuf;
- t_nextstep *nexthdr = (t_nextstep *)headerbuf;
- t_aiff *aiffhdr = (t_aiff *)headerbuf;
- int fd, headersize = 0;
-
- strncpy(filenamebuf, filename, MAXPDSTRING-10);
- filenamebuf[MAXPDSTRING-10] = 0;
-
- if (filetype == FORMAT_NEXT)
- {
- if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".snd"))
- strcat(filenamebuf, ".snd");
- if (bigendian)
- strncpy(nexthdr->ns_fileid, ".snd", 4);
- else strncpy(nexthdr->ns_fileid, "dns.", 4);
- nexthdr->ns_onset = swap4(sizeof(*nexthdr), swap);
- nexthdr->ns_length = 0;
- nexthdr->ns_format = swap4((bytespersamp == 3 ? NS_FORMAT_LINEAR_24 :
- (bytespersamp == 4 ? NS_FORMAT_FLOAT : NS_FORMAT_LINEAR_16)), swap);
- nexthdr->ns_sr = swap4(samplerate, swap);
- nexthdr->ns_nchans = swap4(nchannels, swap);
- strcpy(nexthdr->ns_info, "Pd ");
- swapstring(nexthdr->ns_info, swap);
- headersize = sizeof(t_nextstep);
- }
- else if (filetype == FORMAT_AIFF)
- {
- long datasize = nframes * nchannels * bytespersamp;
- long longtmp;
- static unsigned char dogdoo[] =
- {0x40, 0x0e, 0xac, 0x44, 0, 0, 0, 0, 0, 0, 'S', 'S', 'N', 'D'};
- if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".aif") &&
- strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff"))
- strcat(filenamebuf, ".aif");
- strncpy(aiffhdr->a_fileid, "FORM", 4);
- aiffhdr->a_chunksize = swap4(datasize + sizeof(*aiffhdr) + 4, swap);
- strncpy(aiffhdr->a_aiffid, "AIFF", 4);
- strncpy(aiffhdr->a_fmtid, "COMM", 4);
- aiffhdr->a_fmtchunksize = swap4(18, swap);
- aiffhdr->a_nchannels = swap2(nchannels, swap);
- longtmp = swap4(nframes, swap);
- memcpy(&aiffhdr->a_nframeshi, &longtmp, 4);
- aiffhdr->a_bitspersamp = swap2(8 * bytespersamp, swap);
- memcpy(aiffhdr->a_samprate, dogdoo, sizeof(dogdoo));
- longtmp = swap4(datasize, swap);
- memcpy(aiffhdr->a_samprate + sizeof(dogdoo), &longtmp, 4);
- headersize = AIFFPLUS;
- }
- else /* WAVE format */
- {
- long datasize = nframes * nchannels * bytespersamp;
- if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".wav"))
- strcat(filenamebuf, ".wav");
- strncpy(wavehdr->w_fileid, "RIFF", 4);
- wavehdr->w_chunksize = swap4(datasize + sizeof(*wavehdr) - 8, swap);
- strncpy(wavehdr->w_waveid, "WAVE", 4);
- strncpy(wavehdr->w_fmtid, "fmt ", 4);
- wavehdr->w_fmtchunksize = swap4(16, swap);
- wavehdr->w_fmttag =
- swap2((bytespersamp == 4 ? WAV_FLOAT : WAV_INT), swap);
- wavehdr->w_nchannels = swap2(nchannels, swap);
- wavehdr->w_samplespersec = swap4(samplerate, swap);
- wavehdr->w_navgbytespersec =
- swap4((int)(samplerate * nchannels * bytespersamp), swap);
- wavehdr->w_nblockalign = swap2(nchannels * bytespersamp, swap);
- wavehdr->w_nbitspersample = swap2(8 * bytespersamp, swap);
- strncpy(wavehdr->w_datachunkid, "data", 4);
- wavehdr->w_datachunksize = swap4(datasize, swap);
- headersize = sizeof(t_wave);
- }
-
- canvas_makefilename(canvas, filenamebuf, buf2, MAXPDSTRING);
- sys_bashfilename(buf2, buf2);
- if ((fd = open(buf2, BINCREATE, 0666)) < 0)
- return (-1);
-
- if (write(fd, headerbuf, headersize) < headersize)
- {
- close (fd);
- return (-1);
- }
- return (fd);
-}
-
-static void soundfile_finishwrite(void *obj, char *filename, int fd,
- int filetype, long nframes, long itemswritten, int bytesperframe, int swap)
-{
- if (itemswritten < nframes)
- {
- if (nframes < 0x7fffffff)
- pd_error(obj, "soundfiler_write: %d out of %d bytes written",
- itemswritten, nframes);
- /* try to fix size fields in header */
- if (filetype == FORMAT_WAVE)
- {
- long datasize = itemswritten * bytesperframe, mofo;
-
- if (lseek(fd,
- ((char *)(&((t_wave *)0)->w_chunksize)) - (char *)0,
- SEEK_SET) == 0)
- goto baddonewrite;
- mofo = swap4(datasize + sizeof(t_wave) - 8, swap);
- if (write(fd, (char *)(&mofo), 4) < 4)
- goto baddonewrite;
- if (lseek(fd,
- ((char *)(&((t_wave *)0)->w_datachunksize)) - (char *)0,
- SEEK_SET) == 0)
- goto baddonewrite;
- mofo = swap4(datasize, swap);
- if (write(fd, (char *)(&mofo), 4) < 4)
- goto baddonewrite;
- }
- if (filetype == FORMAT_AIFF)
- {
- long mofo;
- if (lseek(fd,
- ((char *)(&((t_aiff *)0)->a_nframeshi)) - (char *)0,
- SEEK_SET) == 0)
- goto baddonewrite;
- mofo = swap4(nframes, swap);
- if (write(fd, (char *)(&mofo), 4) < 4)
- goto baddonewrite;
- }
- if (filetype == FORMAT_NEXT)
- {
- /* do it the lazy way: just set the size field to 'unknown size'*/
- uint32 nextsize = 0xffffffff;
- if (lseek(fd, 8, SEEK_SET) == 0)
- {
- goto baddonewrite;
- }
- if (write(fd, &nextsize, 4) < 4)
- {
- goto baddonewrite;
- }
- }
- }
- return;
-baddonewrite:
- post("%s: %s", filename, strerror(errno));
-}
-
-static void soundfile_xferout(int nchannels, float **vecs,
- unsigned char *buf, int nitems, long onset, int bytespersamp,
- int bigendian, float normalfactor)
-{
- int i, j;
- unsigned char *sp, *sp2;
- float *fp;
- int bytesperframe = bytespersamp * nchannels;
- long xx;
- for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
- {
- if (bytespersamp == 2)
- {
- float ff = normalfactor * 32768.;
- if (bigendian)
- {
- for (j = 0, sp2 = sp, fp = vecs[i] + onset;
- j < nitems; j++, sp2 += bytesperframe, fp++)
- {
- int xx = 32768. + (*fp * ff);
- xx -= 32768;
- if (xx < -32767)
- xx = -32767;
- if (xx > 32767)
- xx = 32767;
- sp2[0] = (xx >> 8);
- sp2[1] = xx;
- }
- }
- else
- {
- for (j = 0, sp2 = sp, fp=vecs[i] + onset;
- j < nitems; j++, sp2 += bytesperframe, fp++)
- {
- int xx = 32768. + (*fp * ff);
- xx -= 32768;
- if (xx < -32767)
- xx = -32767;
- if (xx > 32767)
- xx = 32767;
- sp2[1] = (xx >> 8);
- sp2[0] = xx;
- }
- }
- }
- else if (bytespersamp == 3)
- {
- float ff = normalfactor * 8388608.;
- if (bigendian)
- {
- for (j = 0, sp2 = sp, fp=vecs[i] + onset;
- j < nitems; j++, sp2 += bytesperframe, fp++)
- {
- int xx = 8388608. + (*fp * ff);
- xx -= 8388608;
- if (xx < -8388607)
- xx = -8388607;
- if (xx > 8388607)
- xx = 8388607;
- sp2[0] = (xx >> 16);
- sp2[1] = (xx >> 8);
- sp2[2] = xx;
- }
- }
- else
- {
- for (j = 0, sp2 = sp, fp=vecs[i] + onset;
- j < nitems; j++, sp2 += bytesperframe, fp++)
- {
- int xx = 8388608. + (*fp * ff);
- xx -= 8388608;
- if (xx < -8388607)
- xx = -8388607;
- if (xx > 8388607)
- xx = 8388607;
- sp2[2] = (xx >> 16);
- sp2[1] = (xx >> 8);
- sp2[0] = xx;
- }
- }
- }
- else if (bytespersamp == 4)
- {
- if (bigendian)
- {
- for (j = 0, sp2 = sp, fp=vecs[i] + onset;
- j < nitems; j++, sp2 += bytesperframe, fp++)
- {
- float f2 = *fp * normalfactor;
- xx = *(long *)&f2;
- sp2[0] = (xx >> 24); sp2[1] = (xx >> 16);
- sp2[2] = (xx >> 8); sp2[3] = xx;
- }
- }
- else
- {
- for (j = 0, sp2 = sp, fp=vecs[i] + onset;
- j < nitems; j++, sp2 += bytesperframe, fp++)
- {
- float f2 = *fp * normalfactor;
- xx = *(long *)&f2;
- sp2[3] = (xx >> 24); sp2[2] = (xx >> 16);
- sp2[1] = (xx >> 8); sp2[0] = xx;
- }
- }
- }
- }
-}
-
-
-
-/* ------- threadedsf - reads and writes soundfiles to/from "garrays" ---- */
-
-// in pd's soundfiler maxsize is 4000000
-// threaded we should be able to hande a bit more
-#define DEFMAXSIZE 40000000
-#define SAMPBUFSIZE 1024
-
-
-static t_class *threadedsf_class;
-
-typedef struct _threadedsf
-{
- t_object x_obj;
- t_canvas *x_canvas;
-} t_threadedsf;
-
-#include <sched.h>
-
-#ifdef _POSIX_MEMLOCK
-#include <sys/mman.h>
-#endif /* _POSIX_MEMLOCK */
-
-#ifdef DEBUG
-#define SFDEBUG
-#endif
-
-static pthread_t sf_thread_id; /* id of soundfiler thread */
-//static pthread_attr_t sf_attr;
-
-typedef struct _sfprocess
-{
- void (* process) (t_threadedsf *,t_symbol *,
- int, t_atom *); /* function to call */
- t_threadedsf * x; /* soundfiler */
- int argc;
- t_atom * argv;
- struct _sfprocess * next; /* next object in queue */
- pthread_mutex_t mutex;
-} t_sfprocess;
-
-/* this is the queue for all threadedsf objects */
-typedef struct _sfqueue
-{
- t_sfprocess * begin;
- t_sfprocess * end;
- pthread_mutex_t mutex;
- pthread_cond_t cond;
-} t_sfqueue;
-
-static t_sfqueue * threadedsf_queue;
-
-
-/* we fill the queue */
-void threadedsf_queue_add(void (* process) (t_threadedsf *,t_symbol *,
- int,t_atom *), void * x,
- int argc, t_atom * argv)
-{
- /* preparing entry */
- t_sfprocess * last_entry = (t_sfprocess*)getbytes(sizeof(t_sfprocess));
-
-#ifdef SFDEBUG
- post("adding process to queue");
-#endif
-
- pthread_mutex_init(&(last_entry->mutex), NULL);
- pthread_mutex_lock(&(last_entry->mutex));
- last_entry->process = process;
- last_entry->x = x;
- last_entry->argc = argc;
- last_entry->argv = copybytes (argv, argc * sizeof(t_atom));
- last_entry->next = NULL;
- pthread_mutex_unlock(&(last_entry->mutex));
-
- /* add new entry to queue */
- pthread_mutex_lock(&(threadedsf_queue->mutex));
-
- if (threadedsf_queue->begin==NULL)
- {
- threadedsf_queue->begin=last_entry;
- threadedsf_queue->end=last_entry;
- }
- else
- {
- pthread_mutex_lock(&(threadedsf_queue->end->mutex));
- threadedsf_queue->end->next=last_entry;
- pthread_mutex_unlock(&(threadedsf_queue->end->mutex));
- threadedsf_queue->end=last_entry;
- }
-
-
- if ( threadedsf_queue->begin == threadedsf_queue->end )
- {
-#ifdef DEBUG
- post("signaling");
-#endif
- pthread_mutex_unlock(&(threadedsf_queue->mutex));
-
- /* and signal the helper thread */
- pthread_cond_signal(&(threadedsf_queue->cond));
- }
- else
- {
-#ifdef DEBUG
- post("not signaling");
-#endif
- pthread_mutex_unlock(&(threadedsf_queue->mutex));
- }
- return;
-}
-
-/* global threadedsf thread ... sleeping until signaled */
-void threadedsf_thread(void)
-{
- t_sfprocess * me;
- t_sfprocess * next;
-
-#ifdef DEBUG
- post("threadedsf_thread ID: %d", pthread_self());
-#endif
- while (1)
- {
-#ifdef DEBUG
- post("Soundfiler sleeping");
-#endif
- pthread_cond_wait(&threadedsf_queue->cond, &threadedsf_queue->mutex);
-#ifdef DEBUG
- post("Soundfiler awake");
-#endif
-
- /* work on the queue */
- while (threadedsf_queue->begin!=NULL)
- {
- post("threadedsf: locked queue");
- /* locking process */
- pthread_mutex_lock(&(threadedsf_queue->begin->mutex));
-
- me = threadedsf_queue->begin;
-
- pthread_mutex_unlock(&(me->mutex));
- pthread_mutex_unlock(&(threadedsf_queue->mutex));
-#ifdef DEBUG
- post("threadedsf: mutex unlocked, running process");
-#endif
-
- /* running the specific function */
- me->process(me->x, NULL, me->argc, me->argv);
-#ifdef DEBUG
- post("threadedsf: process done, locking mutex");
-#endif
-
- pthread_mutex_lock(&(threadedsf_queue->mutex));
- pthread_mutex_lock(&(me->mutex));
-
- /* freeing the argument vector */
- freebytes(me->argv, sizeof(t_atom) * me->argc);
-
- /* the process struct */
- next=me->next;
- threadedsf_queue->begin=next;
- freebytes(me, sizeof(t_sfprocess));
- };
- threadedsf_queue->end=NULL;
- }
-}
-
-extern int sys_hipriority; /* real-time flag, true if priority boosted */
-
-/* create soundfiler thread */
-void sys_start_sfthread(void)
-{
- pthread_attr_t sf_attr;
- struct sched_param sf_param;
-
- int status;
-
- //initialize queue
- threadedsf_queue = getbytes (sizeof(t_sfqueue));
-
- pthread_mutex_init (&threadedsf_queue->mutex,NULL);
- pthread_cond_init (&threadedsf_queue->cond,NULL);
-
- threadedsf_queue->begin=threadedsf_queue->end=NULL;
-/* pthread_mutex_unlock(&(threadedsf_queue->mutex)); */
-
- // initialize thread
- pthread_attr_init(&sf_attr);
-
-//#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
- sf_param.sched_priority=sched_get_priority_min(SCHED_OTHER);
- pthread_attr_setschedparam(&sf_attr,&sf_param);
-/* pthread_attr_setinheritsched(&sf_attr,PTHREAD_EXPLICIT_SCHED); */
-
-#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);
- }
- else
- {
-/* pthread_attr_setschedpolicy(&sf_attr,SCHED_OTHER); */
-/* sf_param.sched_priority=sched_get_priority_min(SCHED_OTHER); */
- }
-#endif /* UNIX */
-
-//#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
-
- //start thread
- status = pthread_create(&sf_thread_id, &sf_attr,
- (void *) threadedsf_thread,NULL);
- if (status != 0)
- error("Couldn't create threadedsf thread: %d",status);
-#ifdef DEBUG
- else
- post("global threadedsf thread launched, priority: %d",
- sf_param.sched_priority);
-#endif
-}
-
-static void threadedsf_t_write(t_threadedsf *x, t_symbol *s,
- int argc, t_atom *argv);
-
-static void threadedsf_t_write_addq(t_threadedsf *x, t_symbol *s,
- int argc, t_atom *argv)
-{
- threadedsf_queue_add(threadedsf_t_write,(void *)x,argc, argv);
-}
-
-static void threadedsf_t_read(t_threadedsf *x, t_symbol *s,
- int argc, t_atom *argv);
-
-static void threadedsf_t_read_addq(t_threadedsf *x, t_symbol *s,
- int argc, t_atom *argv)
-{
- threadedsf_queue_add(threadedsf_t_read,(void *)x,argc, argv);
-}
-
-
- /* threadedsf_read ...
-
- usage: read [flags] filename table ...
- flags:
- -skip <frames> ... frames to skip in file
- -nframes <frames>
- -onset <frames> ... onset in table to read into (NOT DONE YET)
- -raw <headersize channels bytes endian>
- -resize
- -maxsize <max-size>
-
- TB: adapted for threaded use
- */
-
-/* callback prototypes */
-static t_int threadedsf_read_update_garray(t_int * w);
-static t_int threadedsf_read_update_graphics(t_int * w);
-static t_int threadedsf_read_output(t_int * w);
-
-
-static void threadedsf_t_read(t_threadedsf *x, t_symbol *s,
- int argc, t_atom *argv)
-{
- int headersize = -1, channels = 0, bytespersamp = 0, bigendian = 0,
- resize = 0, i, j;
- long skipframes = 0,
- nframes = 0,
- finalsize = 0, /* new size */
- maxsize = DEFMAXSIZE,
- itemsread = 0,
- bytelimit = 0x7fffffff;
- int fd = -1;
- char endianness, *filename;
- t_garray *garrays[MAXSFCHANS];
- t_float *vecs[MAXSFCHANS]; /* the old array */
- t_float *nvecs[MAXSFCHANS]; /* the new array */
- int vecsize[MAXSFCHANS]; /* the old array size */
- char sampbuf[SAMPBUFSIZE];
- int bufframes, nitems;
- FILE *fp;
- pthread_cond_t resume_after_callback = PTHREAD_COND_INITIALIZER;
- pthread_mutex_t resume_after_callback_mutex = PTHREAD_MUTEX_INITIALIZER; /* dummy */
- t_int* outargs;
-
- while (argc > 0 && argv->a_type == A_SYMBOL &&
- *argv->a_w.w_symbol->s_name == '-')
- {
- char *flag = argv->a_w.w_symbol->s_name + 1;
- if (!strcmp(flag, "skip"))
- {
- if (argc < 2 || argv[1].a_type != A_FLOAT ||
- ((skipframes = argv[1].a_w.w_float) < 0))
- goto usage;
- argc -= 2; argv += 2;
- }
- else if (!strcmp(flag, "nframes"))
- {
- if (argc < 2 || argv[1].a_type != A_FLOAT ||
- ((nframes = argv[1].a_w.w_float) < 0))
- goto usage;
- argc -= 2; argv += 2;
- }
- else if (!strcmp(flag, "raw"))
- {
- if (argc < 5 ||
- argv[1].a_type != A_FLOAT ||
- ((headersize = argv[1].a_w.w_float) < 0) ||
- argv[2].a_type != A_FLOAT ||
- ((channels = argv[2].a_w.w_float) < 1) ||
- (channels > MAXSFCHANS) ||
- argv[3].a_type != A_FLOAT ||
- ((bytespersamp = argv[3].a_w.w_float) < 2) ||
- (bytespersamp > 4) ||
- argv[4].a_type != A_SYMBOL ||
- ((endianness = argv[4].a_w.w_symbol->s_name[0]) != 'b'
- && endianness != 'l' && endianness != 'n'))
- goto usage;
- if (endianness == 'b')
- bigendian = 1;
- else if (endianness == 'l')
- bigendian = 0;
- else
- bigendian = garray_ambigendian();
- argc -= 5; argv += 5;
- }
- else if (!strcmp(flag, "resize"))
- {
- resize = 1;
- argc -= 1; argv += 1;
- }
- else if (!strcmp(flag, "maxsize"))
- {
- if (argc < 2 || argv[1].a_type != A_FLOAT ||
- ((maxsize = argv[1].a_w.w_float) < 0))
- goto usage;
- resize = 1; /* maxsize implies resize. */
- argc -= 2; argv += 2;
- }
- else goto usage;
- }
- if (argc < 2 || argc > MAXSFCHANS + 1 || argv[0].a_type != A_SYMBOL)
- goto usage;
- filename = argv[0].a_w.w_symbol->s_name;
- argc--; argv++;
-
- for (i = 0; i < argc; i++)
- {
- if (argv[i].a_type != A_SYMBOL)
- goto usage;
- if (!(garrays[i] =
- (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
- {
- pd_error(x, "%s: no such table", argv[i].a_w.w_symbol->s_name);
- goto done;
- }
- else if (!garray_getfloatarray(garrays[i], &vecsize[i], &vecs[i]))
- error("%s: bad template for tabwrite",
- argv[i].a_w.w_symbol->s_name);
- if (finalsize && finalsize != vecsize[i] && !resize)
- {
- post("threadedsf_read: arrays have different lengths; resizing...");
- resize = 1;
- }
- finalsize = vecsize[i];
- }
- fd = open_soundfile(canvas_getdir(x->x_canvas)->s_name, filename,
- headersize, &bytespersamp, &bigendian, &channels, &bytelimit,
- skipframes);
-
- if (fd < 0)
- {
- pd_error(x, "threadedsf_read: %s: %s", filename, (errno == EIO ?
- "unknown or bad header format" : strerror(errno)));
- goto done;
- }
-
- if (resize)
- {
- /* figure out what to resize to */
- long poswas, eofis, framesinfile;
-
- poswas = lseek(fd, 0, SEEK_CUR);
- eofis = lseek(fd, 0, SEEK_END);
- if (poswas < 0 || eofis < 0)
- {
- pd_error(x, "lseek failed");
- goto done;
- }
- lseek(fd, poswas, SEEK_SET);
- framesinfile = (eofis - poswas) / (channels * bytespersamp);
- if (framesinfile > maxsize)
- {
- pd_error(x, "threadedsf_read: truncated to %d elements", maxsize);
- framesinfile = maxsize;
- }
- if (framesinfile > bytelimit / (channels * bytespersamp))
- framesinfile = bytelimit / (channels * bytespersamp);
- finalsize = framesinfile;
-
- }
- if (!finalsize) finalsize = 0x7fffffff;
- if (finalsize > bytelimit / (channels * bytespersamp))
- finalsize = bytelimit / (channels * bytespersamp);
- fp = fdopen(fd, "rb");
- bufframes = SAMPBUFSIZE / (channels * bytespersamp);
-
-#ifdef SFDEBUG
- post("buffers: %d", argc);
- post("channels: %d", channels);
-#endif
-
-#ifdef _POSIX_MEMLOCK
- munlockall();
-#endif
-
- /* allocate memory for new array */
- if (resize)
- for (i = 0; i < argc; i++)
- {
-#ifdef SFDEBUG
- post("allocating buffer %d",i);
-#endif
- nvecs[i]=getbytes (finalsize * sizeof(t_float));
- /* if we are out of memory, free it again and quit */
- if (nvecs[i]==0)
- {
- pd_error(x, "resize failed");
- for (j=0; j!=i;++j)
- /* if the resizing fails, we'll have to free all arrays again */
- freebytes (nvecs[i],finalsize * sizeof(t_float));
- goto done;
- }
- /* zero samples */
- if(i > channels)
- {
- memset(nvecs[i],0,vecsize[i] * sizeof(t_float));
- }
- }
- else
- for (i = 0; i < argc; i++)
- {
- nvecs[i] = getbytes (vecsize[i] * sizeof(t_float));
- /* if we are out of memory, free it again and quit */
- if (nvecs[i]==0)
- {
- pd_error(x, "resize failed");
- for (j=0; j!=i;++j)
- /* if the resizing fails, we'll have to free all arrays again */
- freebytes (nvecs[i],vecsize[i] * sizeof(t_float));
- goto done;
- }
- /* zero samples */
- if(i > channels)
- memset(nvecs[i],0,vecsize[i] * sizeof(t_float));
- }
-
-#ifdef SFDEBUG
- post("transfer soundfile");
-#endif
-
- for (itemsread = 0; itemsread < finalsize; )
- {
- int thisread = finalsize - itemsread;
- thisread = (thisread > bufframes ? bufframes : thisread);
- nitems = fread(sampbuf, channels * bytespersamp, thisread, fp);
- if (nitems <= 0) break;
- soundfile_xferin(channels, argc, nvecs, itemsread,
- (unsigned char *)sampbuf, nitems, bytespersamp, bigendian);
- itemsread += nitems;
- }
-
-#ifdef SFDEBUG
- post("zeroing remaining elements");
-#endif
- /* zero out remaining elements of vectors */
- for (i = 0; i < argc; i++)
- {
- for (j = itemsread; j < finalsize; j++)
- nvecs[i][j] = 0;
- }
-
- /* set idle callback to switch pointers */
-#ifdef SFDEBUG
- post("locked");
-#endif
- for (i = 0; i < argc; i++)
- {
- t_int* w = (t_int*)getbytes(4*sizeof(t_int));
-
- w[0] = (t_int)(garrays[i]);
- w[1] = (t_int)nvecs[i];
- w[2] = (t_int)finalsize;
- w[3] = (t_int)(&resume_after_callback);
-
- h_set_callback(&threadedsf_read_update_garray, w, 4);
-
- pthread_cond_wait(&resume_after_callback, &resume_after_callback_mutex);
- }
-
-#ifdef SFDEBUG
- post("unlocked, doing graphics updates");
-#endif
-
- /* do all graphics updates
- * run this in the main thread via callback */
- for (i = 0; i < argc; i++)
- {
- t_int* w = (t_int*)getbytes(2*sizeof(t_int));
-
- w[0] = (t_int)(garrays[i]);
- w[1] = (t_int)finalsize;
-
- h_set_callback(&threadedsf_read_update_graphics, w, 2);
- }
-
- /* free the old arrays */
- for (i = 0; i < argc; i++)
- freebytes(vecs[i], vecsize[i] * sizeof(t_float));
-
- fclose(fp);
- fd = -1;
- goto done;
-
- usage:
- pd_error(x, "usage: read [flags] filename tablename...");
- post("flags: -skip <n> -nframes <n> -resize -maxsize <n> ...");
- post("-raw <headerbytes> <channels> <bytespersamp> <endian (b, l, or n)>.");
-
- done:
- if (fd >= 0)
- close (fd);
-
-#ifdef _POSIX_MEMLOCK
- mlockall(MCL_FUTURE);
-#endif
-
- outargs = (t_int*)getbytes(2*sizeof(t_int));
- outargs[0] = (t_int)x->x_obj.ob_outlet;
- outargs[1] = (t_int)itemsread;
- h_set_callback(&threadedsf_read_output, outargs, 2);
-}
-
-/* idle callback for threadsafe synchronisation */
-static t_int threadedsf_read_update_garray(t_int * w)
-{
- t_garray* garray = (t_garray*)w[0];
- t_array *data = garray_getarray(garray);
- t_int nvec = w[1];
- t_int finalsize = w[2];
- pthread_cond_t * conditional = (pthread_cond_t*) w[3];
-
-#ifdef SFDEBUG
- post("lock array %p", garray);
-#endif
-
- // no garray_locks in current pd
- //garray_lock(garray);
-
- data->a_vec = (char *) nvec;
- data->a_n = finalsize;
- if (garray->x_usedindsp) canvas_update_dsp();
-
-#ifdef SFDEBUG
- post("unlock array %p", garray);
-#endif
-
- // no garray_locks in current pd
- //garray_unlock(garray);
-
- /* signal helper thread */
- pthread_cond_broadcast(conditional);
-
- return 0;
-}
-
-static t_int threadedsf_read_update_graphics(t_int * w)
-{
- t_garray* garray = (t_garray*) w[0];
- t_glist *gl;
- int n = w[1];
- /* if this is the only array in the graph,
- reset the graph's coordinates */
-
-#ifdef SFDEBUG
- post("redraw array %p", garray);
-#endif
-
- gl = garray->x_glist;
- if (gl->gl_list == &garray->x_gobj && !garray->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(garray);
-
- return 0;
-}
-
-
-static t_int threadedsf_read_output(t_int * w)
-{
- t_outlet* outlet = (t_outlet*) w[0];
- float itemsread = (float) w[1];
-
-#ifdef SFDEBUG
- post("bang %p", outlet);
-#endif
-
- outlet_float (outlet, itemsread);
-
- return 0;
-}
-
-
-
-
- /* this is broken out from threadedsf_write below so garray_write can
- call it too... not done yet though. */
-
-long threadedsf_t_dowrite(void *obj, t_canvas *canvas,
- int argc, t_atom *argv)
-{
- int bytespersamp, bigendian,
- swap, filetype, normalize, i, j, nchannels;
- long onset, nframes, itemswritten = 0;
- t_garray *garrays[MAXSFCHANS];
- t_float *vecs[MAXSFCHANS];
- char sampbuf[SAMPBUFSIZE];
- int bufframes;
- int fd = -1;
- float normfactor, biggest = 0, samplerate;
- t_symbol *filesym;
-
- if (soundfiler_writeargparse(obj, &argc, &argv, &filesym, &filetype,
- &bytespersamp, &swap, &bigendian, &normalize, &onset, &nframes,
- &samplerate))
- goto usage;
- nchannels = argc;
- if (nchannels < 1 || nchannels > MAXSFCHANS)
- goto usage;
- if (samplerate < 0)
- samplerate = sys_getsr();
- for (i = 0; i < nchannels; i++)
- {
- int vecsize;
- if (argv[i].a_type != A_SYMBOL)
- goto usage;
- if (!(garrays[i] =
- (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
- {
- pd_error(obj, "%s: no such table", argv[i].a_w.w_symbol->s_name);
- goto fail;
- }
- else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
- error("%s: bad template for tabwrite",
- argv[i].a_w.w_symbol->s_name);
- if (nframes > vecsize - onset)
- nframes = vecsize - onset;
-
- for (j = 0; j < vecsize; j++)
- {
- if (vecs[i][j] > biggest)
- biggest = vecs[i][j];
- else if (-vecs[i][j] > biggest)
- biggest = -vecs[i][j];
- }
- }
- if (nframes <= 0)
- {
- pd_error(obj, "threadedsf_write: no samples at onset %ld", onset);
- goto fail;
- }
-
- if ((fd = create_soundfile(canvas, filesym->s_name, filetype,
- nframes, bytespersamp, bigendian, nchannels,
- swap, samplerate)) < 0)
- {
- post("%s: %s\n", filesym->s_name, strerror(errno));
- goto fail;
- }
- if (!normalize)
- {
- if ((bytespersamp != 4) && (biggest > 1))
- {
- post("%s: normalizing max amplitude %f to 1", filesym->s_name, biggest);
- normalize = 1;
- }
- else post("%s: biggest amplitude = %f", filesym->s_name, biggest);
- }
- if (normalize)
- normfactor = (biggest > 0 ? 32767./(32768. * biggest) : 1);
- else normfactor = 1;
-
- bufframes = SAMPBUFSIZE / (nchannels * bytespersamp);
-
- for (itemswritten = 0; itemswritten < nframes; )
- {
- int thiswrite = nframes - itemswritten, nbytes;
- thiswrite = (thiswrite > bufframes ? bufframes : thiswrite);
- soundfile_xferout(argc, vecs, (unsigned char *)sampbuf, thiswrite,
- onset, bytespersamp, bigendian, normfactor);
- nbytes = write(fd, sampbuf, nchannels * bytespersamp * thiswrite);
- if (nbytes < nchannels * bytespersamp * thiswrite)
- {
- post("%s: %s", filesym->s_name, strerror(errno));
- if (nbytes > 0)
- itemswritten += nbytes / (nchannels * bytespersamp);
- break;
- }
- itemswritten += thiswrite;
- onset += thiswrite;
- }
- if (fd >= 0)
- {
- soundfile_finishwrite(obj, filesym->s_name, fd,
- filetype, nframes, itemswritten, nchannels * bytespersamp, swap);
- close (fd);
- }
- return ((float)itemswritten);
-usage:
- pd_error(obj, "usage: write [flags] filename tablename...");
- post("flags: -skip <n> -nframes <n> -bytes <n> -wave -aiff -nextstep ...");
- post("-big -little -normalize");
- post("(defaults to a 16-bit wave file).");
-fail:
- if (fd >= 0)
- close (fd);
- return (0);
-}
-
-static void threadedsf_t_write(t_threadedsf *x, t_symbol *s,
- int argc, t_atom *argv)
-{
- long bozo = threadedsf_t_dowrite(x, x->x_canvas,
- argc, argv);
- sys_lock();
- outlet_float(x->x_obj.ob_outlet, (float)bozo);
- sys_lock();
-}
-
-static void threadedsf_t_resize(t_threadedsf *x, t_symbol *s,
- int argc, t_atom *argv);
-
-static void threadedsf_t_resize_addq(t_threadedsf *x, t_symbol *s,
- int argc, t_atom *argv)
-{
- threadedsf_queue_add(threadedsf_t_resize,(void *)x,argc, argv);
-}
-
-
- /* TB: threadedsf_t_resize ...
- usage: resize table size
- adapted from garray_resize
- */
-static void threadedsf_t_resize(t_threadedsf *y, t_symbol *s,
- 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 = garray_getarray(x); // TODO muss der im lock sein ?
-
- 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);
-
-#ifdef _POSIX_MEMLOCK
- 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");
-#ifdef _POSIX_MEMLOCK
- mlockall(MCL_FUTURE);
-#endif
- return;
- }
-
-
- /* TB: we'll have to be sure that no one is accessing the array */
- sys_lock();
-
- // no garray_locks in current pd
-//#ifdef GARRAY_THREAD_LOCK
- //garray_lock(x);
-//#endif
-
- data->a_vec = nvec;
- data->a_n = n;
-
- // no garray_locks in current pd
-//#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);
-#ifdef _POSIX_MEMLOCK
- 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");
-}
-
-
-//static void threadedsf_t_const(t_threadedsf *x, t_symbol *s,
-// int argc, t_atom *argv);
-//
-//static void threadedsf_t_const_addq(t_threadedsf *x, t_symbol *s,
-// int argc, t_atom *argv)
-//{
-// threadedsf_queue_add(threadedsf_t_const,(void *)x,argc, argv);
-//}
-
-
-/* TB: threadedsf_t_const ...
- usage: const table value
-*/
-//static void threadedsf_t_const(t_threadedsf *y, t_symbol *s,
-// int argc, t_atom *argv)
-//{
-// int size, elemsize; /* array contains was elements of size elemsize */
-// t_float * vec; /* old array */
-// t_glist *gl;
-// int val; /* value */
-// char *nvec; /* new array */
-// int i;
-//
-// t_garray * x = (t_garray *)pd_findbyclass(argv[0].a_w.w_symbol, garray_class);
-// t_array *data = garray_getarray(x); // TODO muss der im lock sein ?
-//
-// 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;
-// size = data->a_n;
-//
-// if ((argv+1)->a_type == A_FLOAT)
-// {
-// val = (int) (argv+1)->a_w.w_float;
-// }
-// else
-// {
-// goto usage;
-// }
-//
-//#ifdef SFDEBUG
-// post("array size: %d; new value: %d",size,val);
-//#endif
-//
-// elemsize = template_findbyname(data->a_templatesym)->t_n * sizeof(t_word);
-//
-//
-// /* allocating memory */
-//#ifdef _POSIX_MEMLOCK
-// munlockall();
-//#endif
-// nvec = getbytes(size * elemsize);
-//
-// if (!nvec)
-// {
-// pd_error(x, "array resize failed: out of memory");
-//#ifdef _POSIX_MEMLOCK
-// mlockall(MCL_FUTURE);
-//#endif
-// return;
-// }
-//
-// /* setting array */
-// for (i=0; i!=size; ++i)
-// {
-// nvec[i]=val;
-// }
-//
-// /* 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;
-//#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)(size > 1 ? size-1 : 1), gl->gl_y2);
-// /* close any dialogs that might have the wrong info now... */
-// gfxstub_deleteforkey(gl);
-// }
-// else garray_redraw(x);
-//
-// freebytes (vec, size * elemsize);
-//#ifdef _POSIX_MEMLOCK
-// mlockall(MCL_FUTURE);
-//#endif
-// sys_lock();
-// outlet_float(y->x_obj.ob_outlet, size);
-// sys_unlock();
-// return;
-//
-// usage:
-// pd_error(x, "usage: const tablename value");
-//}
-
-
-static t_threadedsf *threadedsf_new(void)
-{
- t_threadedsf *x = (t_threadedsf *)pd_new(threadedsf_class);
- x->x_canvas = canvas_getcurrent();
- outlet_new(&x->x_obj, &s_float);
- return (x);
-}
-
-
-void threadedsf_setup(void)
-{
- threadedsf_class = class_new(gensym("threadedsf"), (t_newmethod)threadedsf_new,
- 0, sizeof(t_threadedsf), 0, 0);
-
- class_addmethod(threadedsf_class, (t_method)threadedsf_t_read_addq,
- gensym("read"), A_GIMME, 0);
- class_addmethod(threadedsf_class, (t_method)threadedsf_t_write_addq,
- gensym("write"), A_GIMME, 0);
- class_addmethod(threadedsf_class, (t_method)threadedsf_t_resize_addq,
- gensym("resize"), A_GIMME, 0);
-// class_addmethod(threadedsf_class, (t_method)threadedsf_t_const_addq,
-// gensym("const"), A_GIMME, 0);
-}
diff --git a/threadlib/src/threadlib.c b/threadlib/src/threadlib.c
index da17100..6cdf1af 100755
--- a/threadlib/src/threadlib.c
+++ b/threadlib/src/threadlib.c
@@ -33,7 +33,7 @@ t_class *threadlib_class;
static void threadlib_help(void)
{
- post("\nthreadlib vers."VERSION", library for threaded patching\n"
+ post("\nthreadlib vers."VERSION", library for threaded patching and externals\n"
"2005, by Georg Holzmann <grh@mur.at>\n"
"heavily based on pd_devel code by Tim Blechmann\n"
@@ -41,7 +41,6 @@ static void threadlib_help(void)
"\tdetach run part of the patch in a helper thread\n"
"\tjoin synchronize messages to pd's main thread\n"
"\tsleep block system for specific time\n"
- "\tthreadedsf threaded soundfiler from pd_devel_0.38\n"
"WARNING: this is very experimental and can crash your patches !\n");
}
@@ -55,24 +54,18 @@ void *threadlib_new(void)
void sleep_setup();
void detach_setup();
void join_setup();
-void threadedsf_setup();
-void sys_start_sfthread();
-void threadlib_setup(void)
+void threadlib_setup(void)
{
// call all the setup functions:
sleep_setup();
detach_setup();
join_setup();
- threadedsf_setup();
// init callback system
h_init_callbacks();
-
- // start global soundfiler helper thread
- sys_start_sfthread();
- post("\nthreadlib vers."VERSION", library for threaded patching\n"
+ post("\nthreadlib vers."VERSION", library for threaded patching and externals\n"
"2005, by Georg Holzmann <grh@mur.at>\n"
"heavily based on pd_devel code by Tim Blechmann\n"
"WARNING: this is very experimental and may crash your patches !\n");
@@ -80,4 +73,6 @@ void threadlib_setup(void)
threadlib_class = class_new(gensym("threadlib"), threadlib_new, 0,
sizeof(t_threadlib), 0, 0);
class_addmethod(threadlib_class, (t_method)threadlib_help, gensym("help"), 0);
+
+ return 0;
}
diff --git a/threadlib/src/threadlib.h b/threadlib/src/threadlib.h
index 80a7449..b94fc93 100755
--- a/threadlib/src/threadlib.h
+++ b/threadlib/src/threadlib.h
@@ -28,6 +28,12 @@
#include "m_pd.h"
#include "pthread.h"
+#ifdef MSW
+#define THREADLIB_EXTERN __declspec(dllexport) extern
+#else
+#define THREADLIB_EXTERN extern
+#endif /* MSW */
+
// threadlib version string
#define VERSION "0.1"
@@ -38,6 +44,8 @@
// for debuging
//#define DEBUG
+// setup function
+THREADLIB_EXTERN void threadlib_setup(void);
/* --------- lockfree FIFO of pd devel ----------- */
// (implemted in fifo.c)
@@ -47,12 +55,12 @@ EXTERN_STRUCT _fifo;
#define t_fifo struct _fifo
/* function prototypes */
-t_fifo * fifo_init(void);
-void fifo_destroy(t_fifo*);
+THREADLIB_EXTERN t_fifo * fifo_init(void);
+THREADLIB_EXTERN void fifo_destroy(t_fifo*);
/* fifo_put() and fifo_get are the only threadsafe functions!!! */
-void fifo_put(t_fifo*, void*);
-void* fifo_get(t_fifo*);
+THREADLIB_EXTERN void fifo_put(t_fifo*, void*);
+THREADLIB_EXTERN void* fifo_get(t_fifo*);
/* --------- callback FIFO of pd devel ----------- */
@@ -65,17 +73,19 @@ void* fifo_get(t_fifo*);
* clock callbacks
*/
+/* register a new callback in FIFO */
+/* tb: to be called at idle time */
+/* Holzmann: idle callbacks of current PD are not reliable, so
+ it will be called by the clock-callbacks for now */
+THREADLIB_EXTERN void sys_callback(t_int (*callback) (t_int* argv),
+ t_int* argv, t_int argc);
+
+/* private: */
+
/* set up callback fifo and start clock callback */
void h_init_callbacks();
/* free fifo and clock callback */
void h_free_callbacks();
-/* tb: to be called at idle time */
-/* Holzmann: idle callbacks of current PD are not reliable, so
- it will be called by the clock-callbacks for now */
-/* register a new callback in FIFO */
-void h_set_callback(t_int (*callback) (t_int* argv), t_int* argv, t_int argc);
-
-
#endif // __PD_THREADLIB_H_