Add channel-matrix slewing

This commit is contained in:
Jack Andersen 2016-05-21 11:45:55 -10:00
parent e48f5d36c7
commit 53f4e32c46
5 changed files with 227 additions and 66 deletions

View File

@ -63,10 +63,10 @@ struct IAudioVoice
virtual void setDefaultMatrixCoefficients()=0; virtual void setDefaultMatrixCoefficients()=0;
/** Set channel-gains for mono audio source (AudioChannel enum for array index) */ /** Set channel-gains for mono audio source (AudioChannel enum for array index) */
virtual void setMonoMatrixCoefficients(const float coefs[8])=0; virtual void setMonoMatrixCoefficients(const float coefs[8], bool slew)=0;
/** Set channel-gains for stereo audio source (AudioChannel enum for array index) */ /** Set channel-gains for stereo audio source (AudioChannel enum for array index) */
virtual void setStereoMatrixCoefficients(const float coefs[8][2])=0; virtual void setStereoMatrixCoefficients(const float coefs[8][2], bool slew)=0;
/** Called by client to dynamically adjust the pitch of voices with dynamic pitch enabled */ /** Called by client to dynamically adjust the pitch of voices with dynamic pitch enabled */
virtual void setPitchRatio(double ratio, bool slew)=0; virtual void setPitchRatio(double ratio, bool slew)=0;

View File

