From 6c1cc431b3c21c204f39ed48e92507d87bc0301e Mon Sep 17 00:00:00 2001 From: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com> Date: Sun, 3 Jul 2022 01:16:44 -0700 Subject: [PATCH] Add AIFF audio dumping option, this should eliminate the gradual desync in audio dumps (as it supports a non-integer sample rate), make it the default for non-Windows systems. --- Source/Core/AudioCommon/AudioCommon.cpp | 10 +- Source/Core/AudioCommon/AudioFile.cpp | 300 ++++++++++++++++++ .../AudioCommon/{WaveFile.h => AudioFile.h} | 26 +- Source/Core/AudioCommon/CMakeLists.txt | 4 +- Source/Core/AudioCommon/Mixer.cpp | 30 +- Source/Core/AudioCommon/Mixer.h | 10 +- Source/Core/AudioCommon/WaveFile.cpp | 164 ---------- Source/Core/Core/Config/MainSettings.cpp | 5 + Source/Core/Core/Config/MainSettings.h | 1 + Source/Core/DolphinLib.props | 4 +- Source/Core/DolphinQt/Settings/AudioPane.cpp | 27 ++ Source/Core/DolphinQt/Settings/AudioPane.h | 6 + 12 files changed, 384 insertions(+), 203 deletions(-) create mode 100644 Source/Core/AudioCommon/AudioFile.cpp rename Source/Core/AudioCommon/{WaveFile.h => AudioFile.h} (74%) delete mode 100644 Source/Core/AudioCommon/WaveFile.cpp diff --git a/Source/Core/AudioCommon/AudioCommon.cpp b/Source/Core/AudioCommon/AudioCommon.cpp index 19ac9f6e9f03..395e1678dc79 100644 --- a/Source/Core/AudioCommon/AudioCommon.cpp +++ b/Source/Core/AudioCommon/AudioCommon.cpp @@ -207,18 +207,20 @@ void SendAIBuffer(const short* samples, unsigned int num_samples) void StartAudioDump() { std::time_t start_time = std::time(nullptr); + bool aiff = Config::Get(Config::MAIN_DUMP_AUDIO_USE_AIFF); std::string path_prefix = File::GetUserPath(D_DUMPAUDIO_IDX) + SConfig::GetInstance().GetGameID(); + std::string path_extension = aiff ? ".aiff" : ".wav"; std::string base_name = fmt::format("{}_{:%Y-%m-%d_%H-%M-%S}", path_prefix, fmt::localtime(start_time)); - const std::string audio_file_name_dtk = fmt::format("{}_dtkdump.wav", base_name); - const std::string audio_file_name_dsp = fmt::format("{}_dspdump.wav", base_name); + const std::string audio_file_name_dtk = fmt::format("{}_dtkdump{}", base_name, path_extension); + const std::string audio_file_name_dsp = fmt::format("{}_dspdump{}", base_name, path_extension); File::CreateFullPath(audio_file_name_dtk); File::CreateFullPath(audio_file_name_dsp); - g_sound_stream->GetMixer()->StartLogDTKAudio(audio_file_name_dtk); - g_sound_stream->GetMixer()->StartLogDSPAudio(audio_file_name_dsp); + g_sound_stream->GetMixer()->StartLogDTKAudio(audio_file_name_dtk, aiff); + g_sound_stream->GetMixer()->StartLogDSPAudio(audio_file_name_dsp, aiff); s_audio_dump_start = true; } diff --git a/Source/Core/AudioCommon/AudioFile.cpp b/Source/Core/AudioCommon/AudioFile.cpp new file mode 100644 index 000000000000..f3c2815cb998 --- /dev/null +++ b/Source/Core/AudioCommon/AudioFile.cpp @@ -0,0 +1,300 @@ +// Copyright 2008 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "AudioCommon/AudioFile.h" +#include "AudioCommon/Mixer.h" + +#include + +#include "Common/CommonTypes.h" +#include "Common/FileUtil.h" +#include "Common/IOFile.h" +#include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" +#include "Common/StringUtil.h" +#include "Common/Swap.h" +#include "Core/Config/MainSettings.h" +#include "Core/ConfigManager.h" + +constexpr size_t AudioFileWriter::BUFFER_SIZE; + +AudioFileWriter::AudioFileWriter() +{ +} + +AudioFileWriter::~AudioFileWriter() +{ + Stop(); +} + +bool AudioFileWriter::Start(const std::string& filename, unsigned int hle_sample_rate_divisor, + bool aiff) +{ + // Ask to delete file + if (File::Exists(filename)) + { + if (Config::Get(Config::MAIN_DUMP_AUDIO_SILENT) || + AskYesNoFmtT("Delete the existing file '{0}'?", filename)) + { + File::Delete(filename); + } + else + { + // Stop and cancel dumping the audio + return false; + } + } + + // Check if the file is already open + if (file) + { + PanicAlertFmtT("The file {0} was already open, the file header will not be written.", filename); + return false; + } + + file.Open(filename, "wb"); + if (!file) + { + PanicAlertFmtT( + "The file {0} could not be opened for writing. Please check if it's already opened " + "by another program.", + filename); + return false; + } + + audio_size = 0; + + if (basename.empty()) + SplitPath(filename, nullptr, &basename, nullptr); + + current_sample_rate_divisor = hle_sample_rate_divisor; + use_aiff = aiff; + + if (use_aiff) + { + // ----------------- + // Write aiff file header + // ----------------- + Write4("FORM"); + Write(100 * 1000 * 1000); // write big value in case the file gets truncated + Write4("AIFC"); + + Write4("FVER"); + Write(4); // size of fver block + Write(0xA2805140); // AIFCVersion1 + + Write4("COMM"); + Write(0x18); // size of comm block + + Write(2); // channels + Write(100 * 1000 * 1000 / 2); // write big value in case the file gets truncated + Write(16); // bit depth + + // sample rate is stored as a 80 bit IEEE Standard 754 floating point number + // on x86 systems, this is generally long double, so we can directly use the result from that + // (probably) + + // on other systems, we'll try to use a normal double, and convert it over to a 80 + // bit float + + // ok, this is just a typical long double on x86, we can directly use it + if (sizeof(long double) == 10 && std::numeric_limits::is_iec559) + { + // evil type punning ahead +#pragma pack(push, 1) + union IEEE80BitFloat + { + long double f; + struct + { + u64 significand; + u16 exponent; + }; + }; +#pragma pack(pop) + + IEEE80BitFloat sample_rate = {}; + sample_rate.f = + Mixer::FIXED_SAMPLE_RATE_DIVIDEND / static_cast(hle_sample_rate_divisor); + + Write(sample_rate.exponent); + Write(sample_rate.significand); + } + // fall back on double (probably precice enough) + else if (sizeof(double) == 8 && std::numeric_limits::is_iec559) + { + // more evil type punning ahead +#pragma pack(push, 1) + union IEEE64BitFloat + { + double f; + struct + { + u64 significand : 52; + u64 exponent : 12; + }; + }; +#pragma pack(pop) + + IEEE64BitFloat sample_rate = {}; + sample_rate.f = + Mixer::FIXED_SAMPLE_RATE_DIVIDEND / static_cast(hle_sample_rate_divisor); + + // 11 -> 15 bit exponent (we probably can assume the sign bit is 0?) + u16 exponent = 0x3FFF + (sample_rate.exponent - 0x3FF); + u64 significand = sample_rate.significand; + // 52 -> 63 bit significand + significand <<= 63 - 52; + // "normalize" the float + significand |= 0x8000000000000000ULL; + + Write(exponent); + Write(significand); + } + else + // well this is weird? is_iec559 probably returned false somehow, so we're on a very strange + // machine, generic integer to 80-bit float conversion ahead (is this needed?) + { + u16 exponent = 0x3FFF + 63; + u64 significand = Mixer::FIXED_SAMPLE_RATE_DIVIDEND / hle_sample_rate_divisor; + + while ((significand & (1ULL << 63)) == 0) + { + significand <<= 1; + exponent--; + } + + Write(exponent); + Write(significand); + } + + Write4("sowt"); // little endian samples + Write(0); // compression name (don't bother) + + Write4("SSND"); + Write(100 * 1000 * 1000); // write big value in case the file gets truncated + Write(0); + Write(0); + + // We are now at offset 72 + if (file.Tell() != 72) + PanicAlertFmt("Wrong offset: {}", file.Tell()); + } + else // wav + { + // ----------------- + // Write wav file header + // ----------------- + Write4("RIFF"); + Write(100 * 1000 * 1000); // write big value in case the file gets truncated + Write4("WAVE"); + Write4("fmt "); + + Write(16); // size of fmt block + Write(0x00020001); // two channels, uncompressed + + const u32 sample_rate = Mixer::FIXED_SAMPLE_RATE_DIVIDEND / hle_sample_rate_divisor; + Write(sample_rate); + Write(sample_rate * 2 * 2); // two channels, 16bit + + Write(0x00100004); + Write4("data"); + Write(100 * 1000 * 1000 - 32); + + // We are now at offset 44 + if (file.Tell() != 44) + PanicAlertFmt("Wrong offset: {}", file.Tell()); + } + + return true; +} + +void AudioFileWriter::Stop() +{ + if (use_aiff) + { + file.Seek(4, File::SeekOrigin::Begin); + Write(audio_size + 72 - 8); + + file.Seek(34, File::SeekOrigin::Begin); + Write(audio_size / 4); + + file.Seek(60, File::SeekOrigin::Begin); + Write(audio_size - 8); + } + else // wav + { + file.Seek(4, File::SeekOrigin::Begin); + Write(audio_size + 36); + + file.Seek(40, File::SeekOrigin::Begin); + Write(audio_size); + } + + file.Close(); +} + +template +void AudioFileWriter::Write(T value) +{ + if (use_aiff) // AIFF uses BE for its values instead of LE (value is assumed LE) + { + value = Common::FromBigEndian(value); + } + + file.WriteArray(&value, 1); +} + +void AudioFileWriter::Write4(const char* ptr) +{ + file.WriteBytes(ptr, 4); +} + +void AudioFileWriter::AddStereoSamplesBE(const short* sample_data, u32 count, + int sample_rate_divisor, int l_volume, int r_volume) +{ + if (!file) + ERROR_LOG_FMT(AUDIO, "AudioFileWriter - file not open."); + + if (count > BUFFER_SIZE * 2) + ERROR_LOG_FMT(AUDIO, "AudioFileWriter - buffer too small (count = {}).", count); + + if (skip_silence) + { + bool all_zero = true; + + for (u32 i = 0; i < count * 2; i++) + { + if (sample_data[i]) + all_zero = false; + } + + if (all_zero) + return; + } + + for (u32 i = 0; i < count; i++) + { + // Flip the audio channels from RL to LR + conv_buffer[2 * i] = Common::swap16((u16)sample_data[2 * i + 1]); + conv_buffer[2 * i + 1] = Common::swap16((u16)sample_data[2 * i]); + + // Apply volume (volume ranges from 0 to 256) + conv_buffer[2 * i] = conv_buffer[2 * i] * l_volume / 256; + conv_buffer[2 * i + 1] = conv_buffer[2 * i + 1] * r_volume / 256; + } + + if (sample_rate_divisor != current_sample_rate_divisor) + { + Stop(); + file_index++; + std::ostringstream filename; + filename << File::GetUserPath(D_DUMPAUDIO_IDX) << basename << file_index + << (use_aiff ? ".aiff" : ".wav"); + Start(filename.str(), sample_rate_divisor, use_aiff); + current_sample_rate_divisor = sample_rate_divisor; + } + + file.WriteBytes(conv_buffer.data(), count * 4); + audio_size += count * 4; +} diff --git a/Source/Core/AudioCommon/WaveFile.h b/Source/Core/AudioCommon/AudioFile.h similarity index 74% rename from Source/Core/AudioCommon/WaveFile.h rename to Source/Core/AudioCommon/AudioFile.h index 7100b73cd1b8..d964d7d305c5 100644 --- a/Source/Core/AudioCommon/WaveFile.h +++ b/Source/Core/AudioCommon/AudioFile.h @@ -2,7 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // --------------------------------------------------------------------------------- -// Class: WaveFileWriter +// Class: AudioFileWriter // Description: Simple utility class to make it easy to write long 16-bit stereo // audio streams to disk. // Use Start() to start recording to a file, and AddStereoSamples to add wave data. @@ -19,24 +19,24 @@ #include "Common/CommonTypes.h" #include "Common/IOFile.h" -class WaveFileWriter +class AudioFileWriter { public: - WaveFileWriter(); - ~WaveFileWriter(); + AudioFileWriter(); + ~AudioFileWriter(); - WaveFileWriter(const WaveFileWriter&) = delete; - WaveFileWriter& operator=(const WaveFileWriter&) = delete; - WaveFileWriter(WaveFileWriter&&) = delete; - WaveFileWriter& operator=(WaveFileWriter&&) = delete; + AudioFileWriter(const AudioFileWriter&) = delete; + AudioFileWriter& operator=(const AudioFileWriter&) = delete; + AudioFileWriter(AudioFileWriter&&) = delete; + AudioFileWriter& operator=(AudioFileWriter&&) = delete; - bool Start(const std::string& filename, unsigned int HLESampleRate); + bool Start(const std::string& filename, unsigned int HLESampleRate, bool aiff); void Stop(); void SetSkipSilence(bool skip) { skip_silence = skip; } + // big endian void AddStereoSamplesBE(const short* sample_data, u32 count, int sample_rate_divisor, - int l_volume, - int r_volume); // big endian + int l_volume, int r_volume); u32 GetAudioSize() const { return audio_size; } private: @@ -46,9 +46,11 @@ class WaveFileWriter bool skip_silence = false; u32 audio_size = 0; std::array conv_buffer{}; - void Write(u32 value); + template + void Write(T value); void Write4(const char* ptr); std::string basename; int current_sample_rate_divisor; + bool use_aiff; int file_index = 0; }; diff --git a/Source/Core/AudioCommon/CMakeLists.txt b/Source/Core/AudioCommon/CMakeLists.txt index b3a9c57b426a..3d752bb21563 100644 --- a/Source/Core/AudioCommon/CMakeLists.txt +++ b/Source/Core/AudioCommon/CMakeLists.txt @@ -1,6 +1,8 @@ add_library(audiocommon AudioCommon.cpp AudioCommon.h + AudioFile.cpp + AudioFile.h AudioStretcher.cpp AudioStretcher.h CubebStream.cpp @@ -14,8 +16,6 @@ add_library(audiocommon SurroundDecoder.h NullSoundStream.cpp NullSoundStream.h - WaveFile.cpp - WaveFile.h ) find_package(OpenSLES) diff --git a/Source/Core/AudioCommon/Mixer.cpp b/Source/Core/AudioCommon/Mixer.cpp index 8a268adb0284..3a2ae64e689c 100644 --- a/Source/Core/AudioCommon/Mixer.cpp +++ b/Source/Core/AudioCommon/Mixer.cpp @@ -262,8 +262,8 @@ void Mixer::PushSamples(const short* samples, unsigned int num_samples) { int sample_rate_divisor = m_dma_mixer.GetInputSampleRateDivisor(); auto volume = m_dma_mixer.GetVolume(); - m_wave_writer_dsp.AddStereoSamplesBE(samples, num_samples, sample_rate_divisor, volume.first, - volume.second); + m_audio_writer_dsp.AddStereoSamplesBE(samples, num_samples, sample_rate_divisor, volume.first, + volume.second); } } @@ -274,8 +274,8 @@ void Mixer::PushStreamingSamples(const short* samples, unsigned int num_samples) { int sample_rate_divisor = m_streaming_mixer.GetInputSampleRateDivisor(); auto volume = m_streaming_mixer.GetVolume(); - m_wave_writer_dtk.AddStereoSamplesBE(samples, num_samples, sample_rate_divisor, volume.first, - volume.second); + m_audio_writer_dtk.AddStereoSamplesBE(samples, num_samples, sample_rate_divisor, volume.first, + volume.second); } } @@ -333,20 +333,21 @@ void Mixer::SetGBAVolume(int device_number, unsigned int lvolume, unsigned int r m_gba_mixers[device_number].SetVolume(lvolume, rvolume); } -void Mixer::StartLogDTKAudio(const std::string& filename) +void Mixer::StartLogDTKAudio(const std::string& filename, bool aiff) { if (!m_log_dtk_audio) { - bool success = m_wave_writer_dtk.Start(filename, m_streaming_mixer.GetInputSampleRateDivisor()); + bool success = + m_audio_writer_dtk.Start(filename, m_streaming_mixer.GetInputSampleRateDivisor(), aiff); if (success) { m_log_dtk_audio = true; - m_wave_writer_dtk.SetSkipSilence(false); + m_audio_writer_dtk.SetSkipSilence(false); NOTICE_LOG_FMT(AUDIO, "Starting DTK Audio logging"); } else { - m_wave_writer_dtk.Stop(); + m_audio_writer_dtk.Stop(); NOTICE_LOG_FMT(AUDIO, "Unable to start DTK Audio logging"); } } @@ -361,7 +362,7 @@ void Mixer::StopLogDTKAudio() if (m_log_dtk_audio) { m_log_dtk_audio = false; - m_wave_writer_dtk.Stop(); + m_audio_writer_dtk.Stop(); NOTICE_LOG_FMT(AUDIO, "Stopping DTK Audio logging"); } else @@ -370,20 +371,21 @@ void Mixer::StopLogDTKAudio() } } -void Mixer::StartLogDSPAudio(const std::string& filename) +void Mixer::StartLogDSPAudio(const std::string& filename, bool aiff) { if (!m_log_dsp_audio) { - bool success = m_wave_writer_dsp.Start(filename, m_dma_mixer.GetInputSampleRateDivisor()); + bool success = + m_audio_writer_dsp.Start(filename, m_dma_mixer.GetInputSampleRateDivisor(), aiff); if (success) { m_log_dsp_audio = true; - m_wave_writer_dsp.SetSkipSilence(false); + m_audio_writer_dsp.SetSkipSilence(false); NOTICE_LOG_FMT(AUDIO, "Starting DSP Audio logging"); } else { - m_wave_writer_dsp.Stop(); + m_audio_writer_dsp.Stop(); NOTICE_LOG_FMT(AUDIO, "Unable to start DSP Audio logging"); } } @@ -398,7 +400,7 @@ void Mixer::StopLogDSPAudio() if (m_log_dsp_audio) { m_log_dsp_audio = false; - m_wave_writer_dsp.Stop(); + m_audio_writer_dsp.Stop(); NOTICE_LOG_FMT(AUDIO, "Stopping DSP Audio logging"); } else diff --git a/Source/Core/AudioCommon/Mixer.h b/Source/Core/AudioCommon/Mixer.h index 7191fd6ab027..dd1bfbcee6a5 100644 --- a/Source/Core/AudioCommon/Mixer.h +++ b/Source/Core/AudioCommon/Mixer.h @@ -6,9 +6,9 @@ #include #include +#include "AudioCommon/AudioFile.h" #include "AudioCommon/AudioStretcher.h" #include "AudioCommon/SurroundDecoder.h" -#include "AudioCommon/WaveFile.h" #include "Common/CommonTypes.h" class PointerWrap; @@ -42,10 +42,10 @@ class Mixer final void SetWiimoteSpeakerVolume(unsigned int lvolume, unsigned int rvolume); void SetGBAVolume(int device_number, unsigned int lvolume, unsigned int rvolume); - void StartLogDTKAudio(const std::string& filename); + void StartLogDTKAudio(const std::string& filename, bool aiff); void StopLogDTKAudio(); - void StartLogDSPAudio(const std::string& filename); + void StartLogDSPAudio(const std::string& filename, bool aiff); void StopLogDSPAudio(); float GetCurrentSpeed() const { return m_speed.load(); } @@ -111,8 +111,8 @@ class Mixer final AudioCommon::SurroundDecoder m_surround_decoder; std::array m_scratch_buffer{}; - WaveFileWriter m_wave_writer_dtk; - WaveFileWriter m_wave_writer_dsp; + AudioFileWriter m_audio_writer_dtk; + AudioFileWriter m_audio_writer_dsp; bool m_log_dtk_audio = false; bool m_log_dsp_audio = false; diff --git a/Source/Core/AudioCommon/WaveFile.cpp b/Source/Core/AudioCommon/WaveFile.cpp deleted file mode 100644 index ef4eba048dc3..000000000000 --- a/Source/Core/AudioCommon/WaveFile.cpp +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2008 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "AudioCommon/WaveFile.h" -#include "AudioCommon/Mixer.h" - -#include - -#include "Common/CommonTypes.h" -#include "Common/FileUtil.h" -#include "Common/IOFile.h" -#include "Common/Logging/Log.h" -#include "Common/MsgHandler.h" -#include "Common/StringUtil.h" -#include "Common/Swap.h" -#include "Core/Config/MainSettings.h" -#include "Core/ConfigManager.h" - -constexpr size_t WaveFileWriter::BUFFER_SIZE; - -WaveFileWriter::WaveFileWriter() -{ -} - -WaveFileWriter::~WaveFileWriter() -{ - Stop(); -} - -bool WaveFileWriter::Start(const std::string& filename, unsigned int hle_sample_rate_divisor) -{ - // Ask to delete file - if (File::Exists(filename)) - { - if (Config::Get(Config::MAIN_DUMP_AUDIO_SILENT) || - AskYesNoFmtT("Delete the existing file '{0}'?", filename)) - { - File::Delete(filename); - } - else - { - // Stop and cancel dumping the audio - return false; - } - } - - // Check if the file is already open - if (file) - { - PanicAlertFmtT("The file {0} was already open, the file header will not be written.", filename); - return false; - } - - file.Open(filename, "wb"); - if (!file) - { - PanicAlertFmtT( - "The file {0} could not be opened for writing. Please check if it's already opened " - "by another program.", - filename); - return false; - } - - audio_size = 0; - - if (basename.empty()) - SplitPath(filename, nullptr, &basename, nullptr); - - current_sample_rate_divisor = hle_sample_rate_divisor; - - // ----------------- - // Write file header - // ----------------- - Write4("RIFF"); - Write(100 * 1000 * 1000); // write big value in case the file gets truncated - Write4("WAVE"); - Write4("fmt "); - - Write(16); // size of fmt block - Write(0x00020001); // two channels, uncompressed - - const u32 sample_rate = Mixer::FIXED_SAMPLE_RATE_DIVIDEND / hle_sample_rate_divisor; - Write(sample_rate); - Write(sample_rate * 2 * 2); // two channels, 16bit - - Write(0x00100004); - Write4("data"); - Write(100 * 1000 * 1000 - 32); - - // We are now at offset 44 - if (file.Tell() != 44) - PanicAlertFmt("Wrong offset: {}", file.Tell()); - - return true; -} - -void WaveFileWriter::Stop() -{ - file.Seek(4, File::SeekOrigin::Begin); - Write(audio_size + 36); - - file.Seek(40, File::SeekOrigin::Begin); - Write(audio_size); - - file.Close(); -} - -void WaveFileWriter::Write(u32 value) -{ - file.WriteArray(&value, 1); -} - -void WaveFileWriter::Write4(const char* ptr) -{ - file.WriteBytes(ptr, 4); -} - -void WaveFileWriter::AddStereoSamplesBE(const short* sample_data, u32 count, - int sample_rate_divisor, int l_volume, int r_volume) -{ - if (!file) - ERROR_LOG_FMT(AUDIO, "WaveFileWriter - file not open."); - - if (count > BUFFER_SIZE * 2) - ERROR_LOG_FMT(AUDIO, "WaveFileWriter - buffer too small (count = {}).", count); - - if (skip_silence) - { - bool all_zero = true; - - for (u32 i = 0; i < count * 2; i++) - { - if (sample_data[i]) - all_zero = false; - } - - if (all_zero) - return; - } - - for (u32 i = 0; i < count; i++) - { - // Flip the audio channels from RL to LR - conv_buffer[2 * i] = Common::swap16((u16)sample_data[2 * i + 1]); - conv_buffer[2 * i + 1] = Common::swap16((u16)sample_data[2 * i]); - - // Apply volume (volume ranges from 0 to 256) - conv_buffer[2 * i] = conv_buffer[2 * i] * l_volume / 256; - conv_buffer[2 * i + 1] = conv_buffer[2 * i + 1] * r_volume / 256; - } - - if (sample_rate_divisor != current_sample_rate_divisor) - { - Stop(); - file_index++; - std::ostringstream filename; - filename << File::GetUserPath(D_DUMPAUDIO_IDX) << basename << file_index << ".wav"; - Start(filename.str(), sample_rate_divisor); - current_sample_rate_divisor = sample_rate_divisor; - } - - file.WriteBytes(conv_buffer.data(), count * 4); - audio_size += count * 4; -} diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index d7d146e3e298..70bc779d6510 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -243,6 +243,11 @@ const Info MAIN_DSP_CAPTURE_LOG{{System::Main, "DSP", "CaptureLog"}, false const Info MAIN_DSP_JIT{{System::Main, "DSP", "EnableJIT"}, true}; const Info MAIN_DUMP_AUDIO{{System::Main, "DSP", "DumpAudio"}, false}; const Info MAIN_DUMP_AUDIO_SILENT{{System::Main, "DSP", "DumpAudioSilent"}, false}; +#ifdef _WIN32 +const Info MAIN_DUMP_AUDIO_USE_AIFF{{System::Main, "DSP", "DumpAudioUseAIFF"}, false}; +#else +const Info MAIN_DUMP_AUDIO_USE_AIFF{{System::Main, "DSP", "DumpAudioUseAIFF"}, true}; +#endif const Info MAIN_DUMP_UCODE{{System::Main, "DSP", "DumpUCode"}, false}; const Info MAIN_AUDIO_BACKEND{{System::Main, "DSP", "Backend"}, AudioCommon::GetDefaultSoundBackend()}; diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index e1b538f2b60c..edffb031ca02 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -147,6 +147,7 @@ extern const Info MAIN_DSP_CAPTURE_LOG; extern const Info MAIN_DSP_JIT; extern const Info MAIN_DUMP_AUDIO; extern const Info MAIN_DUMP_AUDIO_SILENT; +extern const Info MAIN_DUMP_AUDIO_USE_AIFF; extern const Info MAIN_DUMP_UCODE; extern const Info MAIN_AUDIO_BACKEND; extern const Info MAIN_AUDIO_VOLUME; diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index ca81c1ff48ec..ce9ab99080b2 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -2,6 +2,7 @@ + @@ -12,7 +13,6 @@ - @@ -698,6 +698,7 @@ + @@ -706,7 +707,6 @@ - diff --git a/Source/Core/DolphinQt/Settings/AudioPane.cpp b/Source/Core/DolphinQt/Settings/AudioPane.cpp index f6f2629fe3ea..5560998cb650 100644 --- a/Source/Core/DolphinQt/Settings/AudioPane.cpp +++ b/Source/Core/DolphinQt/Settings/AudioPane.cpp @@ -155,12 +155,30 @@ void AudioPane::CreateWidgets() stretching_layout->addWidget(m_stretching_buffer_slider, 1, 1); stretching_layout->addWidget(m_stretching_buffer_indicator, 1, 2); + auto* dump_format_box = new QGroupBox(tr("Audio Dump Format")); + auto* dump_format_layout = new QVBoxLayout; + + dump_format_box->setLayout(dump_format_layout); + m_dump_aiff = new QRadioButton(tr("AIFF")); + m_dump_wav = new QRadioButton(tr("WAV")); + + m_dump_aiff->setToolTip(tr( + "Uses the AIFF format for audio dumps. This format is more common for non-Windows systems.")); + m_dump_wav->setToolTip( + tr("Uses the WAV format for audio dumps. This format is more common for Windows systems.")); + + dump_format_layout->addStretch(1); + dump_format_layout->addWidget(m_dump_aiff); + dump_format_layout->addWidget(m_dump_wav); + dump_format_layout->addStretch(1); + dsp_box->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); auto* const main_vbox_layout = new QVBoxLayout; main_vbox_layout->addWidget(dsp_box); main_vbox_layout->addWidget(backend_box); main_vbox_layout->addWidget(stretching_box); + main_vbox_layout->addWidget(dump_format_box); m_main_layout = new QHBoxLayout; m_main_layout->addLayout(main_vbox_layout); @@ -187,6 +205,8 @@ void AudioPane::ConnectWidgets() connect(m_dsp_hle, &QRadioButton::toggled, this, &AudioPane::SaveSettings); connect(m_dsp_lle, &QRadioButton::toggled, this, &AudioPane::SaveSettings); connect(m_dsp_interpreter, &QRadioButton::toggled, this, &AudioPane::SaveSettings); + connect(m_dump_aiff, &QRadioButton::toggled, this, &AudioPane::SaveSettings); + connect(m_dump_wav, &QRadioButton::toggled, this, &AudioPane::SaveSettings); #ifdef _WIN32 connect(m_wasapi_device_combo, qOverload(&QComboBox::currentIndexChanged), this, @@ -260,6 +280,10 @@ void AudioPane::LoadSettings() QString::fromStdString(Config::Get(Config::MAIN_WASAPI_DEVICE))); } #endif + + // Dump Format + m_dump_aiff->setChecked(Config::Get(Config::MAIN_DUMP_AUDIO_USE_AIFF)); + m_dump_wav->setChecked(!Config::Get(Config::MAIN_DUMP_AUDIO_USE_AIFF)); } void AudioPane::SaveSettings() @@ -327,6 +351,9 @@ void AudioPane::SaveSettings() Config::SetBaseOrCurrent(Config::MAIN_WASAPI_DEVICE, device); #endif + // Dump Format + Config::SetBaseOrCurrent(Config::MAIN_DUMP_AUDIO_USE_AIFF, m_dump_aiff->isChecked()); + AudioCommon::UpdateSoundStream(); } diff --git a/Source/Core/DolphinQt/Settings/AudioPane.h b/Source/Core/DolphinQt/Settings/AudioPane.h index 50fa27717b5d..0d2872716bb2 100644 --- a/Source/Core/DolphinQt/Settings/AudioPane.h +++ b/Source/Core/DolphinQt/Settings/AudioPane.h @@ -76,4 +76,10 @@ class AudioPane final : public QWidget QLabel* m_stretching_buffer_label; QSlider* m_stretching_buffer_slider; QLabel* m_stretching_buffer_indicator; + + // Audio Dump Format + QRadioButton* m_dump_aiff; + QLabel* m_aiff_label; + QRadioButton* m_dump_wav; + QLabel* m_wav_label; };