From c28a8bf4edc82a43c6eabbdd50335d15be4da5c8 Mon Sep 17 00:00:00 2001 From: SuslikV Date: Mon, 16 Mar 2020 14:41:49 +0200 Subject: [PATCH 1/4] Fix float to int16_t conversion Float values after mix or gain applied can exceed the (1.0; -1.0) range. This caused distortion in audio instead of limiting values at max. --- src/FFmpegWriter.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index e6a1d180..2b97ba91 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1525,11 +1525,23 @@ void FFmpegWriter::write_audio_packets(bool is_final) { // Calculate total samples total_frame_samples = samples_in_frame * channels_in_frame; - // Translate audio sample values back to 16 bit integers - for (int s = 0; s < total_frame_samples; s++, frame_position++) - // Translate sample value and copy into buffer - all_queued_samples[frame_position] = int(frame_samples_float[s] * (1 << 15)); + // Translate audio sample values back to 16 bit integers with saturation + float valF; + int16_t conv; + const int16_t max16 = 32767; + const int16_t min16 = -32768; + for (int s = 0; s < total_frame_samples; s++, frame_position++) { + valF = frame_samples_float[s] * (1 << 15); + if (valF > max16) + conv = max16; + else if (valF < min16) + conv = min16; + else + conv = int(valF + 32768.5) - 32768; // +0.5 is for rounding + // Copy into buffer + all_queued_samples[frame_position] = conv; + } // Deallocate float array delete[] frame_samples_float; From dff42011ff41cc1c2e1799e5e4601c45f743fe7e Mon Sep 17 00:00:00 2001 From: SuslikV Date: Mon, 16 Mar 2020 14:49:41 +0200 Subject: [PATCH 2/4] Restore default gain when adding audio Incorrect conversion of float to int16_t caused distortion that was mistakenly perceived as clipping. Now because the convertion was fixed, there is no more sense to reduce input gain of the source. --- src/FFmpegReader.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 2b03994b..080a652d 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -1627,9 +1627,8 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr else partial_frame = true; - // Add samples for current channel to the frame. Reduce the volume to 98%, to prevent - // some louder samples from maxing out at 1.0 (not sure why this happens) - f->AddAudio(true, channel_filter, start, iterate_channel_buffer, samples, 0.98f); + // Add samples for current channel to the frame. + f->AddAudio(true, channel_filter, start, iterate_channel_buffer, samples, 1.0f); // Debug output ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ProcessAudioPacket (f->AddAudio)", "frame", starting_frame_number, "start", start, "samples", samples, "channel", channel_filter, "partial_frame", partial_frame, "samples_per_frame", samples_per_frame); From 54a82ff0a68fb39bb875b63157cc91c549771647 Mon Sep 17 00:00:00 2001 From: SuslikV Date: Mon, 16 Mar 2020 16:22:41 +0200 Subject: [PATCH 3/4] Fix test sample values Previously, x0.98 gain was applied for all input audio sources. As it's no longer needed, the new values should be specified as reference for the tests. --- tests/FFmpegReader_Tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/FFmpegReader_Tests.cpp b/tests/FFmpegReader_Tests.cpp index 0a8620c9..a1f7a42d 100644 --- a/tests/FFmpegReader_Tests.cpp +++ b/tests/FFmpegReader_Tests.cpp @@ -76,8 +76,8 @@ TEST(FFmpegReader_Check_Audio_File) CHECK_CLOSE(0.0f, samples[50], 0.00001); CHECK_CLOSE(0.0f, samples[100], 0.00001); CHECK_CLOSE(0.0f, samples[200], 0.00001); - CHECK_CLOSE(0.160781f, samples[230], 0.00001); - CHECK_CLOSE(-0.06125f, samples[300], 0.00001); + CHECK_CLOSE(0.16406f, samples[230], 0.00001); + CHECK_CLOSE(-0.06250f, samples[300], 0.00001); // Close reader r.Close(); From 455b6e92bff6de715e3a8f3349f43cc54bf1a8ff Mon Sep 17 00:00:00 2001 From: SuslikV Date: Thu, 26 Mar 2020 10:17:22 +0200 Subject: [PATCH 4/4] Fix float to int16_t conversion in resampler The backward conversion int16_t to float in libopenshot has range (1.0; -1.0], thus conversion -1.0f to int16_t should be secured. Float values can exceed the (1.0; -1.0) range. This can cause distortion in audio instead of limiting values at max/min for the int16_t. --- src/FrameMapper.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index 7c4d04bb..4b213f81 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -785,10 +785,23 @@ void FrameMapper::ResampleMappedAudio(std::shared_ptr frame, int64_t orig // Create a new array (to hold all S16 audio samples for the current queued frames) int16_t* frame_samples = (int16_t*) av_malloc(sizeof(int16_t)*total_frame_samples); - // Translate audio sample values back to 16 bit integers - for (int s = 0; s < total_frame_samples; s++) - // Translate sample value and copy into buffer - frame_samples[s] = int(frame_samples_float[s] * (1 << 15)); + // Translate audio sample values back to 16 bit integers with saturation + float valF; + int16_t conv; + const int16_t max16 = 32767; + const int16_t min16 = -32768; + for (int s = 0; s < total_frame_samples; s++) { + valF = frame_samples_float[s] * (1 << 15); + if (valF > max16) + conv = max16; + else if (valF < min16) + conv = min16; + else + conv = int(valF + 32768.5) - 32768; // +0.5 is for rounding + + // Copy into buffer + frame_samples[s] = conv; + } // Deallocate float array