@ -7,6 +7,8 @@ namespace boo
void AudioMatrixMono::setDefaultMatrixCoefficients(AudioChannelSet acSet) void AudioMatrixMono::setDefaultMatrixCoefficients(AudioChannelSet acSet)
{ {
m_curSlewFrame = 0;
m_slewFrames = 0;
memset(m_coefs, 0, sizeof(m_coefs)); memset(m_coefs, 0, sizeof(m_coefs));
switch (acSet) switch (acSet)
{ {
@ -24,10 +26,30 @@ void AudioMatrixMono::setDefaultMatrixCoefficients(AudioChannelSet acSet)
} }
int16_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, int16_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
const int16_t* dataIn, int16_t* dataOut, size_t samples) const const int16_t* dataIn, int16_t* dataOut, size_t samples)
{ {
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t s=0 ; s<samples ; ++s, ++dataIn) for (size_t s=0 ; s<samples ; ++s, ++dataIn)
{
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
double t = m_curSlewFrame / double(m_slewFrames);
double omt = 1.0 - t;
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown)
{
*dataOut = Clamp16(*dataOut + *dataIn * (m_coefs[int(ch)] * t + m_oldCoefs[int(ch)] * omt));
++dataOut;
}
}
++m_curSlewFrame;
}
else
{
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c) for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{ {
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
@ -37,14 +59,36 @@ int16_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
++dataOut; ++dataOut;
} }
} }
}
}
return dataOut; return dataOut;
} }
int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
const int32_t* dataIn, int32_t* dataOut, size_t samples) const const int32_t* dataIn, int32_t* dataOut, size_t samples)
{ {
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t s=0 ; s<samples ; ++s, ++dataIn) for (size_t s=0 ; s<samples ; ++s, ++dataIn)
{
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
double t = m_curSlewFrame / double(m_slewFrames);
double omt = 1.0 - t;
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown)
{
*dataOut = Clamp32(*dataOut + *dataIn * (m_coefs[int(ch)] * t + m_oldCoefs[int(ch)] * omt));
++dataOut;
}
}
++m_curSlewFrame;
}
else
{
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c) for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{ {
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
@ -54,14 +98,36 @@ int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
++dataOut; ++dataOut;
} }
} }
}
}
return dataOut; return dataOut;
} }
float* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, float* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
const float* dataIn, float* dataOut, size_t samples) const const float* dataIn, float* dataOut, size_t samples)
{ {
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t s=0 ; s<samples ; ++s, ++dataIn) for (size_t s=0 ; s<samples ; ++s, ++dataIn)
{
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
double t = m_curSlewFrame / double(m_slewFrames);
double omt = 1.0 - t;
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown)
{
*dataOut = ClampFlt(*dataOut + *dataIn * (m_coefs[int(ch)] * t + m_oldCoefs[int(ch)] * omt));
++dataOut;
}
}
++m_curSlewFrame;
}
else
{
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c) for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{ {
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
@ -71,11 +137,15 @@ float* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
++dataOut; ++dataOut;
} }
} }
}
}
return dataOut; return dataOut;
} }
void AudioMatrixStereo::setDefaultMatrixCoefficients(AudioChannelSet acSet) void AudioMatrixStereo::setDefaultMatrixCoefficients(AudioChannelSet acSet)
{ {
m_curSlewFrame = 0;
m_slewFrames = 0;
memset(m_coefs, 0, sizeof(m_coefs)); memset(m_coefs, 0, sizeof(m_coefs));
switch (acSet) switch (acSet)
{ {
@ -94,10 +164,32 @@ void AudioMatrixStereo::setDefaultMatrixCoefficients(AudioChannelSet acSet)
} }
int16_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info, int16_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info,
const int16_t* dataIn, int16_t* dataOut, size_t frames) const const int16_t* dataIn, int16_t* dataOut, size_t frames)
{ {
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t f=0 ; f<frames ; ++f, dataIn += 2) for (size_t f=0 ; f<frames ; ++f, dataIn += 2)
{
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
double t = m_curSlewFrame / double(m_slewFrames);
double omt = 1.0 - t;
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown)
{
*dataOut = Clamp16(*dataOut +
*dataIn * (m_coefs[int(ch)][0] * t + m_oldCoefs[int(ch)][0] * omt) +
*dataIn * (m_coefs[int(ch)][1] * t + m_oldCoefs[int(ch)][1] * omt));
++dataOut;
}
}
++m_curSlewFrame;
}
else
{
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c) for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{ {
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
@ -109,14 +201,38 @@ int16_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& i
++dataOut; ++dataOut;
} }
} }
}
}
return dataOut; return dataOut;
} }
int32_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info, int32_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info,
const int32_t* dataIn, int32_t* dataOut, size_t frames) const const int32_t* dataIn, int32_t* dataOut, size_t frames)
{ {
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t f=0 ; f<frames ; ++f, dataIn += 2) for (size_t f=0 ; f<frames ; ++f, dataIn += 2)
{
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
double t = m_curSlewFrame / double(m_slewFrames);
double omt = 1.0 - t;
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown)
{
*dataOut = Clamp32(*dataOut +
*dataIn * (m_coefs[int(ch)][0] * t + m_oldCoefs[int(ch)][0] * omt) +
*dataIn * (m_coefs[int(ch)][1] * t + m_oldCoefs[int(ch)][1] * omt));
++dataOut;
}
}
++m_curSlewFrame;
}
else
{
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c) for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{ {
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
@ -128,14 +244,38 @@ int32_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& i
++dataOut; ++dataOut;
} }
} }
}
}
return dataOut; return dataOut;
} }
float* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info, float* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info,
const float* dataIn, float* dataOut, size_t frames) const const float* dataIn, float* dataOut, size_t frames)
{ {
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t f=0 ; f<frames ; ++f, dataIn += 2) for (size_t f=0 ; f<frames ; ++f, dataIn += 2)
{
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
double t = m_curSlewFrame / double(m_slewFrames);
double omt = 1.0 - t;
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown)
{
*dataOut = ClampFlt(*dataOut +
*dataIn * (m_coefs[int(ch)][0] * t + m_oldCoefs[int(ch)][0] * omt) +
*dataIn * (m_coefs[int(ch)][1] * t + m_oldCoefs[int(ch)][1] * omt));
++dataOut;
}
}
++m_curSlewFrame;
}
else
{
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c) for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{ {
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
@ -147,6 +287,8 @@ float* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& inf
++dataOut; ++dataOut;
} }
} }
}
}
return dataOut; return dataOut;
} }

View File

