HLE DSP: Initial mixer work

This commit is contained in:
wheremyfoodat 2024-09-29 00:32:51 +03:00
parent a8041bce8c
commit 3e72323653
3 changed files with 94 additions and 7 deletions

View file

@ -324,8 +324,8 @@ namespace Audio::HLE {
BitField<15, 1, u32> outputBufferCountDirty;
BitField<16, 1, u32> masterVolumeDirty;
BitField<24, 1, u32> auxReturnVolume0Dirty;
BitField<25, 1, u32> auxReturnVolume1Dirty;
BitField<24, 1, u32> auxVolume0Dirty;
BitField<25, 1, u32> auxVolume1Dirty;
BitField<26, 1, u32> outputFormatDirty;
BitField<27, 1, u32> clippingModeDirty;
BitField<28, 1, u32> headphonesConnectedDirty;
@ -337,7 +337,7 @@ namespace Audio::HLE {
/// The DSP has three intermediate audio mixers. This controls the volume level (0.0-1.0) for
/// each at the final mixer.
float_le masterVolume;
std::array<float_le, 2> auxReturnVolume;
std::array<float_le, 2> auxVolumes;
u16_le outputBufferCount;
u16 pad1[2];
@ -422,7 +422,7 @@ namespace Audio::HLE {
struct DspStatus {
u16_le unknown;
u16_le dropped_frames;
u16_le droppedFrames;
u16 pad0[0xE];
};
ASSERT_DSP_STRUCT(DspStatus, 32);

View file

@ -95,8 +95,7 @@ namespace Audio {
DSPSource() { reset(); }
};
class HLE_DSP : public DSPCore {
// The audio frame types are public in case we want to use them for unit tests
class DSPMixer {
public:
template <typename T, usize channelCount = 1>
using Sample = std::array<T, channelCount>;
@ -113,6 +112,43 @@ namespace Audio {
template <typename T>
using QuadFrame = Frame<T, 4>;
private:
using ChannelFormat = HLE::DspConfiguration::OutputFormat;
// The audio from each DSP voice is converted to quadraphonic and then fed into 3 intermediate mixing stages
// Two of these intermediate mixers (second and third) are used for effects, including custom effects done on the CPU
static constexpr usize mixerStageCount = 3;
public:
ChannelFormat channelFormat = ChannelFormat::Stereo;
std::array<float, mixerStageCount> volumes;
std::array<bool, 2> enableAuxStages;
void reset() {
channelFormat = ChannelFormat::Stereo;
volumes.fill(0.0);
enableAuxStages.fill(false);
}
};
class HLE_DSP : public DSPCore {
// The audio frame types are public in case we want to use them for unit tests
public:
template <typename T, usize channelCount = 1>
using Sample = DSPMixer::Sample<T, channelCount>;
template <typename T, usize channelCount>
using Frame = DSPMixer::Frame<T, channelCount>;
template <typename T>
using MonoFrame = DSPMixer::MonoFrame<T>;
template <typename T>
using StereoFrame = DSPMixer::StereoFrame<T>;
template <typename T>
using QuadFrame = DSPMixer::QuadFrame<T>;
using Source = Audio::DSPSource;
using SampleBuffer = Source::SampleBuffer;
@ -131,6 +167,7 @@ namespace Audio {
std::array<Source, Audio::HLE::sourceCount> sources; // DSP voices
Audio::HLE::DspMemory dspRam;
Audio::DSPMixer mixer;
std::unique_ptr<Audio::AAC::Decoder> aacDecoder;
void resetAudioPipe();
@ -175,10 +212,13 @@ namespace Audio {
void handleAACRequest(const AAC::Message& request);
void updateSourceConfig(Source& source, HLE::SourceConfiguration::Configuration& config, s16_le* adpcmCoefficients);
void updateMixerConfig(HLE::SharedMemory& sharedMem);
void generateFrame(StereoFrame<s16>& frame);
void generateFrame(DSPSource& source);
void outputFrame();
// Perform the final mix, mixing the quadraphonic samples from all voices into the output audio frame
void performMix(Audio::HLE::SharedMemory& readRegion, Audio::HLE::SharedMemory& writeRegion);
// Decode an entire buffer worth of audio
void decodeBuffer(DSPSource& source);