]> git.sesse.net Git - nageru/commitdiff
Add some controls for locking the master speed to 100%.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 16 Jan 2019 21:46:47 +0000 (22:46 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 16 Jan 2019 21:46:47 +0000 (22:46 +0100)
futatabi/behringer_cmd_pl1.midimapping
futatabi/futatabi_midi_mapping.proto
futatabi/lock.svg [new file with mode: 0644]
futatabi/mainwindow.cpp
futatabi/mainwindow.h
futatabi/mainwindow.qrc [new file with mode: 0644]
futatabi/mainwindow.ui
futatabi/midi_mapper.cpp
futatabi/midi_mapper.h
meson.build

index 9b6e439ec4b5f005502206f498345a41d71b7599..c2ff473cfb235ef45fcf2a6f754bb5c0021cdf4c 100644 (file)
@@ -39,3 +39,7 @@ preview_enabled: { note_number: 27 }
 
 # The slider (pitch bend) is mapped to master speed.
 master_speed: { controller_number: 128 }
+
+# Master speed lock is mapped to lock.
+toggle_lock: { note_number: 25 }
+locked: { note_number: 25 }
index c1415cd1ca429e96fb0f4aa18470dd4db635c6d9..0487b968d8b9634985171617018f6430935abca0 100644 (file)
@@ -45,6 +45,10 @@ message MIDIMappingProto {
        optional int32 play_bank = 25;
        optional MIDILightProto play_enabled = 26;
 
+       optional MIDIButtonProto toggle_lock = 36;
+       optional int32 toggle_lock_bank = 37;
+       optional MIDILightProto locked = 38;
+
        optional MIDIButtonProto cue_in = 27;
        optional int32 cue_in_bank = 28;
        optional MIDILightProto cue_in_enabled = 29;  // In practice always true currently.
diff --git a/futatabi/lock.svg b/futatabi/lock.svg
new file mode 100644 (file)
index 0000000..c6d82e8
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright 2019 Yngve Molnes, licensed under GPLv3 -->
+<svg width="18px" height="24px" viewBox="0 0 18 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>lock</title>
+    <defs>https://www.gnu.org/licenses/gpl-3.0.txt</defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="Artboard" transform="translate(-470.000000, -322.000000)" stroke="#979797">
+            <g id="lock" transform="translate(470.000000, 323.000000)">
+                <rect id="Rectangle-2" stroke-width="2" fill="#D8D8D8" x="1" y="8" width="16" height="14" rx="2"></rect>
+                <path d="M3,7.85714286 C3.01575393,5.22004386 3.5871825,3.25575815 4.71428571,1.96428571 C5.85714286,0.654761905 7.28571429,3.72189052e-14 9,0 C10.7142857,2.06266882e-14 12.1428571,0.654761905 13.2857143,1.96428571 C14.4285714,3.27380952 15,5.23809524 15,7.85714286" id="Path-2" stroke-width="2"></path>
+                <g id="Group" transform="translate(7.000000, 12.000000)" fill="#979797">
+                    <circle id="Oval" cx="2" cy="2" r="2"></circle>
+                    <path d="M1.10442487,2.5 L0.571091532,6.5 L3.42890847,6.5 L2.89557513,2.5 L1.10442487,2.5 Z" id="Rectangle-3"></path>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>
index c69f67a17ad0cc43ab209b0b7c07ad4f8d2360c5..77b1cfe448f9f4406b39c7c54c33203e1d24e677 100644 (file)
@@ -182,6 +182,7 @@ MainWindow::MainWindow()
        ui->stop_btn->setEnabled(false);
 
        connect(ui->speed_slider, &QAbstractSlider::valueChanged, this, &MainWindow::speed_slider_changed);
+       connect(ui->speed_lock_btn, &QPushButton::clicked, this, &MainWindow::speed_lock_clicked);
 
        connect(ui->playlist_duplicate_btn, &QPushButton::clicked, this, &MainWindow::playlist_duplicate);
 
@@ -629,10 +630,18 @@ void MainWindow::stop_clicked()
 void MainWindow::speed_slider_changed(int percent)
 {
        float speed = percent / 100.0f;
-       ui->speed_label->setText(QString::fromStdString(to_string(percent) + "%"));
+       ui->speed_lock_btn->setText(QString::fromStdString(" " + to_string(percent) + "%"));
        live_player->set_master_speed(speed);
 }
 
+void MainWindow::speed_lock_clicked()
+{
+       // TODO: Make for a less abrupt transition if we're not already at 100%.
+       ui->speed_slider->setValue(100);  // Also actually sets the master speed and updates the label.
+       ui->speed_slider->setEnabled(!ui->speed_lock_btn->isChecked());
+       midi_mapper.set_locked(ui->speed_lock_btn->isChecked());
+}
+
 void MainWindow::live_player_done()
 {
        playlist_selection_changed();
@@ -1200,6 +1209,14 @@ void MainWindow::play()
        });
 }
 
