From b79d5bfad3473f54ab24c0b7852fc4bfc9d9ebb0 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Tue, 19 Feb 2008 01:31:24 +0000 Subject: [PATCH] 'Channel safe' MIDI: Resolve note on/off pairs in MidiModel. Add channel field to Parameter (for associating a channel with a CC list). Add channel selector to 'add controller automation' dialog. Write out note and CC MIDI events with proper channel. git-svn-id: svn://localhost/ardour2/branches/3.0@3085 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/add_midi_cc_track_dialog.cc | 38 +++++++----- gtk2_ardour/add_midi_cc_track_dialog.h | 2 + libs/ardour/SConscript | 1 + libs/ardour/ardour/note.h | 2 +- libs/ardour/ardour/parameter.h | 82 +++++-------------------- libs/ardour/midi_model.cc | 10 ++- libs/ardour/note.cc | 8 ++- 7 files changed, 52 insertions(+), 91 deletions(-) diff --git a/gtk2_ardour/add_midi_cc_track_dialog.cc b/gtk2_ardour/add_midi_cc_track_dialog.cc index e1a3a89bd6..fcd3ebbe40 100644 --- a/gtk2_ardour/add_midi_cc_track_dialog.cc +++ b/gtk2_ardour/add_midi_cc_track_dialog.cc @@ -36,40 +36,50 @@ using namespace PBD; using namespace ARDOUR; AddMidiCCTrackDialog::AddMidiCCTrackDialog () - : Dialog (_("ardour: add midi controller track")), - _cc_num_adjustment (1, 0, 127, 1, 10), - _cc_num_spinner (_cc_num_adjustment) + : Dialog (_("ardour: add midi controller track")) + , _chan_adjustment (1, 1, 16, 8) + , _chan_spinner (_chan_adjustment) + , _cc_num_adjustment (1, 0, 127, 1, 10) + , _cc_num_spinner (_cc_num_adjustment) { set_name ("AddMidiCCTrackDialog"); set_wmclass (X_("ardour_add_track_bus"), "Ardour"); set_position (Gtk::WIN_POS_MOUSE); set_resizable (false); - + _chan_spinner.set_name ("AddMidiCCTrackDialogSpinner"); _cc_num_spinner.set_name ("AddMidiCCTrackDialogSpinner"); - HBox *hbox = manage (new HBox()); - Label *label = manage(new Label("Controller Number: ")); + HBox *chan_box = manage (new HBox()); + Label *chan_label = manage(new Label("Channel: ")); + chan_box->pack_start(*chan_label, true, true, 4); + chan_box->pack_start(_chan_spinner, false, false, 4); + get_vbox()->pack_start(*chan_box, true, true, 4); - hbox->pack_start(*label, true, true, 4); - hbox->pack_start(_cc_num_spinner, false, false, 4); - - get_vbox()->pack_start(*hbox, true, true, 4); + HBox* num_box = manage (new HBox()); + Label *num_label = manage(new Label("Controller: ")); + num_box->pack_start(*num_label, true, true, 4); + num_box->pack_start(_cc_num_spinner, false, false, 4); + get_vbox()->pack_start(*num_box, true, true, 4); add_button (Stock::CANCEL, RESPONSE_CANCEL); add_button (Stock::ADD, RESPONSE_ACCEPT); - + + _chan_spinner.show(); + chan_box->show(); + chan_label->show(); _cc_num_spinner.show(); - hbox->show(); - label->show(); + num_box->show(); + num_label->show(); } ARDOUR::Parameter AddMidiCCTrackDialog::parameter () { + int chan = _chan_spinner.get_value_as_int() - 1; int cc_num = _cc_num_spinner.get_value_as_int(); - return Parameter(MidiCCAutomation, cc_num); + return Parameter(MidiCCAutomation, cc_num, chan); } diff --git a/gtk2_ardour/add_midi_cc_track_dialog.h b/gtk2_ardour/add_midi_cc_track_dialog.h index f1ca24990f..d3124044fe 100644 --- a/gtk2_ardour/add_midi_cc_track_dialog.h +++ b/gtk2_ardour/add_midi_cc_track_dialog.h @@ -37,6 +37,8 @@ class AddMidiCCTrackDialog : public Gtk::Dialog ARDOUR::Parameter parameter (); private: + Gtk::Adjustment _chan_adjustment; + Gtk::SpinButton _chan_spinner; Gtk::Adjustment _cc_num_adjustment; Gtk::SpinButton _cc_num_spinner; }; diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index 942905c341..b8a003cb08 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -95,6 +95,7 @@ mtc_slave.cc named_selection.cc note.cc panner.cc +parameter.cc pcm_utils.cc playlist.cc playlist_factory.cc diff --git a/libs/ardour/ardour/note.h b/libs/ardour/ardour/note.h index d88ecd05b0..ea598573e8 100644 --- a/libs/ardour/ardour/note.h +++ b/libs/ardour/ardour/note.h @@ -34,7 +34,7 @@ namespace ARDOUR { */ class Note { public: - Note(double time=0, double dur=0, uint8_t note=0, uint8_t vel=0x40); + Note(uint8_t chan=0, double time=0, double dur=0, uint8_t note=0, uint8_t vel=0x40); Note(const Note& copy); const Note& operator=(const Note& copy); diff --git a/libs/ardour/ardour/parameter.h b/libs/ardour/ardour/parameter.h index d56124ee53..92fa672e22 100644 --- a/libs/ardour/ardour/parameter.h +++ b/libs/ardour/ardour/parameter.h @@ -48,85 +48,32 @@ namespace ARDOUR { class Parameter { public: - inline Parameter(AutomationType type = NullAutomation, uint32_t id=0) : _type(type), _id(id) {} + Parameter(AutomationType type = NullAutomation, uint32_t id=0, uint8_t channel=0) + : _type(type), _id(id), _channel(channel) + {} - /** Construct an Parameter from a string returned from Parameter::to_string - * (AutomationList automation-id property) - */ - Parameter(const std::string& str) : _type(NullAutomation), _id(0) { - if (str == "gain") { - _type = GainAutomation; - } else if (str == "solo") { - _type = SoloAutomation; - } else if (str == "mute") { - _type = MuteAutomation; - } else if (str == "fadein") { - _type = FadeInAutomation; - } else if (str == "fadeout") { - _type = FadeOutAutomation; - } else if (str == "envelope") { - _type = EnvelopeAutomation; - } else if (str == "pan") { - _type = PanAutomation; - } else if (str.length() > 4 && str.substr(0, 4) == "pan-") { - _type = PanAutomation; - _id = atoi(str.c_str()+4); - } else if (str.length() > 10 && str.substr(0, 10) == "parameter-") { - _type = PluginAutomation; - _id = atoi(str.c_str()+10); - } else if (str.length() > 7 && str.substr(0, 7) == "midicc-") { - _type = MidiCCAutomation; - _id = atoi(str.c_str()+7); - } else { - PBD::warning << "Unknown Parameter '" << str << "'" << endmsg; - } + Parameter(const std::string& str); + + inline AutomationType type() const { return _type; } + inline uint32_t id() const { return _id; } + inline uint8_t channel() const { return _channel; } + + inline bool operator==(const Parameter& id) const { + return (_type == id._type && _id == id._id); } - - inline AutomationType type() const { return _type; } - inline uint32_t id() const { return _id; } - - inline bool operator==(const Parameter& id) const - { return (_type == id._type && _id == id._id); } - /** Arbitrary but fixed ordering, so we're comparable (usable in std::map) */ + /** Arbitrary but fixed ordering (for use in e.g. std::map) */ inline bool operator<(const Parameter& id) const { #ifndef NDEBUG if (_type == NullAutomation) PBD::warning << "Uninitialized Parameter compared." << endmsg; #endif - return (_type < id._type || _id < id._id); + return (_channel < id._channel || _type < id._type || _id < id._id); } inline operator bool() const { return (_type != 0); } - /** Unique string representation, suitable as an XML property value. - * e.g. - */ - inline std::string to_string() const { - if (_type == GainAutomation) { - return "gain"; - } else if (_type == PanAutomation) { - return string_compose("pan-%1", _id); - } else if (_type == SoloAutomation) { - return "solo"; - } else if (_type == MuteAutomation) { - return "mute"; - } else if (_type == FadeInAutomation) { - return "fadein"; - } else if (_type == FadeOutAutomation) { - return "fadeout"; - } else if (_type == EnvelopeAutomation) { - return "envelope"; - } else if (_type == PluginAutomation) { - return string_compose("parameter-%1", _id); - } else if (_type == MidiCCAutomation) { - return string_compose("midicc-%1", _id); - } else { - assert(false); - PBD::warning << "Uninitialized Parameter to_string() called." << endmsg; - return ""; - } - } + std::string to_string() const; /* The below properties are only used for CC right now, but unchanging properties * of parameters (rather than changing parameters of automation lists themselves) @@ -154,6 +101,7 @@ private: // default copy constructor is ok AutomationType _type; uint32_t _id; + uint8_t _channel; }; diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index b2c7369edd..00fcd44021 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -304,9 +304,10 @@ MidiModel::control_to_midi_event(MidiEvent& ev, const MidiControlIterator& iter) ev.set_buffer((Byte*)malloc(3), true); assert(iter.first); + assert(iter.first->parameter().channel() < 16); assert(iter.first->parameter().id() <= INT8_MAX); assert(iter.second.second <= INT8_MAX); - ev.buffer()[0] = MIDI_CMD_CONTROL; + ev.buffer()[0] = MIDI_CMD_CONTROL + iter.first->parameter().channel(); ev.buffer()[1] = (Byte)iter.first->parameter().id(); ev.buffer()[2] = (Byte)iter.second.second; ev.time() = iter.second.first; // x @@ -412,7 +413,7 @@ MidiModel::append_note_on_unlocked(uint8_t chan, double time, uint8_t note_num, assert(chan < 16); assert(_writing); - _notes.push_back(boost::shared_ptr(new Note(time, 0, note_num, velocity))); + _notes.push_back(boost::shared_ptr(new Note(chan, time, 0, note_num, velocity))); if (_note_mode == Sustained) { //cerr << "MM Sustained: Appending active note on " << (unsigned)(uint8_t)note_num << endl; _write_notes[chan].push_back(_notes.size() - 1); @@ -471,10 +472,7 @@ MidiModel::append_cc_unlocked(uint8_t chan, double time, uint8_t number, uint8_t assert(chan < 16); assert(_writing); - if (chan != 0) // FIXME - cerr << "WARNING: CC on non-0 channel, channel information lost!" << endl; - - Parameter param(MidiCCAutomation, number); + Parameter param(MidiCCAutomation, number, chan); boost::shared_ptr control = Automatable::control(param, true); control->list()->fast_simple_add(time, (double)value); diff --git a/libs/ardour/note.cc b/libs/ardour/note.cc index 1cd691c3d7..27f50e4092 100644 --- a/libs/ardour/note.cc +++ b/libs/ardour/note.cc @@ -22,15 +22,17 @@ namespace ARDOUR { -Note::Note(double t, double d, uint8_t n, uint8_t v) +Note::Note(uint8_t chan, double t, double d, uint8_t n, uint8_t v) : _on_event(t, 3, NULL, true) , _off_event(t + d, 3, NULL, true) { - _on_event.buffer()[0] = MIDI_CMD_NOTE_ON; + assert(chan < 16); + + _on_event.buffer()[0] = MIDI_CMD_NOTE_ON + chan; _on_event.buffer()[1] = n; _on_event.buffer()[2] = v; - _off_event.buffer()[0] = MIDI_CMD_NOTE_OFF; + _off_event.buffer()[0] = MIDI_CMD_NOTE_OFF + chan; _off_event.buffer()[1] = n; _off_event.buffer()[2] = 0x40;