blob: d230d2b3f92acbd0ca50be663898ec77c56a9c06 [file] [log] [blame]
Bill Coxca02d872010-11-02 15:10:52 -04001/* Sonic library
2 Copyright 2010
3 Bill Cox
4 This file is part of the Sonic Library.
5
Bill Coxa9999872010-11-11 14:36:59 -05006 The Sonic Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
Bill Coxca02d872010-11-02 15:10:52 -040010
Bill Coxa9999872010-11-11 14:36:59 -050011 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
Bill Coxca02d872010-11-02 15:10:52 -040015
Bill Coxa9999872010-11-11 14:36:59 -050016 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
Bill Cox882fb1d2010-11-02 16:27:20 -040020#include <stdio.h>
Bill Coxca02d872010-11-02 15:10:52 -040021#include <stdlib.h>
22#include <string.h>
Bill Coxa33e3bd2010-11-16 19:57:43 -050023#include <stdarg.h>
Bill Coxca02d872010-11-02 15:10:52 -040024#include "sonic.h"
25
26struct sonicStreamStruct {
27 double speed;
28 float *inputBuffer;
29 float *outputBuffer;
30 int inputBufferSize;
31 int outputBufferSize;
32 int numInputSamples;
33 int numOutputSamples;
34 int minPeriod;
35 int maxPeriod;
36 int maxRequired;
37 int remainingInputToCopy;
38 int sampleRate;
39};
40
Bill Coxa33e3bd2010-11-16 19:57:43 -050041void sonicMSG(char *format, ...)
42{
43 char buffer[4096];
44 va_list ap;
45 FILE *file;
46
47 va_start(ap, format);
48 vsprintf((char *)buffer, (char *)format, ap);
49 va_end(ap);
50 file=fopen("/tmp/sonic.log", "a");
51 fprintf(file, "%s", buffer);
52 fclose(file);
53}
54
Bill Coxaf9a6242010-11-08 09:32:27 -050055/* Get the speed of the stream. */
56double sonicGetSpeed(
57 sonicStream stream)
58{
59 return stream->speed;
60}
61
62/* Get the sample rate of the stream. */
63int sonicGetSampleRate(
64 sonicStream stream)
65{
66 return stream->sampleRate;
67}
68
Bill Coxca02d872010-11-02 15:10:52 -040069/* Destroy the sonic stream. */
70void sonicDestroyStream(
71 sonicStream stream)
72{
73 if(stream->inputBuffer != NULL) {
74 free(stream->inputBuffer);
75 }
76 if(stream->outputBuffer != NULL) {
77 free(stream->outputBuffer);
78 }
79 free(stream);
80}
81
82/* Create a sonic stream. Return NULL only if we are out of memory and cannot
83 allocate the stream. */
84sonicStream sonicCreateStream(
85 double speed,
86 int sampleRate)
87{
88 sonicStream stream = (sonicStream)calloc(1, sizeof(struct sonicStreamStruct));
89 int minPeriod = sampleRate/SONIC_MAX_PITCH;
90 int maxPeriod = sampleRate/SONIC_MIN_PITCH;
91 int maxRequired = 2*maxPeriod;
92
93 if(stream == NULL) {
94 return NULL;
95 }
96 stream->inputBuffer = (float *)calloc(maxRequired, sizeof(float));
97 if(stream->inputBuffer == NULL) {
98 sonicDestroyStream(stream);
99 return NULL;
100 }
101 stream->outputBuffer = (float *)calloc(maxRequired, sizeof(float));
102 if(stream->outputBuffer == NULL) {
103 sonicDestroyStream(stream);
104 return NULL;
105 }
106 stream->speed = speed;
107 stream->sampleRate = sampleRate;
108 stream->minPeriod = minPeriod;
109 stream->maxPeriod = maxPeriod;
110 stream->maxRequired = maxRequired;
111 stream->inputBufferSize = maxRequired;
112 stream->outputBufferSize = maxRequired;
113 return stream;
114}
115
Bill Coxca02d872010-11-02 15:10:52 -0400116/* Enlarge the output buffer if needed. */
117static int enlargeOutputBufferIfNeeded(
118 sonicStream stream,
119 int numSamples)
120{
121 if(stream->numOutputSamples + numSamples > stream->outputBufferSize) {
122 stream->outputBufferSize += (stream->outputBufferSize >> 1) + numSamples;
123 stream->outputBuffer = (float *)realloc(stream->outputBuffer,
124 stream->outputBufferSize*sizeof(float));
125 if(stream->outputBuffer == NULL) {
Bill Coxca02d872010-11-02 15:10:52 -0400126 return 0;
127 }
128 }
129 return 1;
130}
131
Bill Coxca02d872010-11-02 15:10:52 -0400132/* Enlarge the input buffer if needed. */
133static int enlargeInputBufferIfNeeded(
134 sonicStream stream,
135 int numSamples)
136{
137 if(stream->numInputSamples + numSamples > stream->inputBufferSize) {
138 stream->inputBufferSize += (stream->inputBufferSize >> 1) + numSamples;
139 stream->inputBuffer = (float *)realloc(stream->inputBuffer,
140 stream->inputBufferSize*sizeof(float));
141 if(stream->inputBuffer == NULL) {
Bill Coxca02d872010-11-02 15:10:52 -0400142 return 0;
143 }
144 }
145 return 1;
146}
147
148/* Add the input samples to the input buffer. */
Bill Cox0c4c0602010-11-08 11:46:30 -0500149static int addFloatSamplesToInputBuffer(
Bill Coxca02d872010-11-02 15:10:52 -0400150 sonicStream stream,
151 float *samples,
152 int numSamples)
153{
154 if(numSamples == 0) {
155 return 1;
156 }
157 if(!enlargeInputBufferIfNeeded(stream, numSamples)) {
158 return 0;
159 }
160 memcpy(stream->inputBuffer + stream->numInputSamples, samples, numSamples*sizeof(float));
Bill Cox14efa442010-11-02 15:43:58 -0400161 stream->numInputSamples += numSamples;
Bill Coxca02d872010-11-02 15:10:52 -0400162 return 1;
163}
164
Bill Cox0c4c0602010-11-08 11:46:30 -0500165/* Add the input samples to the input buffer. */
166static int addShortSamplesToInputBuffer(
167 sonicStream stream,
168 short *samples,
169 int numSamples)
170{
171 float *buffer;
172 int count = numSamples;
173
174 if(numSamples == 0) {
175 return 1;
176 }
177 if(!enlargeInputBufferIfNeeded(stream, numSamples)) {
178 return 0;
179 }
180 buffer = stream->inputBuffer + stream->numInputSamples;
181 while(count--) {
Bill Coxea5aa0c2010-11-16 18:55:07 -0500182 *buffer++ = (*samples++)/32767.0;
Bill Cox0c4c0602010-11-08 11:46:30 -0500183 }
184 stream->numInputSamples += numSamples;
185 return 1;
186}
187
Bill Cox8a23d2f2010-11-16 18:49:36 -0500188/* Add the input samples to the input buffer. */
189static int addUnsignedCharSamplesToInputBuffer(
190 sonicStream stream,
191 unsigned char *samples,
192 int numSamples)
193{
194 float *buffer;
195 int count = numSamples;
196
197 if(numSamples == 0) {
198 return 1;
199 }
200 if(!enlargeInputBufferIfNeeded(stream, numSamples)) {
201 return 0;
202 }
203 buffer = stream->inputBuffer + stream->numInputSamples;
204 while(count--) {
205 *buffer++ = (*samples++ - 128)/127.0;
Bill Coxca02d872010-11-02 15:10:52 -0400206 }
207 stream->numInputSamples += numSamples;
208 return 1;
209}
210
211/* Remove input samples that we have already processed. */
212static void removeInputSamples(
213 sonicStream stream,
214 int position)
215{
216 int remainingSamples = stream->numInputSamples - position;
217
218 if(remainingSamples > 0) {
219 memmove(stream->inputBuffer, stream->inputBuffer + position,
220 remainingSamples*sizeof(float));
221 }
222 stream->numInputSamples = remainingSamples;
223}
224
Bill Cox59e65122010-11-03 10:06:29 -0400225/* Just copy from the array to the output buffer */
Bill Cox0c4c0602010-11-08 11:46:30 -0500226static int copyFloatToOutput(
Bill Cox59e65122010-11-03 10:06:29 -0400227 sonicStream stream,
228 float *samples,
229 int numSamples)
230{
231 if(!enlargeOutputBufferIfNeeded(stream, numSamples)) {
232 return 0;
233 }
234 memcpy(stream->outputBuffer + stream->numOutputSamples, samples, numSamples*sizeof(float));
235 stream->numOutputSamples += numSamples;
236 return numSamples;
237}
238
Bill Cox0c4c0602010-11-08 11:46:30 -0500239/* Just copy from the array to the output buffer */
240static int copyShortToOutput(
241 sonicStream stream,
242 short *samples,
243 int numSamples)
244{
245 float *buffer;
246 int count = numSamples;
247
248 if(!enlargeOutputBufferIfNeeded(stream, numSamples)) {
249 return 0;
250 }
251 buffer = stream->outputBuffer + stream->numOutputSamples;
252 while(count--) {
Bill Coxea5aa0c2010-11-16 18:55:07 -0500253 *buffer++ = (*samples++)/32767;
Bill Cox0c4c0602010-11-08 11:46:30 -0500254 }
255 stream->numOutputSamples += numSamples;
256 return numSamples;
257}
258
Bill Cox8a23d2f2010-11-16 18:49:36 -0500259/* Just copy from the array to the output buffer */
260static int copyUnsignedCharToOutput(
261 sonicStream stream,
262 unsigned char *samples,
263 int numSamples)
264{
265 float *buffer;
266 int count = numSamples;
267
268 if(!enlargeOutputBufferIfNeeded(stream, numSamples)) {
269 return 0;
270 }
271 buffer = stream->outputBuffer + stream->numOutputSamples;
272 while(count--) {
273 *buffer++ = (*samples++ -128)/127.0;
Bill Coxca02d872010-11-02 15:10:52 -0400274 }
275 stream->numOutputSamples += numSamples;
276 return numSamples;
277}
278
Bill Cox882fb1d2010-11-02 16:27:20 -0400279/* Just copy from the input buffer to the output buffer. Return 0 if we fail to
280 resize the output buffer. Otherwise, return numSamples */
281static int copyInputToOutput(
282 sonicStream stream,
283 int position)
284{
285 int numSamples = stream->remainingInputToCopy;
286
287 if(numSamples > stream->maxRequired) {
288 numSamples = stream->maxRequired;
289 }
Bill Cox0c4c0602010-11-08 11:46:30 -0500290 if(!copyFloatToOutput(stream, stream->inputBuffer + position, numSamples)) {
Bill Cox882fb1d2010-11-02 16:27:20 -0400291 return 0;
292 }
Bill Cox882fb1d2010-11-02 16:27:20 -0400293 stream->remainingInputToCopy -= numSamples;
294 return numSamples;
295}
296
Bill Coxca02d872010-11-02 15:10:52 -0400297/* Read data out of the stream. Sometimes no data will be available, and zero
298 is returned, which is not an error condition. */
Bill Cox0c4c0602010-11-08 11:46:30 -0500299int sonicReadFloatFromStream(
Bill Coxca02d872010-11-02 15:10:52 -0400300 sonicStream stream,
301 float *samples,
302 int maxSamples)
303{
304 int numSamples = stream->numOutputSamples;
305 int remainingSamples = 0;
306
307 if(numSamples == 0) {
308 return 0;
309 }
310 if(numSamples > maxSamples) {
Bill Coxca02d872010-11-02 15:10:52 -0400311 remainingSamples = numSamples - maxSamples;
Bill Cox9bf11b52010-11-03 05:33:09 -0400312 numSamples = maxSamples;
Bill Coxca02d872010-11-02 15:10:52 -0400313 }
314 memcpy(samples, stream->outputBuffer, numSamples*sizeof(float));
315 if(remainingSamples > 0) {
316 memmove(stream->outputBuffer, stream->outputBuffer + numSamples,
317 remainingSamples*sizeof(float));
318 }
319 stream->numOutputSamples = remainingSamples;
320 return numSamples;
321}
322
Bill Cox0c4c0602010-11-08 11:46:30 -0500323/* Read short data out of the stream. Sometimes no data will be available, and zero
324 is returned, which is not an error condition. */
325int sonicReadShortFromStream(
326 sonicStream stream,
327 short *samples,
328 int maxSamples)
329{
330 int numSamples = stream->numOutputSamples;
331 int remainingSamples = 0;
332 float *buffer;
333 int i;
334
335 if(numSamples == 0) {
336 return 0;
337 }
338 if(numSamples > maxSamples) {
339 remainingSamples = numSamples - maxSamples;
340 numSamples = maxSamples;
341 }
342 buffer = stream->outputBuffer;
343 for(i = 0; i < numSamples; i++) {
Bill Coxea5aa0c2010-11-16 18:55:07 -0500344 *samples++ = (*buffer++) * 32767;
Bill Cox0c4c0602010-11-08 11:46:30 -0500345 }
346 if(remainingSamples > 0) {
347 memmove(stream->outputBuffer, stream->outputBuffer + numSamples,
348 remainingSamples*sizeof(float));
349 }
350 stream->numOutputSamples = remainingSamples;
351 return numSamples;
352}
353
Bill Cox8a23d2f2010-11-16 18:49:36 -0500354/* Read unsigned char data out of the stream. Sometimes no data will be available, and zero
355 is returned, which is not an error condition. */
356int sonicReadUnsignedCharFromStream(
357 sonicStream stream,
358 unsigned char *samples,
359 int maxSamples)
360{
361 int numSamples = stream->numOutputSamples;
362 int remainingSamples = 0;
363 float *buffer;
364 int i;
365
366 if(numSamples == 0) {
367 return 0;
368 }
369 if(numSamples > maxSamples) {
370 remainingSamples = numSamples - maxSamples;
371 numSamples = maxSamples;
372 }
373 buffer = stream->outputBuffer;
374 for(i = 0; i < numSamples; i++) {
375 *samples++ = (*buffer++) * 127 + 128;
Bill Coxca02d872010-11-02 15:10:52 -0400376 }
377 if(remainingSamples > 0) {
378 memmove(stream->outputBuffer, stream->outputBuffer + numSamples,
379 remainingSamples*sizeof(float));
380 }
381 stream->numOutputSamples = remainingSamples;
382 return numSamples;
383}
384
385/* Force the sonic stream to generate output using whatever data it currently
Bill Cox4bbbbcc2010-11-09 05:32:38 -0500386 has. No extra delay will be added to the output, but flushing in the middle of
387 words could introduce distortion. */
Bill Coxca02d872010-11-02 15:10:52 -0400388int sonicFlushStream(
389 sonicStream stream)
390{
391 int maxRequired = stream->maxRequired;
392 int numSamples = stream->numInputSamples;
Bill Cox4bbbbcc2010-11-09 05:32:38 -0500393 int remainingSpace, numOutputSamples, expectedSamples;
Bill Coxca02d872010-11-02 15:10:52 -0400394
395 if(numSamples == 0) {
396 return 1;
397 }
Bill Cox0c4c0602010-11-08 11:46:30 -0500398 if(numSamples >= maxRequired && !sonicWriteFloatToStream(stream, NULL, 0)) {
Bill Coxca02d872010-11-02 15:10:52 -0400399 return 0;
400 }
401 numSamples = stream->numInputSamples; /* Now numSamples < maxRequired */
Bill Cox4bbbbcc2010-11-09 05:32:38 -0500402 if(numSamples == 0) {
403 return 1;
404 }
Bill Coxca02d872010-11-02 15:10:52 -0400405 remainingSpace = maxRequired - numSamples;
406 memset(stream->inputBuffer + numSamples, 0, remainingSpace*sizeof(float));
407 stream->numInputSamples = maxRequired;
Bill Cox4bbbbcc2010-11-09 05:32:38 -0500408 numOutputSamples = stream->numOutputSamples;
409 if(!sonicWriteFloatToStream(stream, NULL, 0)) {
410 return 0;
411 }
412 /* Throw away any extra samples we generated due to the silence we added */
413 expectedSamples = (int)(numSamples*stream->speed + 0.5);
414 if(stream->numOutputSamples > numOutputSamples + expectedSamples) {
415 stream->numOutputSamples = numOutputSamples + expectedSamples;
416 }
417 return 1;
Bill Coxca02d872010-11-02 15:10:52 -0400418}
419
420/* Return the number of samples in the output buffer */
Bill Cox3a7abf92010-11-06 15:18:49 -0400421int sonicSamplesAvailable(
Bill Coxca02d872010-11-02 15:10:52 -0400422 sonicStream stream)
423{
424 return stream->numOutputSamples;
425}
Bill Cox9bf11b52010-11-03 05:33:09 -0400426
Bill Cox0cd49c82010-11-03 10:46:22 -0400427/* Find the best frequency match in the range, and given a sample skip multiple. */
428static int findPitchPeriodInRange(
Bill Cox0cd49c82010-11-03 10:46:22 -0400429 float *samples,
430 int minPeriod,
431 int maxPeriod,
432 int skip)
433{
434 int period, bestPeriod = 0;
435 double minDiff = 0.0;
436 double diff;
437 float value, *s, *p;
438 int xSample;
439
440 for(period = minPeriod; period <= maxPeriod; period += skip) {
441 diff = 0.0;
442 s = samples;
443 p = samples + period;
444 for(xSample = 0; xSample < period; xSample += skip) {
445 value = *s - *p;
446 s += skip;
447 p += skip;
448 diff += value >= 0.0? value : -value;
449 }
450 if(bestPeriod == 0 || diff < minDiff*period) {
451 diff /= period;
452 minDiff = diff;
453 bestPeriod = period;
454 }
455 }
456 return bestPeriod;
457}
458
Bill Cox9bf11b52010-11-03 05:33:09 -0400459/* Find the pitch period. This is a critical step, and we may have to try
Bill Cox0cd49c82010-11-03 10:46:22 -0400460 multiple ways to get a good answer. This version uses AMDF. To improve
461 speed, we down sample by an integer factor get in the 11KHz range, and then
462 do it again with a narrower frequency range without down sampling */
Bill Cox9bf11b52010-11-03 05:33:09 -0400463static int findPitchPeriod(
464 sonicStream stream,
465 float *samples)
466{
467 int minPeriod = stream->minPeriod;
468 int maxPeriod = stream->maxPeriod;
Bill Cox0cd49c82010-11-03 10:46:22 -0400469 int sampleRate = stream->sampleRate;
470 int skip = 1;
471 int period;
Bill Cox9bf11b52010-11-03 05:33:09 -0400472
Bill Cox0cd49c82010-11-03 10:46:22 -0400473 if(sampleRate > SONIC_AMDF_FREQ) {
474 skip = sampleRate/SONIC_AMDF_FREQ;
Bill Cox9bf11b52010-11-03 05:33:09 -0400475 }
Bill Coxa33e3bd2010-11-16 19:57:43 -0500476 period = findPitchPeriodInRange(samples, minPeriod, maxPeriod, skip);
Bill Cox0cd49c82010-11-03 10:46:22 -0400477 minPeriod = period*(1.0 - SONIC_AMDF_RANGE);
478 maxPeriod = period*(1.0 + SONIC_AMDF_RANGE);
479 if(minPeriod < stream->minPeriod) {
480 minPeriod = stream->minPeriod;
481 }
482 if(maxPeriod > stream->maxPeriod) {
483 maxPeriod = stream->maxPeriod;
484 }
485 return findPitchPeriodInRange(stream, samples, minPeriod, maxPeriod, 1);
Bill Cox9bf11b52010-11-03 05:33:09 -0400486}
487
Bill Cox59e65122010-11-03 10:06:29 -0400488/* Skip over a pitch period, and copy period/speed samples to the output */
489static int skipPitchPeriod(
Bill Cox9bf11b52010-11-03 05:33:09 -0400490 sonicStream stream,
491 float *samples,
492 double speed,
493 int period)
494{
495 int t, newSamples;
496 double scale;
497 float *out;
498
499 if(speed >= 2.0) {
500 newSamples = period/(speed - 1.0);
501 } else if(speed > 1.0) {
502 newSamples = period;
503 stream->remainingInputToCopy = period*(2.0 - speed)/(speed - 1.0);
Bill Cox9bf11b52010-11-03 05:33:09 -0400504 }
505 scale = 1.0/newSamples;
506 if(!enlargeOutputBufferIfNeeded(stream, newSamples)) {
507 return 0;
508 }
509 out = stream->outputBuffer + stream->numOutputSamples;
510 for(t = 0; t < newSamples; t++) {
511 out[t] = scale*(samples[t]*(newSamples - t) + samples[t + period]*t);
512 }
513 stream->numOutputSamples += newSamples;
514 return newSamples;
515}
516
Bill Cox59e65122010-11-03 10:06:29 -0400517/* Insert a pitch period, and determine how much input to copy directly. */
518static int insertPitchPeriod(
519 sonicStream stream,
520 float *samples,
521 double speed,
522 int period)
523{
524 int t, newSamples;
525 double scale;
526 float *out;
527
528 if(speed < 0.5) {
529 newSamples = period*speed/(1.0 - speed);
530 } else {
531 newSamples = period;
532 stream->remainingInputToCopy = period*(2.0*speed - 1.0)/(1.0 - speed);
533 }
534 if(!enlargeOutputBufferIfNeeded(stream, period + newSamples)) {
535 return 0;
536 }
537 out = stream->outputBuffer + stream->numOutputSamples;
538 memcpy(out, samples, period*sizeof(float));
539 out += period;
540 scale = 1.0/newSamples;
541 for(t = 0; t < newSamples; t++) {
542 out[t] = scale*(samples[t]*t + samples[t + period]*(newSamples - t));
543 }
544 stream->numOutputSamples += period + newSamples;
545 return newSamples;
546}
547
Bill Cox9bf11b52010-11-03 05:33:09 -0400548/* Resample as many pitch periods as we have buffered on the input. Return 0 if
549 we fail to resize an input or output buffer */
Bill Cox0c4c0602010-11-08 11:46:30 -0500550static int processStreamInput(
551 sonicStream stream)
Bill Cox9bf11b52010-11-03 05:33:09 -0400552{
Bill Cox0c4c0602010-11-08 11:46:30 -0500553 float *samples = stream->inputBuffer;
554 int numSamples = stream->numInputSamples;
Bill Cox9bf11b52010-11-03 05:33:09 -0400555 double speed = stream->speed;
556 int position = 0, period, newSamples;
557 int maxRequired = stream->maxRequired;
558
Bill Cox9bf11b52010-11-03 05:33:09 -0400559 if(stream->numInputSamples < maxRequired) {
560 return 1;
561 }
Bill Cox9bf11b52010-11-03 05:33:09 -0400562 do {
563 if(stream->remainingInputToCopy > 0) {
Bill Cox9bf11b52010-11-03 05:33:09 -0400564 newSamples = copyInputToOutput(stream, position);
Bill Cox59e65122010-11-03 10:06:29 -0400565 position += newSamples;
Bill Cox9bf11b52010-11-03 05:33:09 -0400566 } else {
567 period = findPitchPeriod(stream, samples + position);
Bill Cox59e65122010-11-03 10:06:29 -0400568 if(speed > 1.0) {
569 newSamples = skipPitchPeriod(stream, samples + position, speed, period);
570 position += period + newSamples;
571 } else {
572 newSamples = insertPitchPeriod(stream, samples + position, speed, period);
573 position += newSamples;
574 }
Bill Cox9bf11b52010-11-03 05:33:09 -0400575 }
576 if(newSamples == 0) {
577 return 0; /* Failed to resize output buffer */
578 }
Bill Cox9bf11b52010-11-03 05:33:09 -0400579 } while(position + maxRequired <= numSamples);
580 removeInputSamples(stream, position);
581 return 1;
582}
Bill Cox0c4c0602010-11-08 11:46:30 -0500583
584/* Write floating point data to the input buffer and process it. */
585int sonicWriteFloatToStream(
586 sonicStream stream,
587 float *samples,
588 int numSamples)
589{
590 double speed = stream->speed;
591
592 if(speed > 0.999999 && speed < 1.000001) {
593 /* No speed change - just copy to the output */
594 return copyFloatToOutput(stream, samples, numSamples);
595 }
596 if(!addFloatSamplesToInputBuffer(stream, samples, numSamples)) {
597 return 0;
598 }
599 return processStreamInput(stream);
600}
601
602/* Simple wrapper around sonicWriteFloatToStream that does the short to float
603 conversion for you. */
604int sonicWriteShortToStream(
605 sonicStream stream,
606 short *samples,
607 int numSamples)
608{
609 double speed = stream->speed;
610
611 if(speed > 0.999999 && speed < 1.000001) {
612 /* No speed change - just copy to the output */
613 return copyShortToOutput(stream, samples, numSamples);
614 }
615 if(!addShortSamplesToInputBuffer(stream, samples, numSamples)) {
616 return 0;
617 }
618 return processStreamInput(stream);
619}
620
Bill Cox8a23d2f2010-11-16 18:49:36 -0500621/* Simple wrapper around sonicWriteFloatToStream that does the unsigned char to float
622 conversion for you. */
623int sonicWriteUnsignedCharToStream(
624 sonicStream stream,
625 unsigned char *samples,
626 int numSamples)
627{
628 double speed = stream->speed;
629
630 if(speed > 0.999999 && speed < 1.000001) {
631 /* No speed change - just copy to the output */
632 return copyUnsignedCharToOutput(stream, samples, numSamples);
633 }
634 if(!addUnsignedCharSamplesToInputBuffer(stream, samples, numSamples)) {
635 return 0;
636 }
637 return processStreamInput(stream);
638}
639
Bill Cox036d7322010-11-09 09:29:24 -0500640/* This is a non-stream oriented interface to just change the speed of a sound sample */
641int sonicChangeFloatSpeed(
642 float *samples,
643 int numSamples,
644 double speed,
645 int sampleRate)
646{
647 sonicStream stream = sonicCreateStream(speed, sampleRate);
648
649 sonicWriteFloatToStream(stream, samples, numSamples);
650 sonicFlushStream(stream);
651 numSamples = sonicSamplesAvailable(stream);
652 sonicReadFloatFromStream(stream, samples, numSamples);
653 sonicDestroyStream(stream);
654 return numSamples;
655}
656
657/* This is a non-stream oriented interface to just change the speed of a sound sample */
658int sonicChangeShortSpeed(
659 short *samples,
660 int numSamples,
661 double speed,
662 int sampleRate)
663{
664 sonicStream stream = sonicCreateStream(speed, sampleRate);
665
666 sonicWriteShortToStream(stream, samples, numSamples);
667 sonicFlushStream(stream);
668 numSamples = sonicSamplesAvailable(stream);
669 sonicReadShortFromStream(stream, samples, numSamples);
670 sonicDestroyStream(stream);
671 return numSamples;
672}
673