File: sound.h

package info (click to toggle)
audacity 2.1.2-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 86,844 kB
  • sloc: ansic: 225,005; cpp: 221,240; sh: 27,327; python: 16,896; makefile: 8,186; lisp: 8,002; perl: 317; xml: 307; sed: 16
file content (653 lines) | stat: -rw-r--r-- 22,417 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
/* sound.h -- new nyquist sound data type */

/* CHANGE LOG
 * --------------------------------------------------------------------
 * 28Apr03  dm  changes for portability: moved some defns out of here
 */

#include <math.h>
#include "stdefs.h"

/* used for *AUDIO-MARKERS* */
extern long sound_frames;
extern double sound_srate;

#if OSC
extern int nosc_enabled; /* enable polling for OSC messages */
#endif

#if USE_PRINTF
#define nyquist_printf printf
#endif

#define PERMS            0644           /* -rw-r--r-- */

/* default stop sample count (for clipping) */
#define MAX_STOP 0x7FFFFFFF

/* default stop time (for clipping) */
#define MAX_STOP_TIME 10E20
/* LISP-SRC: (SETF MAX-STOP-TIME 10E20) */
#define MIN_START_TIME -10E20
/* LISP-SRC: (SETF MIN-START-TIME -10E20) */

/* conversion from float to integer */
#define SCALE_FACTOR_TO_BYTE 127
#define SCALE_FACTOR_TO_SHORT 32767
#define SCALE_FACTOR_TO_24BIT 0x7FFFFF
#define SCALE_FACTOR_TO_LONG 2147483647

/* Note that the values assigned here are not arbitrary, but represent
   a dominance relationship among the interpolation types.
*/
#define INTERP_n 0
#define INTERP_s 1
#define INTERP_i 2
#define INTERP_r 3

#define INTERP_nn 0
#define INTERP_ns 1
#define INTERP_ni 2
#define INTERP_nr 3
#define INTERP_sn 4
#define INTERP_ss 5
#define INTERP_si 6
#define INTERP_sr 7
#define INTERP_in 8
#define INTERP_is 9
#define INTERP_ii 10
#define INTERP_ir 11
#define INTERP_rn 12
#define INTERP_rs 13
#define INTERP_ri 14
#define INTERP_rr 15

#define INTERP_nnn 0
#define INTERP_nns 1
#define INTERP_nni 2
#define INTERP_nnr 3
#define INTERP_nsn 4
#define INTERP_nss 5
#define INTERP_nsi 6
#define INTERP_nsr 7
#define INTERP_nin 8
#define INTERP_nis 9
#define INTERP_nii 10
#define INTERP_nir 11
#define INTERP_nrn 12
#define INTERP_nrs 13
#define INTERP_nri 14
#define INTERP_nrr 15
#define INTERP_snn 16
#define INTERP_sns 17
#define INTERP_sni 18
#define INTERP_snr 19
#define INTERP_ssn 20
#define INTERP_sss 21
#define INTERP_ssi 22
#define INTERP_ssr 23
#define INTERP_sin 24
#define INTERP_sis 25
#define INTERP_sii 26
#define INTERP_sir 27
#define INTERP_srn 28
#define INTERP_srs 29
#define INTERP_sri 30
#define INTERP_srr 31

#define INTERP_inn 32
#define INTERP_ins 33
#define INTERP_ini 34
#define INTERP_inr 35
#define INTERP_isn 36
#define INTERP_iss 37
#define INTERP_isi 38
#define INTERP_isr 39
#define INTERP_iin 40
#define INTERP_iis 41
#define INTERP_iii 42
#define INTERP_iir 43
#define INTERP_irn 44
#define INTERP_irs 45
#define INTERP_iri 46
#define INTERP_irr 47
#define INTERP_rnn 48
#define INTERP_rns 49
#define INTERP_rni 50
#define INTERP_rnr 51
#define INTERP_rsn 52
#define INTERP_rss 53
#define INTERP_rsi 54
#define INTERP_rsr 55
#define INTERP_rin 56
#define INTERP_ris 57
#define INTERP_rii 58
#define INTERP_rir 59
#define INTERP_rrn 60
#define INTERP_rrs 61
#define INTERP_rri 62
#define INTERP_rrr 63

