X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=audio_mixer.cpp;h=6b7ffeb0d6d28fb1ffdbfa8308ab341970893b20;hb=54067dbc70999d936adf9d263b5ff2b1efb4dfd0;hp=40470f3a18e70c5d43e158303f89e84960d6018e;hpb=4380d627aecf9f4dbe4dff524dacd4b550b07f14;p=nageru diff --git a/audio_mixer.cpp b/audio_mixer.cpp index 40470f3..6b7ffeb 100644 --- a/audio_mixer.cpp +++ b/audio_mixer.cpp @@ -6,6 +6,9 @@ #include #include #include +#ifdef __SSE__ +#include +#endif #include "db.h" #include "flags.h" @@ -77,7 +80,9 @@ void convert_fixed32_to_fp32(float *dst, size_t out_channel, size_t out_num_chan } } -float find_peak(const float *samples, size_t num_samples) +float find_peak_plain(const float *samples, size_t num_samples) __attribute__((unused)); + +float find_peak_plain(const float *samples, size_t num_samples) { float m = fabs(samples[0]); for (size_t i = 1; i < num_samples; ++i) { @@ -86,6 +91,54 @@ float find_peak(const float *samples, size_t num_samples) return m; } +#ifdef __SSE__ +static inline float horizontal_max(__m128 m) +{ + __m128 tmp = _mm_shuffle_ps(m, m, _MM_SHUFFLE(1, 0, 3, 2)); + m = _mm_max_ps(m, tmp); + tmp = _mm_shuffle_ps(m, m, _MM_SHUFFLE(2, 3, 0, 1)); + m = _mm_max_ps(m, tmp); + return _mm_cvtss_f32(m); +} + +float find_peak(const float *samples, size_t num_samples) +{ + const __m128 abs_mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffffu)); + __m128 m = _mm_setzero_ps(); + for (size_t i = 0; i < (num_samples & ~3); i += 4) { + __m128 x = _mm_loadu_ps(samples + i); + x = _mm_and_ps(x, abs_mask); + m = _mm_max_ps(m, x); + } + float result = horizontal_max(m); + + for (size_t i = (num_samples & ~3); i < num_samples; ++i) { + result = max(result, fabs(samples[i])); + } + +#if 0 + // Self-test. We should be bit-exact the same. + float reference_result = find_peak_plain(samples, num_samples); + if (result != reference_result) { + fprintf(stderr, "Error: Peak is %f [%f %f %f %f]; should be %f.\n", + result, + _mm_cvtss_f32(_mm_shuffle_ps(m, m, _MM_SHUFFLE(0, 0, 0, 0))), + _mm_cvtss_f32(_mm_shuffle_ps(m, m, _MM_SHUFFLE(1, 1, 1, 1))), + _mm_cvtss_f32(_mm_shuffle_ps(m, m, _MM_SHUFFLE(2, 2, 2, 2))), + _mm_cvtss_f32(_mm_shuffle_ps(m, m, _MM_SHUFFLE(3, 3, 3, 3))), + reference_result); + abort(); + } +#endif + return result; +} +#else +float find_peak(const float *samples, size_t num_samples) +{ + return find_peak_plain(samples, num_samples); +} +#endif + void deinterleave_samples(const vector &in, vector *out_l, vector *out_r) { size_t num_samples = in.size() / 2; @@ -211,8 +264,7 @@ bool AudioMixer::add_audio(DeviceSpec device_spec, const uint8_t *data, unsigned assert(num_channels > 0); // Convert the audio to fp32. - vector audio; - audio.resize(num_samples * num_channels); + unique_ptr audio(new float[num_samples * num_channels]); unsigned channel_index = 0; for (auto channel_it = device->interesting_channels.cbegin(); channel_it != device->interesting_channels.end(); ++channel_it, ++channel_index) { switch (audio_format.bits_per_sample) { @@ -220,13 +272,13 @@ bool AudioMixer::add_audio(DeviceSpec device_spec, const uint8_t *data, unsigned assert(num_samples == 0); break; case 16: - convert_fixed16_to_fp32(&audio[0], channel_index, num_channels, data, *channel_it, audio_format.num_channels, num_samples); + convert_fixed16_to_fp32(audio.get(), channel_index, num_channels, data, *channel_it, audio_format.num_channels, num_samples); break; case 24: - convert_fixed24_to_fp32(&audio[0], channel_index, num_channels, data, *channel_it, audio_format.num_channels, num_samples); + convert_fixed24_to_fp32(audio.get(), channel_index, num_channels, data, *channel_it, audio_format.num_channels, num_samples); break; case 32: - convert_fixed32_to_fp32(&audio[0], channel_index, num_channels, data, *channel_it, audio_format.num_channels, num_samples); + convert_fixed32_to_fp32(audio.get(), channel_index, num_channels, data, *channel_it, audio_format.num_channels, num_samples); break; default: fprintf(stderr, "Cannot handle audio with %u bits per sample\n", audio_format.bits_per_sample); @@ -236,7 +288,7 @@ bool AudioMixer::add_audio(DeviceSpec device_spec, const uint8_t *data, unsigned // Now add it. int64_t local_pts = device->next_local_pts; - device->resampling_queue->add_input_samples(local_pts / double(TIMEBASE), audio.data(), num_samples); + device->resampling_queue->add_input_samples(local_pts / double(TIMEBASE), audio.get(), num_samples); device->next_local_pts = local_pts + frame_length; return true; } @@ -410,10 +462,6 @@ vector AudioMixer::get_output(double pts, unsigned num_samples, Resamplin } } - // TODO: We should measure post-fader. - deinterleave_samples(samples_bus, &left, &right); - measure_bus_levels(bus_index, left, right); - float volume = from_db(fader_volume_db[bus_index]); if (bus_index == 0) { for (unsigned i = 0; i < num_samples * 2; ++i) { @@ -424,6 +472,9 @@ vector AudioMixer::get_output(double pts, unsigned num_samples, Resamplin samples_out[i] += samples_bus[i] * volume; } } + + deinterleave_samples(samples_bus, &left, &right); + measure_bus_levels(bus_index, left, right, volume); } { @@ -490,12 +541,36 @@ vector AudioMixer::get_output(double pts, unsigned num_samples, Resamplin return samples_out; } -void AudioMixer::measure_bus_levels(unsigned bus_index, const vector &left, const vector &right) +void AudioMixer::measure_bus_levels(unsigned bus_index, const vector &left, const vector &right, float volume) { - const float *ptrs[] = { left.data(), right.data() }; - { - lock_guard lock(audio_measure_mutex); - bus_r128[bus_index]->process(left.size(), const_cast(ptrs)); + assert(left.size() == right.size()); + const float peak_levels[2] = { + find_peak(left.data(), left.size()) * volume, + find_peak(right.data(), right.size()) * volume + }; + for (unsigned channel = 0; channel < 2; ++channel) { + // Compute the current value, including hold and falloff. + // The constants are borrowed from zita-mu1 by Fons Adriaensen. + static constexpr float hold_sec = 0.5f; + static constexpr float falloff_db_sec = 15.0f; // dB/sec falloff after hold. + float current_peak; + PeakHistory &history = peak_history[bus_index][channel]; + if (history.age_seconds < hold_sec) { + current_peak = history.last_peak; + } else { + current_peak = history.last_peak * from_db(-falloff_db_sec * (history.age_seconds - hold_sec)); + } + + // See if we have a new peak to replace the old (possibly falling) one. + if (peak_levels[channel] > current_peak) { + history.last_peak = peak_levels[channel]; + history.age_seconds = 0.0f; // Not 100% correct, but more than good enough given our frame sizes. + current_peak = peak_levels[channel]; + } else { + history.age_seconds += float(left.size()) / OUTPUT_FREQUENCY; + } + history.current_level = peak_levels[channel]; + history.current_peak = current_peak; } } @@ -557,9 +632,20 @@ void AudioMixer::send_audio_level_callback() vector bus_levels; bus_levels.resize(input_mapping.buses.size()); - for (unsigned bus_index = 0; bus_index < bus_r128.size(); ++bus_index) { - bus_levels[bus_index].loudness_lufs = bus_r128[bus_index]->loudness_S(); - bus_levels[bus_index].gain_staging_db = gain_staging_db[bus_index]; + { + lock_guard lock(compressor_mutex); + for (unsigned bus_index = 0; bus_index < bus_levels.size(); ++bus_index) { + bus_levels[bus_index].current_level_dbfs[0] = to_db(peak_history[bus_index][0].current_level); + bus_levels[bus_index].current_level_dbfs[1] = to_db(peak_history[bus_index][1].current_level); + bus_levels[bus_index].peak_level_dbfs[0] = to_db(peak_history[bus_index][0].current_peak); + bus_levels[bus_index].peak_level_dbfs[1] = to_db(peak_history[bus_index][1].current_peak); + bus_levels[bus_index].gain_staging_db = gain_staging_db[bus_index]; + if (compressor_enabled[bus_index]) { + bus_levels[bus_index].compressor_attenuation_db = -to_db(compressor[bus_index]->get_attenuation()); + } else { + bus_levels[bus_index].compressor_attenuation_db = 0.0; + } + } } audio_level_callback(loudness_s, to_db(peak), bus_levels, @@ -633,17 +719,6 @@ void AudioMixer::set_input_mapping(const InputMapping &new_input_mapping) } } - { - lock_guard lock(audio_measure_mutex); - bus_r128.resize(new_input_mapping.buses.size()); - for (unsigned bus_index = 0; bus_index < bus_r128.size(); ++bus_index) { - if (bus_r128[bus_index] == nullptr) { - bus_r128[bus_index].reset(new Ebu_r128_proc); - } - bus_r128[bus_index]->init(2, OUTPUT_FREQUENCY); - } - } - input_mapping = new_input_mapping; }