From d5c507ae2f61367df3bd4b538d119b6aa3794af9 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Fri, 8 Mar 2019 22:56:52 +0100 Subject: [PATCH] Allow controlling video mixing from MIDI events. Adapted from a patch by Yann Dubreuil, from the BreizhCamp repository. --- nageru/mainwindow.cpp | 86 +++++++++++++++++++++++--------- nageru/mainwindow.h | 9 ++++ nageru/midi_mapper.cpp | 12 +++++ nageru/midi_mapper.h | 8 +++ nageru/midi_mapping_dialog.cpp | 14 ++++++ nageru/midi_mapping_dialog.h | 7 +++ nageru/nageru_midi_mapping.proto | 20 ++++++++ 7 files changed, 133 insertions(+), 23 deletions(-) diff --git a/nageru/mainwindow.cpp b/nageru/mainwindow.cpp index d436040..96552a5 100644 --- a/nageru/mainwindow.cpp +++ b/nageru/mainwindow.cpp @@ -253,30 +253,16 @@ MainWindow::MainWindow() qRegisterMetaType("Mixer::Output"); // Hook up the prev/next buttons on the audio views. - auto prev_page = [this]{ - if (global_audio_mixer->get_mapping_mode() == AudioMixer::MappingMode::MULTICHANNEL) { - ui->audio_views->setCurrentIndex((ui->audio_views->currentIndex() + 2) % 3); - } else { - ui->audio_views->setCurrentIndex(2 - ui->audio_views->currentIndex()); // Switch between 0 and 2. - } - }; - auto next_page = [this]{ - if (global_audio_mixer->get_mapping_mode() == AudioMixer::MappingMode::MULTICHANNEL) { - ui->audio_views->setCurrentIndex((ui->audio_views->currentIndex() + 1) % 3); - } else { - ui->audio_views->setCurrentIndex(2 - ui->audio_views->currentIndex()); // Switch between 0 and 2. - } - }; - connect(ui->compact_prev_page, &QAbstractButton::clicked, prev_page); - connect(ui->compact_next_page, &QAbstractButton::clicked, next_page); - connect(ui->full_prev_page, &QAbstractButton::clicked, prev_page); - connect(ui->full_next_page, &QAbstractButton::clicked, next_page); - connect(ui->video_grid_prev_page, &QAbstractButton::clicked, prev_page); - connect(ui->video_grid_next_page, &QAbstractButton::clicked, next_page); + connect(ui->compact_prev_page, &QAbstractButton::clicked, this, &MainWindow::prev_page); + connect(ui->compact_next_page, &QAbstractButton::clicked, this, &MainWindow::next_page); + connect(ui->full_prev_page, &QAbstractButton::clicked, this, &MainWindow::prev_page); + connect(ui->full_next_page, &QAbstractButton::clicked, this, &MainWindow::next_page); + connect(ui->video_grid_prev_page, &QAbstractButton::clicked, this, &MainWindow::prev_page); + connect(ui->video_grid_next_page, &QAbstractButton::clicked, this, &MainWindow::next_page); // And bind the same to PgUp/PgDown. - connect(new QShortcut(QKeySequence::MoveToNextPage, this), &QShortcut::activated, next_page); - connect(new QShortcut(QKeySequence::MoveToPreviousPage, this), &QShortcut::activated, prev_page); + connect(new QShortcut(QKeySequence::MoveToNextPage, this), &QShortcut::activated, this, &MainWindow::next_page); + connect(new QShortcut(QKeySequence::MoveToPreviousPage, this), &QShortcut::activated, this, &MainWindow::prev_page); // When the audio view changes, move the previews. connect(ui->audio_views, &QStackedWidget::currentChanged, bind(&MainWindow::audio_view_changed, this, _1)); @@ -295,7 +281,7 @@ MainWindow::MainWindow() if (!load_midi_mapping_from_file(global_flags.midi_mapping_filename, &midi_mapping)) { fprintf(stderr, "Couldn't load MIDI mapping '%s'; exiting.\n", global_flags.midi_mapping_filename.c_str()); - exit(1); + ::exit(1); } midi_mapper.set_midi_mapping(midi_mapping); } @@ -306,6 +292,24 @@ MainWindow::MainWindow() } } +void MainWindow::prev_page() +{ + if (global_audio_mixer->get_mapping_mode() == AudioMixer::MappingMode::MULTICHANNEL) { + ui->audio_views->setCurrentIndex((ui->audio_views->currentIndex() + 2) % 3); + } else { + ui->audio_views->setCurrentIndex(2 - ui->audio_views->currentIndex()); // Switch between 0 and 2. + } +} + +void MainWindow::next_page() +{ + if (global_audio_mixer->get_mapping_mode() == AudioMixer::MappingMode::MULTICHANNEL) { + ui->audio_views->setCurrentIndex((ui->audio_views->currentIndex() + 1) % 3); + } else { + ui->audio_views->setCurrentIndex(2 - ui->audio_views->currentIndex()); // Switch between 0 and 2. + } +} + void MainWindow::resizeEvent(QResizeEvent* event) { QMainWindow::resizeEvent(event); @@ -1244,6 +1248,42 @@ void MainWindow::toggle_auto_makeup_gain() } } +void MainWindow::switch_video_channel(int channel_number) +{ + global_mixer->channel_clicked(channel_number); +} + +void MainWindow::apply_transition(int transition_number) +{ + global_mixer->transition_clicked(transition_number); +} + +void MainWindow::prev_audio_view() +{ + post_to_main_thread([this]{ + prev_page(); + }); +} + +void MainWindow::next_audio_view() +{ + post_to_main_thread([this]{ + next_page(); + }); +} + +void MainWindow::begin_new_segment() +{ + global_mixer->schedule_cut(); +} + +void MainWindow::exit() +{ + post_to_main_thread([this]{ + close(); + }); +} + void MainWindow::highlight_locut(bool highlight) { post_to_main_thread([this, highlight]{ diff --git a/nageru/mainwindow.h b/nageru/mainwindow.h index 36be4b8..37b1ce0 100644 --- a/nageru/mainwindow.h +++ b/nageru/mainwindow.h @@ -96,6 +96,13 @@ public slots: void toggle_limiter() override; void toggle_auto_makeup_gain() override; + void switch_video_channel(int channel_number) override; + void apply_transition(int transition_number) override; + void prev_audio_view() override; + void next_audio_view() override; + void begin_new_segment() override; + void exit() override; + void clear_all_highlights() override; void highlight_locut(bool highlight) override; @@ -133,6 +140,8 @@ private: void update_stereo_label(unsigned bus_index, int stereo_width_percent); void update_eq_label(unsigned bus_index, EQBand band, float gain_db); void setup_theme_menu(); + void prev_page(); + void next_page(); // Called from DiskSpaceEstimator. void report_disk_space(off_t free_bytes, double estimated_seconds_left); diff --git a/nageru/midi_mapper.cpp b/nageru/midi_mapper.cpp index d0a42ec..1dccd8e 100644 --- a/nageru/midi_mapper.cpp +++ b/nageru/midi_mapper.cpp @@ -179,6 +179,18 @@ void MIDIMapper::note_on_received(int note) bind(&ControllerReceiver::toggle_limiter, receiver)); match_button(note, MIDIMappingBusProto::kToggleAutoMakeupGainFieldNumber, MIDIMappingProto::kToggleAutoMakeupGainBankFieldNumber, bind(&ControllerReceiver::toggle_auto_makeup_gain, receiver)); + match_button(note, MIDIMappingBusProto::kSwitchVideoChannelFieldNumber, MIDIMappingProto::kSwitchVideoChannelBankFieldNumber, + bind(&ControllerReceiver::switch_video_channel, receiver, _1)); + match_button(note, MIDIMappingBusProto::kApplyTransitionFieldNumber, MIDIMappingProto::kApplyTransitionBankFieldNumber, + bind(&ControllerReceiver::apply_transition, receiver, _1)); + match_button(note, MIDIMappingBusProto::kPrevAudioViewFieldNumber, MIDIMappingProto::kPrevAudioViewBankFieldNumber, + bind(&ControllerReceiver::prev_audio_view, receiver)); + match_button(note, MIDIMappingBusProto::kNextAudioViewFieldNumber, MIDIMappingProto::kNextAudioViewBankFieldNumber, + bind(&ControllerReceiver::prev_audio_view, receiver)); + match_button(note, MIDIMappingBusProto::kBeginNewVideoSegmentFieldNumber, MIDIMappingProto::kBeginNewVideoSegmentBankFieldNumber, + bind(&ControllerReceiver::begin_new_segment, receiver)); + match_button(note, MIDIMappingBusProto::kExitFieldNumber, MIDIMappingProto::kExitBankFieldNumber, + bind(&ControllerReceiver::exit, receiver)); } void MIDIMapper::update_num_subscribers(unsigned num_subscribers) diff --git a/nageru/midi_mapper.h b/nageru/midi_mapper.h index dd5c7ab..72272a1 100644 --- a/nageru/midi_mapper.h +++ b/nageru/midi_mapper.h @@ -47,6 +47,14 @@ public: virtual void toggle_limiter() = 0; virtual void toggle_auto_makeup_gain() = 0; + // Non-audio events. + virtual void switch_video_channel(int channel_number) = 0; + virtual void apply_transition(int transition_number) = 0; + virtual void prev_audio_view() = 0; + virtual void next_audio_view() = 0; + virtual void begin_new_segment() = 0; + virtual void exit() = 0; + // Signals to highlight controls to mark them to the user // as MIDI-controllable (or not). virtual void clear_all_highlights() = 0; diff --git a/nageru/midi_mapping_dialog.cpp b/nageru/midi_mapping_dialog.cpp index d27a0c2..8352729 100644 --- a/nageru/midi_mapping_dialog.cpp +++ b/nageru/midi_mapping_dialog.cpp @@ -88,6 +88,18 @@ vector global_lights = { { "Auto makeup gain is on", MIDIMappingBusProto::kAutoMakeupGainIsOnFieldNumber, 0 }, }; +vector global_video = { + { "Switch video channel", MIDIMappingBusProto::kSwitchVideoChannelFieldNumber, MIDIMappingProto::kSwitchVideoChannelBankFieldNumber }, + { "Apply transition", MIDIMappingBusProto::kApplyTransitionFieldNumber, MIDIMappingProto::kApplyTransitionBankFieldNumber }, +}; + +vector main_ui = { + { "Previous audio view", MIDIMappingBusProto::kPrevAudioViewFieldNumber, MIDIMappingProto::kPrevAudioViewBankFieldNumber }, + { "Next audio view", MIDIMappingBusProto::kNextAudioViewFieldNumber, MIDIMappingProto::kNextAudioViewBankFieldNumber }, + { "Begin new video segment", MIDIMappingBusProto::kBeginNewVideoSegmentFieldNumber, MIDIMappingProto::kBeginNewVideoSegmentBankFieldNumber }, + { "Exit Nageru", MIDIMappingBusProto::kExitFieldNumber, MIDIMappingProto::kExitBankFieldNumber }, +}; + namespace { int get_bank(const MIDIMappingProto &mapping_proto, int bank_field_number, int default_value) @@ -162,8 +174,10 @@ MIDIMappingDialog::MIDIMappingDialog(MIDIMapper *mapper) add_controls("Per-bus controllers", ControlType::CONTROLLER, SpinnerGroup::PER_BUS_CONTROLLERS, mapping_proto, per_bus_controllers); add_controls("Per-bus buttons", ControlType::BUTTON, SpinnerGroup::PER_BUS_BUTTONS, mapping_proto, per_bus_buttons); add_controls("Per-bus lights", ControlType::LIGHT, SpinnerGroup::PER_BUS_LIGHTS, mapping_proto, per_bus_lights); + add_controls("Video mixing", ControlType::BUTTON, SpinnerGroup::GLOBAL_BUTTONS, mapping_proto, global_video); add_controls("Global controllers", ControlType::CONTROLLER, SpinnerGroup::GLOBAL_CONTROLLERS, mapping_proto, global_controllers); add_controls("Global buttons", ControlType::BUTTON, SpinnerGroup::GLOBAL_BUTTONS, mapping_proto, global_buttons); + add_controls("Main UI", ControlType::BUTTON, SpinnerGroup::GLOBAL_BUTTONS, mapping_proto, main_ui); add_controls("Global lights", ControlType::LIGHT, SpinnerGroup::GLOBAL_LIGHTS, mapping_proto, global_lights); fill_controls_from_mapping(mapping_proto); diff --git a/nageru/midi_mapping_dialog.h b/nageru/midi_mapping_dialog.h index c36781d..89374fe 100644 --- a/nageru/midi_mapping_dialog.h +++ b/nageru/midi_mapping_dialog.h @@ -85,6 +85,13 @@ public: void highlight_toggle_limiter(bool highlight) override {} void highlight_toggle_auto_makeup_gain(bool highlight) override {} + void switch_video_channel(int channel_number) override {} + void apply_transition(int transition_number) override {} + void prev_audio_view() override {} + void next_audio_view() override {} + void begin_new_segment() override {} + void exit() override {} + // Raw events; used for the editor dialog only. void controller_changed(unsigned controller) override; void note_on(unsigned note) override; diff --git a/nageru/nageru_midi_mapping.proto b/nageru/nageru_midi_mapping.proto index 6eb8001..a5fbcf9 100644 --- a/nageru/nageru_midi_mapping.proto +++ b/nageru/nageru_midi_mapping.proto @@ -40,6 +40,16 @@ message MIDIMappingBusProto { optional MIDIButtonProto toggle_limiter = 20; optional MIDIButtonProto toggle_auto_makeup_gain = 21; + // Video mixing. + optional MIDIButtonProto switch_video_channel = 38; + optional MIDIButtonProto apply_transition = 39; + + // Main UI. Really global, but see the comment on lo-cut etc. above. + optional MIDIButtonProto prev_audio_view = 40; + optional MIDIButtonProto next_audio_view = 41; + optional MIDIButtonProto begin_new_video_segment = 42; + optional MIDIButtonProto exit = 43; + // These are also global (they belong to the master bus), and unlike // the bank change commands, one would usually have only one of each, // but there's no reason to limit them to one each, and the editor UI @@ -94,6 +104,10 @@ message MIDIMappingProto { optional int32 toggle_compressor_bank = 11; optional int32 clear_peak_bank = 12; + // Bus (not non-audio) buttons. + optional int32 switch_video_channel_bank = 24; + optional int32 apply_transition_bank = 25; + // Global controller banks. optional int32 locut_bank = 13; optional int32 limiter_threshold_bank = 14; @@ -103,5 +117,11 @@ message MIDIMappingProto { optional int32 toggle_limiter_bank = 16; optional int32 toggle_auto_makeup_gain_bank = 17; + // Global non-audio buttons. + optional int32 prev_audio_view_bank = 20; + optional int32 next_audio_view_bank = 21; + optional int32 begin_new_video_segment_bank = 22; + optional int32 exit_bank = 23; + repeated MIDIMappingBusProto bus_mapping = 18; } -- 2.39.2