+void MainWindow::toggle_lock()
+{
+       post_to_main_thread([this] {
+               ui->speed_lock_btn->setChecked(!ui->speed_lock_btn->isChecked());
+               speed_lock_clicked();
+       });
+}
+
 void MainWindow::jog(int delta)
 {
        post_to_main_thread([this, delta] {
@@ -1239,14 +1256,18 @@ void MainWindow::set_master_speed(float speed)
        speed = min(max(speed, 0.1f), 2.0f);
 
        post_to_main_thread([this, speed] {
+               if (ui->speed_lock_btn->isChecked()) {
+                       return;
+               }
+
                int percent = lrintf(speed * 100.0f);
                ui->speed_slider->blockSignals(true);
                ui->speed_slider->setValue(percent);
                ui->speed_slider->blockSignals(false);
-               ui->speed_label->setText(QString::fromStdString(to_string(percent) + "%"));
-       });
+               ui->speed_lock_btn->setText(QString::fromStdString(" " + to_string(percent) + "%"));
 
-       live_player->set_master_speed(speed);
+               live_player->set_master_speed(speed);
+       });
 }
 
 void MainWindow::cue_in()
index c7d0ac756f78ae4c800a4dc0598396b07f8a438c..469cb0ee7181af7761509ea7a602c07296c6e6a7 100644 (file)
@@ -43,6 +43,7 @@ public:
        void preview() override;
        void queue() override;
        void play() override;
+       void toggle_lock() override;
        void jog(int delta) override;
        void switch_camera(unsigned camera_idx) override;
        void set_master_speed(float speed) override;
@@ -130,6 +131,7 @@ private:
        void play_clicked();
        void stop_clicked();
        void speed_slider_changed(int percent);
+       void speed_lock_clicked();
        void live_player_done();
        void live_player_clip_progress(const std::map<uint64_t, double> &progress, double time_remaining);
        void set_output_status(const std::string &status);
diff --git a/futatabi/mainwindow.qrc b/futatabi/mainwindow.qrc
new file mode 100644 (file)
index 0000000..1efc65e
--- /dev/null
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+    <file>lock.svg</file>
+</qresource>
+</RCC>
index e0a4680277d41c2d4d7369a23ccd15549106c287..da05caf0e04903e0515b93bcd6a3e82a0d3e509f 100644 (file)
           </item>
           <item>
            <widget class="QSlider" name="speed_slider">
+            <property name="enabled">
+             <bool>false</bool>
+            </property>
             <property name="minimum">
              <number>10</number>
             </property>
            </widget>
           </item>
           <item>
-           <widget class="QLabel" name="speed_label">
+           <widget class="QPushButton" name="speed_lock_btn">
             <property name="sizePolicy">
-             <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+             <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
               <horstretch>0</horstretch>
               <verstretch>0</verstretch>
              </sizepolicy>
             </property>
             <property name="minimumSize">
              <size>
-              <width>40</width>
+              <width>72</width>
               <height>0</height>
              </size>
             </property>
             <property name="text">
-             <string>100%</string>
+             <string> 100%</string>
             </property>
