mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 21:37:52 -07:00
Mixer: Support GBA samples mixing
This commit is contained in:
parent
1b27f22cbc
commit
502def7f71
@ -47,6 +47,8 @@ void Mixer::DoState(PointerWrap& p)
|
|||||||
m_dma_mixer.DoState(p);
|
m_dma_mixer.DoState(p);
|
||||||
m_streaming_mixer.DoState(p);
|
m_streaming_mixer.DoState(p);
|
||||||
m_wiimote_speaker_mixer.DoState(p);
|
m_wiimote_speaker_mixer.DoState(p);
|
||||||
|
for (auto& mixer : m_gba_mixers)
|
||||||
|
mixer.DoState(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executed from sound stream thread
|
// Executed from sound stream thread
|
||||||
@ -93,20 +95,24 @@ unsigned int Mixer::MixerFifo::Mix(short* samples, unsigned int numSamples,
|
|||||||
s32 lvolume = m_LVolume.load();
|
s32 lvolume = m_LVolume.load();
|
||||||
s32 rvolume = m_RVolume.load();
|
s32 rvolume = m_RVolume.load();
|
||||||
|
|
||||||
|
const auto read_buffer = [this](auto index) {
|
||||||
|
return m_little_endian ? m_buffer[index] : Common::swap16(m_buffer[index]);
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: consider a higher-quality resampling algorithm.
|
// TODO: consider a higher-quality resampling algorithm.
|
||||||
for (; currentSample < numSamples * 2 && ((indexW - indexR) & INDEX_MASK) > 2; currentSample += 2)
|
for (; currentSample < numSamples * 2 && ((indexW - indexR) & INDEX_MASK) > 2; currentSample += 2)
|
||||||
{
|
{
|
||||||
u32 indexR2 = indexR + 2; // next sample
|
u32 indexR2 = indexR + 2; // next sample
|
||||||
|
|
||||||
s16 l1 = Common::swap16(m_buffer[indexR & INDEX_MASK]); // current
|
s16 l1 = read_buffer(indexR & INDEX_MASK); // current
|
||||||
s16 l2 = Common::swap16(m_buffer[indexR2 & INDEX_MASK]); // next
|
s16 l2 = read_buffer(indexR2 & INDEX_MASK); // next
|
||||||
int sampleL = ((l1 << 16) + (l2 - l1) * (u16)m_frac) >> 16;
|
int sampleL = ((l1 << 16) + (l2 - l1) * (u16)m_frac) >> 16;
|
||||||
sampleL = (sampleL * lvolume) >> 8;
|
sampleL = (sampleL * lvolume) >> 8;
|
||||||
sampleL += samples[currentSample + 1];
|
sampleL += samples[currentSample + 1];
|
||||||
samples[currentSample + 1] = std::clamp(sampleL, -32767, 32767);
|
samples[currentSample + 1] = std::clamp(sampleL, -32767, 32767);
|
||||||
|
|
||||||
s16 r1 = Common::swap16(m_buffer[(indexR + 1) & INDEX_MASK]); // current
|
s16 r1 = read_buffer((indexR + 1) & INDEX_MASK); // current
|
||||||
s16 r2 = Common::swap16(m_buffer[(indexR2 + 1) & INDEX_MASK]); // next
|
s16 r2 = read_buffer((indexR2 + 1) & INDEX_MASK); // next
|
||||||
int sampleR = ((r1 << 16) + (r2 - r1) * (u16)m_frac) >> 16;
|
int sampleR = ((r1 << 16) + (r2 - r1) * (u16)m_frac) >> 16;
|
||||||
sampleR = (sampleR * rvolume) >> 8;
|
sampleR = (sampleR * rvolume) >> 8;
|
||||||
sampleR += samples[currentSample];
|
sampleR += samples[currentSample];
|
||||||
@ -122,8 +128,8 @@ unsigned int Mixer::MixerFifo::Mix(short* samples, unsigned int numSamples,
|
|||||||
|
|
||||||
// Padding
|
// Padding
|
||||||
short s[2];
|
short s[2];
|
||||||
s[0] = Common::swap16(m_buffer[(indexR - 1) & INDEX_MASK]);
|
s[0] = read_buffer((indexR - 1) & INDEX_MASK);
|
||||||
s[1] = Common::swap16(m_buffer[(indexR - 2) & INDEX_MASK]);
|
s[1] = read_buffer((indexR - 2) & INDEX_MASK);
|
||||||
s[0] = (s[0] * rvolume) >> 8;
|
s[0] = (s[0] * rvolume) >> 8;
|
||||||
s[1] = (s[1] * lvolume) >> 8;
|
s[1] = (s[1] * lvolume) >> 8;
|
||||||
for (; currentSample < numSamples * 2; currentSample += 2)
|
for (; currentSample < numSamples * 2; currentSample += 2)
|
||||||
@ -158,6 +164,8 @@ unsigned int Mixer::Mix(short* samples, unsigned int num_samples)
|
|||||||
m_dma_mixer.Mix(m_scratch_buffer.data(), available_samples, false);
|
m_dma_mixer.Mix(m_scratch_buffer.data(), available_samples, false);
|
||||||
m_streaming_mixer.Mix(m_scratch_buffer.data(), available_samples, false);
|
m_streaming_mixer.Mix(m_scratch_buffer.data(), available_samples, false);
|
||||||
m_wiimote_speaker_mixer.Mix(m_scratch_buffer.data(), available_samples, false);
|
m_wiimote_speaker_mixer.Mix(m_scratch_buffer.data(), available_samples, false);
|
||||||
|
for (auto& mixer : m_gba_mixers)
|
||||||
|
mixer.Mix(m_scratch_buffer.data(), available_samples, false);
|
||||||
|
|
||||||
if (!m_is_stretching)
|
if (!m_is_stretching)
|
||||||
{
|
{
|
||||||
@ -172,6 +180,8 @@ unsigned int Mixer::Mix(short* samples, unsigned int num_samples)
|
|||||||
m_dma_mixer.Mix(samples, num_samples, true);
|
m_dma_mixer.Mix(samples, num_samples, true);
|
||||||
m_streaming_mixer.Mix(samples, num_samples, true);
|
m_streaming_mixer.Mix(samples, num_samples, true);
|
||||||
m_wiimote_speaker_mixer.Mix(samples, num_samples, true);
|
m_wiimote_speaker_mixer.Mix(samples, num_samples, true);
|
||||||
|
for (auto& mixer : m_gba_mixers)
|
||||||
|
mixer.Mix(samples, num_samples, true);
|
||||||
m_is_stretching = false;
|
m_is_stretching = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,14 +268,19 @@ void Mixer::PushWiimoteSpeakerSamples(const short* samples, unsigned int num_sam
|
|||||||
|
|
||||||
for (unsigned int i = 0; i < num_samples; ++i)
|
for (unsigned int i = 0; i < num_samples; ++i)
|
||||||
{
|
{
|
||||||
samples_stereo[i * 2] = Common::swap16(samples[i]);
|
samples_stereo[i * 2] = samples[i];
|
||||||
samples_stereo[i * 2 + 1] = Common::swap16(samples[i]);
|
samples_stereo[i * 2 + 1] = samples[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
m_wiimote_speaker_mixer.PushSamples(samples_stereo, num_samples);
|
m_wiimote_speaker_mixer.PushSamples(samples_stereo, num_samples);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Mixer::PushGBASamples(int device_number, const short* samples, unsigned int num_samples)
|
||||||
|
{
|
||||||
|
m_gba_mixers[device_number].PushSamples(samples, num_samples);
|
||||||
|
}
|
||||||
|
|
||||||
void Mixer::SetDMAInputSampleRate(unsigned int rate)
|
void Mixer::SetDMAInputSampleRate(unsigned int rate)
|
||||||
{
|
{
|
||||||
m_dma_mixer.SetInputSampleRate(rate);
|
m_dma_mixer.SetInputSampleRate(rate);
|
||||||
@ -276,6 +291,11 @@ void Mixer::SetStreamInputSampleRate(unsigned int rate)
|
|||||||
m_streaming_mixer.SetInputSampleRate(rate);
|
m_streaming_mixer.SetInputSampleRate(rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Mixer::SetGBAInputSampleRates(int device_number, unsigned int rate)
|
||||||
|
{
|
||||||
|
m_gba_mixers[device_number].SetInputSampleRate(rate);
|
||||||
|
}
|
||||||
|
|
||||||
void Mixer::SetStreamingVolume(unsigned int lvolume, unsigned int rvolume)
|
void Mixer::SetStreamingVolume(unsigned int lvolume, unsigned int rvolume)
|
||||||
{
|
{
|
||||||
m_streaming_mixer.SetVolume(lvolume, rvolume);
|
m_streaming_mixer.SetVolume(lvolume, rvolume);
|
||||||
@ -286,6 +306,11 @@ void Mixer::SetWiimoteSpeakerVolume(unsigned int lvolume, unsigned int rvolume)
|
|||||||
m_wiimote_speaker_mixer.SetVolume(lvolume, rvolume);
|
m_wiimote_speaker_mixer.SetVolume(lvolume, rvolume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Mixer::SetGBAVolume(int device_number, unsigned int lvolume, unsigned int rvolume)
|
||||||
|
{
|
||||||
|
m_gba_mixers[device_number].SetVolume(lvolume, rvolume);
|
||||||
|
}
|
||||||
|
|
||||||
void Mixer::StartLogDTKAudio(const std::string& filename)
|
void Mixer::StartLogDTKAudio(const std::string& filename)
|
||||||
{
|
{
|
||||||
if (!m_log_dtk_audio)
|
if (!m_log_dtk_audio)
|
||||||
|
@ -30,11 +30,17 @@ public:
|
|||||||
void PushStreamingSamples(const short* samples, unsigned int num_samples);
|
void PushStreamingSamples(const short* samples, unsigned int num_samples);
|
||||||
void PushWiimoteSpeakerSamples(const short* samples, unsigned int num_samples,
|
void PushWiimoteSpeakerSamples(const short* samples, unsigned int num_samples,
|
||||||
unsigned int sample_rate);
|
unsigned int sample_rate);
|
||||||
|
void PushGBASamples(int device_number, const short* samples, unsigned int num_samples);
|
||||||
|
|
||||||
unsigned int GetSampleRate() const { return m_sampleRate; }
|
unsigned int GetSampleRate() const { return m_sampleRate; }
|
||||||
|
|
||||||
void SetDMAInputSampleRate(unsigned int rate);
|
void SetDMAInputSampleRate(unsigned int rate);
|
||||||
void SetStreamInputSampleRate(unsigned int rate);
|
void SetStreamInputSampleRate(unsigned int rate);
|
||||||
|
void SetGBAInputSampleRates(int device_number, unsigned int rate);
|
||||||
|
|
||||||
void SetStreamingVolume(unsigned int lvolume, unsigned int rvolume);
|
void SetStreamingVolume(unsigned int lvolume, unsigned int rvolume);
|
||||||
void SetWiimoteSpeakerVolume(unsigned int lvolume, unsigned int rvolume);
|
void SetWiimoteSpeakerVolume(unsigned int lvolume, unsigned int rvolume);
|
||||||
|
void SetGBAVolume(int device_number, unsigned int lvolume, unsigned int rvolume);
|
||||||
|
|
||||||
void StartLogDTKAudio(const std::string& filename);
|
void StartLogDTKAudio(const std::string& filename);
|
||||||
void StopLogDTKAudio();
|
void StopLogDTKAudio();
|
||||||
@ -57,7 +63,8 @@ private:
|
|||||||
class MixerFifo final
|
class MixerFifo final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MixerFifo(Mixer* mixer, unsigned sample_rate) : m_mixer(mixer), m_input_sample_rate(sample_rate)
|
MixerFifo(Mixer* mixer, unsigned sample_rate, bool little_endian)
|
||||||
|
: m_mixer(mixer), m_input_sample_rate(sample_rate), m_little_endian(little_endian)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
void DoState(PointerWrap& p);
|
void DoState(PointerWrap& p);
|
||||||
@ -71,6 +78,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
Mixer* m_mixer;
|
Mixer* m_mixer;
|
||||||
unsigned m_input_sample_rate;
|
unsigned m_input_sample_rate;
|
||||||
|
bool m_little_endian;
|
||||||
std::array<short, MAX_SAMPLES * 2> m_buffer{};
|
std::array<short, MAX_SAMPLES * 2> m_buffer{};
|
||||||
std::atomic<u32> m_indexW{0};
|
std::atomic<u32> m_indexW{0};
|
||||||
std::atomic<u32> m_indexR{0};
|
std::atomic<u32> m_indexR{0};
|
||||||
@ -81,9 +89,11 @@ private:
|
|||||||
u32 m_frac = 0;
|
u32 m_frac = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
MixerFifo m_dma_mixer{this, 32000};
|
MixerFifo m_dma_mixer{this, 32000, false};
|
||||||
MixerFifo m_streaming_mixer{this, 48000};
|
MixerFifo m_streaming_mixer{this, 48000, false};
|
||||||
MixerFifo m_wiimote_speaker_mixer{this, 3000};
|
MixerFifo m_wiimote_speaker_mixer{this, 3000, true};
|
||||||
|
std::array<MixerFifo, 4> m_gba_mixers{MixerFifo{this, 48000, true}, MixerFifo{this, 48000, true},
|
||||||
|
MixerFifo{this, 48000, true}, MixerFifo{this, 48000, true}};
|
||||||
unsigned int m_sampleRate;
|
unsigned int m_sampleRate;
|
||||||
|
|
||||||
bool m_is_stretching = false;
|
bool m_is_stretching = false;
|
||||||
|
Loading…
Reference in New Issue
Block a user