@ -39,47 +39,66 @@ static inline float ClampFlt(float in)
class AudioMatrixMono class AudioMatrixMono
{ {
float m_coefs[8]; float m_coefs[8] = {};
float m_oldCoefs[8] = {};
size_t m_slewFrames = 0;
size_t m_curSlewFrame = 0;
public: public:
AudioMatrixMono() {setDefaultMatrixCoefficients(AudioChannelSet::Stereo);} AudioMatrixMono() {setDefaultMatrixCoefficients(AudioChannelSet::Stereo);}
void setDefaultMatrixCoefficients(AudioChannelSet acSet); void setDefaultMatrixCoefficients(AudioChannelSet acSet);
void setMatrixCoefficients(const float coefs[8]) void setMatrixCoefficients(const float coefs[8], size_t slewFrames=0)
{ {
m_slewFrames = slewFrames;
m_curSlewFrame = 0;
for (int i=0 ; i<8 ; ++i) for (int i=0 ; i<8 ; ++i)
{
if (m_curSlewFrame == m_slewFrames)
m_oldCoefs[i] = m_coefs[i];
m_coefs[i] = coefs[i]; m_coefs[i] = coefs[i];
} }
}
int16_t* mixMonoSampleData(const AudioVoiceEngineMixInfo& info, int16_t* mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
const int16_t* dataIn, int16_t* dataOut, size_t samples) const; const int16_t* dataIn, int16_t* dataOut, size_t samples);
int32_t* mixMonoSampleData(const AudioVoiceEngineMixInfo& info, int32_t* mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
const int32_t* dataIn, int32_t* dataOut, size_t samples) const; const int32_t* dataIn, int32_t* dataOut, size_t samples);
float* mixMonoSampleData(const AudioVoiceEngineMixInfo& info, float* mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
const float* dataIn, float* dataOut, size_t samples) const; const float* dataIn, float* dataOut, size_t samples);
}; };
class AudioMatrixStereo class AudioMatrixStereo
{ {
float m_coefs[8][2]; float m_coefs[8][2] = {};
float m_oldCoefs[8][2] = {};
size_t m_slewFrames = 0;
size_t m_curSlewFrame = 0;
public: public:
AudioMatrixStereo() {setDefaultMatrixCoefficients(AudioChannelSet::Stereo);} AudioMatrixStereo() {setDefaultMatrixCoefficients(AudioChannelSet::Stereo);}
void setDefaultMatrixCoefficients(AudioChannelSet acSet); void setDefaultMatrixCoefficients(AudioChannelSet acSet);
void setMatrixCoefficients(const float coefs[8][2]) void setMatrixCoefficients(const float coefs[8][2], size_t slewFrames=0)
{ {
m_slewFrames = slewFrames;
m_curSlewFrame = 0;
for (int i=0 ; i<8 ; ++i) for (int i=0 ; i<8 ; ++i)
{ {
if (m_curSlewFrame == m_slewFrames)
{
m_oldCoefs[i][0] = m_coefs[i][0];
m_oldCoefs[i][1] = m_coefs[i][1];
}
m_coefs[i][0] = coefs[i][0]; m_coefs[i][0] = coefs[i][0];
m_coefs[i][1] = coefs[i][1]; m_coefs[i][1] = coefs[i][1];
} }
} }
int16_t* mixStereoSampleData(const AudioVoiceEngineMixInfo& info, int16_t* mixStereoSampleData(const AudioVoiceEngineMixInfo& info,
const int16_t* dataIn, int16_t* dataOut, size_t frames) const; const int16_t* dataIn, int16_t* dataOut, size_t frames);
int32_t* mixStereoSampleData(const AudioVoiceEngineMixInfo& info, int32_t* mixStereoSampleData(const AudioVoiceEngineMixInfo& info,
const int32_t* dataIn, int32_t* dataOut, size_t frames) const; const int32_t* dataIn, int32_t* dataOut, size_t frames);
float* mixStereoSampleData(const AudioVoiceEngineMixInfo& info, float* mixStereoSampleData(const AudioVoiceEngineMixInfo& info,
const float* dataIn, float* dataOut, size_t frames) const; const float* dataIn, float* dataOut, size_t frames);
}; };
} }

View File

