summaryrefslogtreecommitdiff
path: root/lib/rbcodec/dsp/tdspeed.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/dsp/tdspeed.c')
-rw-r--r--lib/rbcodec/dsp/tdspeed.c468
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 */
42static int32_t** dsp_src; 43#define FIXED_OUTBUFCOUNT 4096
43static int handles[4];
44static int32_t *overlap_buffer[2] = { NULL, NULL };
45static int32_t *outbuf[2] = { NULL, NULL };
46
47static 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
59static struct buflib_callbacks ops = {
60 .move_callback = move_callback,
61 .shrink_callback = NULL,
62};
63 44
64static int ovl_move_callback(int handle, void* current, void* new) 45enum 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
76static struct buflib_callbacks ovl_ops = {
77 .move_callback = ovl_move_callback,
78 .shrink_callback = NULL,
79}; 50};
80 51
81
82static struct tdspeed_state_s 52static 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
95void tdspeed_init(void) 69static int handles[4] = { 0, 0, 0, 0 };
70static 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 */
77static struct dsp_buffer dsp_outbuf;
78
79static 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
124static struct buflib_callbacks ops =
125{
126 .move_callback = move_callback,
127 .shrink_callback = NULL,
128};
129
130/* Allocate timestretch buffers */
131static 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
123void tdspeed_finish(void) 167/* Free timestretch buffers */
168static 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
137bool tdspeed_config(int samplerate, bool stereo, int32_t factor) 180/* Discard all data */
181static 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) 189static 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
201static int tdspeed_apply(int32_t *buf_out[2], int32_t *buf_in[2], 245static 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
421long tdspeed_est_output_size() 468
469/** DSP interface **/
470
471static 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 */
475void 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
426long tdspeed_est_input_size(long size) 484/* Set the timestretch ratio */
485void 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 */
502int32_t dsp_get_timestretch(void)
503{
504 return tdspeed_state.factor;
505}
506
507/* Return whether or not timestretch is enabled and initialized */
508bool 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 */
514static 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
438int tdspeed_doit(int32_t *src[], int count) 551/* Process format changes and settings changes */
552static 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 */
634static 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 */
686DSP_PROC_DB_ENTRY(TIMESTRETCH,
687 tdspeed_configure);