#define INTERP_nnnn 0
#define INTERP_nnns 1
#define INTERP_nnsn 4
#define INTERP_nnss 5
#define INTERP_nsnn 16
#define INTERP_nsns 17
#define INTERP_nssn 20
#define INTERP_nsss 21
#define INTERP_nrrr 63
#define INTERP_snnn 64
#define INTERP_snns 65
#define INTERP_snsn 68
#define INTERP_snss 69
#define INTERP_ssnn 80
#define INTERP_ssns 81
#define INTERP_sssn 84
#define INTERP_ssss 85
#define INTERP_niii 42
#define INTERP_siii 106
#define INTERP_srrr 127
#define INTERP_iiii 170
#define INTERP_rrrr 255

#define INTERP_nnnnnn 0
#define INTERP_nnnnns 1
#define INTERP_nnnnsn 4
#define INTERP_nnnnss 5
#define INTERP_nnnsnn 16
#define INTERP_nnnsns 17
#define INTERP_nnnssn 20
#define INTERP_nnnsss 21
#define INTERP_nnsnnn 64
#define INTERP_nnsnns 65
#define INTERP_nnsnsn 68
#define INTERP_nnsnss 69
#define INTERP_nnssnn 80
#define INTERP_nnssns 81
#define INTERP_nnsssn 84
#define INTERP_nnssss 85
#define INTERP_nsnnnn 256
#define INTERP_nsnnns 257
#define INTERP_nsnnsn 260
#define INTERP_nsnnss 261
#define INTERP_nsnsnn 272
#define INTERP_nsnsns 273
#define INTERP_nsnssn 276
#define INTERP_nsnsss 277
#define INTERP_nssnnn 320
#define INTERP_nssnns 321
#define INTERP_nssnsn 324
#define INTERP_nssnss 325
#define INTERP_nsssnn 336
#define INTERP_nsssns 337
#define INTERP_nssssn 340
#define INTERP_nsssss 341
#define INTERP_snnnnn 1024
#define INTERP_snnnns 1025
#define INTERP_snnnsn 1028
#define INTERP_snnnss 1029
#define INTERP_snnsnn 1040
#define INTERP_snnsns 1041
#define INTERP_snnssn 1044
#define INTERP_snnsss 1045
#define INTERP_snsnnn 1088
#define INTERP_snsnns 1089
#define INTERP_snsnsn 1092
#define INTERP_snsnss 1093
#define INTERP_snssnn 1104
#define INTERP_snssns 1105
#define INTERP_snsssn 1108
#define INTERP_snssss 1109
#define INTERP_ssnnnn 1280
#define INTERP_ssnnns 1281
#define INTERP_ssnnsn 1284
#define INTERP_ssnnss 1285
#define INTERP_ssnsnn 1296
#define INTERP_ssnsns 1297
#define INTERP_ssnssn 1300
#define INTERP_ssnsss 1301
#define INTERP_sssnnn 1344
#define INTERP_sssnns 1345
#define INTERP_sssnsn 1348
#define INTERP_sssnss 1349
#define INTERP_ssssnn 1360
#define INTERP_ssssns 1361
#define INTERP_sssssn 1364
#define INTERP_ssssss 1365
#define INTERP_iiiiii 2730
#define INTERP_rrrrrr 4095

#define INTERP_nnnnnnnn 0
#define INTERP_ssssssss 21845


#define INTERP_MASK 3
#define INTERP_SHIFT 2

LVAL snd_badsr(void);
long check_terminate_cnt(long tc);

typedef double time_type;
typedef double rate_type;
typedef float sample_type;
typedef double promoted_sample_type;

/* use radians or degrees for phase? */
#define ANGLEBASE 360.0

/* used by sndwrite.c for output buffers.  This should be
 * eliminated:
 */
#define MAX_SND_CHANNELS 24

#define max_table_len 100000
/* Set to 4 for debugging block allocation stuff, 1012? for
   production
*/
/* leave a few words short of 1024 in case we allocate powers of 2 */
#define max_sample_block_len 1020
/* #define max_sample_block_len 4 */

/* longest allowed sample is basically 2^31 but a bit lower to 
   allow for rounding */
#define MAX_SND_LEN (MAX_STOP - max_sample_block_len * 2)


/* Defines needed for xlisp */
#define getsound(x)     ((sound_type) getinst(x))
#define xlgasound()     (testarg(typearg(soundp)))

