|
|
|
|
@ -95,7 +95,8 @@ void SoundManager::openOutput() {
|
|
|
|
|
uint64_t route = m_output.route(); |
|
|
|
|
if (previousRoute && route != previousRoute) for (auto* voice : m_voices) if (voice) voice->resetPlayback(); |
|
|
|
|
previousRoute = route; |
|
|
|
|
m_renderErrors.fetch_add(renderOutput(m_engine, m_voices, static_cast<float*>(out), frames, m_output.callbackTimeUs())); |
|
|
|
|
m_renderErrors.fetch_add(renderOutput(m_engine, m_voices, static_cast<float*>(out), frames, |
|
|
|
|
m_output.callbackTimeUs(), m_output.timingMeasured())); |
|
|
|
|
}; |
|
|
|
|
if (m_output.init(m_context, config, "sound-engine", 0, callback) && m_output.start()) { |
|
|
|
|
m_actualOutput = resolveOutput(m_playbackId); return; |
|
|
|
|
@ -154,7 +155,7 @@ void SoundManager::recoverAudio() {
|
|
|
|
|
|
|
|
|
|
/* Последнее смешивание и ограничение: тот же PCM передаётся устройству и всем AEC этого выхода. */ |
|
|
|
|
unsigned SoundManager::renderOutput(ma_engine* engine, const std::array<VoiceAudioIo*, 2>& voices, |
|
|
|
|
float* out, unsigned frames, int64_t firstTimeUs) { |
|
|
|
|
float* out, unsigned frames, int64_t firstTimeUs, bool measured) { |
|
|
|
|
unsigned errors = 0; |
|
|
|
|
for (unsigned offset = 0; offset < frames;) { |
|
|
|
|
unsigned count = std::min(frames - offset, 960u); |
|
|
|
|
@ -163,7 +164,7 @@ unsigned SoundManager::renderOutput(ma_engine* engine, const std::array<VoiceAud
|
|
|
|
|
if (engine && ma_engine_read_pcm_frames(engine, destination, count, nullptr) != MA_SUCCESS) { |
|
|
|
|
++errors; std::fill_n(destination, count * 2, 0.0f); |
|
|
|
|
} |
|
|
|
|
for (auto* voice : voices) if (voice) voice->mix(destination, count, firstTimeUs + (int64_t)offset * 1000000 / 48000); |
|
|
|
|
for (auto* voice : voices) if (voice) voice->mix(destination, count, firstTimeUs + (int64_t)offset * 1000000 / 48000, measured); |
|
|
|
|
for (unsigned i = 0; i < count * 2; ++i) { |
|
|
|
|
float value = destination[i]; |
|
|
|
|
destination[i] = std::isfinite(value) ? std::clamp(value, -1.0f, 1.0f) : 0.0f; |
|
|
|
|
@ -199,7 +200,7 @@ bool SoundManager::openVoiceRoute(VoiceRoute& route) {
|
|
|
|
|
if (physical && physical == m_output.route()) { |
|
|
|
|
std::fill_n(static_cast<float*>(out), frames * 2, 0.0f); return; // GUI объединит совпавшие маршруты.
|
|
|
|
|
} |
|
|
|
|
renderOutput(nullptr, route.voices, static_cast<float*>(out), frames, route.device.callbackTimeUs()); |
|
|
|
|
renderOutput(nullptr, route.voices, static_cast<float*>(out), frames, route.device.callbackTimeUs(), route.device.timingMeasured()); |
|
|
|
|
}; |
|
|
|
|
if (route.device.init(m_context, config, "voice-output", 0, callback) && route.device.start()) { |
|
|
|
|
route.actual = resolveOutput(route.wanted); return true; |
|
|
|
|
|