Updates to support pumped audio voices (ALSA only for now)

This commit is contained in:
Jack Andersen 2016-03-07 21:09:58 -10:00
parent b180b5535b
commit e1964f57a9
8 changed files with 258 additions and 115 deletions

View File

@ -124,7 +124,7 @@ else(NOT GEKKO)
endif() endif()
include_directories(${DBUS_INCLUDE_DIR} ${DBUS_ARCH_INCLUDE_DIR}) include_directories(${DBUS_INCLUDE_DIR} ${DBUS_ARCH_INCLUDE_DIR})
list(APPEND _BOO_SYS_LIBS X11 Xi GL ${DBUS_LIBRARY} pthread) list(APPEND _BOO_SYS_LIBS X11 Xi GL asound ${DBUS_LIBRARY} pthread)
unset(VULKAN_LIBRARY CACHE) unset(VULKAN_LIBRARY CACHE)
find_library(VULKAN_LIBRARY vulkan) find_library(VULKAN_LIBRARY vulkan)
@ -172,8 +172,9 @@ add_library(boo
lib/inputdev/GenericPad.cpp include/boo/inputdev/GenericPad.hpp lib/inputdev/GenericPad.cpp include/boo/inputdev/GenericPad.hpp
lib/inputdev/DeviceBase.cpp include/boo/inputdev/DeviceBase.hpp lib/inputdev/DeviceBase.cpp include/boo/inputdev/DeviceBase.hpp
lib/inputdev/DeviceSignature.cpp include/boo/inputdev/DeviceSignature.hpp lib/inputdev/DeviceSignature.cpp include/boo/inputdev/DeviceSignature.hpp
include/boo/inputdev/IHIDListener.hpp
lib/inputdev/IHIDDevice.hpp lib/inputdev/IHIDDevice.hpp
lib/audiodev/AudioMatrix.cpp
include/boo/inputdev/IHIDListener.hpp
include/boo/IGraphicsContext.hpp include/boo/IGraphicsContext.hpp
include/boo/graphicsdev/IGraphicsDataFactory.hpp include/boo/graphicsdev/IGraphicsDataFactory.hpp
include/boo/graphicsdev/IGraphicsCommandQueue.hpp include/boo/graphicsdev/IGraphicsCommandQueue.hpp

View File

@ -10,14 +10,14 @@ namespace boo
class AudioMatrixMono class AudioMatrixMono
{ {
AudioChannelSet m_setOut; AudioChannelSet m_setOut = AudioChannelSet::Stereo;
float m_coefs[8]; float m_coefs[8];
std::vector<int16_t> m_interleaveBuf; std::vector<int16_t> m_interleaveBuf;
public: public:
AudioMatrixMono(AudioChannelSet setOut) AudioMatrixMono() {setDefaultMatrixCoefficients();}
: m_setOut(setOut) {setDefaultMatrixCoefficients();}
AudioChannelSet setOut() const {return m_setOut;} AudioChannelSet audioChannelSet() const {return m_setOut;}
void setAudioChannelSet(AudioChannelSet set) {m_setOut = set;}
void setDefaultMatrixCoefficients(); void setDefaultMatrixCoefficients();
void setMatrixCoefficients(const float coefs[8]) void setMatrixCoefficients(const float coefs[8])
{ {
@ -30,14 +30,14 @@ public:
class AudioMatrixStereo class AudioMatrixStereo
{ {
AudioChannelSet m_setOut; AudioChannelSet m_setOut = AudioChannelSet::Stereo;
float m_coefs[8][2]; float m_coefs[8][2];
std::vector<int16_t> m_interleaveBuf; std::vector<int16_t> m_interleaveBuf;
public: public:
AudioMatrixStereo(AudioChannelSet setOut) AudioMatrixStereo() {setDefaultMatrixCoefficients();}
: m_setOut(setOut) {setDefaultMatrixCoefficients();}
AudioChannelSet setOut() const {return m_setOut;} AudioChannelSet audioChannelSet() const {return m_setOut;}
void setAudioChannelSet(AudioChannelSet set) {m_setOut = set;}
void setDefaultMatrixCoefficients(); void setDefaultMatrixCoefficients();
void setMatrixCoefficients(const float coefs[8][2]) void setMatrixCoefficients(const float coefs[8][2])
{ {

View File

@ -12,7 +12,8 @@ enum class AudioChannelSet
Stereo, Stereo,
Quad, Quad,
Surround51, Surround51,
Surround71 Surround71,
Unknown = 0xff
}; };
enum class AudioChannel enum class AudioChannel
@ -46,12 +47,15 @@ static inline unsigned ChannelCount(AudioChannelSet layout)
return 6; return 6;
case AudioChannelSet::Surround71: case AudioChannelSet::Surround71:
return 8; return 8;
default: break;
} }
return 0; return 0;
} }
struct IAudioVoice struct IAudioVoice
{ {
virtual ~IAudioVoice() = default;
/** Get voice's actual channel-map based on client request and HW capabilities */ /** Get voice's actual channel-map based on client request and HW capabilities */
virtual const ChannelMap& channelMap() const=0; virtual const ChannelMap& channelMap() const=0;

View File

@ -11,11 +11,13 @@ struct IAudioVoiceCallback
{ {
/** boo calls this on behalf of the audio platform to request more audio /** boo calls this on behalf of the audio platform to request more audio
* frames from the client */ * frames from the client */
virtual void needsNextBuffer(IAudioVoice* voice, size_t frames)=0; virtual void needsNextBuffer(IAudioVoice& voice, size_t frames)=0;
}; };
struct IAudioVoiceAllocator struct IAudioVoiceAllocator
{ {
virtual ~IAudioVoiceAllocator() = default;
/** Client calls this to request allocation of new mixer-voice. /** Client calls this to request allocation of new mixer-voice.
* Returns empty unique_ptr if necessary resources aren't available. * Returns empty unique_ptr if necessary resources aren't available.
* ChannelLayout automatically reduces to maximum-supported layout by HW. * ChannelLayout automatically reduces to maximum-supported layout by HW.
@ -25,8 +27,17 @@ struct IAudioVoiceAllocator
virtual std::unique_ptr<IAudioVoice> allocateNewVoice(AudioChannelSet layoutOut, virtual std::unique_ptr<IAudioVoice> allocateNewVoice(AudioChannelSet layoutOut,
unsigned sampleRate, unsigned sampleRate,
IAudioVoiceCallback* cb)=0; IAudioVoiceCallback* cb)=0;
/** Client may use this to determine current speaker-setup */
virtual AudioChannelSet getAvailableSet()=0;
/** Ensure all voices' platform buffers are filled as much as possible */
virtual void pumpVoices()=0;
}; };
/** Obtain host platform's voice allocator */
std::unique_ptr<IAudioVoiceAllocator> NewAudioVoiceAllocator();
} }
#endif // BOO_IAUDIOVOICEALLOCATOR_HPP #endif // BOO_IAUDIOVOICEALLOCATOR_HPP

View File

@ -1,31 +1,32 @@
#include <memory>
#include <list>
#include "boo/audiodev/IAudioVoiceAllocator.hpp" #include "boo/audiodev/IAudioVoiceAllocator.hpp"
#include "logvisor/logvisor.hpp" #include "logvisor/logvisor.hpp"
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
#include <signal.h>
namespace boo namespace boo
{ {
static logvisor::Module Log("boo::ALSA"); static logvisor::Module Log("boo::ALSA");
struct ALSAAudioVoiceAllocator;
struct ALSAAudioVoice : IAudioVoice struct ALSAAudioVoice : IAudioVoice
{ {
ALSAAudioVoiceAllocator& m_parent;
std::list<ALSAAudioVoice*>::iterator m_parentIt;
ChannelMap m_map; ChannelMap m_map;
IAudioVoiceCallback* m_cb; IAudioVoiceCallback* m_cb;
snd_pcm_t* m_pcm = nullptr; snd_pcm_t* m_pcm = nullptr;
snd_async_handler_t* m_handler = nullptr;
snd_pcm_uframes_t m_bufSize; snd_pcm_uframes_t m_bufSize;
snd_pcm_uframes_t m_periodSize; snd_pcm_uframes_t m_periodSize;
const ChannelMap& channelMap() const {return m_map;} const ChannelMap& channelMap() const {return m_map;}
static void Callback(snd_async_handler_t* handler) ALSAAudioVoice(ALSAAudioVoiceAllocator& parent, AudioChannelSet set,
{ unsigned sampleRate, IAudioVoiceCallback* cb)
ALSAAudioVoice* voice = static_cast<ALSAAudioVoice*>(snd_async_handler_get_callback_private(handler)); : m_parent(parent), m_cb(cb)
voice->m_cb->needsNextBuffer(voice, voice->m_periodSize);
}
ALSAAudioVoice(AudioChannelSet set, unsigned sampleRate, IAudioVoiceCallback* cb)
: m_cb(cb)
{ {
if (snd_pcm_open(&m_pcm, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC) < 0) if (snd_pcm_open(&m_pcm, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC) < 0)
{ {
@ -52,96 +53,92 @@ struct ALSAAudioVoice : IAudioVoice
} }
snd_pcm_chmap_query_t** chmaps = snd_pcm_query_chmaps(m_pcm); snd_pcm_chmap_query_t** chmaps = snd_pcm_query_chmaps(m_pcm);
if (!chmaps) if (chmaps)
{ {
snd_pcm_close(m_pcm); snd_pcm_chmap_t* foundChmap = nullptr;
m_pcm = nullptr; for (snd_pcm_chmap_query_t** chmap = chmaps ; *chmap != nullptr ; ++chmap)
Log.report(logvisor::Error, "unable to query ALSA voice chmaps");
return;
}
snd_pcm_chmap_t* foundChmap = nullptr;
for (snd_pcm_chmap_query_t** chmap = chmaps ; *chmap != nullptr ; ++chmap)
{
if ((*chmap)->map.channels == chCount)
{ {
snd_pcm_chmap_t* chm = &(*chmap)->map; if ((*chmap)->map.channels == chCount)
uint64_t chBits = 0;
for (int c=0 ; c<chm->channels ; ++c)
chBits |= 1 << chm->pos[c];
bool good = false;
switch (set)
{ {
case AudioChannelSet::Stereo: snd_pcm_chmap_t* chm = &(*chmap)->map;
if ((chBits & (1 << SND_CHMAP_FL)) != 0 && uint64_t chBits = 0;
(chBits & (1 << SND_CHMAP_FR)) != 0) for (int c=0 ; c<chm->channels ; ++c)
good = true; chBits |= 1 << chm->pos[c];
break;
case AudioChannelSet::Quad:
if ((chBits & (1 << SND_CHMAP_FL)) != 0 &&
(chBits & (1 << SND_CHMAP_FR)) != 0 &&
(chBits & (1 << SND_CHMAP_RL)) != 0 &&
(chBits & (1 << SND_CHMAP_RR)) != 0)
good = true;
break;
case AudioChannelSet::Surround51:
if ((chBits & (1 << SND_CHMAP_FL)) != 0 &&
(chBits & (1 << SND_CHMAP_FR)) != 0 &&
(chBits & (1 << SND_CHMAP_RL)) != 0 &&
(chBits & (1 << SND_CHMAP_RR)) != 0 &&
(chBits & (1 << SND_CHMAP_FC)) != 0 &&
(chBits & (1 << SND_CHMAP_LFE)) != 0)
good = true;
break;
case AudioChannelSet::Surround71:
if ((chBits & (1 << SND_CHMAP_FL)) != 0 &&
(chBits & (1 << SND_CHMAP_FR)) != 0 &&
(chBits & (1 << SND_CHMAP_RL)) != 0 &&
(chBits & (1 << SND_CHMAP_RR)) != 0 &&
(chBits & (1 << SND_CHMAP_FC)) != 0 &&
(chBits & (1 << SND_CHMAP_LFE)) != 0 &&
(chBits & (1 << SND_CHMAP_SL)) != 0 &&
(chBits & (1 << SND_CHMAP_SR)) != 0)
good = true;
break;
}
if (good) bool good = false;
{ switch (set)
foundChmap = chm; {
break; case AudioChannelSet::Stereo:
if ((chBits & (1 << SND_CHMAP_FL)) != 0 &&
(chBits & (1 << SND_CHMAP_FR)) != 0)
good = true;
break;
case AudioChannelSet::Quad:
if ((chBits & (1 << SND_CHMAP_FL)) != 0 &&
(chBits & (1 << SND_CHMAP_FR)) != 0 &&
(chBits & (1 << SND_CHMAP_RL)) != 0 &&
(chBits & (1 << SND_CHMAP_RR)) != 0)
good = true;
break;
case AudioChannelSet::Surround51:
if ((chBits & (1 << SND_CHMAP_FL)) != 0 &&
(chBits & (1 << SND_CHMAP_FR)) != 0 &&
(chBits & (1 << SND_CHMAP_RL)) != 0 &&
(chBits & (1 << SND_CHMAP_RR)) != 0 &&
(chBits & (1 << SND_CHMAP_FC)) != 0 &&
(chBits & (1 << SND_CHMAP_LFE)) != 0)
good = true;
break;
case AudioChannelSet::Surround71:
if ((chBits & (1 << SND_CHMAP_FL)) != 0 &&
(chBits & (1 << SND_CHMAP_FR)) != 0 &&
(chBits & (1 << SND_CHMAP_RL)) != 0 &&
(chBits & (1 << SND_CHMAP_RR)) != 0 &&
(chBits & (1 << SND_CHMAP_FC)) != 0 &&
(chBits & (1 << SND_CHMAP_LFE)) != 0 &&
(chBits & (1 << SND_CHMAP_SL)) != 0 &&
(chBits & (1 << SND_CHMAP_SR)) != 0)
good = true;
break;
default: break;
}
if (good)
{
foundChmap = chm;
break;
}
} }
} }
}
if (!foundChmap) if (!foundChmap)
{ {
snd_pcm_close(m_pcm); snd_pcm_close(m_pcm);
m_pcm = nullptr; m_pcm = nullptr;
snd_pcm_free_chmaps(chmaps);
Log.report(logvisor::Error, "unable to find matching ALSA voice chmap");
return;
}
m_map.m_channelCount = chCount;
for (int c=0 ; c<foundChmap->channels ; ++c)
m_map.m_channels[c] = AudioChannel(foundChmap->pos[c] - 3);
snd_pcm_set_chmap(m_pcm, foundChmap);
snd_pcm_free_chmaps(chmaps); snd_pcm_free_chmaps(chmaps);
Log.report(logvisor::Error, "unable to find matching ALSA voice chmap");
return;
} }
m_map.m_channelCount = chCount; else
for (int c=0 ; c<foundChmap->channels ; ++c) {
m_map.m_channels[c] = AudioChannel(foundChmap->pos[c] - 3); m_map.m_channelCount = 2;
snd_pcm_set_chmap(m_pcm, foundChmap); m_map.m_channels[0] = AudioChannel::FrontLeft;
snd_pcm_free_chmaps(chmaps); m_map.m_channels[1] = AudioChannel::FrontRight;
}
snd_async_add_pcm_handler(&m_handler, m_pcm, snd_async_callback_t(Callback), this);
snd_pcm_get_params(m_pcm, &m_bufSize, &m_periodSize); snd_pcm_get_params(m_pcm, &m_bufSize, &m_periodSize);
snd_pcm_prepare(m_pcm);
for (int i=0 ; i<3 ; ++i) pump();
m_cb->needsNextBuffer(this, m_periodSize);
} }
~ALSAAudioVoice() ~ALSAAudioVoice();
{
if (m_handler)
snd_async_del_handler(m_handler);
if (m_pcm)
snd_pcm_close(m_pcm);
}
void bufferSampleData(const int16_t* data, size_t frames) void bufferSampleData(const int16_t* data, size_t frames)
{ {
@ -160,20 +157,145 @@ struct ALSAAudioVoice : IAudioVoice
if (m_pcm) if (m_pcm)
snd_pcm_drain(m_pcm); snd_pcm_drain(m_pcm);
} }
void pump()
{
snd_pcm_sframes_t frames = snd_pcm_avail(m_pcm);
if (frames < 0)
{
snd_pcm_state_t st = snd_pcm_state(m_pcm);
if (st == SND_PCM_STATE_XRUN)
{
snd_pcm_prepare(m_pcm);
frames = snd_pcm_avail(m_pcm);
fprintf(stderr, "REC %ld\n", frames);
}
else
return;
}
if (frames < 0)
return;
snd_pcm_sframes_t buffers = frames / m_periodSize;
for (snd_pcm_sframes_t b=0 ; b<buffers ; ++b)
m_cb->needsNextBuffer(*this, m_periodSize);
}
}; };
struct ALSAAudioVoiceAllocator : IAudioVoiceAllocator struct ALSAAudioVoiceAllocator : IAudioVoiceAllocator
{ {
std::list<ALSAAudioVoice*> m_allocatedVoices;
std::unique_ptr<IAudioVoice> allocateNewVoice(AudioChannelSet layoutOut, std::unique_ptr<IAudioVoice> allocateNewVoice(AudioChannelSet layoutOut,
unsigned sampleRate, unsigned sampleRate,
IAudioVoiceCallback* cb) IAudioVoiceCallback* cb)
{ {
ALSAAudioVoice* newVoice = new ALSAAudioVoice(layoutOut, sampleRate, cb); ALSAAudioVoice* newVoice = new ALSAAudioVoice(*this, layoutOut, sampleRate, cb);
newVoice->m_parentIt = m_allocatedVoices.insert(m_allocatedVoices.end(), newVoice);
std::unique_ptr<IAudioVoice> ret(newVoice); std::unique_ptr<IAudioVoice> ret(newVoice);
if (!newVoice->m_pcm) if (!newVoice->m_pcm)
return {}; return {};
return ret; return ret;
} }
AudioChannelSet getAvailableSet()
{
snd_pcm_t* pcm;
if (snd_pcm_open(&pcm, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC) < 0)
{
Log.report(logvisor::Error, "unable to allocate ALSA voice");
return AudioChannelSet::Unknown;
}
snd_pcm_chmap_query_t** chmaps = snd_pcm_query_chmaps(pcm);
if (!chmaps)
{
snd_pcm_close(pcm);
return AudioChannelSet::Stereo;
}
static const std::array<AudioChannelSet, 4> testSets =
{AudioChannelSet::Surround71, AudioChannelSet::Surround51,
AudioChannelSet::Quad, AudioChannelSet::Stereo};
for (AudioChannelSet set : testSets)
{
for (snd_pcm_chmap_query_t** chmap = chmaps ; *chmap != nullptr ; ++chmap)
{
snd_pcm_chmap_t* chm = &(*chmap)->map;
uint64_t chBits = 0;
for (int c=0 ; c<chm->channels ; ++c)
chBits |= 1 << chm->pos[c];
switch (set)
{
case AudioChannelSet::Stereo:
if ((chBits & (1 << SND_CHMAP_FL)) != 0 &&
(chBits & (1 << SND_CHMAP_FR)) != 0)
{
snd_pcm_free_chmaps(chmaps);
return AudioChannelSet::Stereo;
}
break;
case AudioChannelSet::Quad:
if ((chBits & (1 << SND_CHMAP_FL)) != 0 &&
(chBits & (1 << SND_CHMAP_FR)) != 0 &&
(chBits & (1 << SND_CHMAP_RL)) != 0 &&
(chBits & (1 << SND_CHMAP_RR)) != 0)
{
snd_pcm_free_chmaps(chmaps);
return AudioChannelSet::Quad;
}
break;
case AudioChannelSet::Surround51:
if ((chBits & (1 << SND_CHMAP_FL)) != 0 &&
(chBits & (1 << SND_CHMAP_FR)) != 0 &&
(chBits & (1 << SND_CHMAP_RL)) != 0 &&
(chBits & (1 << SND_CHMAP_RR)) != 0 &&
(chBits & (1 << SND_CHMAP_FC)) != 0 &&
(chBits & (1 << SND_CHMAP_LFE)) != 0)
{
snd_pcm_free_chmaps(chmaps);
return AudioChannelSet::Surround51;
}
break;
case AudioChannelSet::Surround71:
if ((chBits & (1 << SND_CHMAP_FL)) != 0 &&
(chBits & (1 << SND_CHMAP_FR)) != 0 &&
(chBits & (1 << SND_CHMAP_RL)) != 0 &&
(chBits & (1 << SND_CHMAP_RR)) != 0 &&
(chBits & (1 << SND_CHMAP_FC)) != 0 &&
(chBits & (1 << SND_CHMAP_LFE)) != 0 &&
(chBits & (1 << SND_CHMAP_SL)) != 0 &&
(chBits & (1 << SND_CHMAP_SR)) != 0)
{
snd_pcm_free_chmaps(chmaps);
return AudioChannelSet::Surround71;
}
break;
default: break;
}
}
}
snd_pcm_free_chmaps(chmaps);
return AudioChannelSet::Unknown;
}
void pumpVoices()
{
for (ALSAAudioVoice* vox : m_allocatedVoices)
vox->pump();
}
}; };
ALSAAudioVoice::~ALSAAudioVoice()
{
if (m_pcm)
snd_pcm_close(m_pcm);
m_parent.m_allocatedVoices.erase(m_parentIt);
}
std::unique_ptr<IAudioVoiceAllocator> NewAudioVoiceAllocator()
{
return std::make_unique<ALSAAudioVoiceAllocator>();
}
} }

View File

@ -218,4 +218,9 @@ struct AQSAudioVoiceAllocator : IAudioVoiceAllocator
} }
}; };
std::unique_ptr<IAudioVoiceAllocator> NewAudioVoiceAllocator()
{
return std::make_unique<AQSAudioVoiceAllocator>();
}
} }

View File

@ -9,16 +9,16 @@ void AudioMatrixMono::setDefaultMatrixCoefficients()
memset(m_coefs, 0, sizeof(m_coefs)); memset(m_coefs, 0, sizeof(m_coefs));
switch (m_setOut) switch (m_setOut)
{ {
case AudioChannelSet::Mono:
case AudioChannelSet::Stereo: case AudioChannelSet::Stereo:
case AudioChannelSet::Quad: case AudioChannelSet::Quad:
m_coefs[AudioChannel::FrontLeft] = 1.0; m_coefs[int(AudioChannel::FrontLeft)] = 1.0;
m_coefs[AudioChannel::FrontRight] = 1.0; m_coefs[int(AudioChannel::FrontRight)] = 1.0;
break; break;
case AudioChannelSet::Surround51: case AudioChannelSet::Surround51:
case AudioChannelSet::Surround71: case AudioChannelSet::Surround71:
m_coefs[AudioChannel::FrontCenter] = 1.0; m_coefs[int(AudioChannel::FrontCenter)] = 1.0;
break; break;
default: break;
} }
} }
@ -34,7 +34,7 @@ void AudioMatrixMono::bufferMonoSampleData(IAudioVoice& voice, const int16_t* da
if (ch == AudioChannel::Unknown) if (ch == AudioChannel::Unknown)
m_interleaveBuf.push_back(0); m_interleaveBuf.push_back(0);
else else
m_interleaveBuf.push_back(data[0] * m_coefs[ch]); m_interleaveBuf.push_back(data[0] * m_coefs[int(ch)]);
} }
voice.bufferSampleData(m_interleaveBuf.data(), samples); voice.bufferSampleData(m_interleaveBuf.data(), samples);
} }
@ -44,22 +44,17 @@ void AudioMatrixStereo::setDefaultMatrixCoefficients()
memset(m_coefs, 0, sizeof(m_coefs)); memset(m_coefs, 0, sizeof(m_coefs));
switch (m_setOut) switch (m_setOut)
{ {
case AudioChannelSet::Mono:
m_coefs[AudioChannel::FrontLeft][0] = 0.5;
m_coefs[AudioChannel::FrontLeft][1] = 0.5;
m_coefs[AudioChannel::FrontRight][0] = 0.5;
m_coefs[AudioChannel::FrontRight][1] = 0.5;
break;
case AudioChannelSet::Stereo: case AudioChannelSet::Stereo:
case AudioChannelSet::Quad: case AudioChannelSet::Quad:
m_coefs[AudioChannel::FrontLeft][0] = 1.0; m_coefs[int(AudioChannel::FrontLeft)][0] = 1.0;
m_coefs[AudioChannel::FrontRight][1] = 1.0; m_coefs[int(AudioChannel::FrontRight)][1] = 1.0;
break; break;
case AudioChannelSet::Surround51: case AudioChannelSet::Surround51:
case AudioChannelSet::Surround71: case AudioChannelSet::Surround71:
m_coefs[AudioChannel::FrontLeft][0] = 1.0; m_coefs[int(AudioChannel::FrontLeft)][0] = 1.0;
m_coefs[AudioChannel::FrontRight][1] = 1.0; m_coefs[int(AudioChannel::FrontRight)][1] = 1.0;
break; break;
default: break;
} }
} }
@ -75,8 +70,8 @@ void AudioMatrixStereo::bufferStereoSampleData(IAudioVoice& voice, const int16_t
if (ch == AudioChannel::Unknown) if (ch == AudioChannel::Unknown)
m_interleaveBuf.push_back(0); m_interleaveBuf.push_back(0);
else else
m_interleaveBuf.push_back(data[0] * m_coefs[ch][0] + m_interleaveBuf.push_back(data[0] * m_coefs[int(ch)][0] +
data[1] * m_coefs[ch][1]); data[1] * m_coefs[int(ch)][1]);
} }
voice.bufferSampleData(m_interleaveBuf.data(), frames); voice.bufferSampleData(m_interleaveBuf.data(), frames);
} }

View File

@ -203,4 +203,9 @@ struct XA2AudioVoiceAllocator : IAudioVoiceAllocator
} }
}; };
std::unique_ptr<IAudioVoiceAllocator> NewAudioVoiceAllocator()
{
return std::make_unique<XA2AudioVoiceAllocator>();
}
} }