diff options
Diffstat (limited to 'lib/rbcodec/dsp/tdspeed.c')
-rw-r--r-- | lib/rbcodec/dsp/tdspeed.c | 468 |
1 files changed, 353 insertions, 115 deletions
diff --git a/lib/rbcodec/dsp/tdspeed.c b/lib/rbcodec/dsp/tdspeed.c index c2f4a3f704..3aa8acc458 100644 --- a/lib/rbcodec/dsp/tdspeed.c +++ b/lib/rbcodec/dsp/tdspeed.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * | 9 | * |
10 | * Copyright (C) 2006 by Nicolas Pitre <nico@cam.org> | 10 | * Copyright (C) 2006 by Nicolas Pitre <nico@cam.org> |
11 | * Copyright (C) 2006-2007 by Stéphane Doyon <s.doyon@videotron.ca> | 11 | * Copyright (C) 2006-2007 by Stéphane Doyon <s.doyon@videotron.ca> |
12 | * Copyright (C) 2012 Michael Sevakis | ||
12 | * | 13 | * |
13 | * This program is free software; you can redistribute it and/or | 14 | * This program is free software; you can redistribute it and/or |
14 | * modify it under the terms of the GNU General Public License | 15 | * modify it under the terms of the GNU General Public License |
@@ -19,69 +20,42 @@ | |||
19 | * KIND, either express or implied. | 20 | * KIND, either express or implied. |
20 | * | 21 | * |
21 | ****************************************************************************/ | 22 | ****************************************************************************/ |
22 | 23 | #include "config.h" | |
23 | #include <inttypes.h> | 24 | #include "system.h" |
24 | #include <stddef.h> | ||
25 | #include <stdio.h> | ||
26 | #include <string.h> | ||
27 | #include "sound.h" | 25 | #include "sound.h" |
28 | #include "core_alloc.h" | 26 | #include "core_alloc.h" |
29 | #include "system.h" | 27 | #include "system.h" |
30 | #include "tdspeed.h" | 28 | #include "tdspeed.h" |
31 | #include "settings.h" | 29 | #include "settings.h" |
32 | #include "dsp-util.h" | 30 | #include "dsp-util.h" |
31 | #include "dsp_proc_entry.h" | ||
33 | 32 | ||
34 | #define assert(cond) | 33 | #define assert(cond) |
35 | 34 | ||
35 | #define TIMESTRETCH_SET_FACTOR (DSP_PROC_SETTING+DSP_PROC_TIMESTRETCH) | ||
36 | |||
36 | #define MIN_RATE 8000 | 37 | #define MIN_RATE 8000 |
37 | #define MAX_RATE 48000 /* double buffer for double rate */ | 38 | #define MAX_RATE 48000 /* double buffer for double rate */ |
38 | #define MINFREQ 100 | 39 | #define MINFREQ 100 |
39 | 40 | ||
40 | #define FIXED_BUFSIZE 3072 /* 48KHz factor 3.0 */ | 41 | #define MAX_INPUTCOUNT 512 /* Max input count so dst doesn't overflow */ |
41 | 42 | #define FIXED_BUFCOUNT 3072 /* 48KHz factor 3.0 */ | |
42 | static int32_t** dsp_src; | 43 | #define FIXED_OUTBUFCOUNT 4096 |
43 | static int handles[4]; | ||
44 | static int32_t *overlap_buffer[2] = { NULL, NULL }; | ||
45 | static int32_t *outbuf[2] = { NULL, NULL }; | ||
46 | |||
47 | static int move_callback(int handle, void* current, void* new) | ||
48 | { | ||
49 | /* TODO */ | ||
50 | (void)handle; | ||
51 | if (dsp_src) | ||
52 | { | ||
53 | int ch = (current == outbuf[0]) ? 0 : 1; | ||
54 | dsp_src[ch] = outbuf[ch] = new; | ||
55 | } | ||
56 | return BUFLIB_CB_OK; | ||
57 | } | ||
58 | |||
59 | static struct buflib_callbacks ops = { | ||
60 | .move_callback = move_callback, | ||
61 | .shrink_callback = NULL, | ||
62 | }; | ||
63 | 44 | ||
64 | static int ovl_move_callback(int handle, void* current, void* new) | 45 | enum tdspeed_ops |
65 | { | 46 | { |
66 | /* TODO */ | 47 | TDSOP_PROCESS, |
67 | (void)handle; | 48 | TDSOP_LAST, |
68 | if (dsp_src) | 49 | TDSOP_PURGE, |
69 | { | ||
70 | int ch = (current == overlap_buffer[0]) ? 0 : 1; | ||
71 | overlap_buffer[ch] = new; | ||
72 | } | ||
73 | return BUFLIB_CB_OK; | ||
74 | } | ||
75 | |||
76 | static struct buflib_callbacks ovl_ops = { | ||
77 | .move_callback = ovl_move_callback, | ||
78 | .shrink_callback = NULL, | ||
79 | }; | 50 | }; |
80 | 51 | ||
81 | |||
82 | static struct tdspeed_state_s | 52 | static struct tdspeed_state_s |
83 | { | 53 | { |
84 | bool stereo; | 54 | struct dsp_proc_entry *this; /* this stage */ |
55 | struct dsp_config *dsp; /* the DSP we use */ | ||
56 | unsigned int channels; /* flags parameter to use in call */ | ||
57 | int32_t samplerate; /* current samplerate of input data */ | ||
58 | int32_t factor; /* stretch factor (perdecimille) */ | ||
85 | int32_t shift_max; /* maximum displacement on a frame */ | 59 | int32_t shift_max; /* maximum displacement on a frame */ |
86 | int32_t src_step; /* source window pace */ | 60 | int32_t src_step; /* source window pace */ |
87 | int32_t dst_step; /* destination window pace */ | 61 | int32_t dst_step; /* destination window pace */ |
@@ -89,62 +63,132 @@ static struct tdspeed_state_s | |||
89 | int32_t ovl_shift; /* overlap buffer frame shift */ | 63 | int32_t ovl_shift; /* overlap buffer frame shift */ |
90 | int32_t ovl_size; /* overlap buffer used size */ | 64 | int32_t ovl_size; /* overlap buffer used size */ |
91 | int32_t ovl_space; /* overlap buffer size */ | 65 | int32_t ovl_space; /* overlap buffer size */ |
92 | int32_t *ovl_buff[2]; /* overlap buffer */ | 66 | int32_t *ovl_buff[2]; /* overlap buffer (L+R) */ |
93 | } tdspeed_state; | 67 | } tdspeed_state; |
94 | 68 | ||
95 | void tdspeed_init(void) | 69 | static int handles[4] = { 0, 0, 0, 0 }; |
70 | static int32_t *buffers[4] = { NULL, NULL, NULL, NULL }; | ||
71 | |||
72 | #define overlap_buffer (&buffers[0]) | ||
73 | #define outbuf (&buffers[2]) | ||
74 | #define out_size FIXED_OUTBUFCOUNT | ||
75 | |||
76 | /* Processed buffer passed out to later stages */ | ||
77 | static struct dsp_buffer dsp_outbuf; | ||
78 | |||
79 | static int move_callback(int handle, void *current, void *new) | ||
96 | { | 80 | { |
97 | if (!global_settings.timestretch_enabled) | 81 | #if 0 |
98 | return; | 82 | /* Should not currently need to block this since DSP loop completes an |
83 | iteration before yielding and begins again at its input buffer */ | ||
84 | if (dsp_is_busy(tdspeed_state.dsp)) | ||
85 | return BUFLIB_CB_CANNOT_MOVE; /* DSP processing in progress */ | ||
86 | #endif | ||
99 | 87 | ||
100 | /* Allocate buffers */ | 88 | ptrdiff_t shift = (int32_t *)new - (int32_t *)current; |
101 | if (overlap_buffer[0] == NULL) | 89 | int32_t **p32 = dsp_outbuf.p32; |
90 | |||
91 | for (unsigned int i = 0; i < ARRAYLEN(handles); i++) | ||
102 | { | 92 | { |
103 | handles[0] = core_alloc_ex("tdspeed ovl left", FIXED_BUFSIZE * sizeof(int32_t), &ovl_ops); | 93 | if (handle != handles[i]) |
104 | overlap_buffer[0] = core_get_data(handles[0]); | 94 | continue; |
95 | |||
96 | switch (i) | ||
97 | { | ||
98 | case 0: case 1: | ||
99 | /* moving overlap (input) buffers */ | ||
100 | tdspeed_state.ovl_buff[i] = new; | ||
101 | break; | ||
102 | |||
103 | case 2: | ||
104 | /* moving outbuf left channel and dsp_outbuf.p32[0] */ | ||
105 | if (p32[0] == p32[1]) | ||
106 | p32[1] += shift; /* mono mode */ | ||
107 | |||
108 | p32[0] += shift; | ||
109 | break; | ||
110 | |||
111 | case 3: | ||
112 | /* moving outbuf right channel and dsp_outbuf.p32[1] */ | ||
113 | p32[1] += shift; | ||
114 | break; | ||
115 | } | ||
116 | |||
117 | buffers[i] = new; | ||
118 | break; | ||
105 | } | 119 | } |
106 | if (overlap_buffer[1] == NULL) | 120 | |
121 | return BUFLIB_CB_OK; | ||
122 | } | ||
123 | |||
124 | static struct buflib_callbacks ops = | ||
125 | { | ||
126 | .move_callback = move_callback, | ||
127 | .shrink_callback = NULL, | ||
128 | }; | ||
129 | |||
130 | /* Allocate timestretch buffers */ | ||
131 | static bool tdspeed_alloc_buffers(void) | ||
132 | { | ||
133 | static const struct | ||
107 | { | 134 | { |
108 | handles[1] = core_alloc_ex("tdspeed ovl right", FIXED_BUFSIZE * sizeof(int32_t), &ovl_ops); | 135 | const char *name; |
109 | overlap_buffer[1] = core_get_data(handles[1]); | 136 | size_t size; |
110 | } | 137 | } bufdefs[4] = |
111 | if (outbuf[0] == NULL) | ||
112 | { | 138 | { |
113 | handles[2] = core_alloc_ex("tdspeed left", TDSPEED_OUTBUFSIZE * sizeof(int32_t), &ops); | 139 | { "tdspeed ovl L", FIXED_BUFCOUNT * sizeof(int32_t) }, |
114 | outbuf[0] = core_get_data(handles[2]); | 140 | { "tdspeed ovl R", FIXED_BUFCOUNT * sizeof(int32_t) }, |
115 | } | 141 | { "tdspeed out L", FIXED_OUTBUFCOUNT * sizeof(int32_t) }, |
116 | if (outbuf[1] == NULL) | 142 | { "tdspeed out R", FIXED_OUTBUFCOUNT * sizeof(int32_t) }, |
143 | }; | ||
144 | |||
145 | for (unsigned int i = 0; i < ARRAYLEN(bufdefs); i++) | ||
117 | { | 146 | { |
118 | handles[3] = core_alloc_ex("tdspeed right", TDSPEED_OUTBUFSIZE * sizeof(int32_t), &ops); | 147 | if (handles[i] <= 0) |
119 | outbuf[1] = core_get_data(handles[3]); | 148 | { |
149 | handles[i] = core_alloc_ex(bufdefs[i].name, bufdefs[i].size, &ops); | ||
150 | |||
151 | if (handles[i] <= 0) | ||
152 | return false; | ||
153 | } | ||
154 | |||
155 | if (buffers[i] == NULL) | ||
156 | { | ||
157 | buffers[i] = core_get_data(handles[i]); | ||
158 | |||
159 | if (buffers[i] == NULL) | ||
160 | return false; | ||
161 | } | ||
120 | } | 162 | } |
163 | |||
164 | return true; | ||
121 | } | 165 | } |
122 | 166 | ||
123 | void tdspeed_finish(void) | 167 | /* Free timestretch buffers */ |
168 | static void tdspeed_free_buffers(void) | ||
124 | { | 169 | { |
125 | for(unsigned i = 0; i < ARRAYLEN(handles); i++) | 170 | for (unsigned int i = 0; i < ARRAYLEN(handles); i++) |
126 | { | 171 | { |
127 | if (handles[i] > 0) | 172 | if (handles[i] > 0) |
128 | { | ||
129 | core_free(handles[i]); | 173 | core_free(handles[i]); |
130 | handles[i] = 0; | 174 | |
131 | } | 175 | handles[i] = 0; |
176 | buffers[i] = NULL; | ||
132 | } | 177 | } |
133 | overlap_buffer[0] = overlap_buffer[1] = NULL; | ||
134 | outbuf[0] = outbuf[1] = NULL; | ||
135 | } | 178 | } |
136 | 179 | ||
137 | bool tdspeed_config(int samplerate, bool stereo, int32_t factor) | 180 | /* Discard all data */ |
181 | static void tdspeed_flush(void) | ||
138 | { | 182 | { |
139 | struct tdspeed_state_s *st = &tdspeed_state; | 183 | struct tdspeed_state_s *st = &tdspeed_state; |
140 | int src_frame_sz; | 184 | st->ovl_size = 0; |
141 | 185 | st->ovl_shift = 0; | |
142 | /* Check buffers were allocated ok */ | 186 | dsp_outbuf.remcount = 0; /* Dump remaining output */ |
143 | if (overlap_buffer[0] == NULL || overlap_buffer[1] == NULL) | 187 | } |
144 | return false; | ||
145 | 188 | ||
146 | if (outbuf[0] == NULL || outbuf[1] == NULL) | 189 | static bool tdspeed_update(int32_t samplerate, int32_t factor) |
147 | return false; | 190 | { |
191 | struct tdspeed_state_s *st = &tdspeed_state; | ||
148 | 192 | ||
149 | /* Check parameters */ | 193 | /* Check parameters */ |
150 | if (factor == PITCH_SPEED_100) | 194 | if (factor == PITCH_SPEED_100) |
@@ -156,7 +200,10 @@ bool tdspeed_config(int samplerate, bool stereo, int32_t factor) | |||
156 | if (factor < STRETCH_MIN || factor > STRETCH_MAX) | 200 | if (factor < STRETCH_MIN || factor > STRETCH_MAX) |
157 | return false; | 201 | return false; |
158 | 202 | ||
159 | st->stereo = stereo; | 203 | /* Save parameters we'll need later if format changes */ |
204 | st->samplerate = samplerate; | ||
205 | st->factor = factor; | ||
206 | |||
160 | st->dst_step = samplerate / MINFREQ; | 207 | st->dst_step = samplerate / MINFREQ; |
161 | 208 | ||
162 | if (factor > PITCH_SPEED_100) | 209 | if (factor > PITCH_SPEED_100) |
@@ -171,7 +218,7 @@ bool tdspeed_config(int samplerate, bool stereo, int32_t factor) | |||
171 | st->src_step = st->dst_step * factor / PITCH_SPEED_100; | 218 | st->src_step = st->dst_step * factor / PITCH_SPEED_100; |
172 | st->shift_max = (st->dst_step > st->src_step) ? st->dst_step : st->src_step; | 219 | st->shift_max = (st->dst_step > st->src_step) ? st->dst_step : st->src_step; |
173 | 220 | ||
174 | src_frame_sz = st->shift_max + st->dst_step; | 221 | int src_frame_sz = st->shift_max + st->dst_step; |
175 | 222 | ||
176 | if (st->dst_step > st->src_step) | 223 | if (st->dst_step > st->src_step) |
177 | src_frame_sz += st->dst_step - st->src_step; | 224 | src_frame_sz += st->dst_step - st->src_step; |
@@ -182,32 +229,27 @@ bool tdspeed_config(int samplerate, bool stereo, int32_t factor) | |||
182 | if (st->src_step > st->dst_step) | 229 | if (st->src_step > st->dst_step) |
183 | st->ovl_space += 2*st->src_step - st->dst_step; | 230 | st->ovl_space += 2*st->src_step - st->dst_step; |
184 | 231 | ||
185 | if (st->ovl_space > FIXED_BUFSIZE) | 232 | if (st->ovl_space > FIXED_BUFCOUNT) |
186 | st->ovl_space = FIXED_BUFSIZE; | 233 | st->ovl_space = FIXED_BUFCOUNT; |
187 | 234 | ||
235 | /* just discard remaining input data */ | ||
188 | st->ovl_size = 0; | 236 | st->ovl_size = 0; |
189 | st->ovl_shift = 0; | 237 | st->ovl_shift = 0; |
190 | 238 | ||
191 | st->ovl_buff[0] = overlap_buffer[0]; | 239 | st->ovl_buff[0] = overlap_buffer[0]; |
192 | 240 | st->ovl_buff[1] = overlap_buffer[1]; /* ignored if mono */ | |
193 | if (stereo) | ||
194 | st->ovl_buff[1] = overlap_buffer[1]; | ||
195 | else | ||
196 | st->ovl_buff[1] = st->ovl_buff[0]; | ||
197 | 241 | ||
198 | return true; | 242 | return true; |
199 | } | 243 | } |
200 | 244 | ||
201 | static int tdspeed_apply(int32_t *buf_out[2], int32_t *buf_in[2], | 245 | static int tdspeed_apply(int32_t *buf_out[2], int32_t *buf_in[2], |
202 | int data_len, int last, int out_size) | 246 | int data_len, enum tdspeed_ops op, int *consumed) |
203 | /* data_len in samples */ | 247 | /* data_len in samples */ |
204 | { | 248 | { |
205 | struct tdspeed_state_s *st = &tdspeed_state; | 249 | struct tdspeed_state_s *st = &tdspeed_state; |
206 | int32_t *dest[2]; | 250 | int32_t *dest[2]; |
207 | int32_t next_frame, prev_frame, src_frame_sz; | 251 | int32_t next_frame, prev_frame, src_frame_sz; |
208 | bool stereo = buf_in[0] != buf_in[1]; | 252 | bool stereo = st->channels > 1; |
209 | |||
210 | assert(stereo == st->stereo); | ||
211 | 253 | ||
212 | src_frame_sz = st->shift_max + st->dst_step; | 254 | src_frame_sz = st->shift_max + st->dst_step; |
213 | 255 | ||
@@ -233,7 +275,7 @@ static int tdspeed_apply(int32_t *buf_out[2], int32_t *buf_in[2], | |||
233 | if (copy > data_len) | 275 | if (copy > data_len) |
234 | copy = data_len; | 276 | copy = data_len; |
235 | 277 | ||
236 | assert(st->ovl_size + copy <= FIXED_BUFSIZE); | 278 | assert(st->ovl_size + copy <= FIXED_BUFCOUNT); |
237 | memcpy(st->ovl_buff[0] + st->ovl_size, buf_in[0], | 279 | memcpy(st->ovl_buff[0] + st->ovl_size, buf_in[0], |
238 | copy * sizeof(int32_t)); | 280 | copy * sizeof(int32_t)); |
239 | 281 | ||
@@ -241,7 +283,9 @@ static int tdspeed_apply(int32_t *buf_out[2], int32_t *buf_in[2], | |||
241 | memcpy(st->ovl_buff[1] + st->ovl_size, buf_in[1], | 283 | memcpy(st->ovl_buff[1] + st->ovl_size, buf_in[1], |
242 | copy * sizeof(int32_t)); | 284 | copy * sizeof(int32_t)); |
243 | 285 | ||
244 | if (!last && have + copy < src_frame_sz) | 286 | *consumed += copy; |
287 | |||
288 | if (op == TDSOP_PROCESS && have + copy < src_frame_sz) | ||
245 | { | 289 | { |
246 | /* still not enough to process at least one frame */ | 290 | /* still not enough to process at least one frame */ |
247 | st->ovl_size += copy; | 291 | st->ovl_size += copy; |
@@ -254,13 +298,14 @@ static int tdspeed_apply(int32_t *buf_out[2], int32_t *buf_in[2], | |||
254 | 298 | ||
255 | if (copy == data_len) | 299 | if (copy == data_len) |
256 | { | 300 | { |
257 | assert(have + copy <= FIXED_BUFSIZE); | 301 | assert(have + copy <= FIXED_BUFCOUNT); |
258 | return tdspeed_apply(buf_out, st->ovl_buff, have+copy, last, | 302 | return tdspeed_apply(buf_out, st->ovl_buff, have+copy, op, |
259 | out_size); | 303 | consumed); |
260 | } | 304 | } |
261 | 305 | ||
262 | assert(have + copy <= FIXED_BUFSIZE); | 306 | assert(have + copy <= FIXED_BUFCOUNT); |
263 | int i = tdspeed_apply(buf_out, st->ovl_buff, have+copy, -1, out_size); | 307 | int i = tdspeed_apply(buf_out, st->ovl_buff, have+copy, |
308 | TDSOP_LAST, consumed); | ||
264 | 309 | ||
265 | dest[0] = buf_out[0] + i; | 310 | dest[0] = buf_out[0] + i; |
266 | dest[1] = buf_out[1] + i; | 311 | dest[1] = buf_out[1] + i; |
@@ -379,12 +424,12 @@ skip:; | |||
379 | } | 424 | } |
380 | 425 | ||
381 | /* now deal with remaining partial frames */ | 426 | /* now deal with remaining partial frames */ |
382 | if (last == -1) | 427 | if (op == TDSOP_LAST) |
383 | { | 428 | { |
384 | /* special overlap buffer processing: remember frame shift only */ | 429 | /* special overlap buffer processing: remember frame shift only */ |
385 | st->ovl_shift = next_frame - prev_frame; | 430 | st->ovl_shift = next_frame - prev_frame; |
386 | } | 431 | } |
387 | else if (last != 0) | 432 | else if (op == TDSOP_PURGE) |
388 | { | 433 | { |
389 | /* last call: purge all remaining data to output buffer */ | 434 | /* last call: purge all remaining data to output buffer */ |
390 | int i = data_len - prev_frame; | 435 | int i = data_len - prev_frame; |
@@ -400,6 +445,8 @@ skip:; | |||
400 | memcpy(dest[1], buf_in[1] + prev_frame, i * sizeof(int32_t)); | 445 | memcpy(dest[1], buf_in[1] + prev_frame, i * sizeof(int32_t)); |
401 | dest[1] += i; | 446 | dest[1] += i; |
402 | } | 447 | } |
448 | |||
449 | *consumed += i; | ||
403 | } | 450 | } |
404 | else | 451 | else |
405 | { | 452 | { |
@@ -408,7 +455,7 @@ skip:; | |||
408 | int i = (st->ovl_shift < 0) ? next_frame : prev_frame; | 455 | int i = (st->ovl_shift < 0) ? next_frame : prev_frame; |
409 | st->ovl_size = data_len - i; | 456 | st->ovl_size = data_len - i; |
410 | 457 | ||
411 | assert(st->ovl_size <= FIXED_BUFSIZE); | 458 | assert(st->ovl_size <= FIXED_BUFCOUNT); |
412 | memcpy(st->ovl_buff[0], buf_in[0] + i, st->ovl_size * sizeof(int32_t)); | 459 | memcpy(st->ovl_buff[0], buf_in[0] + i, st->ovl_size * sizeof(int32_t)); |
413 | 460 | ||
414 | if (stereo) | 461 | if (stereo) |
@@ -418,32 +465,223 @@ skip:; | |||
418 | return dest[0] - buf_out[0]; | 465 | return dest[0] - buf_out[0]; |
419 | } | 466 | } |
420 | 467 | ||
421 | long tdspeed_est_output_size() | 468 | |
469 | /** DSP interface **/ | ||
470 | |||
471 | static void tdspeed_process_new_format(struct dsp_proc_entry *this, | ||
472 | struct dsp_buffer **buf_p); | ||
473 | |||
474 | /* Enable or disable the availability of timestretch */ | ||
475 | void dsp_timestretch_enable(bool enabled) | ||
422 | { | 476 | { |
423 | return TDSPEED_OUTBUFSIZE; | 477 | if (enabled != !tdspeed_state.this) |
478 | return; /* No change */ | ||
479 | |||
480 | dsp_proc_enable(dsp_get_config(CODEC_IDX_AUDIO), DSP_PROC_TIMESTRETCH, | ||
481 | enabled); | ||
424 | } | 482 | } |
425 | 483 | ||
426 | long tdspeed_est_input_size(long size) | 484 | /* Set the timestretch ratio */ |
485 | void dsp_set_timestretch(int32_t percent) | ||
427 | { | 486 | { |
428 | struct tdspeed_state_s *st = &tdspeed_state; | 487 | struct tdspeed_state_s *st = &tdspeed_state; |
429 | 488 | ||
430 | size = (size - st->ovl_size) * st->src_step / st->dst_step; | 489 | if (!st->this) |
490 | return; /* not enabled */ | ||
491 | |||
492 | if (percent <= 0) | ||
493 | percent = PITCH_SPEED_100; | ||
494 | |||
495 | if (percent == st->factor) | ||
496 | return; /* no change */ | ||
497 | |||
498 | dsp_configure(st->dsp, TIMESTRETCH_SET_FACTOR, percent); | ||
499 | } | ||
500 | |||
501 | /* Return the timestretch ratio */ | ||
502 | int32_t dsp_get_timestretch(void) | ||
503 | { | ||
504 | return tdspeed_state.factor; | ||
505 | } | ||
506 | |||
507 | /* Return whether or not timestretch is enabled and initialized */ | ||
508 | bool dsp_timestretch_available(void) | ||
509 | { | ||
510 | return !!tdspeed_state.this; | ||
511 | } | ||
512 | |||
513 | /* Apply timestretch to the input buffer and switch to our output buffer */ | ||
514 | static void tdspeed_process(struct dsp_proc_entry *this, | ||
515 | struct dsp_buffer **buf_p) | ||
516 | { | ||
517 | struct dsp_buffer *src = *buf_p; | ||
518 | struct dsp_buffer *dst = &dsp_outbuf; | ||
519 | |||
520 | *buf_p = dst; /* switch to our buffer */ | ||
521 | |||
522 | int count = dst->remcount; | ||
523 | |||
524 | if (count > 0) | ||
525 | return; /* output remains from an earlier call */ | ||
431 | 526 | ||
432 | if (size < 0) | 527 | dst->p32[0] = outbuf[0]; |
433 | size = 0; | 528 | dst->p32[1] = outbuf[src->format.num_channels - 1]; |
434 | 529 | ||
435 | return size; | 530 | if (src->remcount > 0) |
531 | { | ||
532 | dst->bufcount = 0; /* use this to get consumed src */ | ||
533 | count = tdspeed_apply(dst->p32, src->p32, | ||
534 | MIN(src->remcount, MAX_INPUTCOUNT), | ||
535 | TDSOP_PROCESS, &dst->bufcount); | ||
536 | |||
537 | /* advance src by samples consumed */ | ||
538 | if (dst->bufcount > 0) | ||
539 | dsp_advance_buffer32(src, dst->bufcount); | ||
540 | } | ||
541 | /* else purged dsp_outbuf */ | ||
542 | |||
543 | dst->remcount = count; | ||
544 | |||
545 | /* inherit in-place processed mask from source buffer */ | ||
546 | dst->proc_mask = src->proc_mask; | ||
547 | |||
548 | (void)this; | ||
436 | } | 549 | } |
437 | 550 | ||
438 | int tdspeed_doit(int32_t *src[], int count) | 551 | /* Process format changes and settings changes */ |
552 | static void tdspeed_process_new_format(struct dsp_proc_entry *this, | ||
553 | struct dsp_buffer **buf_p) | ||
439 | { | 554 | { |
440 | dsp_src = src; | 555 | struct dsp_buffer *src = *buf_p; |
441 | count = tdspeed_apply( (int32_t *[2]) { outbuf[0], outbuf[1] }, | 556 | struct dsp_buffer *dst = &dsp_outbuf; |
442 | src, count, 0, TDSPEED_OUTBUFSIZE); | 557 | |
558 | if (dst->remcount > 0) | ||
559 | { | ||
560 | *buf_p = dst; | ||
561 | return; /* output remains from an earlier call */ | ||
562 | } | ||
443 | 563 | ||
444 | src[0] = outbuf[0]; | 564 | DSP_PRINT_FORMAT(DSP_PROC_TIMESTRETCH, DSP_PROC_TIMESTRETCH, src->format); |
445 | src[1] = outbuf[1]; | 565 | |
566 | struct tdspeed_state_s *st = &tdspeed_state; | ||
567 | struct dsp_config *dsp = st->dsp; | ||
568 | struct sample_format *format = &src->format; | ||
569 | unsigned int channels = format->num_channels; | ||
570 | |||
571 | if (format->codec_frequency != st->samplerate) | ||
572 | { | ||
573 | /* relevent parameters are changing - all overlap will be discarded */ | ||
574 | st->channels = channels; | ||
575 | |||
576 | DEBUGF(" DSP_PROC_TIMESTRETCH- new settings: " | ||
577 | "ch:%u chz: %u, %d.%02d%%\n", | ||
578 | channels, | ||
579 | format->codec_frequency, | ||
580 | st->factor / 100, st->factor % 100); | ||
581 | bool active = tdspeed_update(format->codec_frequency, st->factor); | ||
582 | dsp_proc_activate(dsp, DSP_PROC_TIMESTRETCH, active); | ||
583 | |||
584 | if (!active) | ||
585 | { | ||
586 | DEBUGF(" DSP_PROC_RESAMPLE- not active\n"); | ||
587 | dst->format = src->format; /* Keep track */ | ||
588 | return; /* no more for now */ | ||
589 | } | ||
590 | } | ||
591 | else if (channels != st->channels) | ||
592 | { | ||
593 | /* channel count transistion - have to make old data in overlap | ||
594 | buffer compatible with new format */ | ||
595 | DEBUGF(" DSP_PROC_TIMESTRETCH- new ch count: %u=>%u\n", | ||
596 | st->channels, channels); | ||
597 | |||
598 | st->channels = channels; | ||
599 | |||
600 | if (channels > 1) | ||
601 | { | ||
602 | /* mono->stereo: Process the old mono as stereo now */ | ||
603 | memcpy(st->ovl_buff[1], st->ovl_buff[0], | ||
604 | st->ovl_size * sizeof (int32_t)); | ||
605 | } | ||
606 | else | ||
607 | { | ||
608 | /* stereo->mono: Process the old stereo as mono now */ | ||
609 | for (int i = 0; i < st->ovl_size; i++) | ||
610 | { | ||
611 | st->ovl_buff[0][i] = st->ovl_buff[0][i] / 2 + | ||
612 | st->ovl_buff[1][i] / 2; | ||
613 | } | ||
614 | } | ||
615 | } | ||
616 | |||
617 | struct sample_format f = *format; | ||
618 | format_change_ack(format); | ||
619 | |||
620 | if (EQU_SAMPLE_FORMAT(f, dst->format)) | ||
621 | { | ||
622 | DEBUGF(" DSP_PROC_TIMESTRETCH- same dst format\n"); | ||
623 | format_change_ack(&f); /* nothing changed that matters downstream */ | ||
624 | } | ||
625 | |||
626 | dst->format = f; | ||
627 | |||
628 | /* return to normal processing */ | ||
629 | this->process[0] = tdspeed_process; | ||
630 | dsp_proc_call(this, buf_p, 0); | ||
631 | } | ||
632 | |||
633 | /* DSP message hook */ | ||
634 | static intptr_t tdspeed_configure(struct dsp_proc_entry *this, | ||
635 | struct dsp_config *dsp, | ||
636 | unsigned int setting, | ||
637 | intptr_t value) | ||
638 | { | ||
639 | struct tdspeed_state_s *st = &tdspeed_state; | ||
640 | |||
641 | switch (setting) | ||
642 | { | ||
643 | case DSP_INIT: | ||
644 | /* everything is at 100% until dsp_set_timestretch is called with | ||
645 | some other value and timestretch is enabled at the time */ | ||
646 | if (value == CODEC_IDX_AUDIO) | ||
647 | st->factor = PITCH_SPEED_100; | ||
648 | break; | ||
649 | |||
650 | case DSP_FLUSH: | ||
651 | tdspeed_flush(); | ||
652 | break; | ||
653 | |||
654 | case DSP_PROC_INIT: | ||
655 | if (!tdspeed_alloc_buffers()) | ||
656 | return -1; /* fail the init */ | ||
657 | |||
658 | st->this = this; | ||
659 | st->dsp = dsp; | ||
660 | this->ip_mask = 0; /* not in-place */ | ||
661 | this->process[0] = tdspeed_process; | ||
662 | this->process[1] = tdspeed_process_new_format; | ||
663 | break; | ||
664 | |||
665 | case DSP_PROC_CLOSE: | ||
666 | st->this = NULL; | ||
667 | st->factor = PITCH_SPEED_100; | ||
668 | dsp_outbuf.remcount = 0; | ||
669 | tdspeed_free_buffers(); | ||
670 | break; | ||
671 | |||
672 | case TIMESTRETCH_SET_FACTOR: | ||
673 | /* force update as a format change */ | ||
674 | st->samplerate = 0; | ||
675 | st->factor = (int32_t)value; | ||
676 | st->this->process[0] = tdspeed_process_new_format; | ||
677 | dsp_proc_activate(st->dsp, DSP_PROC_TIMESTRETCH, true); | ||
678 | break; | ||
679 | } | ||
446 | 680 | ||
447 | return count; | 681 | return 1; |
682 | (void)value; | ||
448 | } | 683 | } |
449 | 684 | ||
685 | /* Database entry */ | ||
686 | DSP_PROC_DB_ENTRY(TIMESTRETCH, | ||
687 | tdspeed_configure); | ||