Revert "Get rid of WaveRecorder"

This reverts commit 13e985c05b.
This commit is contained in:
twinaphex 2022-03-31 18:03:10 +02:00
parent 372d019f9a
commit 15946b2970
7 changed files with 214 additions and 10 deletions

View File

@ -18,4 +18,9 @@ class IAudioDevice
virtual void Pause() = 0;
virtual void ProcessEndOfFrame() = 0;
virtual void UpdateSoundSettings() = 0;
};
virtual string GetAvailableDevices() = 0;
virtual void SetAudioDevice(string deviceName) = 0;
virtual AudioStatistics GetStatistics() = 0;
};

View File

@ -5,6 +5,7 @@
#include "CPU.h"
#include "VideoRenderer.h"
#include "RewindManager.h"
#include "WaveRecorder.h"
#include "OggMixer.h"
#include "Console.h"
#include "BaseMapper.h"
@ -132,7 +133,7 @@ void SoundMixer::PlayAudioBuffer(uint32_t time)
shared_ptr<RewindManager> rewindManager = _console->GetRewindManager();
if(!_console->GetVideoRenderer()->IsRecording() && !_settings->CheckFlag(EmulationFlags::NsfPlayerEnabled)) {
if(!_console->GetVideoRenderer()->IsRecording() && !_waveRecorder && !_settings->CheckFlag(EmulationFlags::NsfPlayerEnabled)) {
if((_settings->CheckFlag(EmulationFlags::Turbo) || (rewindManager && rewindManager->IsRewinding())) && _settings->CheckFlag(EmulationFlags::ReduceSoundInFastForward)) {
//Reduce volume when fast forwarding or rewinding
_lowPassFilter.ApplyFilter(_outputBuffer, sampleCount, 0, 1.0 - _settings->GetVolumeReduction());
@ -167,6 +168,17 @@ void SoundMixer::PlayAudioBuffer(uint32_t time)
}
if(!_settings->IsRunAheadFrame() && rewindManager && rewindManager->SendAudio(_outputBuffer, (uint32_t)sampleCount, _sampleRate)) {
bool isRecording = _waveRecorder || _console->GetVideoRenderer()->IsRecording();
if(isRecording) {
shared_ptr<WaveRecorder> recorder = _waveRecorder;
if(recorder) {
if(!recorder->WriteSamples(_outputBuffer, (uint32_t)sampleCount, _sampleRate, true)) {
_waveRecorder.reset();
}
}
_console->GetVideoRenderer()->AddRecordingSound(_outputBuffer, (uint32_t)sampleCount, _sampleRate);
}
if(_audioDevice && !_console->IsPaused()) {
_audioDevice->PlayBuffer(_outputBuffer, (uint32_t)sampleCount, _sampleRate, true);
}
@ -361,15 +373,17 @@ void SoundMixer::UpdateEqualizers(bool forceUpdate)
void SoundMixer::StartRecording(string filepath)
{
_waveRecorder.reset(new WaveRecorder(filepath, _settings->GetSampleRate(), true));
}
void SoundMixer::StopRecording()
{
_waveRecorder.reset();
}
bool SoundMixer::IsRecording()
{
return false;
return _waveRecorder.get() != nullptr;
}
void SoundMixer::SetFadeRatio(double fadeRatio)
@ -396,6 +410,15 @@ OggMixer* SoundMixer::GetOggMixer()
return _oggMixer.get();
}
AudioStatistics SoundMixer::GetStatistics()
{
if(_audioDevice) {
return _audioDevice->GetStatistics();
} else {
return AudioStatistics();
}
}
void SoundMixer::ProcessEndOfFrame()
{
if(_audioDevice) {
@ -405,12 +428,55 @@ void SoundMixer::ProcessEndOfFrame()
double SoundMixer::GetRateAdjustment()
{
return 1.0;
return _rateAdjustment;
}
double SoundMixer::GetTargetRateAdjustment()
{
return 1.0;
bool isRecording = _waveRecorder || _console->GetVideoRenderer()->IsRecording();
if(!isRecording && !_settings->CheckFlag(EmulationFlags::DisableDynamicSampleRate)) {
//Don't deviate from selected sample rate while recording
//TODO: Have 2 output streams (one for recording, one for the speakers)
AudioStatistics stats = GetStatistics();
if(stats.AverageLatency > 0 && _settings->GetEmulationSpeed() == 100) {
//Try to stay within +/- 3ms of requested latency
constexpr int32_t maxGap = 3;
constexpr int32_t maxSubAdjustment = 3600;
int32_t requestedLatency = (int32_t)_settings->GetAudioLatency();
double latencyGap = stats.AverageLatency - requestedLatency;
double adjustment = std::min(0.0025, (std::ceil((std::abs(latencyGap) - maxGap) * 8)) * 0.00003125);
if(latencyGap < 0 && _underTarget < maxSubAdjustment) {
_underTarget++;
} else if(latencyGap > 0 && _underTarget > -maxSubAdjustment) {
_underTarget--;
}
//For every ~1 second spent under/over target latency, further adjust rate (GetTargetRate is called approx. 3x per frame)
//This should slowly get us closer to the actual output rate of the sound card
double subAdjustment = 0.00003125 * _underTarget / 180;
if(adjustment > 0) {
if(latencyGap > maxGap) {
_rateAdjustment = 1 - adjustment + subAdjustment;
} else if(latencyGap < -maxGap) {
_rateAdjustment = 1 + adjustment + subAdjustment;
}
} else if(std::abs(latencyGap) < 1) {
//Restore normal rate once we get within +/- 1ms
_rateAdjustment = 1.0 + subAdjustment;
}
} else {
_underTarget = 0;
_rateAdjustment = 1.0;
}
} else {
_underTarget = 0;
_rateAdjustment = 1.0;
}
return _rateAdjustment;
}
void SoundMixer::UpdateTargetSampleRate()
@ -421,4 +487,4 @@ void SoundMixer::UpdateTargetSampleRate()
blip_set_rates(_blipBufRight, _clockRate, targetRate);
_previousTargetRate = targetRate;
}
}
}

View File

@ -13,6 +13,7 @@
#include "CrossFeedFilter.h"
class Console;
class WaveRecorder;
class OggMixer;
namespace orfanidis_eq {
@ -33,6 +34,7 @@ private:
IAudioDevice* _audioDevice;
EmulationSettings* _settings;
shared_ptr<WaveRecorder> _waveRecorder;
double _fadeRatio;
uint32_t _muteFrameCount;
unique_ptr<OggMixer> _oggMixer;
@ -52,6 +54,9 @@ private:
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];
@ -109,6 +114,7 @@ public:
OggMixer* GetOggMixer();
AudioStatistics GetStatistics();
void ProcessEndOfFrame();
double GetRateAdjustment();
};

87
Core/WaveRecorder.cpp Normal file
View File

@ -0,0 +1,87 @@
#include "stdafx.h"
#include "WaveRecorder.h"
#include "MessageManager.h"
WaveRecorder::WaveRecorder(string outputFile, uint32_t sampleRate, bool isStereo)
{
_stream = ofstream(outputFile, ios::out | ios::binary);
_outputFile = outputFile;
_streamSize = 0;
_sampleRate = sampleRate;
_isStereo = isStereo;
if(_stream) {
WriteHeader();
MessageManager::DisplayMessage("SoundRecorder", "SoundRecorderStarted", _outputFile);
}
}
WaveRecorder::~WaveRecorder()
{
CloseFile();
}
void WaveRecorder::WriteHeader()
{
_stream << "RIFF";
uint32_t size = 0;
_stream.write((char*)&size, sizeof(size));
_stream << "WAVE";
_stream << "fmt ";
uint32_t chunkSize = 16;
_stream.write((char*)&chunkSize, sizeof(chunkSize));
uint16_t format = 1; //PCM
uint16_t channelCount = _isStereo ? 2 : 1;
uint16_t bytesPerSample = 2;
uint16_t blockAlign = channelCount * bytesPerSample;
uint32_t byteRate = _sampleRate * channelCount * bytesPerSample;
uint16_t bitsPerSample = bytesPerSample * 8;
_stream.write((char*)&format, sizeof(format));
_stream.write((char*)&channelCount, sizeof(channelCount));
_stream.write((char*)&_sampleRate, sizeof(_sampleRate));
_stream.write((char*)&byteRate, sizeof(byteRate));
_stream.write((char*)&blockAlign, sizeof(blockAlign));
_stream.write((char*)&bitsPerSample, sizeof(bitsPerSample));
_stream << "data";
_stream.write((char*)&size, sizeof(size));
}
bool WaveRecorder::WriteSamples(int16_t * samples, uint32_t sampleCount, uint32_t sampleRate, bool isStereo)
{
if(_sampleRate != sampleRate || _isStereo != isStereo) {
//Format changed, stop recording
CloseFile();
return false;
} else {
uint32_t sampleBytes = sampleCount * (isStereo ? 4 : 2);
_stream.write((char*)samples, sampleBytes);
_streamSize += sampleBytes;
return true;
}
}
void WaveRecorder::UpdateSizeValues()
{
_stream.seekp(4, ios::beg);
uint32_t fileSize = _streamSize + 36;
_stream.write((char*)&fileSize, sizeof(fileSize));
_stream.seekp(40, ios::beg);
_stream.write((char*)&_streamSize, sizeof(_streamSize));
}
void WaveRecorder::CloseFile()
{
if(_stream && _stream.is_open()) {
UpdateSizeValues();
_stream.close();
MessageManager::DisplayMessage("SoundRecorder", "SoundRecorderStopped", _outputFile);
}
}

