source.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. // Copyright 2016 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <array>
  6. #include "audio_core/codec.h"
  7. #include "audio_core/hle/common.h"
  8. #include "audio_core/hle/source.h"
  9. #include "audio_core/interpolate.h"
  10. #include "common/assert.h"
  11. #include "common/logging/log.h"
  12. #include "core/memory.h"
  13. namespace DSP {
  14. namespace HLE {
  15. SourceStatus::Status Source::Tick(SourceConfiguration::Configuration& config, const s16_le (&adpcm_coeffs)[16]) {
  16. ParseConfig(config, adpcm_coeffs);
  17. if (state.enabled) {
  18. GenerateFrame();
  19. }
  20. return GetCurrentStatus();
  21. }
  22. void Source::MixInto(QuadFrame32& dest, size_t intermediate_mix_id) const {
  23. if (!state.enabled)
  24. return;
  25. const std::array<float, 4>& gains = state.gain.at(intermediate_mix_id);
  26. for (size_t samplei = 0; samplei < samples_per_frame; samplei++) {
  27. // Conversion from stereo (current_frame) to quadraphonic (dest) occurs here.
  28. dest[samplei][0] += static_cast<s32>(gains[0] * current_frame[samplei][0]);
  29. dest[samplei][1] += static_cast<s32>(gains[1] * current_frame[samplei][1]);
  30. dest[samplei][2] += static_cast<s32>(gains[2] * current_frame[samplei][0]);
  31. dest[samplei][3] += static_cast<s32>(gains[3] * current_frame[samplei][1]);
  32. }
  33. }
  34. void Source::Reset() {
  35. current_frame.fill({});
  36. state = {};
  37. }
  38. void Source::ParseConfig(SourceConfiguration::Configuration& config, const s16_le (&adpcm_coeffs)[16]) {
  39. if (!config.dirty_raw) {
  40. return;
  41. }
  42. if (config.reset_flag) {
  43. config.reset_flag.Assign(0);
  44. Reset();
  45. LOG_TRACE(Audio_DSP, "source_id=%zu reset", source_id);
  46. }
  47. if (config.partial_reset_flag) {
  48. config.partial_reset_flag.Assign(0);
  49. state.input_queue = std::priority_queue<Buffer, std::vector<Buffer>, BufferOrder>{};
  50. LOG_TRACE(Audio_DSP, "source_id=%zu partial_reset", source_id);
  51. }
  52. if (config.enable_dirty) {
  53. config.enable_dirty.Assign(0);
  54. state.enabled = config.enable != 0;
  55. LOG_TRACE(Audio_DSP, "source_id=%zu enable=%d", source_id, state.enabled);
  56. }
  57. if (config.sync_dirty) {
  58. config.sync_dirty.Assign(0);
  59. state.sync = config.sync;
  60. LOG_TRACE(Audio_DSP, "source_id=%zu sync=%u", source_id, state.sync);
  61. }
  62. if (config.rate_multiplier_dirty) {
  63. config.rate_multiplier_dirty.Assign(0);
  64. state.rate_multiplier = config.rate_multiplier;
  65. LOG_TRACE(Audio_DSP, "source_id=%zu rate=%f", source_id, state.rate_multiplier);
  66. if (state.rate_multiplier <= 0) {
  67. LOG_ERROR(Audio_DSP, "Was given an invalid rate multiplier: source_id=%zu rate=%f", source_id, state.rate_multiplier);
  68. state.rate_multiplier = 1.0f;
  69. // Note: Actual firmware starts producing garbage if this occurs.
  70. }
  71. }
  72. if (config.adpcm_coefficients_dirty) {
  73. config.adpcm_coefficients_dirty.Assign(0);
  74. std::transform(adpcm_coeffs, adpcm_coeffs + state.adpcm_coeffs.size(), state.adpcm_coeffs.begin(),
  75. [](const auto& coeff) { return static_cast<s16>(coeff); });
  76. LOG_TRACE(Audio_DSP, "source_id=%zu adpcm update", source_id);
  77. }
  78. if (config.gain_0_dirty) {
  79. config.gain_0_dirty.Assign(0);
  80. std::transform(config.gain[0], config.gain[0] + state.gain[0].size(), state.gain[0].begin(),
  81. [](const auto& coeff) { return static_cast<float>(coeff); });
  82. LOG_TRACE(Audio_DSP, "source_id=%zu gain 0 update", source_id);
  83. }
  84. if (config.gain_1_dirty) {
  85. config.gain_1_dirty.Assign(0);
  86. std::transform(config.gain[1], config.gain[1] + state.gain[1].size(), state.gain[1].begin(),
  87. [](const auto& coeff) { return static_cast<float>(coeff); });
  88. LOG_TRACE(Audio_DSP, "source_id=%zu gain 1 update", source_id);
  89. }
  90. if (config.gain_2_dirty) {
  91. config.gain_2_dirty.Assign(0);
  92. std::transform(config.gain[2], config.gain[2] + state.gain[2].size(), state.gain[2].begin(),
  93. [](const auto& coeff) { return static_cast<float>(coeff); });
  94. LOG_TRACE(Audio_DSP, "source_id=%zu gain 2 update", source_id);
  95. }
  96. if (config.filters_enabled_dirty) {
  97. config.filters_enabled_dirty.Assign(0);
  98. state.filters.Enable(config.simple_filter_enabled.ToBool(), config.biquad_filter_enabled.ToBool());
  99. LOG_TRACE(Audio_DSP, "source_id=%zu enable_simple=%hu enable_biquad=%hu",
  100. source_id, config.simple_filter_enabled.Value(), config.biquad_filter_enabled.Value());
  101. }
  102. if (config.simple_filter_dirty) {
  103. config.simple_filter_dirty.Assign(0);
  104. state.filters.Configure(config.simple_filter);
  105. LOG_TRACE(Audio_DSP, "source_id=%zu simple filter update");
  106. }
  107. if (config.biquad_filter_dirty) {
  108. config.biquad_filter_dirty.Assign(0);
  109. state.filters.Configure(config.biquad_filter);
  110. LOG_TRACE(Audio_DSP, "source_id=%zu biquad filter update");
  111. }
  112. if (config.interpolation_dirty) {
  113. config.interpolation_dirty.Assign(0);
  114. state.interpolation_mode = config.interpolation_mode;
  115. LOG_TRACE(Audio_DSP, "source_id=%zu interpolation_mode=%zu", source_id, static_cast<size_t>(state.interpolation_mode));
  116. }
  117. if (config.format_dirty || config.embedded_buffer_dirty) {
  118. config.format_dirty.Assign(0);
  119. state.format = config.format;
  120. LOG_TRACE(Audio_DSP, "source_id=%zu format=%zu", source_id, static_cast<size_t>(state.format));
  121. }
  122. if (config.mono_or_stereo_dirty || config.embedded_buffer_dirty) {
  123. config.mono_or_stereo_dirty.Assign(0);
  124. state.mono_or_stereo = config.mono_or_stereo;
  125. LOG_TRACE(Audio_DSP, "source_id=%zu mono_or_stereo=%zu", source_id, static_cast<size_t>(state.mono_or_stereo));
  126. }
  127. if (config.embedded_buffer_dirty) {
  128. config.embedded_buffer_dirty.Assign(0);
  129. state.input_queue.emplace(Buffer{
  130. config.physical_address,
  131. config.length,
  132. static_cast<u8>(config.adpcm_ps),
  133. { config.adpcm_yn[0], config.adpcm_yn[1] },
  134. config.adpcm_dirty.ToBool(),
  135. config.is_looping.ToBool(),
  136. config.buffer_id,
  137. state.mono_or_stereo,
  138. state.format,
  139. false
  140. });
  141. LOG_TRACE(Audio_DSP, "enqueuing embedded addr=0x%08x len=%u id=%hu", config.physical_address, config.length, config.buffer_id);
  142. }
  143. if (config.buffer_queue_dirty) {
  144. config.buffer_queue_dirty.Assign(0);
  145. for (size_t i = 0; i < 4; i++) {
  146. if (config.buffers_dirty & (1 << i)) {
  147. const auto& b = config.buffers[i];
  148. state.input_queue.emplace(Buffer{
  149. b.physical_address,
  150. b.length,
  151. static_cast<u8>(b.adpcm_ps),
  152. { b.adpcm_yn[0], b.adpcm_yn[1] },
  153. b.adpcm_dirty != 0,
  154. b.is_looping != 0,
  155. b.buffer_id,
  156. state.mono_or_stereo,
  157. state.format,
  158. true
  159. });
  160. LOG_TRACE(Audio_DSP, "enqueuing queued %zu addr=0x%08x len=%u id=%hu", i, b.physical_address, b.length, b.buffer_id);
  161. }
  162. }
  163. config.buffers_dirty = 0;
  164. }
  165. if (config.dirty_raw) {
  166. LOG_DEBUG(Audio_DSP, "source_id=%zu remaining_dirty=%x", source_id, config.dirty_raw);
  167. }
  168. config.dirty_raw = 0;
  169. }
  170. void Source::GenerateFrame() {
  171. current_frame.fill({});
  172. if (state.current_buffer.empty() && !DequeueBuffer()) {
  173. state.enabled = false;
  174. state.buffer_update = true;
  175. state.current_buffer_id = 0;
  176. return;
  177. }
  178. size_t frame_position = 0;
  179. state.current_sample_number = state.next_sample_number;
  180. while (frame_position < current_frame.size()) {
  181. if (state.current_buffer.empty() && !DequeueBuffer()) {
  182. break;
  183. }
  184. const size_t size_to_copy = std::min(state.current_buffer.size(), current_frame.size() - frame_position);
  185. std::copy(state.current_buffer.begin(), state.current_buffer.begin() + size_to_copy, current_frame.begin() + frame_position);
  186. state.current_buffer.erase(state.current_buffer.begin(), state.current_buffer.begin() + size_to_copy);
  187. frame_position += size_to_copy;
  188. state.next_sample_number += static_cast<u32>(size_to_copy);
  189. }
  190. state.filters.ProcessFrame(current_frame);
  191. }
  192. bool Source::DequeueBuffer() {
  193. ASSERT_MSG(state.current_buffer.empty(), "Shouldn't dequeue; we still have data in current_buffer");
  194. if (state.input_queue.empty())
  195. return false;
  196. const Buffer buf = state.input_queue.top();
  197. state.input_queue.pop();
  198. if (buf.adpcm_dirty) {
  199. state.adpcm_state.yn1 = buf.adpcm_yn[0];
  200. state.adpcm_state.yn2 = buf.adpcm_yn[1];
  201. }
  202. if (buf.is_looping) {
  203. LOG_ERROR(Audio_DSP, "Looped buffers are unimplemented at the moment");
  204. }
  205. const u8* const memory = Memory::GetPhysicalPointer(buf.physical_address);
  206. if (memory) {
  207. const unsigned num_channels = buf.mono_or_stereo == MonoOrStereo::Stereo ? 2 : 1;
  208. switch (buf.format) {
  209. case Format::PCM8:
  210. state.current_buffer = Codec::DecodePCM8(num_channels, memory, buf.length);
  211. break;
  212. case Format::PCM16:
  213. state.current_buffer = Codec::DecodePCM16(num_channels, memory, buf.length);
  214. break;
  215. case Format::ADPCM:
  216. DEBUG_ASSERT(num_channels == 1);
  217. state.current_buffer = Codec::DecodeADPCM(memory, buf.length, state.adpcm_coeffs, state.adpcm_state);
  218. break;
  219. default:
  220. UNIMPLEMENTED();
  221. break;
  222. }
  223. } else {
  224. LOG_WARNING(Audio_DSP, "source_id=%zu buffer_id=%hu length=%u: Invalid physical address 0x%08X",
  225. source_id, buf.buffer_id, buf.length, buf.physical_address);
  226. state.current_buffer.clear();
  227. return true;
  228. }
  229. switch (state.interpolation_mode) {
  230. case InterpolationMode::None:
  231. state.current_buffer = AudioInterp::None(state.interp_state, state.current_buffer, state.rate_multiplier);
  232. break;
  233. case InterpolationMode::Linear:
  234. state.current_buffer = AudioInterp::Linear(state.interp_state, state.current_buffer, state.rate_multiplier);
  235. break;
  236. case InterpolationMode::Polyphase:
  237. // TODO(merry): Implement polyphase interpolation
  238. state.current_buffer = AudioInterp::Linear(state.interp_state, state.current_buffer, state.rate_multiplier);
  239. break;
  240. default:
  241. UNIMPLEMENTED();
  242. break;
  243. }
  244. state.current_sample_number = 0;
  245. state.next_sample_number = 0;
  246. state.current_buffer_id = buf.buffer_id;
  247. state.buffer_update = buf.from_queue;
  248. LOG_TRACE(Audio_DSP, "source_id=%zu buffer_id=%hu from_queue=%s current_buffer.size()=%zu",
  249. source_id, buf.buffer_id, buf.from_queue ? "true" : "false", state.current_buffer.size());
  250. return true;
  251. }
  252. SourceStatus::Status Source::GetCurrentStatus() {
  253. SourceStatus::Status ret;
  254. // Applications depend on the correct emulation of
  255. // current_buffer_id_dirty and current_buffer_id to synchronise
  256. // audio with video.
  257. ret.is_enabled = state.enabled;
  258. ret.current_buffer_id_dirty = state.buffer_update ? 1 : 0;
  259. state.buffer_update = false;
  260. ret.current_buffer_id = state.current_buffer_id;
  261. ret.buffer_position = state.current_sample_number;
  262. ret.sync = state.sync;
  263. return ret;
  264. }
  265. } // namespace HLE
  266. } // namespace DSP