#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 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 = 11; IAudioDevice* _audioDevice; EmulationSettings* _settings; double _fadeRatio; uint32_t _muteFrameCount; unique_ptr _oggMixer; unique_ptr _eqFrequencyGrid; unique_ptr _equalizerLeft; unique_ptr _equalizerRight; shared_ptr _console; CrossFeedFilter _crossFeedFilter; LowPassFilter _lowPassFilter; StereoPanningFilter _stereoPanning; StereoDelayFilter _stereoDelay; StereoCombFilter _stereoCombFilter; ReverbFilter _reverbFilter; int16_t _previousOutputLeft = 0; int16_t _previousOutputRight = 0; vector _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); ~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(); void ProcessEndOfFrame(); double GetRateAdjustment(); };