From 9ee828b47b461fb2ec2b439635a451fd48a414cd Mon Sep 17 00:00:00 2001 From: Luciano Iam Date: Sat, 5 Sep 2020 13:12:04 +0200 Subject: [PATCH] WS: properly support MIDI strips --- libs/surfaces/websockets/dispatcher.cc | 2 +- libs/surfaces/websockets/feedback.cc | 12 +- libs/surfaces/websockets/mixer.cc | 26 ++++- libs/surfaces/websockets/mixer.h | 15 ++- share/web_surfaces/builtin/mixer/js/main.js | 11 +- .../web_surfaces/builtin/mixer/js/tkwidget.js | 107 ++++++++++++------ share/web_surfaces/builtin/mixer/main.css | 1 + share/web_surfaces/shared/components/strip.js | 34 +++++- 8 files changed, 154 insertions(+), 54 deletions(-) diff --git a/libs/surfaces/websockets/dispatcher.cc b/libs/surfaces/websockets/dispatcher.cc index c2c315edce..c738922fb1 100644 --- a/libs/surfaces/websockets/dispatcher.cc +++ b/libs/surfaces/websockets/dispatcher.cc @@ -65,7 +65,7 @@ WebsocketsDispatcher::update_all_nodes (Client client) ValueVector strip_desc = ValueVector (); strip_desc.push_back (strip.name ()); - strip_desc.push_back (strip.has_pan ()); + strip_desc.push_back ((int)strip.stripable ()->presentation_info ().flags ()); update (client, Node::strip_description, strip_addr, strip_desc); diff --git a/libs/surfaces/websockets/feedback.cc b/libs/surfaces/websockets/feedback.cc index e415bbb5a0..e6c6049488 100644 --- a/libs/surfaces/websockets/feedback.cc +++ b/libs/surfaces/websockets/feedback.cc @@ -219,12 +219,12 @@ void ArdourFeedback::observe_strip_plugins (uint32_t strip_id, ArdourMixerStrip::PluginMap& plugins) { for (ArdourMixerStrip::PluginMap::iterator it = plugins.begin(); it != plugins.end(); ++it) { - uint32_t plugin_id = it->first; - boost::shared_ptr plugin = it->second; - boost::shared_ptr insert = plugin->insert (); - uint32_t bypass = insert->plugin ()->designated_bypass_port (); - Evoral::Parameter param = Evoral::Parameter (PluginAutomation, 0, bypass); - boost::shared_ptr control = insert->automation_control (param); + uint32_t plugin_id = it->first; + boost::shared_ptr plugin = it->second; + boost::shared_ptr insert = plugin->insert (); + uint32_t bypass = insert->plugin ()->designated_bypass_port (); + Evoral::Parameter param = Evoral::Parameter (PluginAutomation, 0, bypass); + boost::shared_ptr control = insert->automation_control (param); if (control) { control->Changed.connect (*plugin, MISSING_INVALIDATOR, diff --git a/libs/surfaces/websockets/mixer.cc b/libs/surfaces/websockets/mixer.cc index 983450917e..db9457cc8f 100644 --- a/libs/surfaces/websockets/mixer.cc +++ b/libs/surfaces/websockets/mixer.cc @@ -174,13 +174,15 @@ ArdourMixerStrip::plugins () double ArdourMixerStrip::gain () const { - return to_db (_stripable->gain_control ()->get_value ()); + double val = _stripable->gain_control ()->get_value (); + return is_midi () ? static_cast (to_velocity (val)) : to_db (val); } void -ArdourMixerStrip::set_gain (double db) +ArdourMixerStrip::set_gain (double gain) { - _stripable->gain_control ()->set_value (from_db (db), PBD::Controllable::NoGroup); + double val = is_midi () ? from_velocity (static_cast (gain)) : from_db (gain); + _stripable->gain_control ()->set_value (val, PBD::Controllable::NoGroup); } bool @@ -238,6 +240,12 @@ ArdourMixerStrip::name () const return _stripable->name (); } +bool +ArdourMixerStrip::is_midi () const +{ + return _stripable->presentation_info ().flags () & PresentationInfo::Flag::MidiTrack; +} + void ArdourMixerStrip::on_drop_plugin (uint32_t plugin_id) { @@ -267,6 +275,18 @@ ArdourMixerStrip::from_db (double db) return static_cast (k); } + +int +ArdourMixerStrip::to_velocity (double k) +{ + return static_cast (127.0 * k / 2.0); +} + +double +ArdourMixerStrip::from_velocity (int k) +{ + return 2.0 * static_cast (k) / 127.0; +} int ArdourMixer::start () diff --git a/libs/surfaces/websockets/mixer.h b/libs/surfaces/websockets/mixer.h index 43a7d75727..22d84577ce 100644 --- a/libs/surfaces/websockets/mixer.h +++ b/libs/surfaces/websockets/mixer.h @@ -48,8 +48,7 @@ public: ArdourMixerPlugin (boost::shared_ptr); ~ArdourMixerPlugin (); - boost::shared_ptr insert () const; - boost::shared_ptr connections () const; + boost::shared_ptr insert () const; bool enabled () const; void set_enabled (bool); @@ -63,7 +62,7 @@ public: static TypedValue param_value (boost::shared_ptr); private: - boost::shared_ptr _insert; + boost::shared_ptr _insert; }; class ArdourMixerStrip : public PBD::ScopedConnectionList @@ -72,8 +71,7 @@ public: ArdourMixerStrip (boost::shared_ptr, PBD::EventLoop*); ~ArdourMixerStrip (); - boost::shared_ptr stripable () const; - boost::shared_ptr connections () const; + boost::shared_ptr stripable () const; typedef std::map > PluginMap; @@ -97,11 +95,16 @@ public: static double to_db (double); static double from_db (double); + static int to_velocity (double); + static double from_velocity (int); + private: - boost::shared_ptr _stripable; + boost::shared_ptr _stripable; PluginMap _plugins; + bool is_midi () const; + void on_drop_plugin (uint32_t); }; diff --git a/share/web_surfaces/builtin/mixer/js/main.js b/share/web_surfaces/builtin/mixer/js/main.js index bcd7180cb5..b166182c50 100644 --- a/share/web_surfaces/builtin/mixer/js/main.js +++ b/share/web_surfaces/builtin/mixer/js/main.js @@ -19,7 +19,8 @@ import ArdourClient from '/shared/ardour.js'; import { createRootContainer, Container, Dialog, Label, Button, Toggle, DiscreteKnob, LinearKnob, LogKnob, PanKnob, - StripGainFader, StripMeter } from './tkwidget.js'; + AudioStripGainFader, MidiStripGainFader, + AudioStripMeter, MidiStripMeter } from './tkwidget.js'; (() => { @@ -95,6 +96,10 @@ import { createRootContainer, Container, Dialog, Label, Button, Toggle, plugins.callback = () => openPlugins (strip); } + if (strip.isMidi || strip.isVca) { + plugins.element.style.visibility = 'hidden'; + } + const pan = new PanKnob(); pan.appendTo(container); @@ -114,11 +119,11 @@ import { createRootContainer, Container, Dialog, Label, Button, Toggle, meterFader.classList.add('strip-meter-fader'); meterFader.appendTo(container); - const gain = new StripGainFader(); + const gain = strip.isMidi ? new MidiStripGainFader : new AudioStripGainFader(); gain.appendTo(meterFader); gain.bindTo(strip, 'gain'); - const meter = new StripMeter(); + const meter = strip.isMidi ? new MidiStripMeter() : new AudioStripMeter(); meter.appendTo(meterFader); meter.bindTo(strip, 'meter'); diff --git a/share/web_surfaces/builtin/mixer/js/tkwidget.js b/share/web_surfaces/builtin/mixer/js/tkwidget.js index 444b2d2c05..602a44cafc 100644 --- a/share/web_surfaces/builtin/mixer/js/tkwidget.js +++ b/share/web_surfaces/builtin/mixer/js/tkwidget.js @@ -27,7 +27,7 @@ export async function createRootContainer () { return root; } -class Widget extends BaseWidget { +class TkWidget extends BaseWidget { constructor (tk) { super(); @@ -40,19 +40,7 @@ class Widget extends BaseWidget { } -export class Label extends Widget { - - constructor () { - super(new TK.Label()); - } - - set text (text) { - this.tk.set('label', text); - } - -} - -class Control extends BaseControl { +class TkControl extends BaseControl { constructor (tk) { super(); @@ -65,7 +53,7 @@ class Control extends BaseControl { } -class RangeControl extends Control { +class TkRangeControl extends TkControl { constructor (tk) { super(tk); @@ -91,7 +79,7 @@ class RangeControl extends Control { } -class Knob extends RangeControl { +class TkKnob extends TkRangeControl { constructor (options) { super(new TK.Knob(options)); @@ -99,6 +87,38 @@ class Knob extends RangeControl { } +class TkFader extends TkRangeControl { + + constructor (options) { + super(new TK.Fader(options)); + } + +} + +class TkMeter extends TkRangeControl { + + constructor (options) { + super(new TK.LevelMeter(options)); + } + + set value (val) { + this.tk.set('value', val); + } + +} + +export class Label extends TkWidget { + + constructor () { + super(new TK.Label()); + } + + set text (text) { + this.tk.set('label', text); + } + +} + export class Container extends BaseContainer { constructor () { @@ -161,7 +181,7 @@ export class Dialog extends BaseDialog { } -export class Button extends Control { +export class Button extends TkControl { constructor () { super(new TK.Button()); @@ -180,7 +200,7 @@ export class Button extends Control { } -export class Toggle extends Control { +export class Toggle extends TkControl { constructor () { super(new TK.Toggle()); @@ -207,36 +227,59 @@ export class Toggle extends Control { } -export class StripGainFader extends RangeControl { +export class AudioStripGainFader extends TkFader { constructor () { - super(new TK.Fader({ + super({ scale: 'decibel', + labels: TK.FORMAT("%d"), min: -58.0, max: 6.0 - })); + }); } } -export class StripMeter extends RangeControl { +export class MidiStripGainFader extends TkFader { constructor () { - super(new TK.LevelMeter({ + super({ + scale: 'linear', + labels: TK.FORMAT("%d"), + min: 0, + max: 127 + }); + } + +} + +export class AudioStripMeter extends TkMeter { + + constructor () { + super({ show_scale: false, scale: 'decibel', min: -58.0, max: 6.0 - })); - } - - set value (val) { - this.tk.set('value', val); + }); } } -export class LinearKnob extends Knob { +export class MidiStripMeter extends TkMeter { + + constructor () { + super({ + show_scale: false, + scale: 'linear', + min: 0, + max: 127 + }); + } + +} + +export class LinearKnob extends TkKnob { constructor (min, max) { super({ @@ -252,7 +295,7 @@ export class LinearKnob extends Knob { } -export class LogKnob extends Knob { +export class LogKnob extends TkKnob { constructor (min, max) { super({ @@ -268,7 +311,7 @@ export class LogKnob extends Knob { } -export class DiscreteKnob extends Knob { +export class DiscreteKnob extends TkKnob { constructor (min, max, step) { super({ @@ -285,7 +328,7 @@ export class DiscreteKnob extends Knob { } -export class PanKnob extends Knob { +export class PanKnob extends TkKnob { constructor () { super({ diff --git a/share/web_surfaces/builtin/mixer/main.css b/share/web_surfaces/builtin/mixer/main.css index c1efc378f1..5a6f939dcf 100644 --- a/share/web_surfaces/builtin/mixer/main.css +++ b/share/web_surfaces/builtin/mixer/main.css @@ -12,6 +12,7 @@ body { width: 100%; position: fixed; margin: 0; + overflow: none; } div { diff --git a/share/web_surfaces/shared/components/strip.js b/share/web_surfaces/shared/components/strip.js index 157bfb0fb8..efb4fd9d2f 100644 --- a/share/web_surfaces/shared/components/strip.js +++ b/share/web_surfaces/shared/components/strip.js @@ -27,13 +27,25 @@ const NodeToProperty = Object.freeze({ [StateNode.STRIP_MUTE] : 'mute' }); +// from presentation_info.h +const StripFlags = Object.freeze({ + AUDIO_TRACK: 0x1, + MIDI_TRACK: 0x2, + AUDIO_BUS: 0x4, + MIDI_BUS: 0x8, + VCA: 0x10, + MASTER_OUT: 0x20, + MONITOR_OUT: 0x40, + AUDITIONER: 0x80 +}); + export default class Strip extends AddressableComponent { constructor (parent, addr, desc) { super(parent, addr); this._plugins = {}; this._name = desc[0]; - this._hasPan = desc[1]; + this._flags = desc[1]; this._meter = 0; this._gain = 0; this._pan = 0; @@ -48,8 +60,8 @@ export default class Strip extends AddressableComponent { return this._name; } - get hasPan () { - return this._hasPan; + get flags () { + return this._flags; } get meter () { @@ -64,6 +76,10 @@ export default class Strip extends AddressableComponent { this.updateRemote('gain', db, StateNode.STRIP_GAIN); } + get hasPan () { + return !this.isMidi && !this.isVca; + } + get pan () { return this._pan; } @@ -80,6 +96,18 @@ export default class Strip extends AddressableComponent { this.updateRemote('mute', value, StateNode.STRIP_MUTE); } + get isAudio () { + return this._flags & StripFlags.AUDIO_TRACK; + } + + get isMidi () { + return this._flags & StripFlags.MIDI_TRACK; + } + + get isVca () { + return this._flags & StripFlags.VCA; + } + handle (node, addr, val) { if (node.startsWith('strip_plugin')) { if (node == StateNode.STRIP_PLUGIN_DESCRIPTION) {