📄 sound.c
字号:
void table_free(table_type table){ long len = (long) (table->length) + 1; long bytes = table_size_in_bytes(len); free(table); table_memory -= bytes;}void table_unref(table_type table){ if (!table) return; table->refcount--; if (table->refcount <= 0) { /* nyquist_printf("table refcount went to zero\n"); */ table_free(table); }}void sound_unref(sound_type snd)/* note that sounds do not have ref counts, so sound_unref * always frees the sound object */{ if (!snd) return; snd_list_unref(snd->list); table_unref(snd->table);/* nyquist_printf("\t\t\t\t\tfreeing sound@%p\n", snd);*/ if (snd->extra) free(snd->extra); ffree_sound(snd, "sound_unref");}void snd_list_ref(snd_list_type list){ list->refcnt++;}void snd_list_terminate(snd_list) snd_list_type snd_list;{ snd_susp_type susp = snd_list->u.next->u.susp; long lsc = susp->log_stop_cnt; long current = susp->current; /* unreference the empty sample block that was allocated: */ sample_block_unref(snd_list->block); /* use zero_block instead */ snd_list->block = zero_block; /* either fetch more zeros or terminate now */ if (lsc != UNKNOWN && lsc > current) { /* nyquist_printf("snd_list_terminate: lsc %d current %d\n", lsc, current); */ susp->fetch = fetch_zeros; fetch_zeros(susp, snd_list); } else { snd_list->block_len = max_sample_block_len; snd_list->logically_stopped = true; snd_list_unref(snd_list->u.next); snd_list->u.next = zero_snd_list; /* be zero forever */ }}void snd_list_unref(snd_list_type list){ void (*freefunc)(); if (list == NULL || list == zero_snd_list) { if (list == NULL) nyquist_printf("why did snd_list_unref get %p?\n", list); return; } list->refcnt--;/* nyquist_printf("snd_list_unref "); print_snd_list_type(list); stdputstr("\n"); */ if (list->refcnt == 0) { if (list->block && list->block != zero_block) { /* there is a next snd_list *//* stdputstr("["); */ sample_block_unref(list->block);/* stdputstr("]"); */ snd_list_unref(list->u.next); } else if (list->block == NULL) { /* the next thing is the susp */ /* free suspension structure */ /* nyquist_printf("freeing susp@%p\n", list->u.susp); */ freefunc = list->u.susp->free; (*freefunc)(list->u.susp); } /* nyquist_printf("freeing snd_list@%p\n", list); */ ffree_snd_list(list, "snd_list_unref"); }}void sample_block_ref(sample_block_type sam){ sam->refcnt++;}void sample_block_test(sample_block_type sam, char *s){ /* see if this block is being watched */ int i; for (i = 0; i < blocks_to_watch_len; i++) { if ((sam > (blocks_to_watch[i] - 1)) && (sam < (blocks_to_watch[i] + 1))) { nyquist_printf( "WOOPS! %s(0x%p) refers to a block 0x%p on the watch list!\n", s, sam, blocks_to_watch[i]); } }}void sample_block_unref(sample_block_type sam){ sam->refcnt--; if (sam->refcnt == 0) {#ifndef GCBUG sample_block_test(sam, "sample_block_unref");#endif /* nyquist_printf("freeing sample block %p\n", sam); */ ffree_sample_block(sam, "sample_block_unref"); }}/***************************************************************************** interp_style* Inputs:* sound_type s: The sound we are using* rate_type sr: The sampling rate* Result: int* A small integer which is one of the symbolic values:* The values are ordered, smallest to largest, as* INTERP_n - none* INTERP_s - scale* INTERP_i - interpolated* INTERP_r - ramp** Notes: * The sampling rate s->sr and scale factor s->scale are compared* with other values exactly (no fuzz). ****************************************************************************/int interp_style(sound_type s, rate_type sr){ if (s->sr == sr) { /* same sample rate */ return ((s->scale == 1.0) ? INTERP_n : INTERP_s); } /* same sample rate */ else if (s->sr * 10.0 > sr) { /* 10x sample rate */ return INTERP_i; } /* 10x sample rate */ else return INTERP_r;}/***************************************************************************** snd_sort_2* Inputs:* sound_type * s1_ptr:* sound_type * s2_ptr:* rate_type sr:* Result: void* * Effect: * If the interp_style of s1 dominates the interp_style of s2,* the sound_types input are interchanged.****************************************************************************//* snd_sort_2 -- sort 2 arguments by interpolation method */void snd_sort_2(sound_type *s1_ptr, sound_type *s2_ptr, rate_type sr){ if (interp_style(*s1_ptr, sr) > interp_style(*s2_ptr, sr)) { sound_type s = *s1_ptr; *s1_ptr = *s2_ptr; *s2_ptr = s; }}/* snd_sref -- access a sound at a given time point *//**/double snd_sref(sound_type s, time_type t){ double exact_cnt; /* how many fractional samples to scan */ int cnt; /* how many samples to flush */ sample_block_type sampblock = NULL; long blocklen; sample_type x1, x2; /* interpolate between these samples */ /* changed true_t0 to just t0 based on comment that true_t0 is only * for use by snd_prepend_zeros -RBD */ exact_cnt = (t - s->t0) * s->sr; if (exact_cnt < 0.0) return 0.0; s = sound_copy(s); /* don't modify s, create new reader */ cnt = (long) exact_cnt; /* rounds down */ exact_cnt -= cnt; /* remember fractional remainder */ /* now flush cnt samples */ while (cnt >= 0) { sampblock = sound_get_next(s, &blocklen); cnt -= blocklen; if (sampblock == zero_block) { sound_unref(s); return 0.0; } } /* -blocklen <= cnt <= -1 */ /* get next 2 samples and interpolate */ x1 = sampblock->samples[blocklen + cnt]; if (cnt == -1) { sampblock = sound_get_next(s, &blocklen); cnt -= blocklen; } x2 = sampblock->samples[blocklen + cnt + 1]; sound_unref(s); /* free the reader */ return (x1 + exact_cnt * (x2 - x1)) * s->scale;}/* snd_sref_inverse -- find time point corresponding to some value *//**/double snd_sref_inverse(sound_type s, double val){ double exact_cnt; /* how many fractional samples to scan */ int i; sample_block_type sampblock; long blocklen; sample_type x1, x2; /* interpolate between these samples */ if (val < 0) { xlcerror("return 0", "negative value", cvflonum(val)); return 0.0; } s = sound_copy(s); /* don't modify s, create new reader */ x1 = 0.0F; /* now flush cnt samples */ while (true) { sampblock = sound_get_next(s, &blocklen); x2 = sampblock->samples[blocklen - 1]; if (x2 >= val) break; x1 = x2; if (sampblock == zero_block) { xlcerror("return 0", "too large, no inverse", cvflonum(val)); sound_unref(s); return 0.0; } } /* x1 = last sample of previous block, sampblock contains a value larger than val blocklen is the length of sampblock */ /* search for first element exceeding val - could * use binary search, but maximum block size places * an upper bound on how bad this can get and we * search for the right block linearly anyway. */ for (i = 0; i < blocklen && sampblock->samples[i] <= val; i++) ; /* now i is index of element exceeding val */ if (i > 1) x1 = sampblock->samples[i - 1]; x2 = sampblock->samples[i]; /* now interpolate to get fractional part */ if (x2 == x1) exact_cnt = 0; else exact_cnt = (val - x1) / (x2 - x1); /* and add the sample count of x1 */ exact_cnt += (s->current - blocklen) + (i - 1); /* negative counts are possible because the first x1 is at * sample -1, so force the location to be at least 0 */ if (exact_cnt < 0) exact_cnt = 0; /* compute time = t0 + count / samplerate; */ exact_cnt = s->t0 + exact_cnt / s->sr; sound_unref(s); /* free the reader */ return exact_cnt;}time_type snd_stop_time(sound_type s){ if (s->stop == MAX_STOP) return MAX_STOP_TIME; else return s->t0 + (s->stop + 0.5) / s->sr;}/* snd_xform -- return a sound with transformations applied *//* * The "logical" sound starts at snd->time and runs until some * as yet unknown termination time. (There is also a possibly * as yet unknown logical stop time that is irrelevant here.) * The sound is clipped (zero) until snd->t0 and after snd->stop, * the latter being a sample count, not a time_type. * So, the "physical" sound starts at snd->t0 and runs for up to * snd->stop samples (or less if the sound terminates beforehand). * * The snd_xform procedure operates at the "logical" level, shifting * the sound from its snd->time to time. The sound is stretched as * a result of setting the sample rate to sr. It is then (further) * clipped between start_time and stop_time. If initial samples * are clipped, the sound is shifted again so that it still starts * at time. The sound is then scaled by scale. * * To support clipping of initial samples, the "physical" start time * t0 is set to when the first unclipped sample will be returned, but * the number of samples to clip is saved as a negative count. The * fetch routine SND_flush is installed to flush the clipped samples * at the time of the first fetch. SND_get_first is then installed * for future fetches. * * An empty (zero) sound will be returned if all samples are clipped. * */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){ long start_cnt, stop_cnt; /* clipping samples (sample 0 at new t0) */ /* start_cnt should reflect max of where the sound starts (t0) * and the new start_time. */ if (start_time == MIN_START_TIME) { start_cnt = 0; } else { double new_start_cnt = ((start_time - time) * sr) + 0.5; start_cnt = ((new_start_cnt > 0) ? (long) new_start_cnt : 0); } /* if (start_cnt < -(snd->current)) start_cnt = -(snd->current); */ /* stop_cnt should reflect min of the new stop_time and the previous * snd->stop. */ if (stop_time == MAX_STOP_TIME) { stop_cnt = MAX_STOP; } else { double new_stop_cnt = ((stop_time - time) * sr) + 0.5; if (new_stop_cnt < MAX_STOP) { stop_cnt = (long) new_stop_cnt; } else { errputstr("Warning: stop count overflow in snd_xform\n"); stop_cnt = MAX_STOP; } } if (stop_cnt > snd->stop) { stop_cnt = snd->stop; } if (stop_cnt < 0 || start_cnt >= stop_cnt) { snd = sound_create(NULL, time, sr, 1.0); /* sound_create goes ahead and allocates a snd_list node, so * we need to free it. * Calling snd_list_unref here seems like the right thing, but * it assumes too much structure is in place. ffree_snd_list * is simpler and more direct: */ ffree_snd_list(snd->list, "snd_xform"); snd->list = zero_snd_list; nyquist_printf("snd_xform: (stop_time < t0 or start >= stop) " "-> zero sound = %p\n", snd); } else { snd = sound_copy(snd); snd->t0 = time; if (start_cnt) { snd->current -= start_cnt; /* indicate flush with negative num. */ /* the following code assumes that SND_get_first is the routine to be called to get the first samples from this sound. We're going to replace it with SND_flush. First, make sure that the assumption is correct: */ if ((snd->get_next != SND_get_first) && (snd->get_next != SND_flush)) { errputstr("snd_xform: SND_get_first expected\n"); EXIT(1); } /* this will flush -current samples and revert to SND_get_first */ snd->get_next = SND_flush; stop_cnt -= start_cnt; } snd->stop = stop_cnt; snd->sr = sr; snd->scale *= (float) scale; } return snd;}/* SND_flush -- the get_next function for flushing clipped samples *//* * this only gets called once: it flushes -current samples (a * non-real-time operation) and installs SND_get_next to return
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -