From aca6e291d64fcbd253ea9c34756db6f8c6915c72 Mon Sep 17 00:00:00 2001 From: Saracen Date: Fri, 27 Jul 2018 03:47:22 +0100 Subject: [PATCH] Fixed audio clipping on WASAPI by fixing argument order on AudioClient Initialize method ensuring a larger capture buffer and adding bounds to the capture and stream. --- drivers/wasapi/audio_driver_wasapi.cpp | 14 +++++++---- servers/audio/audio_stream.cpp | 32 ++++++++++++++++++-------- servers/audio_server.h | 2 ++ 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index 7ae87f04a87..f4d0d3c1dc5 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -65,6 +65,8 @@ const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient); #define REFTIMES_PER_SEC 10000000 #define REFTIMES_PER_MILLISEC 10000 +#define CAPTURE_BUFFER_CHANNELS 2 + static StringName capture_device_id; static bool default_render_device_changed = false; static bool default_capture_device_changed = false; @@ -271,7 +273,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nChannels * (pwfex->wBitsPerSample / 8); } - hr = p_device->audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, streamflags, 0, p_capture ? REFTIMES_PER_SEC : 0, pwfex, NULL); + hr = p_device->audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, streamflags, p_capture ? REFTIMES_PER_SEC : 0, 0, pwfex, NULL); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); if (p_capture) { @@ -338,11 +340,12 @@ Error AudioDriverWASAPI::init_capture_device(bool reinit) { ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); // Set the buffer size - audio_input_buffer.resize(max_frames * 8); + audio_input_buffer.resize(max_frames * CAPTURE_BUFFER_CHANNELS); for (int i = 0; i < audio_input_buffer.size(); i++) { audio_input_buffer.write[i] = 0; } audio_input_position = 0; + audio_input_size = 0; return OK; } @@ -676,7 +679,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { // fixme: Only works for floating point atm for (int j = 0; j < num_frames_available; j++) { - int32_t sample_channel[2]; + int32_t sample_channel[CAPTURE_BUFFER_CHANNELS]; if (flags & AUDCLNT_BUFFERFLAGS_SILENT) { sample_channel[0] = sample_channel[1] = 0; @@ -692,11 +695,14 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { } } - for (int k = 0; k < 2; k++) { + for (int k = 0; k < CAPTURE_BUFFER_CHANNELS; k++) { ad->audio_input_buffer.write[ad->audio_input_position++] = sample_channel[k]; if (ad->audio_input_position >= ad->audio_input_buffer.size()) { ad->audio_input_position = 0; } + if (ad->audio_input_size < ad->audio_input_buffer.size()) { + ad->audio_input_size++; + } } } diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 0c8a1810d27..f7622b8a4ec 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -135,19 +135,31 @@ void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fr AudioDriver::get_singleton()->lock(); Vector buf = AudioDriver::get_singleton()->get_audio_input_buffer(); + unsigned int audio_input_size = AudioDriver::get_singleton()->get_audio_input_size(); - for (int i = 0; i < p_frames; i++) { - - float l = (buf[input_ofs++] >> 16) / 32768.f; - if (input_ofs >= buf.size()) { - input_ofs = 0; - } - float r = (buf[input_ofs++] >> 16) / 32768.f; - if (input_ofs >= buf.size()) { - input_ofs = 0; + // p_frames is multipled by two since an AudioFrame is stereo + if ((p_frames * 2) > audio_input_size) { + for (int i = 0; i < p_frames; i++) { + p_buffer[i] = AudioFrame(0.0f, 0.0f); } + input_ofs = 0; + } else { + for (int i = 0; i < p_frames; i++) { + if (audio_input_size >= input_ofs) { + float l = (buf[input_ofs++] >> 16) / 32768.f; + if (input_ofs >= buf.size()) { + input_ofs = 0; + } + float r = (buf[input_ofs++] >> 16) / 32768.f; + if (input_ofs >= buf.size()) { + input_ofs = 0; + } - p_buffer[i] = AudioFrame(l, r); + p_buffer[i] = AudioFrame(l, r); + } else { + p_buffer[i] = AudioFrame(0.0f, 0.0f); + } + } } AudioDriver::get_singleton()->unlock(); diff --git a/servers/audio_server.h b/servers/audio_server.h index c199a337eb8..a9ed66a2d59 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -55,6 +55,7 @@ class AudioDriver { protected: Vector audio_input_buffer; unsigned int audio_input_position; + unsigned int audio_input_size; void audio_server_process(int p_frames, int32_t *p_buffer, bool p_update_mix_time = true); void update_mix_time(int p_frames); @@ -109,6 +110,7 @@ public: Vector get_audio_input_buffer() { return audio_input_buffer; } unsigned int get_audio_input_position() { return audio_input_position; } + unsigned int get_audio_input_size() { return audio_input_size; } #ifdef DEBUG_ENABLED uint64_t get_profiling_time() const { return prof_time; }