From: Steinar H. Gunderson Date: Sat, 30 Jul 2016 23:26:59 +0000 (+0200) Subject: Store an input mapping, and show it in the UI. X-Git-Tag: 1.4.0~121 X-Git-Url: https://git.sesse.net/?p=nageru;a=commitdiff_plain;h=4bbcd111d04f36a42cf3d40f18fcee5a91c6322a Store an input mapping, and show it in the UI. Edits you do in the UI are not actually editable yet, and the mixer doesn't care about the mapping either. --- diff --git a/audio_mixer.cpp b/audio_mixer.cpp index 2544ad1..15c65de 100644 --- a/audio_mixer.cpp +++ b/audio_mixer.cpp @@ -59,6 +59,16 @@ AudioMixer::AudioMixer(unsigned num_cards) set_compressor_enabled(global_flags.compressor_enabled); set_limiter_enabled(global_flags.limiter_enabled); set_final_makeup_gain_auto(global_flags.final_makeup_gain_auto); + + // Generate a very simple, default input mapping. + InputMapping::Input input; + input.name = "Main"; + input.input_source_type = InputSourceType::CAPTURE_CARD; + input.input_source_index = 0; + input.source_channel[0] = 0; + input.source_channel[1] = 1; + + input_mapping.inputs.push_back(input); } void AudioMixer::reset_card(unsigned card_index) @@ -259,3 +269,33 @@ vector AudioMixer::get_output(double pts, unsigned num_samples, Resamplin return samples_out; } + +vector AudioMixer::get_names() const +{ + vector names; + for (unsigned card_index = 0; card_index < num_cards; ++card_index) { + const CaptureCard *card = &cards[card_index]; + unique_lock lock(card->audio_mutex); + names.push_back(card->name); + } + return names; +} + +void AudioMixer::set_name(unsigned card_index, const string &name) +{ + CaptureCard *card = &cards[card_index]; + unique_lock lock(card->audio_mutex); + card->name = name; +} + +void AudioMixer::set_input_mapping(const InputMapping &input_mapping) +{ + lock_guard lock(mapping_mutex); + this->input_mapping = input_mapping; +} + +InputMapping AudioMixer::get_input_mapping() const +{ + lock_guard lock(mapping_mutex); + return input_mapping; +} diff --git a/audio_mixer.h b/audio_mixer.h index 8e15f54..6f7dbe5 100644 --- a/audio_mixer.h +++ b/audio_mixer.h @@ -29,6 +29,19 @@ namespace bmusb { struct AudioFormat; } // namespace bmusb +enum class InputSourceType { SILENCE, CAPTURE_CARD }; + +struct InputMapping { + struct Input { + std::string name; + InputSourceType input_source_type; + unsigned input_source_index; + int source_channel[2] { -1, -1 }; // Left and right. -1 = none. + }; + + std::vector inputs; +}; + class AudioMixer { public: AudioMixer(unsigned num_cards); @@ -43,6 +56,11 @@ public: void set_current_loudness(double level_lufs) { loudness_lufs = level_lufs; } void set_fader_volume(unsigned card_index, float level_db) { cards[card_index].fader_volume_db = level_db; } + std::vector get_names() const; + void set_name(unsigned card_index, const std::string &name); + + void set_input_mapping(const InputMapping &input_mapping); + InputMapping get_input_mapping() const; void set_locut_cutoff(float cutoff_hz) { @@ -153,10 +171,13 @@ private: unsigned num_cards; struct CaptureCard { - std::mutex audio_mutex; - std::unique_ptr resampling_queue; // Under audio_mutex. - int64_t next_local_pts = 0; // Beginning of next frame, in TIMEBASE units. Under audio_mutex. std::atomic fader_volume_db{0.0f}; + + // Everything below audio_mutex is protected by it. + mutable std::mutex audio_mutex; + std::unique_ptr resampling_queue; + int64_t next_local_pts = 0; + std::string name; }; CaptureCard cards[MAX_CARDS]; @@ -184,6 +205,9 @@ private: double final_makeup_gain = 1.0; // Under compressor_mutex. Read/write by the user. Note: Not in dB, we want the numeric precision so that we can change it slowly. bool final_makeup_gain_auto = true; // Under compressor_mutex. + + mutable std::mutex mapping_mutex; + InputMapping input_mapping; // Under mapping_mutex. }; #endif // !defined(_AUDIO_MIXER_H) diff --git a/input_mapping_dialog.cpp b/input_mapping_dialog.cpp new file mode 100644 index 0000000..ea20fdc --- /dev/null +++ b/input_mapping_dialog.cpp @@ -0,0 +1,67 @@ +#include "input_mapping_dialog.h" + +#include "ui_input_mapping.h" + +#include + +using namespace std; + +InputMappingDialog::InputMappingDialog() + : ui(new Ui::InputMappingDialog) +{ + ui->setupUi(this); + + //connect(ui->button_box, &QDialogButtonBox::accepted, [this]{ this->close(); }); + vector card_names = global_mixer->get_audio_mixer()->get_names(); + fill_ui_from_mapping(global_mixer->get_audio_mixer()->get_input_mapping(), card_names); +} + +void InputMappingDialog::fill_ui_from_mapping(const InputMapping &mapping, const vector &card_names) +{ + ui->table->verticalHeader()->hide(); + + ui->table->setRowCount(mapping.inputs.size()); + for (unsigned row = 0; row < mapping.inputs.size(); ++row) { + // TODO: Mark as some sort of header (by means of background color, probably). + QString name(QString::fromStdString(mapping.inputs[row].name)); + ui->table->setItem(row, 0, new QTableWidgetItem(name)); + + // Card choices. + QComboBox *card_combo = new QComboBox; + card_combo->addItem(QString("(none)")); + for (const string &name : card_names) { + card_combo->addItem(QString::fromStdString(name)); + } + switch (mapping.inputs[row].input_source_type) { + case InputSourceType::SILENCE: + card_combo->setCurrentIndex(0); + break; + case InputSourceType::CAPTURE_CARD: + card_combo->setCurrentIndex(mapping.inputs[row].input_source_index + 1); + break; + default: + assert(false); + } + ui->table->setCellWidget(row, 1, card_combo); + + // Left and right channel. + fill_channel_ui_from_mapping(row, mapping.inputs[row]); + } +} + +void InputMappingDialog::fill_channel_ui_from_mapping(unsigned row, const InputMapping::Input &input) +{ + for (unsigned channel = 0; channel < 2; ++channel) { + QComboBox *channel_combo = new QComboBox; + channel_combo->addItem(QString("(none)")); + if (input.input_source_type == InputSourceType::CAPTURE_CARD) { + for (unsigned source = 0; source < 8; ++source) { // TODO: Ask the card about number of channels, and names. + char buf[256]; + snprintf(buf, sizeof(buf), "Channel %u", source + 1); + channel_combo->addItem(QString(buf)); + } + } + channel_combo->setCurrentIndex(input.source_channel[channel] + 1); + ui->table->setCellWidget(row, 2 + channel, channel_combo); + } +} diff --git a/input_mapping_dialog.h b/input_mapping_dialog.h index c7fea24..4eb5e4c 100644 --- a/input_mapping_dialog.h +++ b/input_mapping_dialog.h @@ -20,6 +20,9 @@ public: InputMappingDialog(); private: + void fill_ui_from_mapping(const InputMapping &mapping, const std::vector &card_names); + void fill_channel_ui_from_mapping(unsigned row, const InputMapping::Input &input); + Ui::InputMappingDialog *ui; }; diff --git a/mixer.cpp b/mixer.cpp index b684b3d..e8bbc02 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -281,11 +281,12 @@ void Mixer::configure_card(unsigned card_index, CaptureInterface *capture, bool if (card->surface == nullptr) { card->surface = create_surface_with_same_format(mixer_surface); } - audio_mixer.reset_card(card_index); while (!card->new_frames.empty()) card->new_frames.pop(); card->fractional_samples = 0; card->last_timecode = -1; card->capture->configure_card(); + audio_mixer.reset_card(card_index); + audio_mixer.set_name(card_index, card->capture->get_description()); } diff --git a/ui_input_mapping.ui b/ui_input_mapping.ui index 82a0d3d..f2c28ab 100644 --- a/ui_input_mapping.ui +++ b/ui_input_mapping.ui @@ -1,7 +1,7 @@ InputMappingDialog - + 0 @@ -15,7 +15,12 @@ - + + + + + + Device @@ -53,7 +58,8 @@ - + + .. @@ -105,7 +111,8 @@ - + + .. @@ -121,7 +128,8 @@ - + + ..