/*
AudioOutputMixer
Simple mixer which can combine multiple inputs to a single output stream
Copyright (C) 2018 Earle F. Philhower, III
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include "AudioOutputMixer.h"
AudioOutputMixerStub::AudioOutputMixerStub(AudioOutputMixer *sink, int id) : AudioOutput()
{
this->id = id;
this->parent = sink;
SetGain(1.0);
}
AudioOutputMixerStub::~AudioOutputMixerStub()
{
parent->RemoveInput(id);
}
bool AudioOutputMixerStub::SetRate(int hz)
{
return parent->SetRate(hz, id);
}
bool AudioOutputMixerStub::SetBitsPerSample(int bits)
{
return parent->SetBitsPerSample(bits, id);
}
bool AudioOutputMixerStub::SetChannels(int channels)
{
return parent->SetChannels(channels, id);
}
bool AudioOutputMixerStub::begin()
{
return parent->begin(id);
}
bool AudioOutputMixerStub::ConsumeSample(int16_t sample[2])
{
int16_t amp[2];
amp[LEFTCHANNEL] = Amplify(sample[LEFTCHANNEL]);
amp[RIGHTCHANNEL] = Amplify(sample[RIGHTCHANNEL]);
return parent->ConsumeSample(amp, id);
}
bool AudioOutputMixerStub::stop()
{
return parent->stop(id);
}
AudioOutputMixer::AudioOutputMixer(int buffSizeSamples, AudioOutput *dest) : AudioOutput()
{
buffSize = buffSizeSamples;
leftAccum = (int32_t*)calloc(sizeof(int32_t), buffSize);
rightAccum = (int32_t*)calloc(sizeof(int32_t), buffSize);
for (int i=0; iSetRate(hz);
}
bool AudioOutputMixer::SetBitsPerSample(int bits, int id)
{
(void) id;
return sink->SetBitsPerSample(bits);
}
bool AudioOutputMixer::SetChannels(int channels, int id)
{
(void) id;
return sink->SetChannels(channels);
}
bool AudioOutputMixer::begin(int id)
{
stubRunning[id] = true;
if (!sinkStarted) {
sinkStarted = true;
return sink->begin();
} else {
return true;
}
}
AudioOutputMixerStub *AudioOutputMixer::NewInput()
{
for (int i=0; i 32767) {
s[LEFTCHANNEL] = 32767;
} else if (leftAccum[readPtr] < -32767) {
s[LEFTCHANNEL] = -32767;
} else {
s[LEFTCHANNEL] = leftAccum[readPtr];
}
if (rightAccum[readPtr] > 32767) {
s[RIGHTCHANNEL] = 32767;
} else if (rightAccum[readPtr] < -32767) {
s[RIGHTCHANNEL] = -32767;
} else {
s[RIGHTCHANNEL] = rightAccum[readPtr];
}
// s[LEFTCHANNEL] = Amplify(s[LEFTCHANNEL]);
// s[RIGHTCHANNEL] = Amplify(s[RIGHTCHANNEL]);
if (!sink->ConsumeSample(s)) {
break; // Can't stuff any more in I2S...
}
// Clear the accums and advance the pointer to next potential sample
leftAccum[readPtr] = 0;
rightAccum[readPtr] = 0;
readPtr = (readPtr + 1) % buffSize;
}
} while (avail);
return true;
}
bool AudioOutputMixer::ConsumeSample(int16_t sample[2], int id)
{
loop(); // Send any pre-existing, completed I2S data we can fit
// Now, do we have space for a new sample?
int nextWritePtr = (writePtr[id] + 1) % buffSize;
if (nextWritePtr == readPtr) {
return false;
}
leftAccum[writePtr[id]] += sample[LEFTCHANNEL];
rightAccum[writePtr[id]] += sample[RIGHTCHANNEL];
writePtr[id] = nextWritePtr;
return true;
}
bool AudioOutputMixer::stop(int id)
{
stubRunning[id] = false;
return true;
}