Mesen-X/Core/SoundMixer.h
Persune a22b17b2c1 Add /A13 and /OE1 audio interference
In hardware, the audio from the 2A03 APU pins go through an inverted
preamp using one of the 74HCU04 inverter chips in the motherboard.
Though this may be cost-effective on Nintendo's part, the signals on the
hex inverter chip can interfere with one another, especially on the
audio. This can be heard as a buzz or a high pitched whine.

The only known signals to interfere with the audio so far is:
- /A13, the inverted signal of PPU A13 going into the cartridge
   connector.
- /OE1, Output enable for controller reads, though this is only found
   present on the RF Famicom.
2021-08-11 17:55:56 +08:00

120 lines
3 KiB
C++

#pragma once
#include "stdafx.h"
#include "EmulationSettings.h"
#include "../Utilities/LowPassFilter.h"
#include "../Utilities/blip_buf.h"
#include "../Utilities/SimpleLock.h"
#include "IAudioDevice.h"
#include "Snapshotable.h"
#include "StereoPanningFilter.h"
#include "StereoDelayFilter.h"
#include "StereoCombFilter.h"
#include "ReverbFilter.h"
#include "CrossFeedFilter.h"
class Console;
class WaveRecorder;
class OggMixer;
namespace orfanidis_eq {
class freq_grid;
class eq1;
}
class SoundMixer : public Snapshotable
{
public:
static constexpr uint32_t CycleLength = 10000;
static constexpr uint32_t BitsPerSample = 16;
private:
static constexpr uint32_t MaxSampleRate = 96000;
static constexpr uint32_t MaxSamplesPerFrame = MaxSampleRate / 60 * 4 * 2; //x4 to allow CPU overclocking up to 10x, x2 for panning stereo
static constexpr uint32_t MaxChannelCount = (uint32_t)AudioChannel::MaxChannelCount;
IAudioDevice* _audioDevice;
EmulationSettings* _settings;
shared_ptr<WaveRecorder> _waveRecorder;
double _fadeRatio;
uint32_t _muteFrameCount;
unique_ptr<OggMixer> _oggMixer;
unique_ptr<orfanidis_eq::freq_grid> _eqFrequencyGrid;
unique_ptr<orfanidis_eq::eq1> _equalizerLeft;
unique_ptr<orfanidis_eq::eq1> _equalizerRight;
shared_ptr<Console> _console;
CrossFeedFilter _crossFeedFilter;
LowPassFilter _lowPassFilter;
StereoPanningFilter _stereoPanning;
StereoDelayFilter _stereoDelay;
StereoCombFilter _stereoCombFilter;
ReverbFilter _reverbFilter;
int16_t _previousOutputLeft = 0;
int16_t _previousOutputRight = 0;
double _rateAdjustment = 1.0;
int32_t _underTarget = 0;
vector<uint32_t> _timestamps;
int16_t _channelOutput[MaxChannelCount][CycleLength];
int16_t _currentOutput[MaxChannelCount];
blip_t* _blipBufLeft;
blip_t* _blipBufRight;
int16_t *_outputBuffer;
double _volumes[MaxChannelCount];
double _panning[MaxChannelCount];
NesModel _model;
uint32_t _sampleRate;
uint32_t _clockRate;
bool _hasPanning;
double _previousTargetRate;
double GetChannelOutput(AudioChannel channel, bool forRightChannel);
int16_t GetOutputVolume(bool forRightChannel);
void EndFrame(uint32_t time);
void UpdateRates(bool forceUpdate);
void UpdateEqualizers(bool forceUpdate);
void ApplyEqualizer(orfanidis_eq::eq1* equalizer, size_t sampleCount);
double GetTargetRateAdjustment();
void UpdateTargetSampleRate();
protected:
virtual void StreamState(bool saving) override;
public:
SoundMixer(shared_ptr<Console> console);
~SoundMixer();
void SetNesModel(NesModel model);
void Reset();
void PlayAudioBuffer(uint32_t cycle);
void AddDelta(AudioChannel channel, uint32_t time, int16_t delta);
void StartRecording(string filepath);
void StopRecording();
bool IsRecording();
//For NSF/NSFe
uint32_t GetMuteFrameCount();
void ResetMuteFrameCount();
void SetFadeRatio(double fadeRatio);
void StopAudio(bool clearBuffer = false);
void RegisterAudioDevice(IAudioDevice *audioDevice);
OggMixer* GetOggMixer();
AudioStatistics GetStatistics();
void ProcessEndOfFrame();
double GetRateAdjustment();
};