#include "config.h"
#if ENABLE(WEB_AUDIO)
#include "PushPullFIFO.h"
#include "AudioBus.h"
namespace WebCore {
PushPullFIFO::PushPullFIFO(unsigned numberOfChannels, size_t fifoLength)
: m_fifoLength(fifoLength)
{
ASSERT(m_fifoLength <= maxFIFOLength);
m_fifoBus = AudioBus::create(numberOfChannels, m_fifoLength);
}
PushPullFIFO::~PushPullFIFO() = default;
void PushPullFIFO::push(const AudioBus* inputBus)
{
ASSERT(inputBus);
ASSERT(inputBus->length() <= m_fifoLength);
ASSERT(m_indexWrite < m_fifoLength);
const size_t inputBusLength = inputBus->length();
const size_t remainder = m_fifoLength - m_indexWrite;
for (unsigned i = 0; i < m_fifoBus->numberOfChannels(); ++i) {
float* fifoBusChannel = m_fifoBus->channel(i)->mutableData();
const float* inputBusChannel = inputBus->channel(i)->data();
if (remainder >= inputBusLength) {
memcpy(fifoBusChannel + m_indexWrite, inputBusChannel, inputBusLength * sizeof(*fifoBusChannel));
} else {
memcpy(fifoBusChannel + m_indexWrite, inputBusChannel, remainder * sizeof(*fifoBusChannel));
memcpy(fifoBusChannel, inputBusChannel + remainder, (inputBusLength - remainder) * sizeof(*fifoBusChannel));
}
}
m_indexWrite = (m_indexWrite + inputBusLength) % m_fifoLength;
if (inputBusLength > m_fifoLength - m_framesAvailable)
m_indexRead = m_indexWrite;
m_framesAvailable = std::min(m_framesAvailable + inputBusLength, m_fifoLength);
ASSERT(((m_indexRead + m_framesAvailable) % m_fifoLength) == m_indexWrite);
}
size_t PushPullFIFO::pull(AudioBus* outputBus, size_t framesRequested)
{
ASSERT(outputBus);
ASSERT(framesRequested <= outputBus->length());
ASSERT(framesRequested <= m_fifoLength);
ASSERT(m_indexRead < m_fifoLength);
const size_t remainder = m_fifoLength - m_indexRead;
const size_t framesToFill = std::min(m_framesAvailable, framesRequested);
for (unsigned i = 0; i < m_fifoBus->numberOfChannels(); ++i) {
const float* fifoBusChannel = m_fifoBus->channel(i)->data();
float* outputBusChannel = outputBus->channel(i)->mutableData();
if (remainder >= framesToFill) {
memcpy(outputBusChannel, fifoBusChannel + m_indexRead, framesToFill * sizeof(*fifoBusChannel));
} else {
memcpy(outputBusChannel, fifoBusChannel + m_indexRead, remainder * sizeof(*fifoBusChannel));
memcpy(outputBusChannel + remainder, fifoBusChannel, (framesToFill - remainder) * sizeof(*fifoBusChannel));
}
if (framesRequested > framesToFill)
memset(outputBusChannel + framesToFill, 0, (framesRequested - framesToFill) * sizeof(*outputBusChannel));
}
m_indexRead = (m_indexRead + framesToFill) % m_fifoLength;
if (framesRequested > framesToFill)
m_indexWrite = m_indexRead;
m_framesAvailable -= framesToFill;
ASSERT(((m_indexRead + m_framesAvailable) % m_fifoLength) == m_indexWrite);
return framesRequested > m_framesAvailable ? framesRequested - m_framesAvailable : 0;
}
unsigned PushPullFIFO::numberOfChannels() const
{
return m_fifoBus->numberOfChannels();
}
}
#endif // ENABLE(WEB_AUDIO)