// Copyright 2017 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include #include "audio_core/dsp_interface.h" #include "audio_core/sink.h" #include "audio_core/sink_details.h" #include "common/assert.h" #include "core/settings.h" namespace AudioCore { DspInterface::DspInterface() = default; DspInterface::~DspInterface() = default; void DspInterface::SetSink(const std::string& sink_id, const std::string& audio_device) { sink.reset(); const SinkDetails& sink_details = GetSinkDetails(sink_id); sink = sink_details.factory(audio_device); sink->SetCallback( [this](s16* buffer, std::size_t num_frames) { OutputCallback(buffer, num_frames); }); time_stretcher.SetOutputSampleRate(sink->GetNativeSampleRate()); } Sink& DspInterface::GetSink() { ASSERT(sink); return *sink.get(); } void DspInterface::EnableStretching(bool enable) { if (perform_time_stretching == enable) return; if (!enable) { flushing_time_stretcher = true; } perform_time_stretching = enable; } void DspInterface::OutputFrame(StereoFrame16& frame) { if (!sink) return; // Implementation of the hardware volume slider with a dynamic range of 60 dB double volume_scale_factor = std::exp(6.90775 * Settings::values.volume) * 0.001; for (std::size_t i = 0; i < frame.size(); i++) { frame[i][0] = static_cast(frame[i][0] * volume_scale_factor); frame[i][1] = static_cast(frame[i][1] * volume_scale_factor); } fifo.Push(frame.data(), frame.size()); } void DspInterface::OutputCallback(s16* buffer, std::size_t num_frames) { std::size_t frames_written; if (perform_time_stretching) { const std::vector in{fifo.Pop()}; const std::size_t num_in{in.size() / 2}; frames_written = time_stretcher.Process(in.data(), num_in, buffer, num_frames); } else if (flushing_time_stretcher) { time_stretcher.Flush(); frames_written = time_stretcher.Process(nullptr, 0, buffer, num_frames); frames_written += fifo.Pop(buffer, num_frames - frames_written); flushing_time_stretcher = false; } else { frames_written = fifo.Pop(buffer, num_frames); } if (frames_written > 0) { std::memcpy(&last_frame[0], buffer + 2 * (frames_written - 1), 2 * sizeof(s16)); } // Hold last emitted frame; this prevents popping. for (std::size_t i = frames_written; i < num_frames; i++) { std::memcpy(buffer + 2 * i, &last_frame[0], 2 * sizeof(s16)); } } } // namespace AudioCore