aboutsummaryrefslogtreecommitdiff
path: root/src/z_sfplay.c
diff options
context:
space:
mode:
authorIOhannes m zmölnig <zmoelnig@users.sourceforge.net>2005-03-22 20:58:25 +0000
committerIOhannes m zmölnig <zmoelnig@users.sourceforge.net>2005-03-22 20:58:25 +0000
commit2b60d55c919e7588f5aff15936e83c300b3660bb (patch)
tree14d860de7f28083d3756ad91b627de70f26788f6 /src/z_sfplay.c
parentc500bc542cb7cc78d6dac3f7da3bff626056b1aa (diff)
zexy-2.0:
- use of abstractions for objects that allow it - some objects are build both as externals and abstractions (as slower fallbacks) - code-layout is now 1:1 c-file<->object (this should allow for building of zexy as a collection of externals instead as a big library) - matrix-objects have moved to iemmatrix !! svn path=/trunk/externals/zexy/; revision=2641
Diffstat (limited to 'src/z_sfplay.c')
-rw-r--r--src/z_sfplay.c658
1 files changed, 0 insertions, 658 deletions
diff --git a/src/z_sfplay.c b/src/z_sfplay.c
deleted file mode 100644
index 39ed4b9..0000000
--- a/src/z_sfplay.c
+++ /dev/null
@@ -1,658 +0,0 @@
-/*
-sfplay.c - Author: Winfried Ritsch - IEM Graz 10.Mai 99 -
-Modified:
-
- Description:
-
- Soundfile player for playing many soundfiles in single speed.
- (Made for "3 Farben Schwarz" - exhibition in Graz 99 )
-
- Filename must have the path or actual directory, since pathname
- search ist not supported to garantuee a fast open call.
-
- They idea is a state machine which handles open, skip, play, close, error
- so that a minimum intervall between OS-calls are made, to avoid peak load.
-
- It has shown, that the open call is slow if there are a lot of files
- to search for, then with the first skip the first part of a
- soundfile is also loaded by the OS.
-
- I experimented with asynchronous buffering with paralell
- process,which has shown no much performance hit, since more
- processes has to be handled and the modern OS's do caching anyway
- also caching is done in modern hard disk, so an additional cache
- woud be an overhead, if not special behaviour is needed (big jumps
- etc).
-
- This sfplayers should be used with an appropriate audio buffer for
- good performance, so also buffering on the object is an overhead.
-
- The sfread for linux using mmap has also not much improvement over this, if plain playing in one
- direction is done for random access the sfread should be used, even not knowing how to mmap in
- NT.
-
-Todo:
- Add the SPEED feature, but therefore there should be an own external using e.g. a 4-point interpolation.
- so overhead is reduced in this one.
-
- Split open to an own object called sfopen to hold more soundfiles
- then players and to enable glueless switching between soundfiles.
-
-please mail problems and ideas for improvements to
-ritsch@iem.kug.ac.at */
-
-/*#define DEBUG_ME // for debugging messages */
-
-#include "zexy.h"
-
-/*#include "m_imp.h"*/
-
-#define DACBLKSIZE 64 /* in m_imp.h, but error if it is included it here*/
-
-#ifdef NT
-#pragma warning( disable : 4244 )
-#pragma warning( disable : 4305 )
-#pragma warning( disable : 4018 )
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-
-/* ------------------------ sfplay ----------------------------- */
-#define MAX_CHANS 8 /* channels for soundfiles 1,2,4,8 */
-
-#ifdef NT
-#define BINREADMODE "rb"
-#endif
-#ifdef unix
-#include <unistd.h>
-#include <sys/mman.h>
-#define BINREADMODE "r"
-#endif
-
-static t_class *sfplay_class;
-
-typedef struct _sfplay
-{
- t_object x_obj;
-
- t_outlet *bangout; /* end of file */
-
- void* filep; /* pointer to file data read in mem */
- t_symbol* filename; /* filename */
- /*
- because there is no command queue,
- flags are used instead
- */
- t_int play; /* play: 1, stop: 0 */
- t_int please_stop; /* can be reset only by stop-state itself */
- t_int please_close; /* can be reset only by close-state */
- t_int x_channels; /* channels to play */
- t_float x_offset; /* offsetto start reading */
- t_float offset; /* inlet value offset in secs */
- t_float x_skip; /* skip bytes because header */
- t_int skip; /* pending skip if 1 */
- t_float x_speed; /* play speed, not supported in this version */
- t_int size; /* size of file (if memory mapped) */
- t_int swap; /* swap bytes from l->b or b->m */
- FILE *fp; /* file oper non-NULL of open */
- t_int state; /* which state is player in */
- t_int count; /* count for ticks before next step */
-
-} t_sfplay;
-
-/* states of statemachine */
-#define SFPLAY_WAIT 0 /* wait for open */
-#define SFPLAY_OPEN 1
-#define SFPLAY_CLOSE 2
-#define SFPLAY_SKIP 3
-#define SFPLAY_PLAY 4
-#define SFPLAY_STOP 5
-#define SFPLAY_ERROR -1
-
-#define SFPLAY_WAITTICKS 10 /* 1 tick of 64 Samples is ca. 1.5ms on 441000 */
-
-/* split the os-calls in as many steps as possible
-to split them on different ticks in steps of SFPLAY_WAITTICKS
-to avoid peak performance */
-
-/* like the one from garray */
-static int sfplay_am_i_big_endian()
-{
- unsigned short s = 1;
- unsigned char c = *(char *) (&s);
- return(c==0);
-}
-
-
-void helper(t_sfplay *x)
-{
- post("\nsfplay :: a soundfile-player (c) winfried ritsch 1999");
- post("\ncreation :: sfplay <channels> <bytes> : channels set the number of channels, bytes skip fileheader");
- post("\nopen [<path>]<filename> [<endianity>]\t::open b(ig) or l(ittle) endian file"
- "\nclose\t\t\t::close file (aka eject)"
- "\nstart\t\t\t::start playing"
- "\nstop\t\t\t::stop playing"
- "\nrewind\t\t\t::rewind tape"
- "\ngoto <n>\t\t::play from byte n");
- post("\n\nyou can also start playing with a ´bang´ or a ´1´, and stop with a ´0´"
- "\nthe last outlet will do a bang after the last sample has been played");
-
-}
-
-
-/* METHOD: "open" file */
-
-/* this dont use memory map, because I dont know about this on NT ?
-Use of the buffered functions fopen, fseek fread fclose instead the
-non buffered ones open read close */
-
-void sfplay_open(t_sfplay *x,t_symbol *filename,t_symbol *endian)
-{
-
- if(x->state != SFPLAY_WAIT)
- {
- post("sfplay: first close %s before open %s",x->filename->s_name,filename->s_name);
- return;
- }
-
-/* test if big endian else asume little endian
- should be 'l' but could be anything*/
-
- if(sfplay_am_i_big_endian())
- x->swap = !(endian->s_name[0] == 'b');
- else
- x->swap = (endian->s_name[0] == 'b');
-
- x->skip = 1; /* skip header after open */
-
- x->filename = filename;
-
-#ifdef DEBUG_ME
- post("sfplay: filename = %s",x->filename->s_name);
-#endif
-
- if (x->fp != NULL)fclose(x->fp); /* should not happen */
-
- if (!(x->fp = fopen(x->filename->s_name,BINREADMODE)))
- {
- error("sfplay: can't open %s", x->filename->s_name);
- }
-}
-
-
-
-/* METHOD: close */
-static void sfplay_close(t_sfplay *x)
-{
- x->play = 0;
- x->please_close = 1;
-
- /* now in state machine
- if(x->fp != NULL)
- {
- fclose(x->fp);
- x->fp = NULL;
- }
- */
-
-#ifdef DEBUG_ME
- post("sfplay: close ");
-#endif
- return;
-}
-
-/* for skipping header of soundfile Dont use this for memory map */
-
-static int sfplay_skip(t_sfplay *x)
-{
- if(!x->skip) return 0;
-
- x->skip = 0;
-
- if(fseek(x->fp, (long) x->x_offset, SEEK_SET) < 0)
- {
- error(" sfplay can't seek to byte %ld",(long) x->x_offset);
- x->x_offset = x->x_skip;
- x->skip = 1;
- return 0;
- }
-
-#ifdef DEBUG_ME
- post("sfplay:skip to %f",x->x_offset);
-#endif
- return 1;
-}
-
-/* Input, method for Start stop */
-
-static void sfplay_start(t_sfplay *x)
-{
- long of = x->offset * sys_getsr() * x->x_channels;
-
- if(of < 0) of = x->x_skip;
- else of += x->x_skip; /* offset in sec */
-
- of &= ~0x111l; /* no odds please (8 channels boundary) */
-
-#ifdef DEBUG_ME
- post("sfplay: start");
-#endif
-
- /* new offset postion ? (fom inlet offset) */
- if( ((float) of) != x->x_offset)
- {
- x->skip=1;
- x->x_offset = of;
- }
- x->play=1;
-}
-
-static void sfplay_stop(t_sfplay *x)
-{
-#ifdef DEBUG_ME
- post("sfplay: stop");
-#endif
-
- x->play=0;
- x->please_stop = 1;
-}
-
-static void sfplay_float(t_sfplay *x, t_floatarg f)
-{
- int t = f;
- if (t) sfplay_start(x);
- else sfplay_stop(x);
-}
-
-/* start playing at position offset*/
-static void sfplay_offset(t_sfplay *x, t_floatarg f)
-{
- x->offset = f;
- x->skip = 1;
- /* correction in sfplay_play() */
-
-#ifdef DEBUG_ME
- post("sfplay: offset %f",f);
-#endif
- return;
-}
-
-static void sfplay_rewind(t_sfplay *x)
-{
-#ifdef DEBUG_ME
- post("sfplay: rewind to %f",x->x_skip);
-#endif
-
- if(!x->fp)return;
-
- x->play=0;
- fseek(x->fp,(long) x->x_skip,SEEK_SET);
-}
-
-/* restart with bang */
-
-void sfplay_bang(t_sfplay* x)
-{
- x->skip = 1;
- sfplay_start(x);
-}
-
-static t_int *sfplay_perform(t_int *w)
-{
- t_sfplay* x = (t_sfplay*)(w[1]);
- short* buf = x->filep;
- int c = x->x_channels;
-
- int i,j,n;
- t_float* out[MAX_CHANS];
-
- short s;
- int swap = x->swap;
-
- for (i=0;i<c;i++)
- out[i] = (t_float *)(w[3+i]);
-
- n = (int)(w[3+c]);
-
- /* loop */
-
-
- switch(x->state){
-
- /* just wait */
- case SFPLAY_WAIT:
-
- if(x->fp != NULL){
-#ifdef DEBUG_ME
- post("wait -> open");
-#endif
- x->state = SFPLAY_OPEN;
- x->count = SFPLAY_WAITTICKS;
- };
- break;
-
- /* if in open state, already opened but wait for skip */
- case SFPLAY_OPEN: /* file hase opened wait some time */
-
- if(!(x->count--)){
-#ifdef DEBUG_ME
- post("open -> skip");
-#endif
- x->state = SFPLAY_SKIP;
- x->count = SFPLAY_WAITTICKS;
- };
-
- break;
-
-
- /* in skipmode wait until ready for stop */
- case SFPLAY_SKIP:
-
-
- if(x->count == SFPLAY_WAITTICKS)
- {
- if(!x->fp)
- {
- x->state = SFPLAY_CLOSE;
- x->count=1;
-#ifdef DEBUG_ME
- post("skip -> close");
-#endif
- break;
- }
- sfplay_skip(x);
- }
- if(!(x->count--))
- {
-#ifdef DEBUG_ME
- post("skip -> stop");
-#endif
- x->state = SFPLAY_STOP;
- x->count = SFPLAY_WAITTICKS;
- };
- break;
-
-
-
- case SFPLAY_STOP: /* in stop state mainly waits for play */
-
- x->please_stop = 0;
-
- if(x->please_close)
- {
- x->state = SFPLAY_CLOSE;
- x->count = SFPLAY_WAITTICKS;
-#ifdef DEBUG_ME
- post("stop -> close");
-#endif
- }
- else if(x->skip)
- {
- x->state = SFPLAY_SKIP;
- x->count = SFPLAY_WAITTICKS;
-
-#ifdef DEBUG_ME
- post("stop -> skip");
-#endif
-
- }
- else if(x->play)
- {
-
-#ifdef DEBUG_ME
- post("stop -> play");
-#endif
- x->state = SFPLAY_PLAY;
- }
- break;
-
-
- case SFPLAY_PLAY: /* yes play now */
-
-
- if(!x->play || x->please_stop)
- {
-
- /* if closing dont need o go to stop */
- if(x->please_close)
- {
- x->state = SFPLAY_CLOSE;
- x->count = SFPLAY_WAITTICKS;
-#ifdef DEBUG_ME
- post("play -> close");
-#endif
- }
- else
- {
- x->state = SFPLAY_STOP;
-#ifdef DEBUG_ME
- post("play -> stop");
-#endif
- };
- break;
- }
-
- /* should never happen */
- if(!x->filep){
- x->state = SFPLAY_ERROR;
- error("sfplay: playing but no buffer ???? play");
- return (w+4+c);
- }
-
- /* first read soundfile 16 bit*/
- if((j=fread(buf,sizeof(short),c*n,x->fp)) < (unsigned int) n)
- {
-
- outlet_bang(x->bangout);
-
- if(feof(x->fp)){
-
- while (n--) {
- for (i=0;i<c;i++) {
- if(--j > 0){
- s = *buf++;
- if(swap) s = ((s & 0xFF)<< 8) | ((s& 0xFF00) >> 8);
- *out[i]++ = s*(1./32768.);
- }
- else *out[i]++ = 0;
- }
- }
-
- x->state = SFPLAY_STOP;
- x->play = 0;
- return(w+c+4);
- }
-
- /* or error if(ferror()) */
- x->state = SFPLAY_ERROR;
- x->count = SFPLAY_WAITTICKS;
-
-#ifdef DEBUG_ME
- post("play -> read error");
-#endif
- break;
- };
-
- /* copy 16 Bit to floats and swap if neccesairy */
- while (n--) {
- for (i=0;i<c;i++) {
- s = *buf++;
- if(swap) s = ((s & 0xFF)<< 8) | ((s& 0xFF00) >> 8);
- *out[i]++ = s*(1./32768.);
- }
- }
- return (w+c+4); /* dont zero out outs */
-
- /* ok read error please close */
- case SFPLAY_ERROR:
-
- if(!(x->count--)){
- x->state = SFPLAY_CLOSE;
- sfplay_close(x);
-#ifdef DEBUG_ME
- post("sfplay error reading sf: error -> close");
-#endif
- x->count = SFPLAY_WAITTICKS;
- }
- break;
-
- /* in close state go to wait afterwards */
- case SFPLAY_CLOSE:
-
- x->please_close = 0;
-
- /* wait until ready for close operation */
- if(!(x->count--)){
-
- x->state = SFPLAY_WAIT;
- x->count = SFPLAY_WAITTICKS;
-
- /* avoid openfiles */
- if(x->fp){fclose(x->fp);x->fp = NULL;};
-
-#ifdef DEBUG_ME
- post("sfplay: close -> wait");
-#endif
- }
- break;
-
- }; /*case */
-
- /* zero out outs */
- while (n--) {
- for (i=0;i<c;i++)
- *out[i]++ = 0.;
- };
-
- return(w+c+4);
-}
-
-
-/* ---------------------- Setup junk -------------------------- */
-
-static void sfplay_dsp(t_sfplay *x, t_signal **sp)
-{
-
-#ifdef DEBUG_ME
- post("sfplay: dsp");
-#endif
-
- switch (x->x_channels) {
- case 1:
- dsp_add(sfplay_perform, 4, x,
- sp[0]->s_vec,
- sp[1]->s_vec, /* out 1 */
- sp[0]->s_n);
- break;
- case 2:
- dsp_add(sfplay_perform, 5, x,
- sp[0]->s_vec, /* out 1*/
- sp[1]->s_vec, /* out 2*/
- sp[2]->s_vec,
- sp[0]->s_n);
- break;
- case 4:
- dsp_add(sfplay_perform, 7, x,
- sp[0]->s_vec,
- sp[1]->s_vec,
- sp[2]->s_vec,
- sp[3]->s_vec,
- sp[4]->s_vec,
- sp[0]->s_n);
- break;
- case 8:
- dsp_add(sfplay_perform, 11, x,
- sp[0]->s_vec,
- sp[1]->s_vec,
- sp[2]->s_vec,
- sp[3]->s_vec,
- sp[4]->s_vec,
- sp[5]->s_vec,
- sp[6]->s_vec,
- sp[7]->s_vec,
- sp[8]->s_vec,
- sp[0]->s_n);
- break;
- }
-}
-
-
-/* create sfplay with args <channels> <skip> */
-static void *sfplay_new(t_floatarg chan,t_floatarg skip)
-{
- t_sfplay *x = (t_sfplay *)pd_new(sfplay_class);
- t_int c = chan;
-
- switch(c){
- /* ok */
- case 1: case 2: case 4: case 8: break;
- /* try it, good luck ... */
- case 3: c = 2; break;
- case 5: case 6: case 7: c=7; break;
- default: c=1; break;
- }
-
- floatinlet_new(&x->x_obj, &x->offset); /* inlet 2 */
- /* floatinlet_new(&x->x_obj, &x->speed); *//* inlet 3 */
-
- x->x_channels = c;
- x->x_skip = x->x_offset = skip;
- x->offset = 0.;
- x->skip = 1;
- x->x_speed = 1.0;
- x->play = 0;
- x->please_stop = 0;
- x->please_close = 0;
- x->state = SFPLAY_WAIT;
- x->count = 0;
- x->filename = NULL;
- x->fp = NULL;
- x->swap = 1;
-
- while (c--) {
- outlet_new(&x->x_obj, gensym("signal")); /* channels outlet */
- }
- x->bangout = outlet_new(&x->x_obj, &s_bang);
-
- x->filep = t_getbytes(DACBLKSIZE*sizeof(short)*x->x_channels);
-
-#ifdef DEBUG_ME
- post("get_bytes DACBLKSIZE*%d*%d->%ld",sizeof(short),x->x_channels,x->filep);
- post("sfplay: x_channels = %d, x_speed = %f, x_skip = %f",x->x_channels,x->x_speed,x->x_skip);
-#endif
-
- return (x);
-}
-
-
-static void sfplay_free(t_sfplay *x)
-{
- freebytes(x->filep, DACBLKSIZE*sizeof(short)*x->x_channels);
-}
-
-void z_sfplay_setup(void)
-{
- sfplay_class = class_new(gensym("sfplay"), (t_newmethod)sfplay_new, (t_method)sfplay_free,
- sizeof(t_sfplay), 0, A_DEFFLOAT, A_DEFFLOAT,0);
- class_addmethod(sfplay_class, nullfn, gensym("signal"), 0);
- class_addmethod(sfplay_class, (t_method)sfplay_dsp, gensym("dsp"), 0);
-
- class_addmethod(sfplay_class, (t_method)helper, gensym("help"), A_NULL);
- class_sethelpsymbol(sfplay_class, gensym("zexy/sf-play_record"));
-
- /* method open with filename */
- class_addmethod(sfplay_class, (t_method)sfplay_open, gensym("open"), A_SYMBOL,A_SYMBOL,A_NULL);
- class_addmethod(sfplay_class, (t_method)sfplay_close, gensym("close"), A_NULL);
-
- class_addmethod(sfplay_class, (t_method)sfplay_start, gensym("start"), A_NULL);
- class_addmethod(sfplay_class, (t_method)sfplay_stop, gensym("stop"), A_NULL);
- class_addmethod(sfplay_class, (t_method)sfplay_rewind, gensym("rewind"), A_NULL);
- class_addmethod(sfplay_class, (t_method)sfplay_offset, gensym("goto"), A_DEFFLOAT, A_NULL);
-
- /* start stop with 0 and 1 */
- class_addfloat(sfplay_class, sfplay_float);
- /* start with bang */
- class_addbang(sfplay_class,sfplay_bang);
-}