diff options
author | IOhannes m zmölnig <zmoelnig@users.sourceforge.net> | 2005-03-22 20:58:25 +0000 |
---|---|---|
committer | IOhannes m zmölnig <zmoelnig@users.sourceforge.net> | 2005-03-22 20:58:25 +0000 |
commit | 2b60d55c919e7588f5aff15936e83c300b3660bb (patch) | |
tree | 14d860de7f28083d3756ad91b627de70f26788f6 /src/z_sfplay.c | |
parent | c500bc542cb7cc78d6dac3f7da3bff626056b1aa (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.c | 658 |
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); -} |