typedef short SFDataType, *SFDataPtr;

typedef sample_type  sample_block_values[max_sample_block_len], 
                    *sample_block_values_type;

typedef struct {
    long                refcnt;                          /* reference count */
    sample_block_values samples;
} sample_block_node, *sample_block_type;
 

/* forward declaration for circular type dependencies */
typedef struct snd_list_struct *snd_list_type;

typedef struct snd_susp_struct {
    void  (*fetch)(struct snd_susp_struct *, snd_list_type snd_list);
    void  (*keep_fetch)(struct snd_susp_struct *, snd_list_type snd_list);
    void  (*free)(struct snd_susp_struct *);
    void  (*mark)(struct snd_susp_struct *);  /* marks LVAL nodes for GC */
    void  (*print_tree)(struct snd_susp_struct *, int);    /* debugging */
    char *name;        /* string name for debugging */
    long  toss_cnt;    /* return this many zeros, then compute */
    long  current;     /* current sample number */
    double sr;         /* sample rate */
    time_type t0;      /* starting time */
    long log_stop_cnt; /* logical stop count */
    /* other susp dependent stuff will be here... */
} snd_susp_node, *snd_susp_type;


typedef struct snd_list_struct {
    sample_block_type   block;  /* pointer to block of samples */
    union {
        struct snd_list_struct  *next;
        snd_susp_type           susp;
    }       u;
    short   refcnt;
    short   block_len;
    boolean logically_stopped;
} snd_list_node; /* , *snd_list_type; -- defined above */

extern snd_list_type list_watch; //DBY


typedef struct table_struct {
    long refcount;  /* reference count */
    double length;  /* number of samples in table 
                       (double allows fractional length)*/
    sample_type samples[1]; /* arbitrary length array of sample */
} table_node, *table_type;


/* some counts are biased by -max_sample_block_len, so UNKNOWN can't be -1
 * Any number less than -max_sample_block should do
 */
#define UNKNOWN (-10-max_sample_block_len)

typedef struct sound_struct {
    sample_block_type   (*get_next)(struct sound_struct *snd, long *cnt);
    time_type           time;   /* logical starting time */
    time_type           t0;     /* quantized time of first sample */
    long                stop;  /* stop (clipping) sample no. */
    time_type           true_t0;    /* exact time of first sample */
    rate_type           sr;     /* sample rate */
    long                current;        /* current sample number,
                                         if negative, then the first 
                                         -current samples must be dropped
                                         in order to find the first sample */
    long                logical_stop_cnt; /* log stop sample no, -1=unknwn */
    snd_list_type       list;   /* sample block list, starting at curr. samp */
    sample_type         scale;  /* scale factor for the result */
    long                prepend_cnt;    /* how many zeros to prepend */
    /* function to use as get_next after prepended zeros are generated: */
    sample_block_type   (*after_prepend)
                        (struct sound_struct * snd, long * cnt);
    table_type table;   /* pointer to table-ized version of this sound */
    long *extra;        /* used for extra state information, first word of extra
			   state should be the length of the extra state 
			   (see sound_unref())
                         */
} sound_node, *sound_type;

/* convert number of samples to memory size: */
#define table_size_in_bytes(n) \
    (sizeof(table_node) + sizeof(sample_type) * ((n) - 1))

extern sample_block_type zero_block;
extern sample_block_type internal_zero_block;

extern snd_list_type zero_snd_list;

extern sound_type printing_this_sound;  /* debugging global */

extern double sound_latency; /* controls output latency */
double snd_set_latency(double latency); 
/* LISP: (SND-SET-LATENCY FLONUM) */

double compute_phase(double phase, double key, long n, double srate,
                     double new_srate, double freq, double *incr_ptr);

boolean soundp(LVAL);
/* LISP: (SOUNDP ANY) */

void snd_list_ref(snd_list_type list);
void sound_unref(sound_type snd);
void snd_list_unref(snd_list_type list);

LVAL cvsound(sound_type);
extern LVAL a_sound;

sample_block_type SND_get_next(sound_type snd, long * cnt);
sample_block_type SND_get_first(sound_type snd, long * cnt);
sample_block_type SND_get_zeros(sound_type snd, long * cnt);
sample_block_type SND_flush(sound_type snd, long * cnt);

double hz_to_step(double);    /* LISP: (HZ-TO-STEP ANYNUM) */
int interp_style(sound_type s, rate_type sr);
void set_logical_stop_time(sound_type sound, time_type when); /* LISP: (SND-SET-LOGICAL-STOP SOUND ANYNUM) */

#define xlog(x) log(x)
/* LISP: double (LOG FLONUM) */
snd_list_type snd_list_create(snd_susp_type susp);
void snd_list_terminate(snd_list_type snd_list);
void snd_sort_2(sound_type * s1_ptr, sound_type * s2_ptr, rate_type sr);

double snd_sref(sound_type s, time_type t); 
    /* LISP: (SND-SREF SOUND ANYNUM) */

double snd_sref_inverse(sound_type s, double val);
    /* LISP: (SREF-INVERSE SOUND ANYNUM) */

double snd_stop_time(sound_type s); /* LISP: (SND-STOP-TIME SOUND) */
#define snd_time(s) (s)->time
    /* LISP: double (SND-TIME SOUND) */

#define snd_srate(s) (s)->sr
    /* LISP: double (SND-SRATE SOUND) */
#define snd_t0(s) (s)->t0
    /* LISP: double (SND-T0 SOUND) */

sound_type snd_xform(sound_type snd, rate_type sr, time_type time, 
        time_type start_time, time_type stop_time, promoted_sample_type scale);
    /* LISP: (SND-XFORM SOUND ANYNUM ANYNUM ANYNUM ANYNUM ANYNUM) */
sound_type sound_create(snd_susp_type susp, time_type t0, rate_type sr,
        promoted_sample_type scale);

void min_cnt(long *cnt_ptr, sound_type sound, snd_susp_type susp, long cnt);
void indent(int n);
void sound_prepend_zeros(sound_type snd, time_type t0);



#ifndef GCBUG
#define blocks_to_watch_max 50
extern long blocks_to_watch_len;
extern sample_block_type blocks_to_watch[blocks_to_watch_max];

void block_watch(long sample_block);
    /* LISP: (BLOCK-WATCH FIXNUM) */
long sound_nth_block(sound_type snd, long n);
    /* LISP: (SOUND-NTH-BLOCK SOUND FIXNUM) */
#endif

sound_type sound_copy(sound_type snd); 
    /* LISP: (SND-COPY SOUND) */
void sound_xlmark(void *a_sound);
void sound_print(LVAL snd_expr, long n);
    /* LISP: (SND-PRINT ANY FIXNUM) */
void sound_play(LVAL snd_expr);
    /* LISP: (SND-PLAY ANY) */
void stats(void);
    /* LISP: (STATS) */
void sound_print_tree(sound_type snd);
    /* LISP: (SND-PRINT-TREE SOUND) */
    
void mark_audio_time(void);

void sound_print_tree_1(sound_type snd, int n);

sound_type sound_scale(double factor, sound_type snd);
    /* LISP: (SND-SCALE ANYNUM SOUND) */
void sound_init(void);

void sound_symbols(void);

table_type sound_to_table(sound_type s);

void table_unref(table_type table);

sound_type sound_zero(time_type t0, rate_type sr);
    /* LISP: (SND-ZERO ANYNUM ANYNUM) */

#define sound_get_next(s, n) ((*(s->get_next))(s, n))

#define susp_print_tree(s, n) (*((s)->print_tree))(s, n)

double step_to_hz(double);
    /* LISP: (STEP-TO-HZ ANYNUM) */

#ifdef WIN32
double log2(double x);
#endif WIN32

/* macros for access to samples within a suspension */
/* NOTE: assume suspension structure is named "susp" */

/* susp_check_samples points sample_ptr to a new sample block if necessary */
#define susp_check_samples(sound, sample_ptr, sample_cnt) \
    if (susp->sample_cnt == 0) \
        susp_get_samples(sound, sample_ptr, sample_cnt)

/* susp_check_samples_break is similar to susp_check_samples - "_break"
 *   normally means that this code will break out of the inner loop, but in
 *   this case, there is no reason (neither log nor term) to break.
 *   x2_sample is taken from sound
 */
#define susp_check_samples_break(sound, sample_ptr, sample_cnt, x2_sample) \
    if (susp->sample_cnt == 0) { \
        susp_get_samples(sound, sample_ptr, sample_cnt); \
        x2_sample = susp_current_sample(sound, sample_ptr); }


/* susp_get_samples always gets next block (useful only in initialization code) */
#define susp_get_samples(sound, sample_ptr, sample_cnt) \
        susp->sample_ptr = sound_get_next(susp->sound, &(susp->sample_cnt))->samples

/* susp_get_block_samples always gets next block (useful only in initialization code) */
#define susp_get_block_samples(sound, sample_block_ptr, sample_ptr, sample_cnt) \
    susp->sample_block_ptr = sound_get_next(susp->sound, &susp->sample_cnt); \
    susp->sample_ptr = susp->sample_block_ptr->samples

/* susp_took is called after you've taken n samples */
#define susp_took(sample_cnt, n) susp->sample_cnt -= n

/* susp_fetch_sample is used to grab just one sample, doesn't check for samples!,
 *    but applies scale factor:  */
#define susp_fetch_sample(sound, sample_ptr, sample_cnt) \
          (susp->sound->scale * (susp->sample_cnt--, *(susp->sample_ptr++)))

/* susp_current_sample grabs sample without advancing to next, applies scale
 *     factor: */
#define susp_current_sample(sound, sample_ptr) \
          (susp->sound->scale * (*(susp->sample_ptr)))

/* susp_check_term_samples checks for samples; if new ones are fetched, then
 * run termination test on signal and record result.
 */
#define susp_check_term_samples(sound, sample_ptr, sample_cnt) \
    if (susp->sample_cnt == 0) { \
        susp_get_samples(sound, sample_ptr, sample_cnt); \
        terminate_test(sample_ptr, sound, susp->sample_cnt); }

/* susp_check_term_log_samples checks for samples
 * if new ones are fetched, then run termination test and logical stop
 * test on signal and record results.
 */
#define susp_check_term_log_samples(sound, sample_ptr, sample_cnt) \
    if (susp->sample_cnt == 0) { \
        susp_get_samples(sound, sample_ptr, sample_cnt); \
        logical_stop_test(sound, susp->sample_cnt); \
        terminate_test(sample_ptr, sound, susp->sample_cnt); }

/* susp_check_term_log_block_samples checks for samples
 * if new ones are fetched, then run termination test and logical stop
 * test on signal and record results.  In this case, termination and logical
 * stop happen at the MAXIMUM of termination and logical stop times, resp.
 *
 * Originally, this code assumed that logical stops occurred on block boundaries,
 * but because of the SET-LOGICAL-STOP function, which just writes a stop time
 * into the sound_struct, the logical stop can be anywhere. As soon as the 
 * logical stop is known, we want to propagate the value from the sound being
 * read into the sound being computed. The propagation should set the logical
 * stop of the computed sound to the MAX of any current value and the new 
 * value. When the bit fields indicate that all logical stop times have been
 * encountered, then the sound being computed will make the logical stop happen
 * on a block boundary and set the flag on the block of samples where the stop
 * occurs.
 */
#define susp_check_term_log_block_samples(sound, sample_block_ptr, sample_ptr, sample_cnt, bit, all) \
    if (susp->sample_cnt == 0) { \
        susp_get_block_samples(sound, sample_block_ptr, sample_ptr, sample_cnt); \
/*OLD   if (susp->sound->logical_stop_cnt ==                  \
            susp->sound->current - susp->sample_cnt) { \
*/ \
        if (susp->sound->logical_stop_cnt != UNKNOWN && \
            !(susp->logical_stop_bits & bit)) { \
            susp->logical_stop_bits |= bit; \
/*OLD \
            if (susp->logical_stop_bits == all) { \
                susp->susp.log_stop_cnt = (long) \
                 ((((susp->sound->current - susp->sample_cnt) / \
                   susp->sound->sr + susp->sound->t0) - \
                   susp->susp.t0) * susp->susp.sr + 0.5); \
                assert(susp->susp.log_stop_cnt >= 0); } } \
*/ \
            susp->susp.log_stop_cnt = max(susp->susp.log_stop_cnt, \
                    (((susp->sound->logical_stop_cnt / \
                       susp->sound->sr + susp->sound->t0) - \
                      susp->susp.t0) * susp->susp.sr + 0.5)); } \
        if (susp->sample_ptr == zero_block->samples) { \
            susp->terminate_bits |= bit; \
            if (susp->terminate_bits == all) { \
                susp->terminate_cnt = (long) \
                 ((((susp->sound->current - susp->sample_cnt) / \
                   susp->sound->sr + susp->sound->t0) - \
                   susp->susp.t0) * susp->susp.sr + 0.5); \
    } } }


