1 /* inverse.c -- compute the inverse of a sampled function */
2
3 /* CHANGE LOG
4 * --------------------------------------------------------------------
5 * 28Apr03 dm changes for portability and fix compiler warnings
6 */
7
8
9 #include "stdio.h"
10 #ifndef mips
11 #include "stdlib.h"
12 #endif
13 #include "xlisp.h"
14 #include "sound.h"
15 #include "cext.h"
16
17 #include "falloc.h"
18 #include "inverse.h"
19
20 void inverse_free(snd_susp_type a_susp);
21
22
23 typedef struct inverse_susp_struct {
24 snd_susp_node susp;
25 int64_t terminate_cnt;
26 boolean logically_stopped;
27 sound_type s;
28 int s_cnt;
29 sample_block_values_type s_ptr;
30 double s_prev;
31 double s_time;
32 double s_time_increment;
33 double out_time_increment;
34 boolean started;
35 } inverse_susp_node, *inverse_susp_type;
36
inverse_fetch(snd_susp_type a_susp,snd_list_type snd_list)37 void inverse_fetch(snd_susp_type a_susp, snd_list_type snd_list)
38 {
39 inverse_susp_type susp = (inverse_susp_type) a_susp;
40 int cnt = 0; /* how many samples read from s */
41 int out_cnt = 0; /* how many samples output */
42 int togo = 0; /* how many more to read from s in inner loop */
43 int n;
44 sample_block_type out;
45 double out_time = susp->susp.current * susp->out_time_increment;
46
47 register sample_block_values_type out_ptr;
48
49 register sample_block_values_type s_ptr_reg;
50 falloc_sample_block(out, "inverse_fetch");
51 out_ptr = out->samples;
52 snd_list->block = out;
53
54 /* make sure we are primed with first value */
55 /* This is a lot of work just to prefetch susp->s_prev! */
56 if (!susp->started) {
57 susp->started = true;
58 /* see comments below about susp_check_term_log_samples() */
59 if (susp->s_cnt == 0) {
60 susp_get_samples(s, s_ptr, s_cnt);
61 if (susp->s_ptr == zero_block->samples) {
62 susp->terminate_cnt = susp->susp.current;
63 }
64 }
65 susp->s_prev = susp_fetch_sample(s, s_ptr, s_cnt);
66 }
67
68 while (out_cnt < max_sample_block_len) { /* outer loop */
69 /* first compute how many samples to generate in inner loop: */
70 /* don't run past the s input sample block: */
71 /* most fetch routines call susp_check_term_log_samples() here
72 * but we can't becasue susp_check_term_log_samples() assumes
73 * that output time progresses at the same rate as input time.
74 * Here, some time warping is going on, so this doesn't work.
75 * Instead, check for termination of s and fix terminate_cnt to
76 * be the current output count rather than the current input time.
77 */
78 if (susp->s_cnt == 0) {
79 susp_get_samples(s, s_ptr, s_cnt);
80 if (susp->s_ptr == zero_block->samples) {
81 susp->terminate_cnt = susp->susp.current + out_cnt;
82 /* we can't simply terminate here because we might have
83 * some output samples computed already, in which case we
84 * want to return them now and terminate the NEXT time we're
85 * called.
86 */
87 }
88 }
89 togo = susp->s_cnt;
90
91 /* if we ran past terminate time, fix up output */
92 if (susp->terminate_cnt != UNKNOWN &&
93 susp->terminate_cnt <= susp->susp.current + out_cnt) {
94 /* pretend like we computed the correct number of samples */
95 togo = 0;
96 out_cnt = (long) (susp->terminate_cnt - susp->susp.current);
97 /* exit the loop to complete the termination */
98 break;
99 }
100 n = togo;
101 s_ptr_reg = susp->s_ptr;
102 if (n) do { /* the inner sample computation loop */
103 /* scan s_ptr_reg to time t, output and loop */
104 register double next_value = *s_ptr_reg++;
105 while (out_time < next_value) {
106 *out_ptr++ = (float) (susp->s_time +
107 (out_time - susp->s_prev) /
108 (susp->s->sr * (next_value - susp->s_prev)));
109 out_time += susp->out_time_increment;
110 if (++out_cnt >= max_sample_block_len) goto output_full;
111 }
112 susp->s_prev = next_value;
113 susp->s_time += susp->s_time_increment;
114 } while (--n); /* inner loop */
115 output_full:
116 /* using s_ptr_reg is a bad idea on RS/6000: */
117 susp->s_ptr += (togo - n);
118 susp_took(s_cnt, (togo - n));
119 cnt += (togo - n);
120 } /* outer loop */
121
122 /* test for termination */
123 if (togo == 0 && out_cnt == 0) {
124 snd_list_terminate(snd_list);
125 } else {
126 snd_list->block_len = out_cnt;
127 susp->susp.current += out_cnt;
128 }
129 } /* inverse_fetch */
130
131
inverse_toss_fetch(snd_susp_type a_susp,snd_list_type snd_list)132 void inverse_toss_fetch(snd_susp_type a_susp, snd_list_type snd_list)
133 {
134 inverse_susp_type susp = (inverse_susp_type) a_susp;
135 int64_t final_count = MIN(susp->susp.current + max_sample_block_len,
136 susp->susp.toss_cnt);
137 time_type final_time = susp->susp.t0 + final_count / susp->susp.sr;
138 long n;
139
140 /* fetch samples from s up to final_time for this block of zeros */
141 while (((long) ((final_time - susp->s->t0) * susp->s->sr + 0.5)) >=
142 susp->s->current)
143 susp_get_samples(s, s_ptr, s_cnt);
144 /* convert to normal processing when we hit final_count */
145 /* we want each signal positioned at final_time */
146 if (final_count == susp->susp.toss_cnt) {
147 n = (long) ROUNDBIG((final_time - susp->s->t0) * susp->s->sr -
148 (susp->s->current - susp->s_cnt));
149 susp->s_ptr += n;
150 susp_took(s_cnt, n);
151 susp->susp.fetch = susp->susp.keep_fetch;
152 }
153 snd_list->block_len = (short) (final_count - susp->susp.current);
154 susp->susp.current = final_count;
155 snd_list->u.next = snd_list_create((snd_susp_type) susp);
156 snd_list->block = internal_zero_block;
157 }
158
159
inverse_mark(snd_susp_type a_susp)160 void inverse_mark(snd_susp_type a_susp)
161 {
162 inverse_susp_type susp = (inverse_susp_type) a_susp;
163 sound_xlmark(susp->s);
164 }
165
166
inverse_free(snd_susp_type a_susp)167 void inverse_free(snd_susp_type a_susp)
168 {
169 inverse_susp_type susp = (inverse_susp_type) a_susp;
170 sound_unref(susp->s);
171 ffree_generic(susp, sizeof(inverse_susp_node), "inverse_free");
172 }
173
174
inverse_print_tree(snd_susp_type a_susp,int n)175 void inverse_print_tree(snd_susp_type a_susp, int n)
176 {
177 inverse_susp_type susp = (inverse_susp_type) a_susp;
178 indent(n);
179 stdputstr("s:");
180 sound_print_tree_1(susp->s, n);
181 }
182
183
snd_make_inverse(sound_type s,time_type t0,rate_type sr)184 sound_type snd_make_inverse(sound_type s, time_type t0, rate_type sr)
185 {
186 register inverse_susp_type susp;
187
188 falloc_generic(susp, inverse_susp_node, "snd_make_inverse");
189 susp->susp.fetch = inverse_fetch;
190 susp->terminate_cnt = UNKNOWN;
191
192 /* initialize susp state */
193 susp->susp.free = inverse_free;
194 susp->susp.sr = sr;
195 susp->susp.t0 = t0;
196 susp->susp.mark = inverse_mark;
197 susp->susp.print_tree = inverse_print_tree;
198 susp->susp.name = "inverse";
199 susp->logically_stopped = false;
200 susp->susp.log_stop_cnt = UNKNOWN; /* log stop time = term time */
201 susp->susp.current = 0;
202 susp->s = s;
203 susp->s_cnt = 0;
204 susp->s_prev = 0;
205 susp->s_time = 0;
206 susp->s_time_increment = 1 / s->sr;
207 susp->out_time_increment = 1 / (sr * s->scale);
208 susp->started = false;
209 return sound_create((snd_susp_type)susp, t0, sr, 1.0 /* scale */);
210 }
211
212
snd_inverse(sound_type s,time_type t0,rate_type sr)213 sound_type snd_inverse(sound_type s, time_type t0, rate_type sr)
214 {
215 sound_type s_copy = sound_copy(s);
216 return snd_make_inverse(s_copy, t0, sr);
217 }
218