📄 sound.c
字号:
}}/* * additional routines */void sound_print(snd_expr, n) LVAL snd_expr; long n;{ LVAL result; xlsave1(result); result = xleval(snd_expr); if (vectorp(result)) { /* make sure all elements are of type a_sound */ long i = getsize(result); while (i > 0) { i--; if (!exttypep(getelement(result, i), a_sound)) { xlerror("sound_print: array has non-sound element", result); } } sound_print_array(result, n); } else if (exttypep(result, a_sound)) { sound_print_sound(getsound(result), n); } else { xlerror("sound_print: expression did not return a sound", result); } xlpop();}void sound_print_sound(sound_type s, long n){ int ntotal = 0; long blocklen; sample_block_type sampblock; /* for debugging */ printing_this_sound = s; nyquist_printf("sound_print: start at time %g\n", s->t0); while (ntotal < n) { if (s->logical_stop_cnt != UNKNOWN) nyquist_printf("LST=%d ", (int)s->logical_stop_cnt); sound_print_tree(s); sampblock = sound_get_next(s, &blocklen); if (sampblock == zero_block || blocklen == 0) { break; } print_sample_block_type("sound_print", sampblock, MIN(blocklen, n - ntotal)); ntotal += blocklen; } nyquist_printf("total samples: %d\n", ntotal);}void sound_print_array(LVAL sa, long n){ long blocklen; long i, len; long upper = 0; sample_block_type sampblock; time_type t0, tmax; len = getsize(sa); if (len == 0) { stdputstr("sound_print: 0 channels!\n"); return; } /* take care of prepending zeros if necessary */ t0 = tmax = (getsound(getelement(sa, 0)))->t0; for (i = 1; i < len; i++) { sound_type s = getsound(getelement(sa, i)); t0 = MIN(s->t0, t0); tmax = MAX(s->t0, tmax); } /* if necessary, prepend zeros */ if (t0 != tmax) { stdputstr("prepending zeros to channels: "); for (i = 0; i < len; i++) { sound_type s = getsound(getelement(sa, i)); if (t0 < s->t0) { nyquist_printf(" %d ", (int)i); sound_prepend_zeros(s, t0); } } stdputstr("\n"); } nyquist_printf("sound_print: start at time %g\n", t0); while (upper < n) { int i; boolean done = true; for (i = 0; i < len; i++) { sound_type s = getsound(getelement(sa, i)); long current = -1; /* always get first block */ while (current < upper) { sampblock = sound_get_next(s, &blocklen); if (sampblock != zero_block && blocklen != 0) { done = false; } current = s->current - blocklen; nyquist_printf("chan %d current %d:\n", i, (int)current); print_sample_block_type("sound_print", sampblock, MIN(blocklen, n - current)); current = s->current; upper = MAX(upper, current); } } if (done) break; } nyquist_printf("total: %d samples x %d channels\n", (int)upper, (int)len);}/* sound_play -- compute sound, do not retain samples *//* * NOTE: we want the capability of computing a sound without * retaining samples. This requires that no references to * the sound exist, but if the sound is passed as an argument, * the argument stack will have a reference. So, we pass in * an expression that evaluates to the sound we want. The * expression is eval'd, the result copied (in case the * expression was a sound or a global variable and we really * want to preserve the sound), and then a GC is run to * get rid of the original if there really are no other * references. Finally, the copy is used to play the * sounds. */void sound_play(snd_expr) LVAL snd_expr;{ int ntotal; long blocklen; sample_block_type sampblock; LVAL result; sound_type s; xlsave1(result); result = xleval(snd_expr); if (!exttypep(result, a_sound)) { xlerror("sound_play: expression did not return a sound", result); } ntotal = 0; s = getsound(result); /* if snd_expr was simply a symbol, then s now points to a shared sound_node. If we read samples from it, then the sound bound to the symbol will be destroyed, so copy it first. If snd_expr was a real expression that computed a new value, then the next garbage collection will reclaim the sound_node. We need to explicitly free the copy since the garbage collector cannot find it. */ s = sound_copy(s); while (1) { sampblock = sound_get_next(s, &blocklen); if (sampblock == zero_block || blocklen == 0) { break; } /* print_sample_block_type("sound_play", sampblock, blocklen); */ ntotal += blocklen; } nyquist_printf("total samples: %d\n", ntotal); sound_unref(s); xlpop();}/* sound_print_tree -- print a tree version of sound structure *//**/void sound_print_tree(snd) sound_type snd;{/* nyquist_printf("sample_block_free %p\n", sample_block_free);*/ nyquist_printf("SOUND PRINT TREE of %p\n", snd); sound_print_tree_1(snd, 0);}void indent(int n){ while (n-- > 0) stdputstr(" ");}void sound_print_tree_1(snd, n) sound_type snd; int n;{ int i; snd_list_type snd_list; if (n > 100) { stdputstr("... (skipping remainder of sound)\n"); return; } nyquist_printf("sound_type@%p(%s@%p)t0 " "%g stop %d sr %g lsc %d scale %g pc %d", snd, (snd->get_next == SND_get_next ? "SND_get_next" : (snd->get_next == SND_get_first ? "SND_get_first" : "?")), snd->get_next, snd->t0, (int)snd->stop, snd->sr, (int)snd->logical_stop_cnt, snd->scale, (int)snd->prepend_cnt); if (!snd) { stdputstr("\n"); return; } snd_list = snd->list; nyquist_printf("->snd_list@%p", snd_list); if (snd_list == zero_snd_list) { stdputstr(" = zero_snd_list\n"); return; } for (i = 0; ; i++) { if (snd_list == zero_snd_list) { if (i > 1) nyquist_printf(" (skipping %d) ", i-1); stdputstr("->zero_snd_list\n"); return; } if (!snd_list->block) { if (i > 0) nyquist_printf(" (skipping %d) ", i); stdputstr("->\n"); indent(n + 2); nyquist_printf("susp@%p(%s)toss_cnt %d " "current %d lsc %d sr %g t0 %g %p\n", snd_list->u.susp, snd_list->u.susp->name, (int)snd_list->u.susp->toss_cnt, (int)snd_list->u.susp->current, (int)snd_list->u.susp->log_stop_cnt, snd_list->u.susp->sr, snd_list->u.susp->t0, snd_list);/* stdputstr("HI THERE AGAIN\n");*/ susp_print_tree(snd_list->u.susp, n + 4); return; } snd_list = snd_list->u.next; }}/* compute constants p1 and p2: pitchconvert(0) * 2 = pitchconvert(12) - octaves exp(p2) * 2 = exp(12 * p1 + p2) 2 = exp(12 * p1) log(2) = 12 * p1 p1 = log(2.0)/12; pitchconvert(69) gives 440Hz exp(69 * p1 + p2) = 440 69 * p1 + p2 = log(440) p2 = log(440.0) - (69 * p1);*/#define p1 0.0577622650466621#define p2 2.1011784386926213double hz_to_step(double hz){ return (log(hz) - p2) / p1;}double step_to_hz(steps) double steps;{ return exp(steps * p1 + p2);}/* * from old stuff... */static void sound_xlfree(s)sound_type s;{/* nyquist_printf("sound_xlfree(%p)\n", s);*/ sound_unref(s);}static void sound_xlprint(LVAL fptr, sound_type s){ /* the type cast from s to LVAL is OK because * putatm does not dereference the 3rd parameter */ putatm(fptr, "Sound", (LVAL) s);}static void sound_xlsave(fp, s)FILE *fp;sound_type s;{ stdputstr("sound_save called\n");}static unsigned char *sound_xlrestore(FILE *fp){ stdputstr("sound_restore called\n"); return NULL;}/* sound_xlmark -- mark LVAL nodes reachable from this sound *//**/void sound_xlmark(s)sound_type s;{ snd_list_type snd_list; long counter = 0;#ifdef TRACESNDGC nyquist_printf("sound_xlmark(%p)\n", s);#endif if (!s) return; /* pointers to sounds are sometimes NULL */ snd_list = s->list; while (snd_list->block != NULL) { if (snd_list == zero_snd_list) {#ifdef TRACESNDGC stdputstr(" terminates at zero_snd_list\n");#endif return; } else if (counter > 1000000) { stdputstr("You created a recursive sound! This is a Nyquist bug.\n"); stdputstr("The only known way to do this is by a SETF on a\n"); stdputstr("local variable or parameter that is being passed to SEQ\n"); stdputstr("or SEQREP. The garbage collector assumes that sounds are\n"); stdputstr("not recursive or circular, and follows sounds to their\n"); stdputstr("end. After following a million nodes, I'm pretty sure\n"); stdputstr("that there is a cycle here, but since this is a bug,\n"); stdputstr("I cannot promise to recover. Prepare to crash. If you\n"); stdputstr("cannot locate the cause of this, contact the author -RBD.\n"); } snd_list = snd_list->u.next; counter++; } if (snd_list->u.susp->mark) {#ifdef TRACESNDGC nyquist_printf(" found susp (%s) at %p with mark method\n", snd_list->u.susp->name, snd_list->u.susp);#endif (*(snd_list->u.susp->mark))(snd_list->u.susp); } else {#ifdef TRACESNDGC nyquist_printf(" no mark method on susp %p (%s)\n", snd_list->u.susp, snd_list->u.susp->name);#endif }}void sound_symbols(){ a_sound = xlenter("SOUND");}/* The SOUND Type: */boolean soundp(s)LVAL s;{ return (exttypep(s, a_sound));}/* sound_zero - create and return a zero that terminates now *//**/sound_type sound_zero(time_type t0,rate_type sr){ sound_type sound; falloc_sound(sound, "sound_zero"); sound->get_next = SND_get_first; sound->list = zero_snd_list; sound->logical_stop_cnt = sound->current = 0; sound->true_t0 = sound->t0 = t0; sound->sr = sr; sound->scale = 1.0F; return sound;}LVAL cvsound(s)sound_type s;{/* nyquist_printf("cvsound(%p)\n", s);*/ return (cvextern(sound_desc, (unsigned char *) s));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -