⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sound.c

📁 Audacity是一款用於錄音和編輯聲音的、免費的開放源碼軟體。它可以執行於Mac OS X、Microsoft Windows、GNU/Linux和其它作業系統
💻 C
📖 第 1 页 / 共 4 页
字号:
/* sound.c -- nyquist sound data type *//* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03  dm  changes for portability and fix compiler warnings *//* define size_t: */#ifdef UNIX#include "sys/types.h"#endif  #include <stdio.h>#include "xlisp.h"#include "sound.h"#include "falloc.h"#include "samples.h"#include "extern.h"#include "debug.h"/* #define GC_DEBUG */#ifdef GC_DEBUGsound_type sound_to_watch;#endif/* #define SNAPSHOTS */long table_memory;sample_block_type zero_block;sample_block_type internal_zero_block;snd_list_type zero_snd_list;xtype_desc sound_desc;LVAL a_sound;static void sound_xlfree();static void sound_xlprint();static void sound_xlsave();static unsigned char *sound_xlrestore();void sound_print_array(LVAL sa, long n);void sound_print_sound(sound_type s, long n);void sample_block_unref(sample_block_type sam);#ifdef SNAPSHOTSboolean sound_created_flag = false;#endif/* xlbadsr - report a "bad combination of sample rates" error */LVAL snd_badsr(void){    xlfail("bad combination of sample rates");    return NIL; /* never happens */}/* compute-phase -  given a phase in radians, a wavetable specified as *  the nominal pitch (in half steps), the table length, and the sample *  rate, compute the sample number corresponding to the phase.  This *  routine makes it easy to initialize the table pointer at the beginning *  of various oscillator implementations in Fugue.  Note that the table *  may represent several periods, in which case phase 360 is not the same *  as 0.  Also note that the phase increment is also computed and returned *  through incr_ptr. */double compute_phase(phase, key, n, srate, new_srate, freq, incr_ptr)  double phase;  /* phase in degrees (depends on ANGLEBASE) */  double key;    /* the semitone number of the table played at srate */  long n;        /* number of samples */  double srate;  /* the sample rate of the table */  double new_srate;  /* sample rate of the result */  double freq;   /* the desired frequency */  double *incr_ptr; /* the sample increment */{    double period = 1.0 / step_to_hz(key);    /* convert phase to sample units */    phase = srate * period * (phase / (double) ANGLEBASE);    /* phase is now in sample units; if phase is less than zero, then increase       it by some number of sLength's to make it positive:     */    if (phase < 0)        phase += (((int) ((-phase) / n)) + 1) * n;    /* if phase is longer than the sample length, wrap it by subtracting the       integer part of the division by sLength:     */    if (phase > n)        phase -= ((int) (phase / n)) * n;    /* Now figure the phase increment: to reproduce original pitch       required incr = srate / new_srate.  To get the new frequency,       scale by freq / nominal_freq = freq * period:     */    *incr_ptr = (srate / new_srate) * freq * period;    return phase;}#ifndef GCBUGsnd_list_type gcbug_snd_list = 0;long blocks_to_watch_len = 0;sample_block_type blocks_to_watch[blocks_to_watch_max];void block_watch(long sample_block){    if (blocks_to_watch_len >= blocks_to_watch_max) {        stdputstr("block_watch - no more space to save pointers\n");        return;    }    blocks_to_watch[blocks_to_watch_len++] = (sample_block_type) sample_block;    nyquist_printf("block_watch - added %d = %x\n",                   (int)sample_block, (int)sample_block);}/* fetch_zeros -- the fetch function for appended zeros *//* * zeros are appended when the logical stop time exceeds the  * (physical) terminate time.  This fetch function is installed * by snd_list_terminate().  When appending zeros, we just return * a pointer to the internal_zero_block and increment current until * it reaches log_stop_cnt.  Then we call snd_list_terminate() to * finish off the sound list. */void fetch_zeros(snd_susp_type susp, snd_list_type snd_list){    int len = MIN(susp->log_stop_cnt - susp->current,                   max_sample_block_len);/*    nyquist_printf("fetch_zeros, lsc %d current %d len %d\n",             susp->log_stop_cnt, susp->current, len); */    if (len < 0) {        char error[80];        sprintf(error, "fetch_zeros susp %p (%s) len %d", susp, susp->name, len);        xlabort(error);    }    if (len == 0) { /* we've reached the logical stop time */        /* nyquist_printf("fetch_zeros: reached the logical stop in %s cnt %d\n",               susp->name, susp->log_stop_cnt); */        snd_list_terminate(snd_list);    } else {        snd_list->block_len = len;        susp->current += len;    }}/* sound_nth_block - fetch the address of the nth sample block of a sound *//* * NOTE: intended to be called from lisp.  Lisp can then call block_watch * to keep an eye on the block. */long sound_nth_block(sound_type snd, long n){    long i;    snd_list_type snd_list = snd->list;    for (i = 0; i < n; i++) {        if (i == 1) {            gcbug_snd_list = snd_list;            nyquist_printf("gcbug_snd_list = 0x%p\n", gcbug_snd_list);        }        if (!snd_list->block) return 0;        snd_list = snd_list->u.next;    }    if (snd_list->block) return (long) snd_list->block;    else return 0;}#endif/*****************************************************************************                               snd_list_create* Inputs:*       snd_susp_type susp: A reference to the suspension* Result: snd_list_type*       A newly-created sound list type* Effect: *       Allocates and initializes a snd_list node:*         block    refcnt  block_len susp  logically_stopped*       +--------+--------+-------+-------+---+*       |////////|   1    |   0   | susp  | F |*       +--------+--------+-------+-------+---+****************************************************************************//* snd_list_create -- alloc and initialize a snd_list node *//**/snd_list_type snd_list_create(snd_susp_type susp){    snd_list_type snd_list;    falloc_snd_list(snd_list, "snd_list_create");    snd_list->block = NULL;             /* no block of samples */    snd_list->u.susp = susp;            /* point to suspension */    snd_list->refcnt = 1;               /* one ref */    snd_list->block_len = 0;            /* no samples */    snd_list->logically_stopped = false;/* not stopped *//*    nyquist_printf("snd_list_create => %p\n", snd_list);*/    return snd_list;}/*****************************************************************************                                sound_create* Inputs:*       snd_susp_type susp: The suspension block to be used for this sound*       time_type t0: The initial time for this sound*       rate_type sr: The sampling rate for this sound*       sample_type scale: The scaling factor for this sound*       sample_block_type (*proc)(...): The get_next_sound method* Result: sound_type*       * Effect: *       Creates and initializes a sound type* Notes:*       The MSDOS conditional is actually a test for ANSI headers; the*       presence of float parameters means that an ANSI prototype and*       a non-ANSI header are incompatible.  Better solution would be*       to ANSIfy source.****************************************************************************/sound_type last_sound = NULL;sound_type sound_create(  snd_susp_type susp,  time_type t0,  rate_type sr,  promoted_sample_type scale){    sound_type sound;    falloc_sound(sound, "sound_create");    if (((long) sound) & 3) errputstr("sound not word aligned\n");    last_sound = sound; /* debug */    /* nyquist_printf("sound_create %p gets %g\n", sound, t0); */    sound->t0 = t0;    sound->time = t0;    sound->stop = MAX_STOP;    sound->sr = sr;    sound->current = 0;    sound->scale = (float) scale;    sound->list = snd_list_create(susp);    sound->get_next = SND_get_first;    sound->logical_stop_cnt = UNKNOWN;    sound->table = NULL;    sound->extra = NULL;    /* nyquist_printf("sound_create susp %p snd_list %p\n", susp, sound->list);       nyquist_printf("sound_create'd %p\n", sound); */#ifdef SNAPSHOTS    sound_created_flag = true;#endif#ifdef GC_DEBUG    if (sound == sound_to_watch) {        nyquist_printf("Created watched sound\n");        watch_snd_list(sound->list);    }#endif    return sound;}/* sound_prepend_zeros -- modify sound_type so that it starts at t0 *//* * assumes t0 is earlier than snd->t0, so the sound should return zeros * until snd->t0 is reached, after which we revert to normal computation. * When we return, the new snd->t0 will be t0, meaning that the first * sample returned will be at time t0. * NOTE: t0 may not be an exact multiple of samples earlier than snd->t0, * but Nyquist allows any sound to be shifted by +/- 0.5 samples in  * order to achieve alignment.  Since sound_prepend_zeros can be called * many times on the same sound_type, there is a chance that rounding  * errors could accumulate.  My first solution was to return with  * snd->t0 computed exactly and not reflecting any fractional sample  * shift of the signal, but this caused problems for the caller: a  * fractional sample shift at a low sample rate could correspond to  * many client samples,fooling the client into thinking that some  * initial samples should be discarded (or else requiring the client * to be pretty smart).  The solution used here is to return to the * client with snd->t0 exactly equal to t0, but to save snd->true_t0 * equal to the time of the first sample with no sound shifting.  This * time is used for any future sound_prepend_zeros operations so that * any accumulated rounding errors are due only to floating point  * precision and not to accumulated fractional sample shifts of snd. */void sound_prepend_zeros(sound_type snd, time_type t0){    long n;    /* first, see if we're already prepending some zeros */    if (snd->get_next != SND_get_zeros) {/*        nyquist_printf("sound_prepend_zeros 1: snd->t0 %g t0 %g\n", snd->t0,  t0); */        /* if not, then initialize some fields that support prepending */        snd->prepend_cnt = 0;        snd->true_t0 = snd->t0;        /* save old get_next and plug in special get_next function */        snd->after_prepend = snd->get_next;        snd->get_next = SND_get_zeros;    }    n = (long) (((snd->true_t0 - t0) * snd->sr) + 0.5); /* how many samples to prepend */    /* add to prepend_cnt so first sample will correspond to new t0 */    snd->prepend_cnt += n;    /* compute the true t0 which corresponds to the time of first sample */    snd->true_t0 -= (n / snd->sr);    /* make caller happy by claiming the sound now starts at exactly t0;     * this is always true within 0.5 samples as allowed by Fugue. */    snd->t0 = t0;/*    nyquist_printf("sound_prepend_zeros: snd %p true_t0 %g sr %g n %d\n",            snd, snd->true_t0, snd->sr, n);*/}/* sound_array_copy -- copy an array of sounds *//* * NOTE: be sure to protect the result from gc! */LVAL sound_array_copy(LVAL sa){    long i = getsize(sa);    LVAL new_sa = newvector(i);    xlprot1(new_sa);    while (i > 0) {        i--;        setelement(new_sa, i,                    cvsound(sound_copy(getsound(getelement(sa, i)))));    }    xlpop();    return new_sa;}/* sound_copy - copy a sound structure, do reference counts *//**/sound_type sound_copy(sound_type snd){    sound_type sndcopy;    falloc_sound(sndcopy, "sound_copy");    *sndcopy = *snd;    /* copy the whole structure */    snd_list_ref(snd->list);    /* copied a reference so fix the count *//*    nyquist_printf("sound_copy'd %p to %p\n", snd, sndcopy); */    if (snd->table) snd->table->refcount++;#ifdef GC_DEBUG    if (sndcopy == sound_to_watch) abort();#endif    return sndcopy;}/* convert a sound to a wavetable, set length *//**/table_type sound_to_table(sound_type s){    long len = snd_length(s, max_table_len);    long tx = 0;        /* table index */    long blocklen;    register double scale_factor = s->scale;    sound_type original_s = s;    table_type table; /* the new table */    long table_bytes; /* how big is the table */    if (s->table) {        s->table->refcount++;        return s->table;    }    if (len >= max_table_len) {        char emsg[100];        sprintf(emsg, "maximum table size (%d) exceeded", max_table_len);        xlcerror("use truncated sound for table", emsg, NIL);    } else if (len == 0) {        xlabort("table size must be greater than 0");    }    len++;      /* allocate extra sample at end of table */    s = sound_copy(s);    /* nyquist_printf("sound_to_table: allocating table of size %d\n", len); */    table_bytes = table_size_in_bytes(len);    table = (table_type) malloc(table_bytes);    if (!table) xlfail("osc_init couldn't allocate memory for table");    table_memory += table_bytes;    table->length = (double) (len - 1);    while (len > 1) {        sample_block_type sampblock = sound_get_next(s, &blocklen);        long togo = MIN(blocklen, len);        long i;        sample_block_values_type sbufp = sampblock->samples;/*      nyquist_printf("in sound_to_table, sampblock = %d\n", sampblock);*/        for (i = 0; i < togo; i++) {            table->samples[tx++] = (float) (*sbufp++ * scale_factor);        }        len -= togo;    }    /* for interpolation, duplicate first sample at end of table */    table->samples[tx] = table->samples[0];    table->refcount = 2;    /* one for the user, one from original_s */    sound_unref(s);    s = NULL;    original_s->table = table;    return table;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -