WaveFile.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // Copyright 2008 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "AudioCommon/WaveFile.h"
  4. #include <string>
  5. #include <fmt/format.h>
  6. #include "AudioCommon/Mixer.h"
  7. #include "Common/CommonTypes.h"
  8. #include "Common/FileUtil.h"
  9. #include "Common/IOFile.h"
  10. #include "Common/Logging/Log.h"
  11. #include "Common/MsgHandler.h"
  12. #include "Common/StringUtil.h"
  13. #include "Common/Swap.h"
  14. #include "Core/Config/MainSettings.h"
  15. #include "Core/ConfigManager.h"
  16. constexpr size_t WaveFileWriter::BUFFER_SIZE;
  17. WaveFileWriter::WaveFileWriter()
  18. {
  19. }
  20. WaveFileWriter::~WaveFileWriter()
  21. {
  22. Stop();
  23. }
  24. bool WaveFileWriter::Start(const std::string& filename, u32 sample_rate_divisor)
  25. {
  26. // Ask to delete file
  27. if (File::Exists(filename))
  28. {
  29. if (Config::Get(Config::MAIN_DUMP_AUDIO_SILENT) ||
  30. AskYesNoFmtT("Delete the existing file '{0}'?", filename))
  31. {
  32. File::Delete(filename);
  33. }
  34. else
  35. {
  36. // Stop and cancel dumping the audio
  37. return false;
  38. }
  39. }
  40. // Check if the file is already open
  41. if (file)
  42. {
  43. PanicAlertFmtT("The file {0} was already open, the file header will not be written.", filename);
  44. return false;
  45. }
  46. file.Open(filename, "wb");
  47. if (!file)
  48. {
  49. PanicAlertFmtT(
  50. "The file {0} could not be opened for writing. Please check if it's already opened "
  51. "by another program.",
  52. filename);
  53. return false;
  54. }
  55. audio_size = 0;
  56. if (basename.empty())
  57. SplitPath(filename, nullptr, &basename, nullptr);
  58. current_sample_rate_divisor = sample_rate_divisor;
  59. // -----------------
  60. // Write file header
  61. // -----------------
  62. Write4("RIFF");
  63. Write(100 * 1000 * 1000); // write big value in case the file gets truncated
  64. Write4("WAVE");
  65. Write4("fmt ");
  66. Write(16); // size of fmt block
  67. Write(0x00020001); // two channels, uncompressed
  68. const u32 sample_rate = Mixer::FIXED_SAMPLE_RATE_DIVIDEND / sample_rate_divisor;
  69. Write(sample_rate);
  70. Write(sample_rate * 2 * 2); // two channels, 16bit
  71. Write(0x00100004);
  72. Write4("data");
  73. Write(100 * 1000 * 1000 - 32);
  74. // We are now at offset 44
  75. if (file.Tell() != 44)
  76. PanicAlertFmt("Wrong offset: {}", file.Tell());
  77. return true;
  78. }
  79. void WaveFileWriter::Stop()
  80. {
  81. file.Seek(4, File::SeekOrigin::Begin);
  82. Write(audio_size + 36);
  83. file.Seek(40, File::SeekOrigin::Begin);
  84. Write(audio_size);
  85. file.Close();
  86. }
  87. void WaveFileWriter::Write(u32 value)
  88. {
  89. file.WriteArray(&value, 1);
  90. }
  91. void WaveFileWriter::Write4(const char* ptr)
  92. {
  93. file.WriteBytes(ptr, 4);
  94. }
  95. void WaveFileWriter::AddStereoSamplesBE(const short* sample_data, u32 count,
  96. u32 sample_rate_divisor, int l_volume, int r_volume)
  97. {
  98. if (!file)
  99. {
  100. ERROR_LOG_FMT(AUDIO, "WaveFileWriter - file not open.");
  101. return;
  102. }
  103. if (count * 2 > BUFFER_SIZE)
  104. {
  105. ERROR_LOG_FMT(AUDIO, "WaveFileWriter - buffer too small (count = {}).", count);
  106. return;
  107. }
  108. if (skip_silence)
  109. {
  110. bool all_zero = true;
  111. for (u32 i = 0; i < count * 2; i++)
  112. {
  113. if (sample_data[i])
  114. all_zero = false;
  115. }
  116. if (all_zero)
  117. return;
  118. }
  119. for (u32 i = 0; i < count; i++)
  120. {
  121. // Flip the audio channels from RL to LR
  122. conv_buffer[2 * i] = Common::swap16((u16)sample_data[2 * i + 1]);
  123. conv_buffer[2 * i + 1] = Common::swap16((u16)sample_data[2 * i]);
  124. // Apply volume (volume ranges from 0 to 256)
  125. conv_buffer[2 * i] = conv_buffer[2 * i] * l_volume / 256;
  126. conv_buffer[2 * i + 1] = conv_buffer[2 * i + 1] * r_volume / 256;
  127. }
  128. if (sample_rate_divisor != current_sample_rate_divisor)
  129. {
  130. Stop();
  131. file_index++;
  132. const std::string filename =
  133. fmt::format("{}{}{}.wav", File::GetUserPath(D_DUMPAUDIO_IDX), basename, file_index);
  134. Start(filename, sample_rate_divisor);
  135. current_sample_rate_divisor = sample_rate_divisor;
  136. }
  137. file.WriteBytes(conv_buffer.data(), count * 4);
  138. audio_size += count * 4;
  139. }