21
Core/WaveRecorder.h Normal file
View File

@ -0,0 +1,21 @@
#include "stdafx.h"
class WaveRecorder
{
private:
std::ofstream _stream;
uint32_t _streamSize;
uint32_t _sampleRate;
bool _isStereo;
string _outputFile;
void WriteHeader();
void UpdateSizeValues();
void CloseFile();
public:
WaveRecorder(string outputFile, uint32_t sampleRate, bool isStereo);
~WaveRecorder();
bool WriteSamples(int16_t* samples, uint32_t sampleCount, uint32_t sampleRate, bool isStereo);
};

View File

@ -7,31 +7,35 @@
class LibretroSoundManager : public IAudioDevice
{
private:
retro_audio_sample_batch_t audio_batch_cb = nullptr;
retro_audio_sample_batch_t _sendAudioSample = nullptr;
bool _skipMode = false;
shared_ptr<Console> _console;
public:
LibretroSoundManager(shared_ptr<Console> console)
{
_console = console;
_console->GetSoundMixer()->RegisterAudioDevice(this);
}
~LibretroSoundManager()
{
_console->GetSoundMixer()->RegisterAudioDevice(nullptr);
}
// Inherited via IAudioDevice
virtual void PlayBuffer(int16_t *soundBuffer, uint32_t sampleCount, uint32_t sampleRate, bool isStereo) override
{
if(!_skipMode && audio_batch_cb) {
if(!_skipMode && _sendAudioSample) {
for(uint32_t total = 0; total < sampleCount; ) {
total += (uint32_t)audio_batch_cb(soundBuffer + total*2, sampleCount - total);
total += (uint32_t)_sendAudioSample(soundBuffer + total*2, sampleCount - total);
}
}
}
void SetSendAudioSample(retro_audio_sample_batch_t sendAudioSample)
{
audio_batch_cb = sendAudioSample;
_sendAudioSample = sendAudioSample;
}
void SetSkipMode(bool skip)
@ -47,6 +51,15 @@ public:
{
}
virtual string GetAvailableDevices() override
{
return string();
}
virtual void SetAudioDevice(string deviceName) override
{
}
virtual void UpdateSoundSettings() override
{
}
@ -54,4 +67,9 @@ public:
virtual void ProcessEndOfFrame() override
{
}
virtual AudioStatistics GetStatistics() override
{
return AudioStatistics();
}
};

View File

@ -106,6 +106,7 @@ SOURCES_CXX := $(LIBRETRO_DIR)/libretro.cpp \
$(CORE_DIR)/VideoRenderer.cpp \
$(CORE_DIR)/VirtualFile.cpp \
$(CORE_DIR)/VsControlManager.cpp \
$(CORE_DIR)/WaveRecorder.cpp \
$(UTIL_DIR)/ArchiveReader.cpp \
$(UTIL_DIR)/AutoResetEvent.cpp \
$(UTIL_DIR)/blip_buf.cpp \