/* logical_stop_cnt_cvt is used to convert from the logical stop count
 * at one sample rate to that of another sample rate -- this macro is
 * used by the snd_make_<op> routine in every <op>.c file, and assumes
 * the target sample rate is susp->susp.sr.
 *
 * NOTE: this macro does not take into account the possibility of different
 * start times - maybe it should.
 */
#define logical_stop_cnt_cvt(sound) \
    (sound->logical_stop_cnt == UNKNOWN ? UNKNOWN : \
     ROUND((sound->logical_stop_cnt / sound->sr) * susp->susp.sr))


/* logical_stop_test tests to see if sound has logically stopped; if so,
 * sets susp->susp.log_stop_cnt.  The resulting logical_stop_cnt will reflect
 * the minimum logical_stop time of all sounds to which this test is applied.
 */
#define logical_stop_test(sound, cnt) \
    if (susp->sound->logical_stop_cnt == susp->sound->current - (cnt)) {\
        min_cnt(&susp->susp.log_stop_cnt, susp->sound, (snd_susp_type) susp, cnt); }

/* terminate_test checks to see if sound has terminated; if so, 
 * sets susp->terminate_cnt.  The resulting terminate_cnt will reflect
 * the minimum termination time of all sounds to which this test is applied.
 */
#define terminate_test(sample_ptr, sound, cnt) \
    if (susp->sample_ptr == zero_block->samples) { \
            min_cnt(&susp->terminate_cnt, susp->sound, (snd_susp_type) susp, cnt); }


/* susp_check_log_samples checks for new samples then checks for
 * termination and logical stop conditions
 */
#define susp_check_log_samples(sound, sample_ptr, sample_cnt) \
    if (susp->sample_cnt == 0) { \
      susp_get_samples(sound, sample_ptr, sample_cnt); \
      logical_stop_test(sound, susp->sample_cnt); }

/* susp_check_term_samples_break checks for new samples then checks for
 * termination condition; breaks from inner loop
 */
#define susp_check_term_samples_break( \
  sound, sample_ptr, sample_cnt, x2_sample) \
    if (susp->sample_cnt == 0) { \
      susp_get_samples(sound, sample_ptr, sample_cnt); \
      x2_sample = susp_current_sample(sound, sample_ptr); \
      terminate_test(sample_ptr, sound, susp->sample_cnt); \
      if (susp->terminate_cnt < susp->susp.current + cnt + togo) { \
          break; }} \
    else x2_sample = susp_current_sample(sound, sample_ptr); 

/* susp_check_log_samples_break checks for new samples then checks for
 * logical stop conditions; breaks from inner loop
 */
#define susp_check_log_samples_break( \
  sound, sample_ptr, sample_cnt, x2_sample) \
    if (susp->sample_cnt == 0) { \
      susp_get_samples(sound, sample_ptr, sample_cnt); \
      x2_sample = susp_current_sample(sound, sample_ptr); \
      logical_stop_test(sound, susp->sample_cnt); \
      if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN && \
          (susp->susp.log_stop_cnt < susp->susp.current + cnt + togo)) { \
          break; }} \
    else x2_sample = susp_current_sample(sound, sample_ptr);


/* susp_check_term_log_samples_break checks for new samples then checks for
 * termination and logical stop conditions; breaks from inner loop
 */
#define susp_check_term_log_samples_break( \
  sound, sample_ptr, sample_cnt, x2_sample) \
    if (susp->sample_cnt == 0) { \
      susp_get_samples(sound, sample_ptr, sample_cnt); \
      x2_sample = susp_current_sample(sound, sample_ptr); \
      terminate_test(sample_ptr, sound, susp->sample_cnt); \
      logical_stop_test(sound, susp->sample_cnt); \
      if ((susp->terminate_cnt != UNKNOWN && \
           susp->terminate_cnt < susp->susp.current + cnt + togo) || \
          (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN && \
           susp->susp.log_stop_cnt < susp->susp.current + cnt + togo)) { \
          break; }} \
    else x2_sample = susp_current_sample(sound, sample_ptr);