]> git.sesse.net Git - nageru/commitdiff
When the fader is moved, interpolate its volume over the next frame.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 28 Aug 2016 21:18:58 +0000 (23:18 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 19 Oct 2016 22:55:44 +0000 (00:55 +0200)
Faders are among the things one should definitely be allowed to move
around during an actual mix without hearing clicking; the gain and threshold
is maybe somewhat less so, so I won't give it the same treatment, at least not
right now.

audio_mixer.cpp
audio_mixer.h

index 7810b43ab8fb991d79387ec135ba4c701254dfe6..18a669f0eb8bcfe399b09cbf305d8718617b6203 100644 (file)
@@ -462,19 +462,9 @@ vector<float> AudioMixer::get_output(double pts, unsigned num_samples, Resamplin
                        }
                }
 
-               float volume = from_db(fader_volume_db[bus_index]);
-               if (bus_index == 0) {
-                       for (unsigned i = 0; i < num_samples * 2; ++i) {
-                               samples_out[i] = samples_bus[i] * volume;
-                       }
-               } else {
-                       for (unsigned i = 0; i < num_samples * 2; ++i) {
-                               samples_out[i] += samples_bus[i] * volume;
-                       }
-               }
-
+               add_bus_to_master(bus_index, samples_bus, &samples_out);
                deinterleave_samples(samples_bus, &left, &right);
-               measure_bus_levels(bus_index, left, right, volume);
+               measure_bus_levels(bus_index, left, right);
        }
 
        {
@@ -541,9 +531,56 @@ vector<float> AudioMixer::get_output(double pts, unsigned num_samples, Resamplin
        return samples_out;
 }
 
-void AudioMixer::measure_bus_levels(unsigned bus_index, const vector<float> &left, const vector<float> &right, float volume)
+void AudioMixer::add_bus_to_master(unsigned bus_index, const vector<float> &samples_bus, vector<float> *samples_out)
+{
+       assert(samples_bus.size() == samples_out->size());
+       assert(samples_bus.size() % 2 == 0);
+       unsigned num_samples = samples_bus.size() / 2;
+       if (fabs(fader_volume_db[bus_index] - last_fader_volume_db[bus_index]) > 1e-3) {
+               // The volume has changed; do a fade over the course of this frame.
+               // (We might have some numerical issues here, but it seems to sound OK.)
+               // For the purpose of fading here, the silence floor is set to -90 dB
+               // (the fader only goes to -84).
+               float old_volume = from_db(max<float>(last_fader_volume_db[bus_index], -90.0f));
+               float volume = from_db(max<float>(fader_volume_db[bus_index], -90.0f));
+
+               float volume_inc = pow(volume / old_volume, 1.0 / num_samples);
+               volume = old_volume;
+               if (bus_index == 0) {
+                       for (unsigned i = 0; i < num_samples; ++i) {
+                               (*samples_out)[i * 2 + 0] = samples_bus[i * 2 + 0] * volume;
+                               (*samples_out)[i * 2 + 1] = samples_bus[i * 2 + 1] * volume;
+                               volume *= volume_inc;
+                       }
+               } else {
+                       for (unsigned i = 0; i < num_samples; ++i) {
+                               (*samples_out)[i * 2 + 0] += samples_bus[i * 2 + 0] * volume;
+                               (*samples_out)[i * 2 + 1] += samples_bus[i * 2 + 1] * volume;
+                               volume *= volume_inc;
+                       }
+               }
+       } else {
+               float volume = from_db(fader_volume_db[bus_index]);
+               if (bus_index == 0) {
+                       for (unsigned i = 0; i < num_samples; ++i) {
+                               (*samples_out)[i * 2 + 0] = samples_bus[i * 2 + 0] * volume;
+                               (*samples_out)[i * 2 + 1] = samples_bus[i * 2 + 1] * volume;
+                       }
+               } else {
+                       for (unsigned i = 0; i < num_samples; ++i) {
+                               (*samples_out)[i * 2 + 0] += samples_bus[i * 2 + 0] * volume;
+                               (*samples_out)[i * 2 + 1] += samples_bus[i * 2 + 1] * volume;
+                       }
+               }
+       }
+
+       last_fader_volume_db[bus_index] = fader_volume_db[bus_index];
+}
+
+void AudioMixer::measure_bus_levels(unsigned bus_index, const vector<float> &left, const vector<float> &right)
 {
        assert(left.size() == right.size());
+       const float volume = from_db(fader_volume_db[bus_index]);
        const float peak_levels[2] = {
                find_peak(left.data(), left.size()) * volume,
                find_peak(right.data(), right.size()) * volume
index 5d65582c939fa191bcf8efad870d6e1c65b65c25..29016eb9ea7e07a68257bb8c02b6617edc4c4b6d 100644 (file)
@@ -238,7 +238,8 @@ private:
        void reset_alsa_mutex_held(DeviceSpec device_spec);
        std::map<DeviceSpec, DeviceInfo> get_devices_mutex_held() const;
        void update_meters(const std::vector<float> &samples);
-       void measure_bus_levels(unsigned bus_index, const std::vector<float> &left, const std::vector<float> &right, float volume);
+       void add_bus_to_master(unsigned bus_index, const std::vector<float> &samples_bus, std::vector<float> *samples_out);
+       void measure_bus_levels(unsigned bus_index, const std::vector<float> &left, const std::vector<float> &right);
        void send_audio_level_callback();
 
        unsigned num_cards;
@@ -286,6 +287,7 @@ private:
 
        InputMapping input_mapping;  // Under audio_mutex.
        std::atomic<float> fader_volume_db[MAX_BUSES] {{ 0.0f }};
+       float last_fader_volume_db[MAX_BUSES] { 0.0f };  // Under audio_mutex.
 
        audio_level_callback_t audio_level_callback = nullptr;
        mutable std::mutex audio_measure_mutex;