@ -166,12 +166,12 @@ void AudioVoiceMono::setDefaultMatrixCoefficients()
m_matrix.setDefaultMatrixCoefficients(m_parent.mixInfo().m_channels); m_matrix.setDefaultMatrixCoefficients(m_parent.mixInfo().m_channels);
} }
void AudioVoiceMono::setMonoMatrixCoefficients(const float coefs[8]) void AudioVoiceMono::setMonoMatrixCoefficients(const float coefs[8], bool slew)
{ {
m_matrix.setMatrixCoefficients(coefs); m_matrix.setMatrixCoefficients(coefs, slew ? m_root.m_5msFrames : 0);
} }
void AudioVoiceMono::setStereoMatrixCoefficients(const float coefs[8][2]) void AudioVoiceMono::setStereoMatrixCoefficients(const float coefs[8][2], bool slew)
{ {
float newCoefs[8] = float newCoefs[8] =
{ {
@ -184,7 +184,7 @@ void AudioVoiceMono::setStereoMatrixCoefficients(const float coefs[8][2])
coefs[6][0], coefs[6][0],
coefs[7][0] coefs[7][0]
}; };
m_matrix.setMatrixCoefficients(newCoefs); m_matrix.setMatrixCoefficients(newCoefs, slew ? m_root.m_5msFrames : 0);
} }
AudioVoiceStereo::AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioMix& parent, IAudioVoiceCallback* cb, AudioVoiceStereo::AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioMix& parent, IAudioVoiceCallback* cb,
@ -286,7 +286,7 @@ void AudioVoiceStereo::setDefaultMatrixCoefficients()
m_matrix.setDefaultMatrixCoefficients(m_parent.mixInfo().m_channels); m_matrix.setDefaultMatrixCoefficients(m_parent.mixInfo().m_channels);
} }
void AudioVoiceStereo::setMonoMatrixCoefficients(const float coefs[8]) void AudioVoiceStereo::setMonoMatrixCoefficients(const float coefs[8], bool slew)
{ {
float newCoefs[8][2] = float newCoefs[8][2] =
{ {
@ -299,12 +299,12 @@ void AudioVoiceStereo::setMonoMatrixCoefficients(const float coefs[8])
{coefs[6], coefs[6]}, {coefs[6], coefs[6]},
{coefs[7], coefs[7]} {coefs[7], coefs[7]}
}; };
m_matrix.setMatrixCoefficients(newCoefs); m_matrix.setMatrixCoefficients(newCoefs, slew ? m_root.m_5msFrames : 0);
} }
void AudioVoiceStereo::setStereoMatrixCoefficients(const float coefs[8][2]) void AudioVoiceStereo::setStereoMatrixCoefficients(const float coefs[8][2], bool slew)
{ {
m_matrix.setMatrixCoefficients(coefs); m_matrix.setMatrixCoefficients(coefs, slew ? m_root.m_5msFrames : 0);
} }
} }

View File

@ -85,8 +85,8 @@ public:
AudioVoiceMono(BaseAudioVoiceEngine& root, IAudioMix& parent, IAudioVoiceCallback* cb, AudioVoiceMono(BaseAudioVoiceEngine& root, IAudioMix& parent, IAudioVoiceCallback* cb,
double sampleRate, bool dynamicRate); double sampleRate, bool dynamicRate);
void setDefaultMatrixCoefficients(); void setDefaultMatrixCoefficients();
void setMonoMatrixCoefficients(const float coefs[8]); void setMonoMatrixCoefficients(const float coefs[8], bool slew);
void setStereoMatrixCoefficients(const float coefs[8][2]); void setStereoMatrixCoefficients(const float coefs[8][2], bool slew);
}; };
class AudioVoiceStereo : public AudioVoice class AudioVoiceStereo : public AudioVoice
@ -105,8 +105,8 @@ public:
AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioMix& parent, IAudioVoiceCallback* cb, AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioMix& parent, IAudioVoiceCallback* cb,
double sampleRate, bool dynamicRate); double sampleRate, bool dynamicRate);
void setDefaultMatrixCoefficients(); void setDefaultMatrixCoefficients();
void setMonoMatrixCoefficients(const float coefs[8]); void setMonoMatrixCoefficients(const float coefs[8], bool slew);
void setStereoMatrixCoefficients(const float coefs[8][2]); void setStereoMatrixCoefficients(const float coefs[8][2], bool slew);
}; };
} }