File: pvshell.c

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 (206 lines) | stat: -rw-r--r-- 6,446 bytes parent folder | download | duplicates (2)
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
// pvshell.c -- This is a skeleton for a Nyquist primitive that
//   returns a sound. The sound is obtained by calling a function
//   with a request consisting of a location to put samples and
//   a count of how many samples are needed. The function returns
//   the actual number of samples computed and flags indicating
//   if the signal has reached the logical stop or termination.
//     In addition, there are interfaces for extracting samples
//   from input sounds. 
//     This code is designed for a time-stretching phase vocoder,
//   but could be used for other purposes. It is derived from
//   compose.c, which might have been implmented with this 
//   skeleton had we started out with this abstraction.

#include "stdio.h"
#ifndef mips
#include "stdlib.h"
#endif
#include "xlisp.h"
#include "sound.h"

#include "falloc.h"
#include "cext.h"
#include "pvshell.h"
#include "assert.h"

/* CHANGE LOG
 * --------------------------------------------------------------------
 * 28Apr03  dm  changes for portability and fix compiler warnings
 */

void pvshell_free();


typedef struct pvshell_susp_struct {
    snd_susp_node susp;
    long terminate_cnt;
    boolean logically_stopped;
    boolean started;

    pvshell_node pvshell;
} pvshell_susp_node, *pvshell_susp_type;


/* pvshell_test_f -- get next sample block and check flags
 *
 * Only call this from PVSHELL_TEST_F macro
 */
long pvshell_test_f(pvshell_type susp)
{
    long flags = 0;
    susp_get_samples(f, f_ptr, f_cnt); /* warning: macro references susp */
    if (susp->f->logical_stop_cnt == susp->f->current - susp->f_cnt) {
        flags |= PVSHELL_FLAG_LOGICAL_STOP;
    }
    if (susp->f_ptr == zero_block->samples) {
        flags |= PVSHELL_FLAG_TERMINATE;
    }
    return flags;
}


/* pvshell_test_g -- get next sample block and check flags
 *
 * Only call this from PVSHELL_TEST_G macro
 */
long pvshell_test_g(pvshell_type susp)
{
    long flags = 0;
    susp_get_samples(g, g_ptr, g_cnt); /* warning: macro references susp */
    if (susp->g->logical_stop_cnt == susp->g->current - susp->g_cnt) {
        flags |= PVSHELL_FLAG_LOGICAL_STOP;
    }
    if (susp->g_ptr == zero_block->samples) {
        flags |= PVSHELL_FLAG_TERMINATE;
    }
    return flags;
}


/* pvshell_fetch -- computes h(f, g, x, y) where f and g are 
 *  sounds, x and y are doubles, and h implemented via a function 
 *  pointer. This could certainly be generalized further, but 
 *  maybe we should take this one step at a time.
 */
void pvshell_fetch(snd_susp_type a_susp, snd_list_type snd_list)
{
    pvshell_susp_type susp = (pvshell_susp_type) a_susp;
    long n, flags;
    sample_block_type out;
    sample_block_values_type out_ptr;

    falloc_sample_block(out, "pvshell_fetch");
    out_ptr = out->samples;
    snd_list->block = out;

    /* don't run past the f input sample block: */
    /* most fetch routines call susp_check_term_log_samples() here
     * but we can't becasue susp_check_term_log_samples() assumes
     * that output time progresses at the same rate as input time.
     * Here, some time warping might be going on, so this doesn't work.
     * It is up to the user to tell us when it is the logical stop
     * time and the terminate time.
     */
    /* don't run past terminate time */
    //        if (susp->terminate_cnt != UNKNOWN &&
    //            susp->terminate_cnt <= susp->susp.current + cnt + togo) {
    //            togo = susp->terminate_cnt - (susp->susp.current + cnt);
    //            if (togo == 0) break;
    //        }
    /* don't run past logical stop time */
    //        if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) {
    //            int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt);
    //            if (to_stop < togo && ((togo = to_stop) == 0)) break;
    //        }
    n = max_sample_block_len; // ideally, compute a whole block of samples

    flags = (susp->pvshell.h)(&(susp->pvshell), out_ptr, &n);

    /* test for termination */
    if (flags & PVSHELL_FLAG_TERMINATE) {
        snd_list_terminate(snd_list);
    } else {
        snd_list->block_len = n;
        susp->susp.current += n;
    }
    /* test for logical stop */
    if (flags & PVSHELL_FLAG_LOGICAL_STOP || susp->logically_stopped) {
        snd_list->logically_stopped = true;
        susp->logically_stopped = true;
    }
} /* pvshell_fetch */


void pvshell_mark(snd_susp_type a_susp)
{
    pvshell_susp_type susp = (pvshell_susp_type) a_susp;
    sound_xlmark(susp->pvshell.f);
    sound_xlmark(susp->pvshell.g);
}


void pvshell_free(snd_susp_type a_susp)
{
    pvshell_susp_type susp = (pvshell_susp_type) a_susp;
    /* note that f or g can be NULL */
    sound_unref(susp->pvshell.f);
    sound_unref(susp->pvshell.g);
    ffree_generic(susp, sizeof(pvshell_susp_node), "pvshell_free");
}


void pvshell_print_tree(snd_susp_type a_susp, int n)
{
    pvshell_susp_type susp = (pvshell_susp_type) a_susp;
    indent(n);
    stdputstr("f:");
    sound_print_tree_1(susp->pvshell.f, n);

    indent(n);
    stdputstr("g:");
    sound_print_tree_1(susp->pvshell.g, n);
}


sound_type snd_make_pvshell(char *name, rate_type sr, time_type t0,
                            h_fn_type h, sound_type f, sound_type g, 
                            double *state, long n)
{
    register pvshell_susp_type susp;
    int i;

    falloc_generic(susp, pvshell_susp_node, "snd_make_pvshell");
    susp->susp.fetch = pvshell_fetch;
    susp->terminate_cnt = UNKNOWN;

    /* initialize susp state */
    susp->susp.free = pvshell_free;
    susp->susp.sr = sr;
    susp->susp.t0 = t0;
    susp->susp.mark = pvshell_mark;
    susp->susp.print_tree = pvshell_print_tree;
    susp->susp.name = name;
    susp->logically_stopped = false;
    susp->susp.log_stop_cnt = UNKNOWN;
    susp->susp.current = 0;

    /* copy the sound so that we have a private "reader" object */
    susp->pvshell.f = (f ? sound_copy(f) : f);
    susp->pvshell.f_cnt = 0;

    susp->pvshell.g = (g ? sound_copy(g) : g);
    susp->pvshell.g_cnt = 0;
    
    susp->pvshell.h = h;

    susp->pvshell.flags = 0; /* terminated and logically stopped flags -- these
                                are for the client of pvshell to use */

    assert(n <= PVSHELL_STATE_MAX);
    for (i = 0; i < n; i++) {
        susp->pvshell.state[i] = state[i];
    }

    susp->started = false;
    return sound_create((snd_susp_type)susp, t0, sr, 1.0);
}