+void AudioMixer::apply_eq(unsigned bus_index, vector<float> *samples_bus)
+{
+ constexpr float bass_freq_hz = 200.0f;
+ constexpr float treble_freq_hz = 4700.0f;
+
+ // Cut away everything under 120 Hz (or whatever the cutoff is);
+ // we don't need it for voice, and it will reduce headroom
+ // and confuse the compressor. (In particular, any hums at 50 or 60 Hz
+ // should be dampened.)
+ if (locut_enabled[bus_index]) {
+ locut[bus_index].render(samples_bus->data(), samples_bus->size() / 2, locut_cutoff_hz * 2.0 * M_PI / OUTPUT_FREQUENCY, 0.5f);
+ }
+
+ // Apply the rest of the EQ. Since we only have a simple three-band EQ,
+ // we can implement it with two shelf filters. We use a simple gain to
+ // set the mid-level filter, and then offset the low and high bands
+ // from that if we need to. (We could perhaps have folded the gain into
+ // the next part, but it's so cheap that the trouble isn't worth it.)
+ if (fabs(eq_level_db[bus_index][EQ_BAND_MID]) > 0.01f) {
+ float g = from_db(eq_level_db[bus_index][EQ_BAND_MID]);
+ for (size_t i = 0; i < samples_bus->size(); ++i) {
+ (*samples_bus)[i] *= g;
+ }
+ }
+
+ float bass_adj_db = eq_level_db[bus_index][EQ_BAND_BASS] - eq_level_db[bus_index][EQ_BAND_MID];
+ if (fabs(bass_adj_db) > 0.01f) {
+ eq[bus_index][EQ_BAND_BASS].render(samples_bus->data(), samples_bus->size() / 2,
+ bass_freq_hz * 2.0 * M_PI / OUTPUT_FREQUENCY, 0.5f, bass_adj_db / 40.0f);
+ }
+
+ float treble_adj_db = eq_level_db[bus_index][EQ_BAND_TREBLE] - eq_level_db[bus_index][EQ_BAND_MID];
+ if (fabs(treble_adj_db) > 0.01f) {
+ eq[bus_index][EQ_BAND_TREBLE].render(samples_bus->data(), samples_bus->size() / 2,
+ treble_freq_hz * 2.0 * M_PI / OUTPUT_FREQUENCY, 0.5f, treble_adj_db / 40.0f);
+ }
+}
+
+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)