-            <property name="alignment">
-             <set>Qt::AlignCenter</set>
+            <property name="icon">
+             <iconset>
+              <normalon>:/lock.svg</normalon>
+             </iconset>
+            </property>
+            <property name="checkable">
+             <bool>true</bool>
+            </property>
+            <property name="checked">
+             <bool>true</bool>
             </property>
            </widget>
           </item>
    <header>jpeg_frame_view.h</header>
   </customwidget>
  </customwidgets>
- <resources/>
+ <resources>
+  <include location="mainwindow.qrc"/>
+ </resources>
  <connections/>
 </ui>
index 1e26985a01537e226f21cedb7f9e789698648be6..d1cfea245178246031397a423625273a602c0cca 100644 (file)
@@ -141,6 +141,8 @@ void MIDIMapper::note_on_received(int note)
                bind(&ControllerReceiver::queue, receiver));
        match_button(note, MIDIMappingProto::kPlayFieldNumber, MIDIMappingProto::kPlayBankFieldNumber,
                bind(&ControllerReceiver::play, receiver));
+       match_button(note, MIDIMappingProto::kToggleLockFieldNumber, MIDIMappingProto::kToggleLockBankFieldNumber,
+               bind(&ControllerReceiver::toggle_lock, receiver));
 
        unsigned num_cameras = std::min(MAX_STREAMS, mapping_proto->camera_size());
        for (unsigned camera_idx = 0; camera_idx < num_cameras; ++camera_idx) {
@@ -228,6 +230,9 @@ void MIDIMapper::update_lights_lock_held()
        if (play_enabled_light) {
                activate_mapped_light(*mapping_proto, MIDIMappingProto::kPlayEnabledFieldNumber, &active_lights);
        }
+       if (locked_light) {
+               activate_mapped_light(*mapping_proto, MIDIMappingProto::kLockedFieldNumber, &active_lights);
+       }
        if (current_highlighted_camera >= 0 && current_highlighted_camera < mapping_proto->camera_size()) {
                const CameraMIDIMappingProto &camera = mapping_proto->camera(current_highlighted_camera);
                activate_mapped_light(camera, CameraMIDIMappingProto::kIsCurrentFieldNumber, &active_lights);
index 0dd14cec2ecabd059298e8931703909afc7d7723..7b489ab274ca8ffa71db117473889179b67ff612 100644 (file)
@@ -32,6 +32,7 @@ public:
        virtual void preview() = 0;
        virtual void queue() = 0;
        virtual void play() = 0;
+       virtual void toggle_lock() = 0;
        virtual void jog(int delta) = 0;
        virtual void switch_camera(unsigned camera_idx) = 0;
        virtual void set_master_speed(float speed) = 0;
@@ -68,6 +69,10 @@ public:
                play_enabled_light = enabled;
                refresh_lights();
        }
+       void set_locked(bool locked) {
+               locked_light = locked;
+               refresh_lights();
+       }
        void highlight_camera_input(int stream_idx) {  // -1 for none.
                current_highlighted_camera = stream_idx;
                refresh_lights();
@@ -99,6 +104,7 @@ private:
        std::atomic<bool> preview_enabled_light{false};
        std::atomic<bool> queue_enabled_light{false};
        std::atomic<bool> play_enabled_light{false};
+       std::atomic<bool> locked_light{true};
        std::atomic<int> current_highlighted_camera{-1};
 
        MIDIDevice midi_device;
index e3e194c3c081df1073f3fcbb2703e189f64e04ed..c66d4a7b5fe7cc9838e3081d682c52802d5bbd96 100644 (file)
@@ -275,6 +275,7 @@ proto_generated = gen.process('futatabi/state.proto', 'futatabi/frame.proto', 'f
 moc_files = qt5.preprocess(
        moc_headers: ['futatabi/mainwindow.h', 'futatabi/jpeg_frame_view.h', 'futatabi/clip_list.h'],
        ui_files: ['futatabi/mainwindow.ui'],
+       qresources: ['futatabi/mainwindow.qrc'],
        dependencies: qt5deps)
 
 # Flow objects.