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

📄 sound.c

📁 Audacity是一款用於錄音和編輯聲音的、免費的開放源碼軟體。它可以執行於Mac OS X、Microsoft Windows、GNU/Linux和其它作業系統
💻 C
📖 第 1 页 / 共 4 页
字号:
 * blocks normally from then on. */sample_block_type SND_flush(sound_type snd, long * cnt){    long mycnt;    sample_block_type block = SND_get_first(snd, &mycnt);    while (snd->current < 0) {        block = SND_get_next(snd, &mycnt);    }    /* at this point, we've read to and including the block with     * the first samples we want to return.  If the block boundary     * is in the right place, we can do a minimal fixup and return:     */    if (snd->current == snd->list->block_len) {        *cnt = snd->current; /* == snd->list->block_len */        /* snd->get_next = SND_get_next; -- done by SND_get_first */        return block;    } else /* snd->current < snd->list->block_len */ {        long i;        sample_block_values_type from_ptr;        /* we have to return a partial block */        /* NOTE: if we had been smart, we would have had SND_get_next         * return a pointer to samples rather than a pointer to the         * block, which has a reference count.  Since the caller         * expects a pointer to a reference count, we have to copy         * snd->current samples to a new block         */        snd_list_type snd_list = snd_list_create((snd_susp_type) snd->list->u.next);        snd_list->u.next->refcnt++;        falloc_sample_block(snd_list->block, "SND_flush");        /* now copy samples */        from_ptr = block->samples + snd->list->block_len - snd->current;        for (i = 0; i < snd->current; i++) {            snd_list->block->samples[i] = from_ptr[i];        }        snd_list_unref(snd->list);        snd->list = snd_list;        *cnt = snd->current;        return snd_list->block;    }}/* SND_get_zeros -- the get_next function for prepended zeros *//* * when prepending zeros, we just return a pointer to the internal_zero_block * and decrement the prepend_cnt until it goes to zero.  Then we revert to  * the normal (original) get_next function. * */sample_block_type SND_get_zeros(sound_type snd, long * cnt){    int len = MIN(snd->prepend_cnt, max_sample_block_len);    /* stdputstr("SND_get_zeros: "); */    if (len < 0) {        char error[80];        sprintf(error, "SND_get_zeros snd %p len %d", snd, len);        xlabort(error);    }    if (len == 0) { /* we've finished prepending zeros */        snd->get_next = snd->after_prepend;        /* stdputstr("done, calling sound_get_next\n"); fflush(stdout); */        return sound_get_next(snd, cnt);    } else {        *cnt = len;        snd->current += len;        snd->prepend_cnt -= len;/*        nyquist_printf("returning internal_zero_block@%p\n", internal_zero_block);        fflush(stdout); */        return internal_zero_block;    }}/*****************************************************************************                                SND_get_next* Inputs:*       sound_type snd: The iterator whose next block is to be computed*       int * cnt: Place to put count of samples returned* Result: snd_list_type*       Pointer to the sample block computed ---------------------------+* Effect:                                                               |*       force suspension to compute next block of samples               |*                                                                       |*  Here's the protocol for using this and related functions:            |*  Every client (sample reader) has a private sound_type (an iterator), |*  and the sound_type's 'list' field points to a header (of type        |*  snd_list_type).  The header in turn points to a block of samples.    |*                                                                       |*                               +---------------------------------------+*                               |*                               |*                               |            sample_block_type*       (snd)                   V            +---+--+--+--+--+--+--+-...-+--+*       sound_type:        snd_list_type +-->|ref|  |  |  |  |//|//|     |//|*       +---------+        +----------+  |   +---+--+--+--+--+--+--+-...-+--+*       | list    +------->| block    +--+                 ^*       +---------+        +----------+                    :*       |  t0     |        | block_len|....................:*       +---------+        +----------+*       |  sr     |        | refcnt   |*       +---------+        +-+--------+*       | current |        | next   +---->...         Note: the union u*       +---------+        |u|........| snd_list_type    points to only one*       | rate    |        | | susp   +---->...          of the indicated*       +---------+        +-+--------+ susp_type        types*       | scalse  |        |log_stop  |*       +---------+        +----------+*       | lsc     |*       +---------+*       |get_next +-----> SND_get_next()*       +---------+**  The sound_type keeps track of where the next sample block will *  come from.  The field 'current' is the number of the first sample of*  the next block to be returned, where sample numbers start*  at zero.  The normal fetch procedure is this one, although special*  cases may generate special block generators, e.g., CONST does not need*  to allocate and refill a block and can reuse the same block over and*  over again, so it may have its own fetch procedure.  This is the*  general fetch procedure, which assumes that the generator function*  actually produces a slightly different value for each sample.**  The distinguishing characteristic of whether the 'u' field is to be*  interpreted as 'next', a link to the next list element, or 'susp', a*  reference to the suspension for generating a new sample block, is*  whether the 'block' parameter is NULL or not.  If it is NULL, then*  u.susp tells how to generate the block; if it is not NULL, u.next is*  a pointer to the next sound block in the list.**  When the 'block' pointer is NULL, we create a block of samples, and*  create a new sound list element which follows it which has a NULL*  'block' pointer; the 'u' field of the current list element is now*  interpreted as 'u.next'.**      The client calls SND_get_next to get a pointer to a block of samples.*      The count of samples generated is returned via a ref parameter, and*      SND_get_next will not be called again until this set is exhausted.**      The next time SND_get_next is called, it knows that the sample block*      has been exhausted.  It releases its reference to the block (and if*      that was the last reference, frees the block to the block allocation*      pool), allocates a new block from the block pool, and proceeds to*      fill it with samples.**      Note that as an optimization, if the refcnt field goes to 0 it*      could immediately re-use the block without freeing back to the block*      pool and reallocating it.**  Because of the way we handle sound sample blocks, the sound sample blocks*  themselves are ref-counted, so freeing the snd_list_type may not free*  the sample block it references.  At the level of this procedure, that*  is transparently handled by the snd_list_unref function.**  Logical stop:**  Logical stop is handled by several mechanisms.  The /intrinsic/ logical*  stop is an immutable property of the signal, and is determined by the*  specification in the algorithm description file.  When it is encountered,*  the 'logically_stopped' flag of the snd_list_node is set.*  The generators guarantee that the first time this is encountered, it*  will always be constructed so that the first sample of the block it*  references is the logical stop time.**  In addition, the client may have set the /explicit logical stop time/ of*  the iterator (e.g., in nyquist, the (set-logical-stop sound time) call copies*  the sound, altering its logical stop).  The logical stop time, when set*  in this way, causes the logical_stop_cnt ('lsc' in the above diagram)*  to be set to the count of the last sample to be generated before the*  <logical stop time.  This will guarantee that the sound will indicate that*  it has reached its logical stop time when the indicated sample is *  generated.****************************************************************************/void add_s1_s2_nn_fetch(); /* for debugging *//* SND_get_first -- the standard fn to get a block, after returning  *    the first block, plug in SND_get_next for successive blocks */sample_block_type SND_get_first(sound_type snd, long * cnt){    register snd_list_type snd_list = snd->list;    /*     * If there is not a block of samples, we need to generate one.     */    if (snd_list->block == NULL) {        /*         * Call the 'fetch' method for this sound_type to generate          * a new block of samples.         */        snd_susp_type susp = snd_list->u.susp;        snd_list->u.next = snd_list_create(susp);        snd_list->block = internal_zero_block;        /* nyquist_printf("SND_get_first: susp->fetch %p\n",                susp->fetch); */        (*(susp->fetch))(susp, snd_list);#ifdef GC_DEBUG        snd_list_debug(snd_list, "SND_get_first");#endif        /* nyquist_printf("SND_get_first: snd_list %p, block %p, length %d\n",               snd_list, snd_list->block, snd_list->block_len); */    }    if ((snd->logical_stop_cnt == UNKNOWN) && snd_list->logically_stopped) {        /* nyquist_printf("SND_get_first/next: snd %p logically stopped at %d\n",                snd, snd->current); */        snd->logical_stop_cnt = snd->current;    }    /* see if clipping needs to be applied */    if (snd->current + snd_list->block_len > snd->stop) {        /* need to clip: is clip on a block boundary? */        if (snd->current == snd->stop) {            /* block boundary: replace with zero sound */            snd->list = zero_snd_list;            snd_list_unref(snd_list);        } else {            /* not a block boundary: build new list */            snd->list = snd_list_create((snd_susp_type) zero_snd_list);            snd->list->block_len = (short) (snd->stop - snd->current);            snd->list->block = snd_list->block;            snd->list->block->refcnt++;            snd_list_unref(snd_list);        }        snd_list = snd->list; /* used below to return block ptr */    }    *cnt = snd_list->block_len;    /* this should never happen */    if (*cnt == 0) {        stdputstr("SND_get_first returned 0 samples\n");        dbg_mem_print("snd_list info:", snd_list);        dbg_mem_print("block info:", snd_list->block);        sound_print_tree(snd);        stdputstr("It is possible that you created a recursive sound\n");        stdputstr("using something like: (SETF X (SEQ (SOUND X) ...))\n");        stdputstr("Nyquist aborts from non-recoverable error\n");        abort();    }    snd->current += snd_list->block_len;    /* count how many we read */    snd->get_next = SND_get_next;    return snd_list->block;}sample_block_type SND_get_next(sound_type snd, long * cnt){    register snd_list_type snd_list = snd->list;    /*     * SND_get_next is installed by SND_get_first, so we know     * when we are called that we are done with the current block     * of samples, so free it now.     */    snd_list_type cur = snd_list;    snd->list = snd_list = cur->u.next;    snd_list_ref(snd_list);    snd_list_unref(cur);  /* release the reference to the current block */    /* now that we've deallocated, we can use SND_get_first to finish the job */    return SND_get_first(snd, cnt);}/*****************************************************************************                               make_zero_block* Inputs:*       * Result: *       * Effect: *       ****************************************************************************/sample_block_type make_zero_block(void)    {     sample_block_type zb;     int i;     falloc_sample_block(zb, "make_zero_block");     /* leave room for lots more references before overflow,         but set the count high so that even a large number of        dereferences will not lead to a deallocation */     zb->refcnt = 0x6FFFFFFF;     for (i = 0; i < max_sample_block_len; i++)         { /* fill with zeros */         zb->samples[i] = 0.0F;        } /* fill with zeros */     return zb;    }/* min_cnt -- help compute the logical stop or terminate as minimum *//* * take the sound (which has just logically stopped or terminated at * current sample) and * convert the stop sample into the equivalent sample count as produced by * susp (which may have a different sample rate).  If the count is less than * the current *cnt_ptr, overwrite cnt_ptr with a new minimum.  By calling * this when each of S1, S2, ... Sn reach their logical stop or termiate * points, *cnt_ptr will end up with the minimum stop count, which is what * we want.  NOTE: the logical stop time and terminate for signal addition  * should be the MAX of logical stop times of arguments, so this routine  * would not be used. */void min_cnt(long *cnt_ptr, sound_type sound, snd_susp_type susp, long cnt){    long c = (long) ((((sound->current - cnt) / sound->sr + sound->t0) - susp->t0) *      susp->sr + 0.5);    /* if *cnt_ptr is uninitialized, just plug in c, otherwise compute min */    if ((*cnt_ptr == UNKNOWN) || (*cnt_ptr > c)) {/*        nyquist_printf("min_cnt %p: new count is %d\n", susp, c);*//*        if (c == 0) sound_print_tree(printing_this_sound);*/        *cnt_ptr = c;    }}/*****************************************************************************                                 sound_init* Result: void*       * Effect: *       Module initialization*       Allocates the 'zero block', the infinitely linked block of*       0-valued sounds.  This is referenced by a list element which*       refers to itself.****************************************************************************/void sound_init(void){    zero_block = make_zero_block();    internal_zero_block = make_zero_block();    falloc_snd_list(zero_snd_list, "sound_init");    zero_snd_list->block = zero_block;    zero_snd_list->u.next = zero_snd_list;    zero_snd_list->refcnt = 2;    zero_snd_list->block_len = max_sample_block_len;    zero_snd_list->logically_stopped = true;#ifdef GC_DEBUG    { long s;      stdputstr("sound_to_watch: ");      scanf("%p", &s);      watch_sound(s);    }#endif   sound_desc = create_desc("SOUND", sound_xlfree, sound_xlprint,                            sound_xlsave, sound_xlrestore, sound_xlmark);}/* sound_scale -- copy and change scale factor of a sound *//**/sound_type sound_scale(double factor, sound_type snd){    sound_type sndcopy = sound_copy(snd);    sndcopy->scale *= (float) factor;    return sndcopy;}/*****************************************************************************                            set_logical_stop_time* Inputs:*       sound_type sound: The sound for which the logical stop time is*                         being set*       time_type  when:  The logical stop time, expressed as an absolute*                         time.* Result: void*       * Effect: *       Converts the time 'when' into a count of samples.****************************************************************************/void set_logical_stop_time(sound_type sound, time_type when)    {     long n;     /*        'when' is an absolute time.  The number of samples to        be generated is the number of samples between 't0' and        'when'.        -----------+---+---+---+---+---+---+---+---+---+                   |                                |                   t0                               when     */     n = (long) ((when - sound->t0) * sound->sr + 0.5);     /*      * n is kept as a local variable for debugging purposes.      */     sound->logical_stop_cnt = n; }/* for debugging */sound_type printing_this_sound = NULL;void ((**watch_me)()) = NULL;void set_watch(where)  void ((**where)());{    if (watch_me == NULL) {        watch_me = where;        nyquist_printf("set_watch: watch_me = %p\n", watch_me);

⌨️ 快捷键说明

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