Mesen-S/Core/SoundMixer.cpp
Sour d204485153 Added Super Game Boy support
Missing support for SGB2's timings and still needs a few tweaks and more testing
2020-06-18 00:58:39 -04:00

158 lines
4.1 KiB
C++

#include "stdafx.h"
#include "SoundMixer.h"
#include "Console.h"
#include "EmuSettings.h"
#include "SoundResampler.h"
#include "RewindManager.h"
#include "VideoRenderer.h"
#include "WaveRecorder.h"
#include "Spc.h"
#include "Msu1.h"
#include "BaseCartridge.h"
#include "SuperGameboy.h"
#include "../Utilities/Equalizer.h"
SoundMixer::SoundMixer(Console *console)
{
_console = console;
_audioDevice = nullptr;
_resampler.reset(new SoundResampler(console));
_sampleBuffer = new int16_t[0x10000];
}
SoundMixer::~SoundMixer()
{
delete[] _sampleBuffer;
}
void SoundMixer::RegisterAudioDevice(IAudioDevice *audioDevice)
{
_audioDevice = audioDevice;
}
AudioStatistics SoundMixer::GetStatistics()
{
if(_audioDevice) {
return _audioDevice->GetStatistics();
} else {
return AudioStatistics();
}
}
void SoundMixer::StopAudio(bool clearBuffer)
{
if(_audioDevice) {
if(clearBuffer) {
_audioDevice->Stop();
} else {
_audioDevice->Pause();
}
}
}
void SoundMixer::PlayAudioBuffer(int16_t* samples, uint32_t sampleCount, uint32_t sourceRate)
{
AudioConfig cfg = _console->GetSettings()->GetAudioConfig();
if(cfg.EnableEqualizer) {
ProcessEqualizer(samples, sampleCount);
}
uint32_t masterVolume = cfg.MasterVolume;
if(_console->GetSettings()->CheckFlag(EmulationFlags::InBackground)) {
if(cfg.MuteSoundInBackground) {
masterVolume = 0;
} else if(cfg.ReduceSoundInBackground) {
masterVolume = cfg.VolumeReduction == 100 ? 0 : masterVolume * (100 - cfg.VolumeReduction) / 100;
}
} else if(cfg.ReduceSoundInFastForward && _console->GetSettings()->CheckFlag(EmulationFlags::TurboOrRewind)) {
masterVolume = cfg.VolumeReduction == 100 ? 0 : masterVolume * (100 - cfg.VolumeReduction) / 100;
}
_leftSample = samples[0];
_rightSample = samples[1];
int16_t *out = _sampleBuffer;
uint32_t count = _resampler->Resample(samples, sampleCount, sourceRate, cfg.SampleRate, out);
SuperGameboy* sgb = _console->GetCartridge()->GetSuperGameboy();
if(sgb) {
uint32_t targetRate = (uint32_t)(cfg.SampleRate * _resampler->GetRateAdjustment());
sgb->MixAudio(targetRate, out, count);
}
shared_ptr<Msu1> msu1 = _console->GetMsu1();
if(msu1) {
msu1->MixAudio(out, count, cfg.SampleRate);
}
if(masterVolume < 100) {
//Apply volume if not using the default value
for(uint32_t i = 0; i < count * 2; i++) {
out[i] = (int32_t)out[i] * (int32_t)masterVolume / 100;
}
}
shared_ptr<RewindManager> rewindManager = _console->GetRewindManager();
if(!_console->IsRunAheadFrame() && rewindManager && rewindManager->SendAudio(out, count)) {
bool isRecording = _waveRecorder || _console->GetVideoRenderer()->IsRecording();
if(isRecording) {
if(_waveRecorder) {
_waveRecorder->WriteSamples(out, count, cfg.SampleRate, true);
}
_console->GetVideoRenderer()->AddRecordingSound(out, count, cfg.SampleRate);
}
if(_audioDevice) {
if(!cfg.EnableAudio) {
_audioDevice->Stop();
return;
}
_audioDevice->PlayBuffer(out, count, cfg.SampleRate, true);
_audioDevice->ProcessEndOfFrame();
}
}
}
void SoundMixer::ProcessEqualizer(int16_t* samples, uint32_t sampleCount)
{
AudioConfig cfg = _console->GetSettings()->GetAudioConfig();
if(!_equalizer) {
_equalizer.reset(new Equalizer());
}
vector<double> bandGains = {
cfg.Band1Gain, cfg.Band2Gain, cfg.Band3Gain, cfg.Band4Gain, cfg.Band5Gain,
cfg.Band6Gain, cfg.Band7Gain, cfg.Band8Gain, cfg.Band9Gain, cfg.Band10Gain,
cfg.Band11Gain, cfg.Band12Gain, cfg.Band13Gain, cfg.Band14Gain, cfg.Band15Gain,
cfg.Band16Gain, cfg.Band17Gain, cfg.Band18Gain, cfg.Band19Gain, cfg.Band20Gain
};
_equalizer->UpdateEqualizers(bandGains, Spc::SpcSampleRate);
_equalizer->ApplyEqualizer(sampleCount, samples);
}
double SoundMixer::GetRateAdjustment()
{
return _resampler->GetRateAdjustment();
}
void SoundMixer::StartRecording(string filepath)
{
_waveRecorder.reset(new WaveRecorder(filepath, _console->GetSettings()->GetAudioConfig().SampleRate, true));
}
void SoundMixer::StopRecording()
{
_waveRecorder.reset();
}
bool SoundMixer::IsRecording()
{
return _waveRecorder.get() != nullptr;
}
void SoundMixer::GetLastSamples(int16_t &left, int16_t &right)
{
left = _leftSample;
right = _rightSample;
}