Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id$ |
| 9 | * |
| 10 | * Copyright (C) 2006 by Nicolas Pitre <nico@cam.org> |
| 11 | * Copyright (C) 2006-2007 by Stéphane Doyon <s.doyon@videotron.ca> |
| 12 | * |
| 13 | * This program is free software; you can redistribute it and/or |
| 14 | * modify it under the terms of the GNU General Public License |
| 15 | * as published by the Free Software Foundation; either version 2 |
| 16 | * of the License, or (at your option) any later version. |
| 17 | * |
| 18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 19 | * KIND, either express or implied. |
| 20 | * |
| 21 | ****************************************************************************/ |
| 22 | |
| 23 | #include <inttypes.h> |
| 24 | #include <stddef.h> |
| 25 | #include <stdio.h> |
| 26 | #include <string.h> |
Alexander Levin | 7765158 | 2009-07-11 17:16:23 +0000 | [diff] [blame] | 27 | #include "sound.h" |
Thomas Martitz | d0b72e2 | 2011-08-30 14:01:33 +0000 | [diff] [blame] | 28 | #include "core_alloc.h" |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 29 | #include "system.h" |
| 30 | #include "tdspeed.h" |
Thomas Martitz | cb57a56 | 2009-06-16 00:59:24 +0000 | [diff] [blame] | 31 | #include "settings.h" |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 32 | |
| 33 | #define assert(cond) |
| 34 | |
| 35 | #define MIN_RATE 8000 |
| 36 | #define MAX_RATE 48000 /* double buffer for double rate */ |
| 37 | #define MINFREQ 100 |
| 38 | |
| 39 | #define FIXED_BUFSIZE 3072 /* 48KHz factor 3.0 */ |
| 40 | |
Thomas Martitz | baa070c | 2011-08-30 14:01:45 +0000 | [diff] [blame] | 41 | static int32_t** dsp_src; |
| 42 | static int handles[4]; |
| 43 | static int32_t *overlap_buffer[2] = { NULL, NULL }; |
| 44 | static int32_t *outbuf[2] = { NULL, NULL }; |
| 45 | |
| 46 | static int move_callback(int handle, void* current, void* new) |
| 47 | { |
| 48 | /* TODO */ |
| 49 | (void)handle; |
| 50 | if (dsp_src) |
| 51 | { |
| 52 | int ch = (current == outbuf[0]) ? 0 : 1; |
| 53 | dsp_src[ch] = outbuf[ch] = new; |
| 54 | } |
| 55 | return BUFLIB_CB_OK; |
| 56 | } |
| 57 | |
| 58 | static struct buflib_callbacks ops = { |
| 59 | .move_callback = move_callback, |
| 60 | .shrink_callback = NULL, |
| 61 | }; |
| 62 | |
| 63 | static int ovl_move_callback(int handle, void* current, void* new) |
| 64 | { |
| 65 | /* TODO */ |
| 66 | (void)handle; |
| 67 | if (dsp_src) |
| 68 | { |
| 69 | int ch = (current == overlap_buffer[0]) ? 0 : 1; |
| 70 | overlap_buffer[ch] = new; |
| 71 | } |
| 72 | return BUFLIB_CB_OK; |
| 73 | } |
| 74 | |
| 75 | static struct buflib_callbacks ovl_ops = { |
| 76 | .move_callback = ovl_move_callback, |
| 77 | .shrink_callback = NULL, |
| 78 | }; |
| 79 | |
| 80 | |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 81 | static struct tdspeed_state_s |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 82 | { |
| 83 | bool stereo; |
| 84 | int32_t shift_max; /* maximum displacement on a frame */ |
| 85 | int32_t src_step; /* source window pace */ |
| 86 | int32_t dst_step; /* destination window pace */ |
| 87 | int32_t dst_order; /* power of two for dst_step */ |
| 88 | int32_t ovl_shift; /* overlap buffer frame shift */ |
| 89 | int32_t ovl_size; /* overlap buffer used size */ |
| 90 | int32_t ovl_space; /* overlap buffer size */ |
| 91 | int32_t *ovl_buff[2]; /* overlap buffer */ |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 92 | } tdspeed_state; |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 93 | |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 94 | void tdspeed_init(void) |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 95 | { |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 96 | if (!global_settings.timestretch_enabled) |
| 97 | return; |
| 98 | |
| 99 | /* Allocate buffers */ |
| 100 | if (overlap_buffer[0] == NULL) |
Thomas Martitz | d0b72e2 | 2011-08-30 14:01:33 +0000 | [diff] [blame] | 101 | { |
Thomas Martitz | baa070c | 2011-08-30 14:01:45 +0000 | [diff] [blame] | 102 | handles[0] = core_alloc_ex("tdspeed ovl left", FIXED_BUFSIZE * sizeof(int32_t), &ovl_ops); |
| 103 | overlap_buffer[0] = core_get_data(handles[0]); |
Thomas Martitz | d0b72e2 | 2011-08-30 14:01:33 +0000 | [diff] [blame] | 104 | } |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 105 | if (overlap_buffer[1] == NULL) |
Thomas Martitz | d0b72e2 | 2011-08-30 14:01:33 +0000 | [diff] [blame] | 106 | { |
Thomas Martitz | baa070c | 2011-08-30 14:01:45 +0000 | [diff] [blame] | 107 | handles[1] = core_alloc_ex("tdspeed ovl right", FIXED_BUFSIZE * sizeof(int32_t), &ovl_ops); |
| 108 | overlap_buffer[1] = core_get_data(handles[1]); |
Thomas Martitz | d0b72e2 | 2011-08-30 14:01:33 +0000 | [diff] [blame] | 109 | } |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 110 | if (outbuf[0] == NULL) |
Thomas Martitz | d0b72e2 | 2011-08-30 14:01:33 +0000 | [diff] [blame] | 111 | { |
Thomas Martitz | baa070c | 2011-08-30 14:01:45 +0000 | [diff] [blame] | 112 | handles[2] = core_alloc_ex("tdspeed left", TDSPEED_OUTBUFSIZE * sizeof(int32_t), &ops); |
| 113 | outbuf[0] = core_get_data(handles[2]); |
Thomas Martitz | d0b72e2 | 2011-08-30 14:01:33 +0000 | [diff] [blame] | 114 | } |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 115 | if (outbuf[1] == NULL) |
Thomas Martitz | d0b72e2 | 2011-08-30 14:01:33 +0000 | [diff] [blame] | 116 | { |
Thomas Martitz | baa070c | 2011-08-30 14:01:45 +0000 | [diff] [blame] | 117 | handles[3] = core_alloc_ex("tdspeed right", TDSPEED_OUTBUFSIZE * sizeof(int32_t), &ops); |
| 118 | outbuf[1] = core_get_data(handles[3]); |
Thomas Martitz | d0b72e2 | 2011-08-30 14:01:33 +0000 | [diff] [blame] | 119 | } |
Steve Bavin | 77f6f4c | 2009-06-15 15:46:09 +0000 | [diff] [blame] | 120 | } |
| 121 | |
Thomas Martitz | baa070c | 2011-08-30 14:01:45 +0000 | [diff] [blame] | 122 | void tdspeed_finish(void) |
| 123 | { |
| 124 | for(unsigned i = 0; i < ARRAYLEN(handles); i++) |
| 125 | { |
| 126 | if (handles[i] > 0) |
| 127 | { |
| 128 | core_free(handles[i]); |
| 129 | handles[i] = 0; |
| 130 | } |
| 131 | } |
| 132 | overlap_buffer[0] = overlap_buffer[1] = NULL; |
| 133 | outbuf[0] = outbuf[1] = NULL; |
| 134 | } |
Steve Bavin | 77f6f4c | 2009-06-15 15:46:09 +0000 | [diff] [blame] | 135 | |
Alexander Levin | cc7c665 | 2009-07-11 16:46:19 +0000 | [diff] [blame] | 136 | bool tdspeed_config(int samplerate, bool stereo, int32_t factor) |
Steve Bavin | 77f6f4c | 2009-06-15 15:46:09 +0000 | [diff] [blame] | 137 | { |
| 138 | struct tdspeed_state_s *st = &tdspeed_state; |
| 139 | int src_frame_sz; |
| 140 | |
| 141 | /* Check buffers were allocated ok */ |
| 142 | if (overlap_buffer[0] == NULL || overlap_buffer[1] == NULL) |
| 143 | return false; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 144 | |
Steve Bavin | 77f6f4c | 2009-06-15 15:46:09 +0000 | [diff] [blame] | 145 | if (outbuf[0] == NULL || outbuf[1] == NULL) |
| 146 | return false; |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 147 | |
| 148 | /* Check parameters */ |
Alexander Levin | cc7c665 | 2009-07-11 16:46:19 +0000 | [diff] [blame] | 149 | if (factor == PITCH_SPEED_100) |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 150 | return false; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 151 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 152 | if (samplerate < MIN_RATE || samplerate > MAX_RATE) |
| 153 | return false; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 154 | |
Steve Bavin | 40d9b21 | 2009-06-22 18:52:14 +0000 | [diff] [blame] | 155 | if (factor < STRETCH_MIN || factor > STRETCH_MAX) |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 156 | return false; |
| 157 | |
| 158 | st->stereo = stereo; |
| 159 | st->dst_step = samplerate / MINFREQ; |
| 160 | |
Alexander Levin | cc7c665 | 2009-07-11 16:46:19 +0000 | [diff] [blame] | 161 | if (factor > PITCH_SPEED_100) |
| 162 | st->dst_step = st->dst_step * PITCH_SPEED_100 / factor; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 163 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 164 | st->dst_order = 1; |
| 165 | |
| 166 | while (st->dst_step >>= 1) |
| 167 | st->dst_order++; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 168 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 169 | st->dst_step = (1 << st->dst_order); |
Alexander Levin | cc7c665 | 2009-07-11 16:46:19 +0000 | [diff] [blame] | 170 | st->src_step = st->dst_step * factor / PITCH_SPEED_100; |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 171 | st->shift_max = (st->dst_step > st->src_step) ? st->dst_step : st->src_step; |
| 172 | |
| 173 | src_frame_sz = st->shift_max + st->dst_step; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 174 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 175 | if (st->dst_step > st->src_step) |
| 176 | src_frame_sz += st->dst_step - st->src_step; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 177 | |
| 178 | st->ovl_space = ((src_frame_sz - 2) / st->src_step) * st->src_step |
| 179 | + src_frame_sz; |
| 180 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 181 | if (st->src_step > st->dst_step) |
| 182 | st->ovl_space += 2*st->src_step - st->dst_step; |
| 183 | |
| 184 | if (st->ovl_space > FIXED_BUFSIZE) |
| 185 | st->ovl_space = FIXED_BUFSIZE; |
| 186 | |
| 187 | st->ovl_size = 0; |
| 188 | st->ovl_shift = 0; |
| 189 | |
| 190 | st->ovl_buff[0] = overlap_buffer[0]; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 191 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 192 | if (stereo) |
| 193 | st->ovl_buff[1] = overlap_buffer[1]; |
| 194 | else |
| 195 | st->ovl_buff[1] = st->ovl_buff[0]; |
| 196 | |
| 197 | return true; |
| 198 | } |
| 199 | |
| 200 | static int tdspeed_apply(int32_t *buf_out[2], int32_t *buf_in[2], |
| 201 | int data_len, int last, int out_size) |
| 202 | /* data_len in samples */ |
| 203 | { |
| 204 | struct tdspeed_state_s *st = &tdspeed_state; |
Michael Sevakis | e4a5762 | 2012-01-13 17:14:47 -0500 | [diff] [blame] | 205 | int32_t *dest[2]; |
| 206 | int32_t next_frame, prev_frame, src_frame_sz; |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 207 | bool stereo = buf_in[0] != buf_in[1]; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 208 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 209 | assert(stereo == st->stereo); |
| 210 | |
| 211 | src_frame_sz = st->shift_max + st->dst_step; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 212 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 213 | if (st->dst_step > st->src_step) |
| 214 | src_frame_sz += st->dst_step - st->src_step; |
| 215 | |
| 216 | /* deal with overlap data first, if any */ |
| 217 | if (st->ovl_size) |
| 218 | { |
| 219 | int32_t have, copy, steps; |
| 220 | have = st->ovl_size; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 221 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 222 | if (st->ovl_shift > 0) |
| 223 | have -= st->ovl_shift; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 224 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 225 | /* append just enough data to have all of the overlap buffer consumed */ |
| 226 | steps = (have - 1) / st->src_step; |
| 227 | copy = steps * st->src_step + src_frame_sz - have; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 228 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 229 | if (copy < src_frame_sz - st->dst_step) |
| 230 | copy += st->src_step; /* one more step to allow for pregap data */ |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 231 | |
| 232 | if (copy > data_len) |
| 233 | copy = data_len; |
| 234 | |
| 235 | assert(st->ovl_size + copy <= FIXED_BUFSIZE); |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 236 | memcpy(st->ovl_buff[0] + st->ovl_size, buf_in[0], |
| 237 | copy * sizeof(int32_t)); |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 238 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 239 | if (stereo) |
| 240 | memcpy(st->ovl_buff[1] + st->ovl_size, buf_in[1], |
| 241 | copy * sizeof(int32_t)); |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 242 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 243 | if (!last && have + copy < src_frame_sz) |
| 244 | { |
| 245 | /* still not enough to process at least one frame */ |
| 246 | st->ovl_size += copy; |
| 247 | return 0; |
| 248 | } |
| 249 | |
| 250 | /* recursively call ourselves to process the overlap buffer */ |
| 251 | have = st->ovl_size; |
| 252 | st->ovl_size = 0; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 253 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 254 | if (copy == data_len) |
| 255 | { |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 256 | assert(have + copy <= FIXED_BUFSIZE); |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 257 | return tdspeed_apply(buf_out, st->ovl_buff, have+copy, last, |
| 258 | out_size); |
| 259 | } |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 260 | |
| 261 | assert(have + copy <= FIXED_BUFSIZE); |
Michael Sevakis | e4a5762 | 2012-01-13 17:14:47 -0500 | [diff] [blame] | 262 | int i = tdspeed_apply(buf_out, st->ovl_buff, have+copy, -1, out_size); |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 263 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 264 | dest[0] = buf_out[0] + i; |
| 265 | dest[1] = buf_out[1] + i; |
| 266 | |
| 267 | /* readjust pointers to account for data already consumed */ |
| 268 | next_frame = copy - src_frame_sz + st->src_step; |
| 269 | prev_frame = next_frame - st->ovl_shift; |
| 270 | } |
| 271 | else |
| 272 | { |
| 273 | dest[0] = buf_out[0]; |
| 274 | dest[1] = buf_out[1]; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 275 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 276 | next_frame = prev_frame = 0; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 277 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 278 | if (st->ovl_shift > 0) |
| 279 | next_frame += st->ovl_shift; |
| 280 | else |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 281 | prev_frame += -st->ovl_shift; |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 282 | } |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 283 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 284 | st->ovl_shift = 0; |
| 285 | |
| 286 | /* process all complete frames */ |
| 287 | while (data_len - next_frame >= src_frame_sz) |
| 288 | { |
| 289 | /* find frame overlap by autocorelation */ |
Michael Sevakis | e4a5762 | 2012-01-13 17:14:47 -0500 | [diff] [blame] | 290 | int const INC1 = 8; |
| 291 | int const INC2 = 32; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 292 | |
Michael Sevakis | b17bdb9 | 2012-01-13 17:54:43 -0500 | [diff] [blame] | 293 | int64_t min_delta = INT64_MAX; /* most positive */ |
Michael Sevakis | e4a5762 | 2012-01-13 17:14:47 -0500 | [diff] [blame] | 294 | int shift = 0; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 295 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 296 | /* Power of 2 of a 28bit number requires 56bits, can accumulate |
| 297 | 256times in a 64bit variable. */ |
| 298 | assert(st->dst_step / INC2 <= 256); |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 299 | assert(next_frame + st->shift_max - 1 + st->dst_step - 1 < data_len); |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 300 | assert(prev_frame + st->dst_step - 1 < data_len); |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 301 | |
Michael Sevakis | e4a5762 | 2012-01-13 17:14:47 -0500 | [diff] [blame] | 302 | for (int i = 0; i < st->shift_max; i += INC1) |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 303 | { |
| 304 | int64_t delta = 0; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 305 | |
Michael Sevakis | e4a5762 | 2012-01-13 17:14:47 -0500 | [diff] [blame] | 306 | int32_t *curr = buf_in[0] + next_frame + i; |
| 307 | int32_t *prev = buf_in[0] + prev_frame; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 308 | |
Michael Sevakis | e4a5762 | 2012-01-13 17:14:47 -0500 | [diff] [blame] | 309 | for (int j = 0; j < st->dst_step; j += INC2, curr += INC2, prev += INC2) |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 310 | { |
| 311 | int32_t diff = *curr - *prev; |
Michael Sevakis | e4a5762 | 2012-01-13 17:14:47 -0500 | [diff] [blame] | 312 | delta += abs(diff); |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 313 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 314 | if (delta >= min_delta) |
| 315 | goto skip; |
| 316 | } |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 317 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 318 | if (stereo) |
| 319 | { |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 320 | curr = buf_in[1] + next_frame + i; |
| 321 | prev = buf_in[1] + prev_frame; |
| 322 | |
Michael Sevakis | e4a5762 | 2012-01-13 17:14:47 -0500 | [diff] [blame] | 323 | for (int j = 0; j < st->dst_step; j += INC2, curr += INC2, prev += INC2) |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 324 | { |
| 325 | int32_t diff = *curr - *prev; |
Michael Sevakis | e4a5762 | 2012-01-13 17:14:47 -0500 | [diff] [blame] | 326 | delta += abs(diff); |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 327 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 328 | if (delta >= min_delta) |
| 329 | goto skip; |
| 330 | } |
| 331 | } |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 332 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 333 | min_delta = delta; |
| 334 | shift = i; |
| 335 | skip:; |
| 336 | } |
| 337 | |
| 338 | /* overlap fading-out previous frame with fading-in current frame */ |
Michael Sevakis | e4a5762 | 2012-01-13 17:14:47 -0500 | [diff] [blame] | 339 | int32_t *curr = buf_in[0] + next_frame + shift; |
| 340 | int32_t *prev = buf_in[0] + prev_frame; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 341 | |
Michael Sevakis | e4a5762 | 2012-01-13 17:14:47 -0500 | [diff] [blame] | 342 | int32_t *d = dest[0]; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 343 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 344 | assert(next_frame + shift + st->dst_step - 1 < data_len); |
| 345 | assert(prev_frame + st->dst_step - 1 < data_len); |
| 346 | assert(dest[0] - buf_out[0] + st->dst_step - 1 < out_size); |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 347 | |
Michael Sevakis | e4a5762 | 2012-01-13 17:14:47 -0500 | [diff] [blame] | 348 | for (int i = 0, j = st->dst_step; j; i++, j--) |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 349 | { |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 350 | *d++ = (*curr++ * (int64_t)i + |
| 351 | *prev++ * (int64_t)j) >> st->dst_order; |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 352 | } |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 353 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 354 | dest[0] = d; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 355 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 356 | if (stereo) |
| 357 | { |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 358 | curr = buf_in[1] + next_frame + shift; |
| 359 | prev = buf_in[1] + prev_frame; |
| 360 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 361 | d = dest[1]; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 362 | |
Michael Sevakis | e4a5762 | 2012-01-13 17:14:47 -0500 | [diff] [blame] | 363 | for (int i = 0, j = st->dst_step; j; i++, j--) |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 364 | { |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 365 | assert(d < buf_out[1] + out_size); |
| 366 | |
| 367 | *d++ = (*curr++ * (int64_t)i + |
| 368 | *prev++ * (int64_t)j) >> st->dst_order; |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 369 | } |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 370 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 371 | dest[1] = d; |
| 372 | } |
| 373 | |
| 374 | /* adjust pointers for next frame */ |
| 375 | prev_frame = next_frame + shift + st->dst_step; |
| 376 | next_frame += st->src_step; |
| 377 | |
| 378 | /* here next_frame - prev_frame = src_step - dst_step - shift */ |
| 379 | assert(next_frame - prev_frame == st->src_step - st->dst_step - shift); |
| 380 | } |
| 381 | |
| 382 | /* now deal with remaining partial frames */ |
| 383 | if (last == -1) |
| 384 | { |
| 385 | /* special overlap buffer processing: remember frame shift only */ |
| 386 | st->ovl_shift = next_frame - prev_frame; |
| 387 | } |
| 388 | else if (last != 0) |
| 389 | { |
| 390 | /* last call: purge all remaining data to output buffer */ |
Michael Sevakis | e4a5762 | 2012-01-13 17:14:47 -0500 | [diff] [blame] | 391 | int i = data_len - prev_frame; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 392 | |
| 393 | assert(dest[0] + i <= buf_out[0] + out_size); |
| 394 | memcpy(dest[0], buf_in[0] + prev_frame, i * sizeof(int32_t)); |
| 395 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 396 | dest[0] += i; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 397 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 398 | if (stereo) |
| 399 | { |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 400 | assert(dest[1] + i <= buf_out[1] + out_size); |
| 401 | memcpy(dest[1], buf_in[1] + prev_frame, i * sizeof(int32_t)); |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 402 | dest[1] += i; |
| 403 | } |
| 404 | } |
| 405 | else |
| 406 | { |
| 407 | /* preserve remaining data + needed overlap data for next call */ |
| 408 | st->ovl_shift = next_frame - prev_frame; |
Michael Sevakis | e4a5762 | 2012-01-13 17:14:47 -0500 | [diff] [blame] | 409 | int i = (st->ovl_shift < 0) ? next_frame : prev_frame; |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 410 | st->ovl_size = data_len - i; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 411 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 412 | assert(st->ovl_size <= FIXED_BUFSIZE); |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 413 | memcpy(st->ovl_buff[0], buf_in[0] + i, st->ovl_size * sizeof(int32_t)); |
| 414 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 415 | if (stereo) |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 416 | memcpy(st->ovl_buff[1], buf_in[1] + i, st->ovl_size * sizeof(int32_t)); |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 417 | } |
| 418 | |
| 419 | return dest[0] - buf_out[0]; |
| 420 | } |
| 421 | |
| 422 | long tdspeed_est_output_size() |
| 423 | { |
| 424 | return TDSPEED_OUTBUFSIZE; |
| 425 | } |
| 426 | |
| 427 | long tdspeed_est_input_size(long size) |
| 428 | { |
| 429 | struct tdspeed_state_s *st = &tdspeed_state; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 430 | |
| 431 | size = (size - st->ovl_size) * st->src_step / st->dst_step; |
| 432 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 433 | if (size < 0) |
| 434 | size = 0; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 435 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 436 | return size; |
| 437 | } |
| 438 | |
| 439 | int tdspeed_doit(int32_t *src[], int count) |
| 440 | { |
Thomas Martitz | baa070c | 2011-08-30 14:01:45 +0000 | [diff] [blame] | 441 | dsp_src = src; |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 442 | count = tdspeed_apply( (int32_t *[2]) { outbuf[0], outbuf[1] }, |
| 443 | src, count, 0, TDSPEED_OUTBUFSIZE); |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 444 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 445 | src[0] = outbuf[0]; |
| 446 | src[1] = outbuf[1]; |
Michael Sevakis | 72213e6 | 2011-08-30 07:42:22 +0000 | [diff] [blame] | 447 | |
Steve Bavin | fb23807 | 2009-06-12 07:20:50 +0000 | [diff] [blame] | 448 | return count; |
| 449 | } |
Thomas Martitz | cb57a56 | 2009-06-16 00:59:24 +0000 | [diff] [blame] | 450 | |