blob: 239a858869b4cc0edd40939e4d546decf75ee3ed [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>
23#include "sonic.h"
24
25struct sonicStreamStruct {
26 double speed;
27 float *inputBuffer;
28 float *outputBuffer;
29 int inputBufferSize;
30 int outputBufferSize;
31 int numInputSamples;
32 int numOutputSamples;
33 int minPeriod;
34 int maxPeriod;
35 int maxRequired;
36 int remainingInputToCopy;
37 int sampleRate;
38};
39
Bill Coxaf9a6242010-11-08 09:32:27 -050040/* Get the speed of the stream. */
41double sonicGetSpeed(
42 sonicStream stream)
43{
44 return stream->speed;
45}
46
47/* Get the sample rate of the stream. */
48int sonicGetSampleRate(
49 sonicStream stream)
50{
51 return stream->sampleRate;
52}
53
Bill Coxca02d872010-11-02 15:10:52 -040054/* Destroy the sonic stream. */
55void sonicDestroyStream(
56 sonicStream stream)
57{
58 if(stream->inputBuffer != NULL) {
59 free(stream->inputBuffer);
60 }
61 if(stream->outputBuffer != NULL) {
62 free(stream->outputBuffer);
63 }
64 free(stream);
65}
66
67/* Create a sonic stream. Return NULL only if we are out of memory and cannot
68 allocate the stream. */
69sonicStream sonicCreateStream(
70 double speed,
71 int sampleRate)
72{
73 sonicStream stream = (sonicStream)calloc(1, sizeof(struct sonicStreamStruct));
74 int minPeriod = sampleRate/SONIC_MAX_PITCH;
75 int maxPeriod = sampleRate/SONIC_MIN_PITCH;
76 int maxRequired = 2*maxPeriod;
77
78 if(stream == NULL) {
79 return NULL;
80 }
81 stream->inputBuffer = (float *)calloc(maxRequired, sizeof(float));
82 if(stream->inputBuffer == NULL) {
83 sonicDestroyStream(stream);
84 return NULL;
85 }
86 stream->outputBuffer = (float *)calloc(maxRequired, sizeof(float));
87 if(stream->outputBuffer == NULL) {
88 sonicDestroyStream(stream);
89 return NULL;
90 }
91 stream->speed = speed;
92 stream->sampleRate = sampleRate;
93 stream->minPeriod = minPeriod;
94 stream->maxPeriod = maxPeriod;
95 stream->maxRequired = maxRequired;
96 stream->inputBufferSize = maxRequired;
97 stream->outputBufferSize = maxRequired;
98 return stream;
99}
100
Bill Coxca02d872010-11-02 15:10:52 -0400101/* Enlarge the output buffer if needed. */
102static int enlargeOutputBufferIfNeeded(
103 sonicStream stream,
104 int numSamples)
105{
106 if(stream->numOutputSamples + numSamples > stream->outputBufferSize) {
107 stream->outputBufferSize += (stream->outputBufferSize >> 1) + numSamples;
108 stream->outputBuffer = (float *)realloc(stream->outputBuffer,
109 stream->outputBufferSize*sizeof(float));
110 if(stream->outputBuffer == NULL) {
Bill Coxca02d872010-11-02 15:10:52 -0400111 return 0;
112 }
113 }
114 return 1;
115}
116
Bill Coxca02d872010-11-02 15:10:52 -0400117/* Enlarge the input buffer if needed. */
118static int enlargeInputBufferIfNeeded(
119 sonicStream stream,
120 int numSamples)
121{
122 if(stream->numInputSamples + numSamples > stream->inputBufferSize) {
123 stream->inputBufferSize += (stream->inputBufferSize >> 1) + numSamples;
124 stream->inputBuffer = (float *)realloc(stream->inputBuffer,
125 stream->inputBufferSize*sizeof(float));
126 if(stream->inputBuffer == NULL) {
Bill Coxca02d872010-11-02 15:10:52 -0400127 return 0;
128 }
129 }
130 return 1;
131}
132
133/* Add the input samples to the input buffer. */
Bill Cox0c4c0602010-11-08 11:46:30 -0500134static int addFloatSamplesToInputBuffer(
Bill Coxca02d872010-11-02 15:10:52 -0400135 sonicStream stream,
136 float *samples,
137 int numSamples)
138{
139 if(numSamples == 0) {
140 return 1;
141 }
142 if(!enlargeInputBufferIfNeeded(stream, numSamples)) {
143 return 0;
144 }
145 memcpy(stream->inputBuffer + stream->numInputSamples, samples, numSamples*sizeof(float));
Bill Cox14efa442010-11-02 15:43:58 -0400146 stream->numInputSamples += numSamples;
Bill Coxca02d872010-11-02 15:10:52 -0400147 return 1;
148}
149
Bill Cox0c4c0602010-11-08 11:46:30 -0500150/* Add the input samples to the input buffer. */
151static int addShortSamplesToInputBuffer(
152 sonicStream stream,
153 short *samples,
154 int numSamples)
155{
156 float *buffer;
157 int count = numSamples;
158
159 if(numSamples == 0) {
160 return 1;
161 }
162 if(!enlargeInputBufferIfNeeded(stream, numSamples)) {
163 return 0;
164 }
165 buffer = stream->inputBuffer + stream->numInputSamples;
166 while(count--) {
167 *buffer++ = *samples++;
168 }
169 stream->numInputSamples += numSamples;
170 return 1;
171}
172
Bill Cox8a23d2f2010-11-16 18:49:36 -0500173/* Add the input samples to the input buffer. */
174static int addUnsignedCharSamplesToInputBuffer(
175 sonicStream stream,
176 unsigned char *samples,
177 int numSamples)
178{
179 float *buffer;
180 int count = numSamples;
181
182 if(numSamples == 0) {
183 return 1;
184 }
185 if(!enlargeInputBufferIfNeeded(stream, numSamples)) {
186 return 0;
187 }
188 buffer = stream->inputBuffer + stream->numInputSamples;
189 while(count--) {
190 *buffer++ = (*samples++ - 128)/127.0;
191 }
192 stream->numInputSamples += numSamples;
193 return 1;
194}
195
Bill Coxca02d872010-11-02 15:10:52 -0400196/* Remove input samples that we have already processed. */
197static void removeInputSamples(
198 sonicStream stream,
199 int position)
200{
201 int remainingSamples = stream->numInputSamples - position;
202
203 if(remainingSamples > 0) {
204 memmove(stream->inputBuffer, stream->inputBuffer + position,
205 remainingSamples*sizeof(float));
206 }
207 stream->numInputSamples = remainingSamples;
208}
209
Bill Cox59e65122010-11-03 10:06:29 -0400210/* Just copy from the array to the output buffer */
Bill Cox0c4c0602010-11-08 11:46:30 -0500211static int copyFloatToOutput(
Bill Cox59e65122010-11-03 10:06:29 -0400212 sonicStream stream,
213 float *samples,
214 int numSamples)
215{
216 if(!enlargeOutputBufferIfNeeded(stream, numSamples)) {
217 return 0;
218 }
219 memcpy(stream->outputBuffer + stream->numOutputSamples, samples, numSamples*sizeof(float));
220 stream->numOutputSamples += numSamples;
221 return numSamples;
222}
223
Bill Cox0c4c0602010-11-08 11:46:30 -0500224/* Just copy from the array to the output buffer */
225static int copyShortToOutput(
226 sonicStream stream,
227 short *samples,
228 int numSamples)
229{
230 float *buffer;
231 int count = numSamples;
232
233 if(!enlargeOutputBufferIfNeeded(stream, numSamples)) {
234 return 0;
235 }
236 buffer = stream->outputBuffer + stream->numOutputSamples;
237 while(count--) {
238 *buffer++ = *samples++;
239 }
240 stream->numOutputSamples += numSamples;
241 return numSamples;
242}
243
Bill Cox8a23d2f2010-11-16 18:49:36 -0500244/* Just copy from the array to the output buffer */
245static int copyUnsignedCharToOutput(
246 sonicStream stream,
247 unsigned char *samples,
248 int numSamples)
249{
250 float *buffer;
251 int count = numSamples;
252
253 if(!enlargeOutputBufferIfNeeded(stream, numSamples)) {
254 return 0;
255 }
256 buffer = stream->outputBuffer + stream->numOutputSamples;
257 while(count--) {
258 *buffer++ = (*samples++ -128)/127.0;
259 }
260 stream->numOutputSamples += numSamples;
261 return numSamples;
262}
263
Bill Cox882fb1d2010-11-02 16:27:20 -0400264/* Just copy from the input buffer to the output buffer. Return 0 if we fail to
265 resize the output buffer. Otherwise, return numSamples */
266static int copyInputToOutput(
267 sonicStream stream,
268 int position)
269{
270 int numSamples = stream->remainingInputToCopy;
271
272 if(numSamples > stream->maxRequired) {
273 numSamples = stream->maxRequired;
274 }
Bill Cox0c4c0602010-11-08 11:46:30 -0500275 if(!copyFloatToOutput(stream, stream->inputBuffer + position, numSamples)) {
Bill Cox882fb1d2010-11-02 16:27:20 -0400276 return 0;
277 }
Bill Cox882fb1d2010-11-02 16:27:20 -0400278 stream->remainingInputToCopy -= numSamples;
279 return numSamples;
280}
281
Bill Coxca02d872010-11-02 15:10:52 -0400282/* Read data out of the stream. Sometimes no data will be available, and zero
283 is returned, which is not an error condition. */
Bill Cox0c4c0602010-11-08 11:46:30 -0500284int sonicReadFloatFromStream(
Bill Coxca02d872010-11-02 15:10:52 -0400285 sonicStream stream,
286 float *samples,
287 int maxSamples)
288{
289 int numSamples = stream->numOutputSamples;
290 int remainingSamples = 0;
291
292 if(numSamples == 0) {
293 return 0;
294 }
295 if(numSamples > maxSamples) {
Bill Coxca02d872010-11-02 15:10:52 -0400296 remainingSamples = numSamples - maxSamples;
Bill Cox9bf11b52010-11-03 05:33:09 -0400297 numSamples = maxSamples;
Bill Coxca02d872010-11-02 15:10:52 -0400298 }
299 memcpy(samples, stream->outputBuffer, numSamples*sizeof(float));
300 if(remainingSamples > 0) {
301 memmove(stream->outputBuffer, stream->outputBuffer + numSamples,
302 remainingSamples*sizeof(float));
303 }
304 stream->numOutputSamples = remainingSamples;
305 return numSamples;
306}
307
Bill Cox0c4c0602010-11-08 11:46:30 -0500308/* Read short data out of the stream. Sometimes no data will be available, and zero
309 is returned, which is not an error condition. */
310int sonicReadShortFromStream(
311 sonicStream stream,
312 short *samples,
313 int maxSamples)
314{
315 int numSamples = stream->numOutputSamples;
316 int remainingSamples = 0;
317 float *buffer;
318 int i;
319
320 if(numSamples == 0) {
321 return 0;
322 }
323 if(numSamples > maxSamples) {
324 remainingSamples = numSamples - maxSamples;
325 numSamples = maxSamples;
326 }
327 buffer = stream->outputBuffer;
328 for(i = 0; i < numSamples; i++) {
329 *samples++ = *buffer++;
330 }
331 if(remainingSamples > 0) {
332 memmove(stream->outputBuffer, stream->outputBuffer + numSamples,
333 remainingSamples*sizeof(float));
334 }
335 stream->numOutputSamples = remainingSamples;
336 return numSamples;
337}
338
Bill Cox8a23d2f2010-11-16 18:49:36 -0500339/* Read unsigned char data out of the stream. Sometimes no data will be available, and zero
340 is returned, which is not an error condition. */
341int sonicReadUnsignedCharFromStream(
342 sonicStream stream,
343 unsigned char *samples,
344 int maxSamples)
345{
346 int numSamples = stream->numOutputSamples;
347 int remainingSamples = 0;
348 float *buffer;
349 int i;
350
351 if(numSamples == 0) {
352 return 0;
353 }
354 if(numSamples > maxSamples) {
355 remainingSamples = numSamples - maxSamples;
356 numSamples = maxSamples;
357 }
358 buffer = stream->outputBuffer;
359 for(i = 0; i < numSamples; i++) {
360 *samples++ = (*buffer++) * 127 + 128;
361 }
362 if(remainingSamples > 0) {
363 memmove(stream->outputBuffer, stream->outputBuffer + numSamples,
364 remainingSamples*sizeof(float));
365 }
366 stream->numOutputSamples = remainingSamples;
367 return numSamples;
368}
369
Bill Coxca02d872010-11-02 15:10:52 -0400370/* Force the sonic stream to generate output using whatever data it currently
Bill Cox4bbbbcc2010-11-09 05:32:38 -0500371 has. No extra delay will be added to the output, but flushing in the middle of
372 words could introduce distortion. */
Bill Coxca02d872010-11-02 15:10:52 -0400373int sonicFlushStream(
374 sonicStream stream)
375{
376 int maxRequired = stream->maxRequired;
377 int numSamples = stream->numInputSamples;
Bill Cox4bbbbcc2010-11-09 05:32:38 -0500378 int remainingSpace, numOutputSamples, expectedSamples;
Bill Coxca02d872010-11-02 15:10:52 -0400379
380 if(numSamples == 0) {
381 return 1;
382 }
Bill Cox0c4c0602010-11-08 11:46:30 -0500383 if(numSamples >= maxRequired && !sonicWriteFloatToStream(stream, NULL, 0)) {
Bill Coxca02d872010-11-02 15:10:52 -0400384 return 0;
385 }
386 numSamples = stream->numInputSamples; /* Now numSamples < maxRequired */
Bill Cox4bbbbcc2010-11-09 05:32:38 -0500387 if(numSamples == 0) {
388 return 1;
389 }
Bill Coxca02d872010-11-02 15:10:52 -0400390 remainingSpace = maxRequired - numSamples;
391 memset(stream->inputBuffer + numSamples, 0, remainingSpace*sizeof(float));
392 stream->numInputSamples = maxRequired;
Bill Cox4bbbbcc2010-11-09 05:32:38 -0500393 numOutputSamples = stream->numOutputSamples;
394 if(!sonicWriteFloatToStream(stream, NULL, 0)) {
395 return 0;
396 }
397 /* Throw away any extra samples we generated due to the silence we added */
398 expectedSamples = (int)(numSamples*stream->speed + 0.5);
399 if(stream->numOutputSamples > numOutputSamples + expectedSamples) {
400 stream->numOutputSamples = numOutputSamples + expectedSamples;
401 }
402 return 1;
Bill Coxca02d872010-11-02 15:10:52 -0400403}
404
405/* Return the number of samples in the output buffer */
Bill Cox3a7abf92010-11-06 15:18:49 -0400406int sonicSamplesAvailable(
Bill Coxca02d872010-11-02 15:10:52 -0400407 sonicStream stream)
408{
409 return stream->numOutputSamples;
410}
Bill Cox9bf11b52010-11-03 05:33:09 -0400411
Bill Cox0cd49c82010-11-03 10:46:22 -0400412/* Find the best frequency match in the range, and given a sample skip multiple. */
413static int findPitchPeriodInRange(
414 sonicStream stream,
415 float *samples,
416 int minPeriod,
417 int maxPeriod,
418 int skip)
419{
420 int period, bestPeriod = 0;
421 double minDiff = 0.0;
422 double diff;
423 float value, *s, *p;
424 int xSample;
425
426 for(period = minPeriod; period <= maxPeriod; period += skip) {
427 diff = 0.0;
428 s = samples;
429 p = samples + period;
430 for(xSample = 0; xSample < period; xSample += skip) {
431 value = *s - *p;
432 s += skip;
433 p += skip;
434 diff += value >= 0.0? value : -value;
435 }
436 if(bestPeriod == 0 || diff < minDiff*period) {
437 diff /= period;
438 minDiff = diff;
439 bestPeriod = period;
440 }
441 }
442 return bestPeriod;
443}
444
Bill Cox9bf11b52010-11-03 05:33:09 -0400445/* Find the pitch period. This is a critical step, and we may have to try
Bill Cox0cd49c82010-11-03 10:46:22 -0400446 multiple ways to get a good answer. This version uses AMDF. To improve
447 speed, we down sample by an integer factor get in the 11KHz range, and then
448 do it again with a narrower frequency range without down sampling */
Bill Cox9bf11b52010-11-03 05:33:09 -0400449static int findPitchPeriod(
450 sonicStream stream,
451 float *samples)
452{
453 int minPeriod = stream->minPeriod;
454 int maxPeriod = stream->maxPeriod;
Bill Cox0cd49c82010-11-03 10:46:22 -0400455 int sampleRate = stream->sampleRate;
456 int skip = 1;
457 int period;
Bill Cox9bf11b52010-11-03 05:33:09 -0400458
Bill Cox0cd49c82010-11-03 10:46:22 -0400459 if(sampleRate > SONIC_AMDF_FREQ) {
460 skip = sampleRate/SONIC_AMDF_FREQ;
Bill Cox9bf11b52010-11-03 05:33:09 -0400461 }
Bill Cox0cd49c82010-11-03 10:46:22 -0400462 period = findPitchPeriodInRange(stream, samples, minPeriod, maxPeriod, skip);
463 minPeriod = period*(1.0 - SONIC_AMDF_RANGE);
464 maxPeriod = period*(1.0 + SONIC_AMDF_RANGE);
465 if(minPeriod < stream->minPeriod) {
466 minPeriod = stream->minPeriod;
467 }
468 if(maxPeriod > stream->maxPeriod) {
469 maxPeriod = stream->maxPeriod;
470 }
471 return findPitchPeriodInRange(stream, samples, minPeriod, maxPeriod, 1);
Bill Cox9bf11b52010-11-03 05:33:09 -0400472}
473
Bill Cox59e65122010-11-03 10:06:29 -0400474/* Skip over a pitch period, and copy period/speed samples to the output */
475static int skipPitchPeriod(
Bill Cox9bf11b52010-11-03 05:33:09 -0400476 sonicStream stream,
477 float *samples,
478 double speed,
479 int period)
480{
481 int t, newSamples;
482 double scale;
483 float *out;
484
485 if(speed >= 2.0) {
486 newSamples = period/(speed - 1.0);
487 } else if(speed > 1.0) {
488 newSamples = period;
489 stream->remainingInputToCopy = period*(2.0 - speed)/(speed - 1.0);
Bill Cox9bf11b52010-11-03 05:33:09 -0400490 }
491 scale = 1.0/newSamples;
492 if(!enlargeOutputBufferIfNeeded(stream, newSamples)) {
493 return 0;
494 }
495 out = stream->outputBuffer + stream->numOutputSamples;
496 for(t = 0; t < newSamples; t++) {
497 out[t] = scale*(samples[t]*(newSamples - t) + samples[t + period]*t);
498 }
499 stream->numOutputSamples += newSamples;
500 return newSamples;
501}
502
Bill Cox59e65122010-11-03 10:06:29 -0400503/* Insert a pitch period, and determine how much input to copy directly. */
504static int insertPitchPeriod(
505 sonicStream stream,
506 float *samples,
507 double speed,
508 int period)
509{
510 int t, newSamples;
511 double scale;
512 float *out;
513
514 if(speed < 0.5) {
515 newSamples = period*speed/(1.0 - speed);
516 } else {
517 newSamples = period;
518 stream->remainingInputToCopy = period*(2.0*speed - 1.0)/(1.0 - speed);
519 }
520 if(!enlargeOutputBufferIfNeeded(stream, period + newSamples)) {
521 return 0;
522 }
523 out = stream->outputBuffer + stream->numOutputSamples;
524 memcpy(out, samples, period*sizeof(float));
525 out += period;
526 scale = 1.0/newSamples;
527 for(t = 0; t < newSamples; t++) {
528 out[t] = scale*(samples[t]*t + samples[t + period]*(newSamples - t));
529 }
530 stream->numOutputSamples += period + newSamples;
531 return newSamples;
532}
533
Bill Cox9bf11b52010-11-03 05:33:09 -0400534/* Resample as many pitch periods as we have buffered on the input. Return 0 if
535 we fail to resize an input or output buffer */
Bill Cox0c4c0602010-11-08 11:46:30 -0500536static int processStreamInput(
537 sonicStream stream)
Bill Cox9bf11b52010-11-03 05:33:09 -0400538{
Bill Cox0c4c0602010-11-08 11:46:30 -0500539 float *samples = stream->inputBuffer;
540 int numSamples = stream->numInputSamples;
Bill Cox9bf11b52010-11-03 05:33:09 -0400541 double speed = stream->speed;
542 int position = 0, period, newSamples;
543 int maxRequired = stream->maxRequired;
544
Bill Cox9bf11b52010-11-03 05:33:09 -0400545 if(stream->numInputSamples < maxRequired) {
546 return 1;
547 }
Bill Cox9bf11b52010-11-03 05:33:09 -0400548 do {
549 if(stream->remainingInputToCopy > 0) {
Bill Cox9bf11b52010-11-03 05:33:09 -0400550 newSamples = copyInputToOutput(stream, position);
Bill Cox59e65122010-11-03 10:06:29 -0400551 position += newSamples;
Bill Cox9bf11b52010-11-03 05:33:09 -0400552 } else {
553 period = findPitchPeriod(stream, samples + position);
Bill Cox59e65122010-11-03 10:06:29 -0400554 if(speed > 1.0) {
555 newSamples = skipPitchPeriod(stream, samples + position, speed, period);
556 position += period + newSamples;
557 } else {
558 newSamples = insertPitchPeriod(stream, samples + position, speed, period);
559 position += newSamples;
560 }
Bill Cox9bf11b52010-11-03 05:33:09 -0400561 }
562 if(newSamples == 0) {
563 return 0; /* Failed to resize output buffer */
564 }
Bill Cox9bf11b52010-11-03 05:33:09 -0400565 } while(position + maxRequired <= numSamples);
566 removeInputSamples(stream, position);
567 return 1;
568}
Bill Cox0c4c0602010-11-08 11:46:30 -0500569
570/* Write floating point data to the input buffer and process it. */
571int sonicWriteFloatToStream(
572 sonicStream stream,
573 float *samples,
574 int numSamples)
575{
576 double speed = stream->speed;
577
578 if(speed > 0.999999 && speed < 1.000001) {
579 /* No speed change - just copy to the output */
580 return copyFloatToOutput(stream, samples, numSamples);
581 }
582 if(!addFloatSamplesToInputBuffer(stream, samples, numSamples)) {
583 return 0;
584 }
585 return processStreamInput(stream);
586}
587
588/* Simple wrapper around sonicWriteFloatToStream that does the short to float
589 conversion for you. */
590int sonicWriteShortToStream(
591 sonicStream stream,
592 short *samples,
593 int numSamples)
594{
595 double speed = stream->speed;
596
597 if(speed > 0.999999 && speed < 1.000001) {
598 /* No speed change - just copy to the output */
599 return copyShortToOutput(stream, samples, numSamples);
600 }
601 if(!addShortSamplesToInputBuffer(stream, samples, numSamples)) {
602 return 0;
603 }
604 return processStreamInput(stream);
605}
606
Bill Cox8a23d2f2010-11-16 18:49:36 -0500607/* Simple wrapper around sonicWriteFloatToStream that does the unsigned char to float
608 conversion for you. */
609int sonicWriteUnsignedCharToStream(
610 sonicStream stream,
611 unsigned char *samples,
612 int numSamples)
613{
614 double speed = stream->speed;
615
616 if(speed > 0.999999 && speed < 1.000001) {
617 /* No speed change - just copy to the output */
618 return copyUnsignedCharToOutput(stream, samples, numSamples);
619 }
620 if(!addUnsignedCharSamplesToInputBuffer(stream, samples, numSamples)) {
621 return 0;
622 }
623 return processStreamInput(stream);
624}
625
Bill Cox036d7322010-11-09 09:29:24 -0500626/* This is a non-stream oriented interface to just change the speed of a sound sample */
627int sonicChangeFloatSpeed(
628 float *samples,
629 int numSamples,
630 double speed,
631 int sampleRate)
632{
633 sonicStream stream = sonicCreateStream(speed, sampleRate);
634
635 sonicWriteFloatToStream(stream, samples, numSamples);
636 sonicFlushStream(stream);
637 numSamples = sonicSamplesAvailable(stream);
638 sonicReadFloatFromStream(stream, samples, numSamples);
639 sonicDestroyStream(stream);
640 return numSamples;
641}
642
Bill Coxa9999872010-11-11 14:36:59 -0500643#include <stdarg.h>
644void MSG(char *format, ...)
645{
646 char buffer[4096];
647 va_list ap;
648 FILE *file;
649
650 va_start(ap, format);
651 vsprintf((char *)buffer, (char *)format, ap);
652 va_end(ap);
653 file=fopen("/tmp/sonic.log", "a");
654 fprintf(file, "%s", buffer);
655 fclose(file);
656}
657
Bill Cox036d7322010-11-09 09:29:24 -0500658/* This is a non-stream oriented interface to just change the speed of a sound sample */
659int sonicChangeShortSpeed(
660 short *samples,
661 int numSamples,
662 double speed,
663 int sampleRate)
664{
665 sonicStream stream = sonicCreateStream(speed, sampleRate);
666
667 sonicWriteShortToStream(stream, samples, numSamples);
668 sonicFlushStream(stream);
669 numSamples = sonicSamplesAvailable(stream);
670 sonicReadShortFromStream(stream, samples, numSamples);
671 sonicDestroyStream(stream);
672 return numSamples;
673}
674