Compiled, but not debugged, multi-channel support
diff --git a/sonic.c b/sonic.c
index d85629b..b4b094b 100644
--- a/sonic.c
+++ b/sonic.c
@@ -24,9 +24,10 @@
#include "sonic.h"
struct sonicStreamStruct {
- float speed;
short *inputBuffer;
short *outputBuffer;
+ float speed;
+ int numChannels;
int inputBufferSize;
int outputBufferSize;
int numInputSamples;
@@ -38,6 +39,7 @@
int sampleRate;
};
+/* Just used for debugging */
void sonicMSG(char *format, ...)
{
char buffer[4096];
@@ -83,7 +85,8 @@
allocate the stream. */
sonicStream sonicCreateStream(
float speed,
- int sampleRate)
+ int sampleRate,
+ int numChannels)
{
sonicStream stream = (sonicStream)calloc(1, sizeof(struct sonicStreamStruct));
int minPeriod = sampleRate/SONIC_MAX_PITCH;
@@ -93,18 +96,19 @@
if(stream == NULL) {
return NULL;
}
- stream->inputBuffer = (short *)calloc(maxRequired, sizeof(short));
+ stream->inputBuffer = (short *)calloc(maxRequired, sizeof(short)*numChannels);
if(stream->inputBuffer == NULL) {
sonicDestroyStream(stream);
return NULL;
}
- stream->outputBuffer = (short *)calloc(maxRequired, sizeof(short));
+ stream->outputBuffer = (short *)calloc(maxRequired, sizeof(short)*numChannels);
if(stream->outputBuffer == NULL) {
sonicDestroyStream(stream);
return NULL;
}
stream->speed = speed;
stream->sampleRate = sampleRate;
+ stream->numChannels = numChannels;
stream->minPeriod = minPeriod;
stream->maxPeriod = maxPeriod;
stream->maxRequired = maxRequired;
@@ -121,7 +125,7 @@
if(stream->numOutputSamples + numSamples > stream->outputBufferSize) {
stream->outputBufferSize += (stream->outputBufferSize >> 1) + numSamples;
stream->outputBuffer = (short *)realloc(stream->outputBuffer,
- stream->outputBufferSize*sizeof(short));
+ stream->outputBufferSize*sizeof(short)*stream->numChannels);
if(stream->outputBuffer == NULL) {
return 0;
}
@@ -137,7 +141,7 @@
if(stream->numInputSamples + numSamples > stream->inputBufferSize) {
stream->inputBufferSize += (stream->inputBufferSize >> 1) + numSamples;
stream->inputBuffer = (short *)realloc(stream->inputBuffer,
- stream->inputBufferSize*sizeof(short));
+ stream->inputBufferSize*sizeof(short)*stream->numChannels);
if(stream->inputBuffer == NULL) {
return 0;
}
@@ -152,7 +156,7 @@
int numSamples)
{
short *buffer;
- int count = numSamples;
+ int count = numSamples*stream->numChannels;
if(numSamples == 0) {
return 1;
@@ -160,7 +164,7 @@
if(!enlargeInputBufferIfNeeded(stream, numSamples)) {
return 0;
}
- buffer = stream->inputBuffer + stream->numInputSamples;
+ buffer = stream->inputBuffer + stream->numInputSamples*stream->numChannels;
while(count--) {
*buffer++ = (*samples++)*32767.0f;
}
@@ -180,7 +184,8 @@
if(!enlargeInputBufferIfNeeded(stream, numSamples)) {
return 0;
}
- memcpy(stream->inputBuffer + stream->numInputSamples, samples, numSamples*sizeof(short));
+ memcpy(stream->inputBuffer + stream->numInputSamples*stream->numChannels, samples,
+ numSamples*sizeof(short)*stream->numChannels);
stream->numInputSamples += numSamples;
return 1;
}
@@ -192,7 +197,7 @@
int numSamples)
{
short *buffer;
- int count = numSamples;
+ int count = numSamples*stream->numChannels;
if(numSamples == 0) {
return 1;
@@ -200,7 +205,7 @@
if(!enlargeInputBufferIfNeeded(stream, numSamples)) {
return 0;
}
- buffer = stream->inputBuffer + stream->numInputSamples;
+ buffer = stream->inputBuffer + stream->numInputSamples*stream->numChannels;
while(count--) {
*buffer++ = (*samples++ - 128) << 8;
}
@@ -216,8 +221,8 @@
int remainingSamples = stream->numInputSamples - position;
if(remainingSamples > 0) {
- memmove(stream->inputBuffer, stream->inputBuffer + position,
- remainingSamples*sizeof(short));
+ memmove(stream->inputBuffer, stream->inputBuffer + position*stream->numChannels,
+ remainingSamples*sizeof(short)*stream->numChannels);
}
stream->numInputSamples = remainingSamples;
}
@@ -229,12 +234,12 @@
int numSamples)
{
short *buffer;
- int count = numSamples;
+ int count = numSamples*stream->numChannels;
if(!enlargeOutputBufferIfNeeded(stream, numSamples)) {
return 0;
}
- buffer = stream->outputBuffer + stream->numOutputSamples;
+ buffer = stream->outputBuffer + stream->numOutputSamples*stream->numChannels;
while(count--) {
*buffer++ = (*samples++)*32767.0f;
}
@@ -251,7 +256,8 @@
if(!enlargeOutputBufferIfNeeded(stream, numSamples)) {
return 0;
}
- memcpy(stream->outputBuffer + stream->numOutputSamples, samples, numSamples*sizeof(short));
+ memcpy(stream->outputBuffer + stream->numOutputSamples*stream->numChannels,
+ samples, numSamples*sizeof(short)*stream->numChannels);
stream->numOutputSamples += numSamples;
return numSamples;
}
@@ -263,12 +269,12 @@
int numSamples)
{
short *buffer;
- int count = numSamples;
+ int count = numSamples*stream->numChannels;
if(!enlargeOutputBufferIfNeeded(stream, numSamples)) {
return 0;
}
- buffer = stream->outputBuffer + stream->numOutputSamples;
+ buffer = stream->outputBuffer + stream->numOutputSamples*stream->numChannels;
while(count--) {
*buffer++ = (*samples++ - 128) << 8;
}
@@ -287,7 +293,8 @@
if(numSamples > stream->maxRequired) {
numSamples = stream->maxRequired;
}
- if(!copyShortToOutput(stream, stream->inputBuffer + position, numSamples)) {
+ if(!copyShortToOutput(stream, stream->inputBuffer + position*stream->numChannels,
+ numSamples)) {
return 0;
}
stream->remainingInputToCopy -= numSamples;
@@ -304,7 +311,7 @@
int numSamples = stream->numOutputSamples;
int remainingSamples = 0;
short *buffer;
- int i;
+ int count;
if(numSamples == 0) {
return 0;
@@ -314,12 +321,13 @@
numSamples = maxSamples;
}
buffer = stream->outputBuffer;
- for(i = 0; i < numSamples; i++) {
+ count = numSamples*stream->numChannels;
+ while(count--) {
*samples++ = (*buffer++)/32767.0f;
}
if(remainingSamples > 0) {
- memmove(stream->outputBuffer, stream->outputBuffer + numSamples,
- remainingSamples*sizeof(short));
+ memmove(stream->outputBuffer, stream->outputBuffer + numSamples*stream->numChannels,
+ remainingSamples*sizeof(short)*stream->numChannels);
}
stream->numOutputSamples = remainingSamples;
return numSamples;
@@ -342,10 +350,10 @@
remainingSamples = numSamples - maxSamples;
numSamples = maxSamples;
}
- memcpy(samples, stream->outputBuffer, numSamples*sizeof(short));
+ memcpy(samples, stream->outputBuffer, numSamples*sizeof(short)*stream->numChannels);
if(remainingSamples > 0) {
- memmove(stream->outputBuffer, stream->outputBuffer + numSamples,
- remainingSamples*sizeof(short));
+ memmove(stream->outputBuffer, stream->outputBuffer + numSamples*stream->numChannels,
+ remainingSamples*sizeof(short)*stream->numChannels);
}
stream->numOutputSamples = remainingSamples;
return numSamples;
@@ -361,7 +369,7 @@
int numSamples = stream->numOutputSamples;
int remainingSamples = 0;
short *buffer;
- int i;
+ int count;
if(numSamples == 0) {
return 0;
@@ -371,12 +379,13 @@
numSamples = maxSamples;
}
buffer = stream->outputBuffer;
- for(i = 0; i < numSamples; i++) {
+ count = numSamples*stream->numChannels;
+ while(count--) {
*samples++ = (char)((*buffer++) >> 8) + 128;
}
if(remainingSamples > 0) {
- memmove(stream->outputBuffer, stream->outputBuffer + numSamples,
- remainingSamples*sizeof(short));
+ memmove(stream->outputBuffer, stream->outputBuffer + numSamples*stream->numChannels,
+ remainingSamples*sizeof(short)*stream->numChannels);
}
stream->numOutputSamples = remainingSamples;
return numSamples;
@@ -403,7 +412,8 @@
return 1;
}
remainingSpace = maxRequired - numSamples;
- memset(stream->inputBuffer + numSamples, 0, remainingSpace*sizeof(short));
+ memset(stream->inputBuffer + numSamples*stream->numChannels, 0,
+ remainingSpace*sizeof(short)*stream->numChannels);
stream->numInputSamples = maxRequired;
numOutputSamples = stream->numOutputSamples;
if(!sonicWriteShortToStream(stream, NULL, 0)) {
@@ -424,9 +434,11 @@
return stream->numOutputSamples;
}
-/* Find the best frequency match in the range, and given a sample skip multiple. */
+/* Find the best frequency match in the range, and given a sample skip multiple.
+ For now, just find the pitch of the first channel. */
static int findPitchPeriodInRange(
short *samples,
+ int numChannels,
int minPeriod,
int maxPeriod,
int skip)
@@ -436,17 +448,18 @@
unsigned long diff, minDiff = 0;
unsigned int numSamples = (minPeriod + skip - 1)/skip;
unsigned int bestNumSamples = 0;
+ int sampleSkip = skip*numChannels;
int i;
for(period = minPeriod; period <= maxPeriod; period += skip) {
diff = 0;
s = samples;
- p = samples + period;
+ p = samples + period*numChannels;
for(i = 0; i < numSamples; i++) {
sVal = *s;
pVal = *p;
- s += skip;
- p += skip;
+ s += sampleSkip;
+ p += sampleSkip;
diff += sVal >= pVal? (unsigned short)(sVal - pVal) :
(unsigned short)(pVal - sVal);
}
@@ -480,7 +493,7 @@
if(sampleRate > SONIC_AMDF_FREQ) {
skip = sampleRate/SONIC_AMDF_FREQ;
}
- period = findPitchPeriodInRange(samples, minPeriod, maxPeriod, skip);
+ period = findPitchPeriodInRange(samples, stream->numChannels, minPeriod, maxPeriod, skip);
if(skip == 1) {
return period;
}
@@ -492,7 +505,7 @@
if(maxPeriod > stream->maxPeriod) {
maxPeriod = stream->maxPeriod;
}
- return findPitchPeriodInRange(samples, minPeriod, maxPeriod, 1);
+ return findPitchPeriodInRange(samples, stream->numChannels, minPeriod, maxPeriod, 1);
}
/* Skip over a pitch period, and copy period/speed samples to the output */
@@ -503,7 +516,9 @@
int period)
{
long t, newSamples;
- short *out;
+ short *out, *prevPeriodSamples, *nextPeriodSamples;
+ int numChannels = stream->numChannels;
+ int i;
if(speed >= 2.0f) {
newSamples = period/(speed - 1.0f);
@@ -514,9 +529,16 @@
if(!enlargeOutputBufferIfNeeded(stream, newSamples)) {
return 0;
}
- out = stream->outputBuffer + stream->numOutputSamples;
- for(t = 0; t < newSamples; t++) {
- out[t] = (samples[t]*(newSamples - t) + samples[t + period]*t)/newSamples;
+ for(i = 0; i < numChannels; i++) {
+ out = stream->outputBuffer + stream->numOutputSamples*numChannels + i;
+ prevPeriodSamples = samples + i;
+ nextPeriodSamples = samples + i + period*numChannels;
+ for(t = 0; t < newSamples; t++) {
+ *out = (*prevPeriodSamples*(newSamples - t) + *nextPeriodSamples*t)/newSamples;
+ out += numChannels;
+ prevPeriodSamples += numChannels;
+ nextPeriodSamples += numChannels;
+ }
}
stream->numOutputSamples += newSamples;
return newSamples;
@@ -530,7 +552,9 @@
int period)
{
unsigned long t, newSamples;
- short *out;
+ short *out, *prevPeriodSamples, *nextPeriodSamples;
+ int numChannels = stream->numChannels;
+ int i;
if(speed < 0.5f) {
newSamples = period*speed/(1.0f - speed);
@@ -541,11 +565,18 @@
if(!enlargeOutputBufferIfNeeded(stream, period + newSamples)) {
return 0;
}
- out = stream->outputBuffer + stream->numOutputSamples;
- memcpy(out, samples, period*sizeof(short));
- out += period;
- for(t = 0; t < newSamples; t++) {
- out[t] = (samples[t]*t + samples[t + period]*(newSamples - t))/newSamples;
+ out = stream->outputBuffer + stream->numOutputSamples*numChannels;
+ memcpy(out, samples, period*sizeof(short)*numChannels);
+ for(i = 0; i < numChannels; i++) {
+ out = stream->outputBuffer + (stream->numOutputSamples + period)*numChannels + i;
+ prevPeriodSamples = samples + i;
+ nextPeriodSamples = samples + i + period*numChannels;
+ for(t = 0; t < newSamples; t++) {
+ *out = (*prevPeriodSamples*t + *nextPeriodSamples*(newSamples - t))/newSamples;
+ out += numChannels;
+ prevPeriodSamples += numChannels;
+ nextPeriodSamples += numChannels;
+ }
}
stream->numOutputSamples += period + newSamples;
return newSamples;
@@ -556,7 +587,7 @@
static int processStreamInput(
sonicStream stream)
{
- short *samples = stream->inputBuffer;
+ short *samples;
int numSamples = stream->numInputSamples;
float speed = stream->speed;
int position = 0, period, newSamples;
@@ -570,12 +601,13 @@
newSamples = copyInputToOutput(stream, position);
position += newSamples;
} else {
- period = findPitchPeriod(stream, samples + position);
+ samples = stream->inputBuffer + position*stream->numChannels;
+ period = findPitchPeriod(stream, samples);
if(speed > 1.0) {
- newSamples = skipPitchPeriod(stream, samples + position, speed, period);
+ newSamples = skipPitchPeriod(stream, samples, speed, period);
position += period + newSamples;
} else {
- newSamples = insertPitchPeriod(stream, samples + position, speed, period);
+ newSamples = insertPitchPeriod(stream, samples, speed, period);
position += newSamples;
}
}
@@ -648,9 +680,10 @@
float *samples,
int numSamples,
float speed,
- int sampleRate)
+ int sampleRate,
+ int numChannels)
{
- sonicStream stream = sonicCreateStream(speed, sampleRate);
+ sonicStream stream = sonicCreateStream(speed, sampleRate, numChannels);
sonicWriteFloatToStream(stream, samples, numSamples);
sonicFlushStream(stream);
@@ -665,9 +698,10 @@
short *samples,
int numSamples,
float speed,
- int sampleRate)
+ int sampleRate,
+ int numChannels)
{
- sonicStream stream = sonicCreateStream(speed, sampleRate);
+ sonicStream stream = sonicCreateStream(speed, sampleRate, numChannels);
sonicWriteShortToStream(stream, samples, numSamples);
sonicFlushStream(stream);
@@ -676,4 +710,3 @@
sonicDestroyStream(stream);
return numSamples;
}
-