~ubuntu-branches/ubuntu/natty/pd-zexy/natty

« back to all changes in this revision

Viewing changes to src/sfplay.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard, IOhannes m zmölnig, Jonas Smedegaard
  • Date: 2010-08-20 12:17:41 UTC
  • mfrom: (2.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20100820121741-4kxozn8b9rhee9fr
Tags: 2.2.3-1
* New upstream version

[ IOhannes m zmölnig ]
* Adopt package, on behalf of Multimedia Team.
  Closes: #546964
* Simply debian/rules with CDBS, and don't unconditionally strip
  binaries.
  Closes: #437763
* Install into /usr/lib/pd/extra/zexy/. Document usage in REAME.Debian
  and warn about change in NEWS.
* git'ify package. Add Vcs-* stanzas to control file.
* Use dpkg source format 3.0 (quilt). Drop build-dependency on quilt.

[ Jonas Smedegaard ]
* Enable CDBS copyright-check routine.
* Add copyright and licensing header to debian/rules.
* Add myself as uploader.
* Rewrite debian/copyright using rev. 135 of draft DEP5 format.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************
 
2
 *
 
3
 * zexy - implementation file
 
4
 *
 
5
 * copyleft (c) IOhannes m zm�lnig
 
6
 *
 
7
 *   1999:forum::f�r::uml�ute:2004
 
8
 *
 
9
 *   institute of electronic music and acoustics (iem)
 
10
 *
 
11
 ******************************************************
 
12
 *
 
13
 * license: GNU General Public License v.2
 
14
 *
 
15
 ******************************************************/
 
16
 
 
17
/*
 
18
sfplay.c - Author: Winfried Ritsch - IEM Graz 10.Mai 99 - 
 
19
Modified:
 
20
 
 
21
  Description:
 
22
  
 
23
  Soundfile player for playing many soundfiles in single speed.
 
24
  (Made for "3 Farben Schwarz" - exhibition in Graz 99 )
 
25
  
 
26
  Filename must have the path or actual directory, since pathname
 
27
  search ist not supported to garantuee a fast open call.
 
28
      
 
29
  They idea is a state machine which handles open, skip, play, close, error
 
30
  so that a minimum intervall between OS-calls are made, to avoid peak load.
 
31
        
 
32
  It has shown, that the open call is slow if there are a lot of files
 
33
  to search for, then with the first skip the first part of a
 
34
  soundfile is also loaded by the OS.               
 
35
          
 
36
  I experimented with asynchronous buffering with paralell
 
37
  process,which has shown no much performance hit, since more
 
38
  processes has to be handled and the modern OS's do caching anyway
 
39
  also caching is done in modern hard disk, so an additional cache
 
40
  woud be an overhead, if not special behaviour is needed (big jumps
 
41
  etc).
 
42
            
 
43
  This sfplayers should be used with an appropriate audio buffer for
 
44
  good performance, so also buffering on the object is an overhead.
 
45
              
 
46
  The sfread for linux using mmap has also not much improvement over this, if plain playing in one 
 
47
  direction is done for random access the sfread should be used, even not knowing how to mmap in
 
48
  NT.
 
49
                
 
50
Todo:
 
51
  Add the SPEED feature, but therefore there should be an own external using e.g. a 4-point interpolation.
 
52
  so overhead is reduced in this one.
 
53
 
 
54
  Split open to an own object called sfopen to hold more soundfiles
 
55
  then players and to enable glueless switching between soundfiles.
 
56
  
 
57
please mail problems and ideas for improvements to
 
58
ritsch@iem.kug.ac.at */
 
59
 
 
60
/*#define DEBUG_ME // for debugging messages */
 
61
 
 
62
#include "zexy.h"
 
63
 
 
64
#define DACBLKSIZE 64 /* in m_imp.h, but error if it is included it here*/
 
65
 
 
66
#include <stdio.h>
 
67
#include <string.h>
 
68
#include <fcntl.h>
 
69
 
 
70
/* ------------------------ sfplay ----------------------------- */
 
71
#define MAX_CHANS 8 /* channels for soundfiles 1,2,4,8 */
 
72
 
 
73
#ifdef __WIN32__
 
74
# define BINREADMODE "rb"
 
75
#else
 
76
# include <unistd.h>
 
77
# include <sys/mman.h>
 
78
# define BINREADMODE "r"
 
79
#endif
 
80
 
 
81
static t_class *sfplay_class;
 
82
 
 
83
typedef struct _sfplay
 
84
{
 
85
   t_object x_obj;
 
86
 
 
87
   t_outlet *bangout;  /* end of file */
 
88
 
 
89
   void*   filep;      /* pointer to file data read in mem */
 
90
   t_symbol* filename; /* filename */
 
91
   /*
 
92
      because there is no command queue,
 
93
      flags are used instead 
 
94
   */
 
95
   t_int play;         /* play: 1, stop: 0 */
 
96
   t_int please_stop;  /* can be reset only by stop-state itself */ 
 
97
   t_int please_close; /* can be reset only by close-state */
 
98
   t_int x_channels;   /* channels to play */
 
99
   t_float x_offset;   /* offsetto start reading */
 
100
   t_float offset;     /* inlet value offset in secs */
 
101
   t_float x_skip;     /* skip bytes because header */
 
102
   t_int skip;         /* pending skip if 1 */
 
103
   t_float x_speed;    /* play speed, not supported in this version */
 
104
   t_int  size;        /* size of file (if memory mapped) */
 
105
   t_int  swap;        /* swap bytes from l->b or b->m */
 
106
   FILE *fp;           /* file oper non-NULL of open */
 
107
   t_int state;        /* which state is player in */
 
108
   t_int count;        /* count for ticks before next step */
 
109
 
 
110
} t_sfplay;
 
111
 
 
112
/* states of statemachine */
 
113
#define SFPLAY_WAIT    0     /* wait for open */
 
114
#define SFPLAY_OPEN    1     
 
115
#define SFPLAY_CLOSE   2
 
116
#define SFPLAY_SKIP    3
 
117
#define SFPLAY_PLAY    4
 
118
#define SFPLAY_STOP    5
 
119
#define SFPLAY_ERROR  -1
 
120
 
 
121
#define SFPLAY_WAITTICKS 10 /* 1 tick of 64 Samples is ca. 1.5ms on 441000 */
 
122
 
 
123
/* split the os-calls in as many steps as possible 
 
124
to split them on different ticks in steps of SFPLAY_WAITTICKS
 
125
to avoid peak performance */
 
126
 
 
127
/* like the one from garray */
 
128
static int sfplay_am_i_big_endian(void) 
 
129
{
 
130
   unsigned short s = 1;
 
131
   unsigned char c = *(char *) (&s);
 
132
   return(c==0);
 
133
}
 
134
 
 
135
 
 
136
static void sfplay_helper(t_sfplay *x)
 
137
{
 
138
  ZEXY_USEVAR(x);
 
139
        post("\nsfplay :: a soundfile-player (c) winfried ritsch 1999");
 
140
        post("\ncreation :: sfplay <channels> <bytes> : channels set the number of channels, bytes skip fileheader");
 
141
        post("\nopen [<path>]<filename> [<endianity>]\t::open b(ig) or l(ittle) endian file"
 
142
                "\nclose\t\t\t::close file (aka eject)"
 
143
                "\nstart\t\t\t::start playing"
 
144
                "\nstop\t\t\t::stop playing"
 
145
                "\nrewind\t\t\t::rewind tape"
 
146
                "\ngoto <n>\t\t::play from byte n");
 
147
        post("\n\nyou can also start playing with a �bang� or a �1�, and stop with a �0�"
 
148
                "\nthe last outlet will do a bang after the last sample has been played");
 
149
 
 
150
}
 
151
 
 
152
 
 
153
/* METHOD: "open" file */
 
154
 
 
155
/* this dont use memory map, because I dont know about this on NT ? 
 
156
Use of the buffered functions fopen, fseek fread fclose instead the 
 
157
non buffered ones open read close */
 
158
 
 
159
static void sfplay_open(t_sfplay *x,t_symbol *filename,t_symbol *endian)
 
160
{
 
161
 
 
162
   if(x->state != SFPLAY_WAIT)
 
163
   {  
 
164
      post("sfplay: first close %s before open %s",x->filename->s_name,filename->s_name);
 
165
      return;
 
166
   }
 
167
 
 
168
/* test if big endian else asume little endian 
 
169
   should be 'l' but could be anything*/
 
170
   
 
171
   if(sfplay_am_i_big_endian())
 
172
      x->swap = !(endian->s_name[0] == 'b');
 
173
   else 
 
174
      x->swap = (endian->s_name[0] == 'b');
 
175
   
 
176
   x->skip = 1; /* skip header after open */
 
177
 
 
178
   x->filename = filename;
 
179
   
 
180
#ifdef DEBUG_ME
 
181
   post("sfplay: filename = %s",x->filename->s_name);
 
182
#endif
 
183
   
 
184
   if (x->fp != NULL)fclose(x->fp); /* should not happen */
 
185
   
 
186
   if (!(x->fp = fopen(x->filename->s_name,BINREADMODE))) 
 
187
   {
 
188
      error("sfplay: can't open %s", x->filename->s_name);
 
189
   }
 
190
}
 
191
 
 
192
 
 
193
 
 
194
/* METHOD: close */
 
195
static void sfplay_close(t_sfplay *x)
 
196
{
 
197
   x->play = 0;
 
198
   x->please_close = 1;
 
199
 
 
200
   /* now in state machine 
 
201
   if(x->fp != NULL)
 
202
   {
 
203
      fclose(x->fp);
 
204
      x->fp = NULL;
 
205
   }
 
206
   */
 
207
 
 
208
#ifdef DEBUG_ME
 
209
   post("sfplay: close ");
 
210
#endif
 
211
   return;
 
212
}
 
213
 
 
214
/* for skipping header of soundfile  Dont use this for memory map */
 
215
 
 
216
static int sfplay_skip(t_sfplay *x)
 
217
{
 
218
   if(!x->skip) return 0;
 
219
   
 
220
   x->skip = 0;
 
221
   
 
222
   if(fseek(x->fp, (long) x->x_offset, SEEK_SET) < 0)
 
223
   {    
 
224
      error(" sfplay can't seek to byte %ld",(long) x->x_offset);
 
225
      x->x_offset = x->x_skip;
 
226
      x->skip = 1;
 
227
      return 0;
 
228
   }
 
229
   
 
230
#ifdef DEBUG_ME
 
231
   post("sfplay:skip to %f",x->x_offset);
 
232
#endif
 
233
   return 1;
 
234
}
 
235
 
 
236
/* Input, method for Start stop */
 
237
 
 
238
static void sfplay_start(t_sfplay *x)
 
239
{
 
240
   long of = x->offset * sys_getsr() * x->x_channels;
 
241
   
 
242
   if(of < 0) of = x->x_skip;
 
243
   else of += x->x_skip; /* offset in sec */
 
244
 
 
245
   of &= ~0x111l; /* no odds please (8 channels boundary) */
 
246
   
 
247
#ifdef DEBUG_ME
 
248
   post("sfplay: start");
 
249
#endif
 
250
   
 
251
   /* new offset postion ? (fom inlet offset) */
 
252
   if( ((t_float) of) != x->x_offset)
 
253
   {
 
254
      x->skip=1;
 
255
      x->x_offset = of;
 
256
   }
 
257
   x->play=1;
 
258
}
 
259
 
 
260
static void sfplay_stop(t_sfplay *x)
 
261
{
 
262
#ifdef DEBUG_ME    
 
263
   post("sfplay: stop");
 
264
#endif
 
265
 
 
266
   x->play=0;
 
267
   x->please_stop = 1;
 
268
}
 
269
 
 
270
static void sfplay_float(t_sfplay *x, t_floatarg f)
 
271
{
 
272
   int t = f;
 
273
   if (t) sfplay_start(x);
 
274
   else sfplay_stop(x);
 
275
}
 
276
 
 
277
/* start playing at position offset*/
 
278
static void sfplay_offset(t_sfplay *x, t_floatarg f)
 
279
{
 
280
   x->offset = f;
 
281
   x->skip = 1;
 
282
   /* correction in sfplay_play() */
 
283
   
 
284
#ifdef DEBUG_ME
 
285
   post("sfplay: offset %f",f);
 
286
#endif
 
287
        return;
 
288
}
 
289
 
 
290
static void sfplay_rewind(t_sfplay *x)
 
291
{
 
292
#ifdef DEBUG_ME
 
293
   post("sfplay: rewind to %f",x->x_skip);      
 
294
#endif
 
295
   
 
296
   if(!x->fp)return;
 
297
   
 
298
   x->play=0;
 
299
   fseek(x->fp,(long) x->x_skip,SEEK_SET);
 
300
}
 
301
 
 
302
/* restart with bang */
 
303
 
 
304
static void sfplay_bang(t_sfplay* x)
 
305
{
 
306
   x->skip = 1;
 
307
   sfplay_start(x);
 
308
}
 
309
 
 
310
static t_int *sfplay_perform(t_int *w)
 
311
{
 
312
   t_sfplay* x = (t_sfplay*)(w[1]);
 
313
   short* buf = x->filep;
 
314
   int c = x->x_channels;
 
315
 
 
316
   int i,j,n;
 
317
   t_float* out[MAX_CHANS];
 
318
 
 
319
   short s;
 
320
   int swap = x->swap;
 
321
   
 
322
   for (i=0;i<c;i++)  
 
323
      out[i] = (t_float *)(w[3+i]);
 
324
 
 
325
   n = (int)(w[3+c]);
 
326
   
 
327
   /* loop */
 
328
   
 
329
   
 
330
   switch(x->state){
 
331
      
 
332
      /* just wait */
 
333
   case SFPLAY_WAIT:
 
334
      
 
335
      if(x->fp != NULL){
 
336
#ifdef DEBUG_ME
 
337
         post("wait -> open");
 
338
#endif
 
339
         x->state = SFPLAY_OPEN;
 
340
         x->count = SFPLAY_WAITTICKS;
 
341
      };
 
342
      break;
 
343
      
 
344
      /* if in open state, already opened but wait for skip */
 
345
   case SFPLAY_OPEN: /* file hase opened wait some time */
 
346
      
 
347
      if(!(x->count--)){
 
348
#ifdef DEBUG_ME
 
349
         post("open -> skip");
 
350
#endif
 
351
         x->state = SFPLAY_SKIP;
 
352
         x->count = SFPLAY_WAITTICKS;
 
353
      };
 
354
      
 
355
      break;
 
356
      
 
357
      
 
358
      /* in skipmode wait until ready for stop */
 
359
   case SFPLAY_SKIP:
 
360
      
 
361
      
 
362
      if(x->count == SFPLAY_WAITTICKS)
 
363
      {
 
364
         if(!x->fp)
 
365
         {
 
366
            x->state = SFPLAY_CLOSE;
 
367
            x->count=1;
 
368
#ifdef DEBUG_ME
 
369
            post("skip -> close");
 
370
#endif
 
371
            break;
 
372
         }
 
373
         sfplay_skip(x);
 
374
      }
 
375
      if(!(x->count--))
 
376
      {
 
377
#ifdef DEBUG_ME
 
378
         post("skip -> stop");
 
379
#endif
 
380
         x->state = SFPLAY_STOP;
 
381
         x->count = SFPLAY_WAITTICKS;
 
382
      };
 
383
      break;
 
384
      
 
385
      
 
386
                    
 
387
   case SFPLAY_STOP:   /* in stop state mainly waits for play */
 
388
      
 
389
      x->please_stop = 0;
 
390
 
 
391
      if(x->please_close)
 
392
      {
 
393
         x->state = SFPLAY_CLOSE;
 
394
         x->count = SFPLAY_WAITTICKS;      
 
395
#ifdef DEBUG_ME
 
396
         post("stop -> close");
 
397
#endif
 
398
      }
 
399
      else if(x->skip)
 
400
      {
 
401
         x->state = SFPLAY_SKIP;
 
402
         x->count = SFPLAY_WAITTICKS;
 
403
 
 
404
#ifdef DEBUG_ME
 
405
         post("stop -> skip");
 
406
#endif
 
407
 
 
408
      }
 
409
      else if(x->play)
 
410
      {
 
411
 
 
412
#ifdef DEBUG_ME
 
413
         post("stop -> play");
 
414
#endif
 
415
         x->state = SFPLAY_PLAY;
 
416
      }
 
417
      break;
 
418
      
 
419
     
 
420
   case SFPLAY_PLAY:             /* yes play now */
 
421
      
 
422
      
 
423
      if(!x->play || x->please_stop)
 
424
      {  
 
425
 
 
426
         /* if closing dont need o go to stop */
 
427
         if(x->please_close)
 
428
         { 
 
429
            x->state = SFPLAY_CLOSE;
 
430
            x->count = SFPLAY_WAITTICKS;
 
431
#ifdef DEBUG_ME
 
432
            post("play -> close");
 
433
#endif
 
434
         } 
 
435
         else
 
436
         { 
 
437
            x->state = SFPLAY_STOP;   
 
438
#ifdef DEBUG_ME
 
439
            post("play -> stop");
 
440
#endif
 
441
         };
 
442
         break;
 
443
      }
 
444
      
 
445
      /* should never happen */
 
446
      if(!x->filep){
 
447
         x->state = SFPLAY_ERROR;
 
448
         error("sfplay: playing but no buffer ???? play");
 
449
         return (w+4+c);
 
450
      }
 
451
      
 
452
      /* first read soundfile 16 bit*/           
 
453
      if((j=fread(buf,sizeof(short),c*n,x->fp)) < n)
 
454
      {   
 
455
 
 
456
                  outlet_bang(x->bangout);
 
457
                  
 
458
                  if(feof(x->fp)){
 
459
 
 
460
                         while (n--) {
 
461
                                for (i=0;i<c;i++)  {
 
462
                                  if(--j > 0){
 
463
                                         s = *buf++;
 
464
                                         if(swap) s = ((s & 0xFF)<< 8) | ((s& 0xFF00) >> 8);
 
465
                                         *out[i]++ = s*(1./32768.);
 
466
                                  }
 
467
                                  else *out[i]++ = 0;
 
468
                                }
 
469
                         }
 
470
 
 
471
                         x->state = SFPLAY_STOP;
 
472
                         x->play = 0;
 
473
                         return(w+c+4);
 
474
                  }
 
475
         
 
476
                  /* or error if(ferror()) */
 
477
                  x->state = SFPLAY_ERROR;
 
478
                  x->count = SFPLAY_WAITTICKS;
 
479
 
 
480
#ifdef DEBUG_ME
 
481
                  post("play -> read error");
 
482
#endif
 
483
                  break;
 
484
      };
 
485
      
 
486
      /* copy 16 Bit to floats and swap if neccesairy */
 
487
      while (n--) {
 
488
         for (i=0;i<c;i++)  {
 
489
            s = *buf++;
 
490
            if(swap) s = ((s & 0xFF)<< 8) | ((s& 0xFF00) >> 8);
 
491
            *out[i]++ = s*(1./32768.);
 
492
         }
 
493
      }
 
494
      return (w+c+4); /* dont zero out outs */
 
495
      
 
496
      /* ok read error please close */
 
497
   case SFPLAY_ERROR:
 
498
      
 
499
      if(!(x->count--)){
 
500
         x->state = SFPLAY_CLOSE;
 
501
         sfplay_close(x);
 
502
#ifdef DEBUG_ME
 
503
         post("sfplay error reading sf: error -> close");
 
504
#endif
 
505
         x->count = SFPLAY_WAITTICKS;
 
506
      }
 
507
      break;
 
508
      
 
509
      /* in close state go to wait afterwards */
 
510
   case SFPLAY_CLOSE:
 
511
      
 
512
      x->please_close = 0;
 
513
 
 
514
      /* wait until ready for close operation */
 
515
      if(!(x->count--)){ 
 
516
 
 
517
         x->state = SFPLAY_WAIT;
 
518
         x->count = SFPLAY_WAITTICKS;
 
519
         
 
520
         /* avoid openfiles */
 
521
         if(x->fp){fclose(x->fp);x->fp = NULL;};
 
522
 
 
523
#ifdef DEBUG_ME
 
524
         post("sfplay: close -> wait");
 
525
#endif
 
526
      }
 
527
      break;
 
528
      
 
529
   }; /*case */
 
530
   
 
531
   /* zero out outs */
 
532
   while (n--) {
 
533
             for (i=0;i<c;i++)
 
534
           *out[i]++ = 0.;
 
535
          };
 
536
   
 
537
   return(w+c+4);
 
538
}
 
539
 
 
540
 
 
541
/* ---------------------- Setup junk -------------------------- */
 
542
 
 
543
static void sfplay_dsp(t_sfplay *x, t_signal **sp)
 
544
{
 
545
 
 
546
#ifdef DEBUG_ME
 
547
   post("sfplay: dsp");
 
548
#endif
 
549
 
 
550
   switch (x->x_channels) {
 
551
   case 1:
 
552
      dsp_add(sfplay_perform, 4, x,
 
553
         sp[0]->s_vec, 
 
554
         sp[1]->s_vec, /* out 1 */
 
555
         sp[0]->s_n);
 
556
      break;
 
557
   case 2:
 
558
      dsp_add(sfplay_perform, 5, x, 
 
559
         sp[0]->s_vec, /* out 1*/
 
560
         sp[1]->s_vec, /* out 2*/
 
561
         sp[2]->s_vec, 
 
562
         sp[0]->s_n);
 
563
      break;
 
564
   case 4:
 
565
      dsp_add(sfplay_perform, 7, x, 
 
566
         sp[0]->s_vec, 
 
567
         sp[1]->s_vec,
 
568
         sp[2]->s_vec,
 
569
         sp[3]->s_vec,
 
570
         sp[4]->s_vec,
 
571
         sp[0]->s_n);
 
572
      break;
 
573
   case 8:
 
574
        dsp_add(sfplay_perform, 11, x, 
 
575
           sp[0]->s_vec, 
 
576
           sp[1]->s_vec,
 
577
           sp[2]->s_vec,
 
578
           sp[3]->s_vec,
 
579
           sp[4]->s_vec,
 
580
           sp[5]->s_vec,
 
581
           sp[6]->s_vec,
 
582
           sp[7]->s_vec,
 
583
           sp[8]->s_vec,
 
584
           sp[0]->s_n);
 
585
        break;
 
586
   }
 
587
}
 
588
 
 
589
 
 
590
/* create sfplay with args <channels> <skip> */
 
591
static void *sfplay_new(t_floatarg chan,t_floatarg skip)
 
592
{
 
593
   t_sfplay *x = (t_sfplay *)pd_new(sfplay_class);
 
594
   t_int c = chan;
 
595
   
 
596
   switch(c){
 
597
      /* ok */
 
598
   case 1: case 2: case 4: case 8: break;
 
599
      /* try it, good luck ... */
 
600
   case 3: c = 2; break;     
 
601
   case 5: case 6: case 7: c=7; break;
 
602
   default: c=1; break;
 
603
   }
 
604
 
 
605
   floatinlet_new(&x->x_obj, &x->offset); /* inlet 2 */
 
606
   /*    floatinlet_new(&x->x_obj, &x->speed);  *//* inlet 3 */
 
607
   
 
608
   x->x_channels = c;
 
609
   x->x_skip = x->x_offset = skip;
 
610
   x->offset = 0.;
 
611
   x->skip = 1;
 
612
   x->x_speed = 1.0;
 
613
   x->play = 0;
 
614
   x->please_stop = 0;
 
615
   x->please_close = 0;
 
616
   x->state = SFPLAY_WAIT;
 
617
   x->count = 0;
 
618
   x->filename = NULL;
 
619
   x->fp = NULL;
 
620
   x->swap = 1;
 
621
   
 
622
   while (c--) {
 
623
      outlet_new(&x->x_obj, gensym("signal")); /* channels outlet */
 
624
   }
 
625
   x->bangout = outlet_new(&x->x_obj,  &s_bang);
 
626
    
 
627
   x->filep = t_getbytes(DACBLKSIZE*sizeof(short)*x->x_channels);
 
628
   
 
629
#ifdef DEBUG_ME
 
630
   post("get_bytes DACBLKSIZE*%d*%d->%ld",sizeof(short),x->x_channels,x->filep);
 
631
   post("sfplay: x_channels = %d, x_speed = %f, x_skip = %f",x->x_channels,x->x_speed,x->x_skip);
 
632
#endif
 
633
   
 
634
   return (x);
 
635
}
 
636
 
 
637
 
 
638
static void sfplay_free(t_sfplay *x)
 
639
{
 
640
   freebytes(x->filep, DACBLKSIZE*sizeof(short)*x->x_channels);
 
641
}
 
642
 
 
643
void sfplay_setup(void)
 
644
{
 
645
   sfplay_class = class_new(gensym("sfplay"), (t_newmethod)sfplay_new, (t_method)sfplay_free,
 
646
      sizeof(t_sfplay), 0, A_DEFFLOAT, A_DEFFLOAT,0);
 
647
   class_addmethod(sfplay_class, nullfn, gensym("signal"), 0);
 
648
   class_addmethod(sfplay_class, (t_method)sfplay_dsp, gensym("dsp"), 0);
 
649
 
 
650
   class_addmethod(sfplay_class, (t_method)sfplay_helper, gensym("help"), A_NULL);
 
651
   class_sethelpsymbol(sfplay_class, gensym("sf-play_record"));
 
652
 
 
653
   /* method open with filename */
 
654
   class_addmethod(sfplay_class, (t_method)sfplay_open, gensym("open"), A_SYMBOL,A_SYMBOL,A_NULL);
 
655
   class_addmethod(sfplay_class, (t_method)sfplay_close, gensym("close"), A_NULL);
 
656
   
 
657
   class_addmethod(sfplay_class, (t_method)sfplay_start, gensym("start"), A_NULL);
 
658
   class_addmethod(sfplay_class, (t_method)sfplay_stop,  gensym("stop"), A_NULL);
 
659
   class_addmethod(sfplay_class, (t_method)sfplay_rewind, gensym("rewind"), A_NULL);
 
660
   class_addmethod(sfplay_class, (t_method)sfplay_offset, gensym("goto"), A_DEFFLOAT, A_NULL);
 
661
 
 
662
   /* start stop with 0 and 1 */
 
663
   class_addfloat(sfplay_class, sfplay_float);
 
664
   /* start with bang */
 
665
   class_addbang(sfplay_class,sfplay_bang);
 
666
  zexy_register("sfplay");
 
667
}