boo/lib/audiodev/AudioVoice.cpp

240 lines
6.6 KiB
C++

#include "AudioVoice.hpp"
#include "AudioVoiceEngine.hpp"
#include "logvisor/logvisor.hpp"
namespace boo
{
static logvisor::Module Log("boo::AudioVoice");
static std::vector<int16_t> scratchIn;
static std::vector<int16_t> scratch16;
static std::vector<int32_t> scratch32;
static std::vector<float> scratchFlt;
AudioVoice::AudioVoice(BaseAudioVoiceEngine& parent, IAudioVoiceCallback* cb, bool dynamicRate)
: m_parent(parent), m_cb(cb), m_dynamicRate(dynamicRate) {}
AudioVoice::~AudioVoice()
{
unbindVoice();
soxr_delete(m_src);
}
void AudioVoice::setPitchRatio(double ratio)
{
if (m_dynamicRate)
{
soxr_error_t err = soxr_set_io_ratio(m_src, ratio, m_parent.mixInfo().m_periodFrames);
if (err)
{
Log.report(logvisor::Fatal, "unable to set resampler rate: %s", soxr_strerror(err));
return;
}
}
}
void AudioVoice::start()
{
m_running = true;
}
void AudioVoice::stop()
{
m_running = false;
}
void AudioVoice::unbindVoice()
{
if (m_bound)
{
m_parent.m_activeVoices.erase(m_parentIt);
m_bound = false;
}
}
AudioVoiceMono::AudioVoiceMono(BaseAudioVoiceEngine& parent, IAudioVoiceCallback* cb,
double sampleRate, bool dynamicRate)
: AudioVoice(parent, cb, dynamicRate)
{
soxr_io_spec_t ioSpec = soxr_io_spec(SOXR_INT16_I, parent.mixInfo().m_sampleFormat);
soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, dynamicRate ? SOXR_VR : 0);
soxr_error_t err;
m_src = soxr_create(sampleRate, parent.mixInfo().m_sampleRate, 1,
&err, &ioSpec, &qSpec, nullptr);
if (err)
{
Log.report(logvisor::Fatal, "unable to create soxr resampler: %s", soxr_strerror(err));
return;
}
soxr_set_input_fn(m_src, soxr_input_fn_t(SRCCallback), this, 0);
}
size_t AudioVoiceMono::SRCCallback(AudioVoiceMono* ctx, int16_t** data, size_t frames)
{
if (scratchIn.size() < frames)
scratchIn.resize(frames);
*data = scratchIn.data();
return ctx->m_cb->supplyAudio(*ctx, frames, scratchIn.data());
}
size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo,
size_t frames, int16_t* buf)
{
if (scratch16.size() < frames)
scratch16.resize(frames);
size_t oDone = soxr_output(m_src, scratch16.data(), frames);
m_matrix.mixMonoSampleData(mixInfo, scratch16.data(), buf, oDone);
return oDone;
}
size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo,
size_t frames, int32_t* buf)
{
if (scratch32.size() < frames)
scratch32.resize(frames);
size_t oDone = soxr_output(m_src, scratch32.data(), frames);
m_matrix.mixMonoSampleData(mixInfo, scratch32.data(), buf, oDone);
return oDone;
}
size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo,
size_t frames, float* buf)
{
if (scratchFlt.size() < frames)
scratchFlt.resize(frames);
size_t oDone = soxr_output(m_src, scratchFlt.data(), frames);
m_matrix.mixMonoSampleData(mixInfo, scratchFlt.data(), buf, oDone);
return oDone;
}
void AudioVoiceMono::setDefaultMatrixCoefficients()
{
m_matrix.setDefaultMatrixCoefficients(m_parent.mixInfo().m_channels);
}
void AudioVoiceMono::setMonoMatrixCoefficients(const float coefs[8])
{
m_matrix.setMatrixCoefficients(coefs);
}
void AudioVoiceMono::setStereoMatrixCoefficients(const float coefs[8][2])
{
float newCoefs[8] =
{
coefs[0][0],
coefs[1][0],
coefs[2][0],
coefs[3][0],
coefs[4][0],
coefs[5][0],
coefs[6][0],
coefs[7][0]
};
m_matrix.setMatrixCoefficients(newCoefs);
}
AudioVoiceStereo::AudioVoiceStereo(BaseAudioVoiceEngine& parent, IAudioVoiceCallback* cb,
double sampleRate, bool dynamicRate)
: AudioVoice(parent, cb, dynamicRate)
{
soxr_io_spec_t ioSpec = soxr_io_spec(SOXR_INT16_I, parent.mixInfo().m_sampleFormat);
soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, dynamicRate ? SOXR_VR : 0);
soxr_error_t err;
m_src = soxr_create(sampleRate, parent.mixInfo().m_sampleRate, 2,
&err, &ioSpec, &qSpec, nullptr);
if (!m_src)
{
Log.report(logvisor::Fatal, "unable to create soxr resampler: %s", soxr_strerror(err));
return;
}
soxr_set_input_fn(m_src, soxr_input_fn_t(SRCCallback), this, 0);
}
size_t AudioVoiceStereo::SRCCallback(AudioVoiceStereo* ctx, int16_t** data, size_t frames)
{
size_t samples = frames * 2;
if (scratchIn.size() < samples)
scratchIn.resize(samples);
*data = scratchIn.data();
return ctx->m_cb->supplyAudio(*ctx, frames, scratchIn.data());
}
size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo,
size_t frames, int16_t* buf)
{
size_t samples = frames * 2;
if (scratch16.size() < samples)
scratch16.resize(samples);
size_t oDone = soxr_output(m_src, scratch16.data(), frames);
m_matrix.mixStereoSampleData(mixInfo, scratch16.data(), buf, oDone);
return oDone;
}
size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo,
size_t frames, int32_t* buf)
{
size_t samples = frames * 2;
if (scratch32.size() < samples)
scratch32.resize(samples);
size_t oDone = soxr_output(m_src, scratch32.data(), frames);
m_matrix.mixStereoSampleData(mixInfo, scratch32.data(), buf, oDone);
return oDone;
}
size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo,
size_t frames, float* buf)
{
size_t samples = frames * 2;
if (scratchFlt.size() < samples)
scratchFlt.resize(samples);
size_t oDone = soxr_output(m_src, scratchFlt.data(), frames);
m_matrix.mixStereoSampleData(mixInfo, scratchFlt.data(), buf, oDone);
return oDone;
}
void AudioVoiceStereo::setDefaultMatrixCoefficients()
{
m_matrix.setDefaultMatrixCoefficients(m_parent.mixInfo().m_channels);
}
void AudioVoiceStereo::setMonoMatrixCoefficients(const float coefs[8])
{
float newCoefs[8][2] =
{
{coefs[0], coefs[0]},
{coefs[1], coefs[1]},
{coefs[2], coefs[2]},
{coefs[3], coefs[3]},
{coefs[4], coefs[4]},
{coefs[5], coefs[5]},
{coefs[6], coefs[6]},
{coefs[7], coefs[7]}
};
m_matrix.setMatrixCoefficients(newCoefs);
}
void AudioVoiceStereo::setStereoMatrixCoefficients(const float coefs[8][2])
{
m_matrix.setMatrixCoefficients(coefs);
}
}