2 Copyright (C) 2006 Paul Davis
3 Author: David Robillard
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 // 'std::isinf()' and 'std::isnan()' are not available in MSVC.
25 #define isinf_local(val) !((bool)_finite((double)val))
26 #define isnan_local(val) (bool)_isnan((double)val)
28 #define isinf_local std::isinf
29 #define isnan_local std::isnan
32 #include "pbd/enumwriter.h"
33 #include "pbd/types_convert.h"
34 #include "evoral/midi_util.h"
36 #include "ardour/beats_frames_converter.h"
37 #include "ardour/buffer_set.h"
38 #include "ardour/debug.h"
39 #include "ardour/delivery.h"
40 #include "ardour/event_type_map.h"
41 #include "ardour/meter.h"
42 #include "ardour/midi_diskstream.h"
43 #include "ardour/midi_playlist.h"
44 #include "ardour/midi_port.h"
45 #include "ardour/midi_region.h"
46 #include "ardour/midi_track.h"
47 #include "ardour/monitor_control.h"
48 #include "ardour/parameter_types.h"
49 #include "ardour/port.h"
50 #include "ardour/processor.h"
51 #include "ardour/profile.h"
52 #include "ardour/route_group_specialized.h"
53 #include "ardour/session.h"
54 #include "ardour/session_playlists.h"
55 #include "ardour/types_convert.h"
56 #include "ardour/utils.h"
61 class InterThreadInfo;
68 using namespace ARDOUR;
71 MidiTrack::MidiTrack (Session& sess, string name, TrackMode mode)
72 : Track (sess, name, PresentationInfo::MidiTrack, mode, DataType::MIDI)
73 , _immediate_events(6096) // FIXME: size?
74 , _step_edit_ring_buffer(64) // FIXME: size?
75 , _note_mode(Sustained)
76 , _step_editing (false)
77 , _input_active (true)
79 _session.SessionLoaded.connect_same_thread (*this, boost::bind (&MidiTrack::restore_controls, this));
82 MidiTrack::~MidiTrack ()
93 _input->changed.connect_same_thread (*this, boost::bind (&MidiTrack::track_input_active, this, _1, _2));
98 boost::shared_ptr<Diskstream>
99 MidiTrack::create_diskstream ()
101 MidiDiskstream::Flag dflags = MidiDiskstream::Flag (MidiDiskstream::Recordable);
103 assert(_mode != Destructive);
105 return boost::shared_ptr<Diskstream> (new MidiDiskstream (_session, name(), dflags));
110 MidiTrack::can_be_record_safe ()
116 return Track::can_be_record_safe ();
120 MidiTrack::can_be_record_enabled ()
126 return Track::can_be_record_enabled ();
130 MidiTrack::set_diskstream (boost::shared_ptr<Diskstream> ds)
132 /* We have to do this here, as Track::set_diskstream will cause a buffer refill,
133 and the diskstream must be set up to fill its buffers using the correct _note_mode.
135 boost::shared_ptr<MidiDiskstream> mds = boost::dynamic_pointer_cast<MidiDiskstream> (ds);
136 mds->set_note_mode (_note_mode);
138 Track::set_diskstream (ds);
140 mds->reset_tracker ();
142 _diskstream->set_track (this);
143 _diskstream->set_record_enabled (false);
145 _diskstream_data_recorded_connection.disconnect ();
146 mds->DataRecorded.connect_same_thread (
147 _diskstream_data_recorded_connection,
148 boost::bind (&MidiTrack::diskstream_data_recorded, this, _1));
150 DiskstreamChanged (); /* EMIT SIGNAL */
153 boost::shared_ptr<MidiDiskstream>
154 MidiTrack::midi_diskstream() const
156 return boost::dynamic_pointer_cast<MidiDiskstream>(_diskstream);
160 MidiTrack::set_state (const XMLNode& node, int version)
162 /* This must happen before Track::set_state(), as there will be a buffer
163 fill during that call, and we must fill buffers using the correct
166 if (!node.get_property (X_("note-mode"), _note_mode)) {
167 _note_mode = Sustained;
170 if (Track::set_state (node, version)) {
174 // No destructive MIDI tracks (yet?)
178 if (node.get_property ("input-active", yn)) {
179 set_input_active (yn);
182 ChannelMode playback_channel_mode = AllChannels;
183 ChannelMode capture_channel_mode = AllChannels;
185 node.get_property ("playback-channel-mode", playback_channel_mode);
186 node.get_property ("capture-channel-mode", capture_channel_mode);
188 if (node.get_property ("channel-mode", playback_channel_mode)) {
189 /* 3.0 behaviour where capture and playback modes were not separated */
190 capture_channel_mode = playback_channel_mode;
193 XMLProperty const * prop;
195 unsigned int playback_channel_mask = 0xffff;
196 unsigned int capture_channel_mask = 0xffff;
198 if ((prop = node.property ("playback-channel-mask")) != 0) {
199 sscanf (prop->value().c_str(), "0x%x", &playback_channel_mask);
201 if ((prop = node.property ("capture-channel-mask")) != 0) {
202 sscanf (prop->value().c_str(), "0x%x", &capture_channel_mask);
204 if ((prop = node.property ("channel-mask")) != 0) {
205 sscanf (prop->value().c_str(), "0x%x", &playback_channel_mask);
206 capture_channel_mask = playback_channel_mask;
209 set_playback_channel_mode (playback_channel_mode, playback_channel_mask);
210 set_capture_channel_mode (capture_channel_mode, capture_channel_mask);
212 pending_state = const_cast<XMLNode*> (&node);
214 if (_session.state_of_the_state() & Session::Loading) {
215 _session.StateReady.connect_same_thread (
216 *this, boost::bind (&MidiTrack::set_state_part_two, this));
218 set_state_part_two ();
225 MidiTrack::state(bool full_state)
227 XMLNode& root (Track::state(full_state));
228 XMLNode* freeze_node;
231 if (_freeze_record.playlist) {
234 freeze_node = new XMLNode (X_("freeze-info"));
235 freeze_node->set_property ("playlist", _freeze_record.playlist->name());
236 freeze_node->set_property ("state", _freeze_record.state);
238 for (vector<FreezeRecordProcessorInfo*>::iterator i = _freeze_record.processor_info.begin(); i != _freeze_record.processor_info.end(); ++i) {
239 inode = new XMLNode (X_("processor"));
240 inode->set_property (X_("id"), id());
241 inode->add_child_copy ((*i)->state);
243 freeze_node->add_child_nocopy (*inode);
246 root.add_child_nocopy (*freeze_node);
249 root.set_property("playback-channel-mode", get_playback_channel_mode());
250 root.set_property("capture-channel-mode", get_capture_channel_mode());
251 snprintf (buf, sizeof(buf), "0x%x", get_playback_channel_mask());
252 root.set_property("playback-channel-mask", std::string(buf));
253 snprintf (buf, sizeof(buf), "0x%x", get_capture_channel_mask());
254 root.set_property("capture-channel-mask", std::string(buf));
256 root.set_property ("note-mode", _note_mode);
257 root.set_property ("step-editing", _step_editing);
258 root.set_property ("input-active", _input_active);
260 for (Controls::const_iterator c = _controls.begin(); c != _controls.end(); ++c) {
261 if (boost::dynamic_pointer_cast<MidiTrack::MidiControl>(c->second)) {
262 boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (c->second);
264 root.add_child_nocopy (ac->get_state ());
272 MidiTrack::set_state_part_two ()
276 /* This is called after all session state has been restored but before
277 have been made ports and connections are established.
280 if (pending_state == 0) {
284 if ((fnode = find_named_node (*pending_state, X_("freeze-info"))) != 0) {
286 _freeze_record.state = Frozen;
288 for (vector<FreezeRecordProcessorInfo*>::iterator i = _freeze_record.processor_info.begin(); i != _freeze_record.processor_info.end(); ++i) {
291 _freeze_record.processor_info.clear ();
294 if (fnode->get_property (X_("playlist"), str)) {
295 boost::shared_ptr<Playlist> pl = _session.playlists->by_name (str);
297 _freeze_record.playlist = boost::dynamic_pointer_cast<MidiPlaylist> (pl);
299 _freeze_record.playlist.reset();
300 _freeze_record.state = NoFreeze;
305 fnode->get_property (X_("state"), _freeze_record.state);
307 XMLNodeConstIterator citer;
308 XMLNodeList clist = fnode->children();
310 for (citer = clist.begin(); citer != clist.end(); ++citer) {
311 if ((*citer)->name() != X_("processor")) {
315 if (!(*citer)->get_property (X_("id"), str)) {
319 FreezeRecordProcessorInfo* frii = new FreezeRecordProcessorInfo (*((*citer)->children().front()),
320 boost::shared_ptr<Processor>());
322 _freeze_record.processor_info.push_back (frii);
326 if (midi_diskstream ()) {
327 midi_diskstream()->set_block_size (_session.get_block_size ());
334 MidiTrack::restore_controls ()
336 // TODO order events (CC before PGM to set banks)
337 for (Controls::const_iterator c = _controls.begin(); c != _controls.end(); ++c) {
338 boost::shared_ptr<MidiTrack::MidiControl> mctrl = boost::dynamic_pointer_cast<MidiTrack::MidiControl>(c->second);
340 mctrl->restore_value();
346 MidiTrack::update_controls(const BufferSet& bufs)
348 const MidiBuffer& buf = bufs.get_midi(0);
349 for (MidiBuffer::const_iterator e = buf.begin(); e != buf.end(); ++e) {
350 const Evoral::Event<framepos_t>& ev = *e;
351 const Evoral::Parameter param = midi_parameter(ev.buffer(), ev.size());
352 const boost::shared_ptr<Evoral::Control> control = this->control(param);
354 control->set_double(ev.value(), _session.transport_frame(), false);
359 /** @param need_butler to be set to true if this track now needs the butler, otherwise it can be left alone
363 MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& need_butler)
365 Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
367 boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream();
368 framecnt_t playback_distance = diskstream->calculate_playback_distance(nframes);
369 if (can_internal_playback_seek(::llabs(playback_distance))) {
370 /* TODO should declick, and/or note-off */
371 internal_playback_seek(playback_distance);
376 boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream();
378 if (n_outputs().n_total() == 0 && _processors.empty()) {
384 if (_meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _diskstream->record_enabled())) {
390 framepos_t transport_frame = _session.transport_frame();
393 framecnt_t playback_distance;
395 if ((nframes = check_initial_delay (nframes, transport_frame)) == 0) {
396 /* need to do this so that the diskstream sets its
397 playback distance to zero, thus causing diskstream::commit
400 BufferSet bufs; /* empty set - is OK, since nothing will happen */
402 dret = diskstream->process (bufs, transport_frame, 0, playback_distance, false);
403 need_butler = diskstream->commit (playback_distance);
407 BufferSet& bufs = _session.get_route_buffers (n_process_buffers());
409 fill_buffers_with_input (bufs, _input, nframes);
411 /* filter captured data before meter sees it */
412 _capture_filter.filter (bufs);
414 if (_meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _diskstream->record_enabled())) {
415 _meter->run (bufs, start_frame, end_frame, 1.0 /*speed()*/, nframes, true);
421 if ((dret = diskstream->process (bufs, transport_frame, nframes, playback_distance, (monitoring_state() == MonitoringDisk))) != 0) {
422 need_butler = diskstream->commit (playback_distance);
427 /* note diskstream uses our filter to filter/map playback channels appropriately. */
429 if (monitoring_state() == MonitoringInput) {
431 /* not actually recording, but we want to hear the input material anyway,
432 at least potentially (depending on monitoring options)
435 /* because the playback buffer is event based and not a
436 * continuous stream, we need to make sure that we empty
437 * it of events every cycle to avoid it filling up with events
438 * read from disk, while we are actually monitoring input
441 diskstream->flush_playback (start_frame, end_frame);
446 /* append immediate messages to the first MIDI buffer (thus sending it to the first output port) */
448 write_out_of_band_data (bufs, start_frame, end_frame, nframes);
450 /* final argument: don't waste time with automation if we're not recording or rolling */
452 process_output_buffers (bufs, start_frame, end_frame, nframes,
453 declick, (!diskstream->record_enabled() && !_session.transport_stopped()));
455 flush_processor_buffers_locked (nframes);
457 need_butler = diskstream->commit (playback_distance);
463 MidiTrack::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool state_changing)
465 int ret = Track::no_roll (nframes, start_frame, end_frame, state_changing);
467 if (ret == 0 && _step_editing) {
468 push_midi_input_to_step_edit_ringbuffer (nframes);
475 MidiTrack::realtime_locate ()
477 Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
483 for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
484 (*i)->realtime_locate ();
487 midi_diskstream()->reset_tracker ();
491 MidiTrack::realtime_handle_transport_stopped ()
493 Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
499 for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
500 (*i)->realtime_handle_transport_stopped ();
505 MidiTrack::non_realtime_locate (framepos_t pos)
507 Track::non_realtime_locate(pos);
509 boost::shared_ptr<MidiPlaylist> playlist = midi_diskstream()->midi_playlist();
514 /* Get the top unmuted region at this position. */
515 boost::shared_ptr<MidiRegion> region = boost::dynamic_pointer_cast<MidiRegion>(
516 playlist->top_unmuted_region_at(pos));
521 /* the source may be missing, but the control still referenced in the GUI */
522 if (!region->midi_source() || !region->model()) {
526 Glib::Threads::Mutex::Lock lm (_control_lock, Glib::Threads::TRY_LOCK);
531 /* Update track controllers based on its "automation". */
532 const framepos_t origin = region->position() - region->start();
533 BeatsFramesConverter bfc(_session.tempo_map(), origin);
534 for (Controls::const_iterator c = _controls.begin(); c != _controls.end(); ++c) {
535 boost::shared_ptr<MidiTrack::MidiControl> tcontrol;
536 boost::shared_ptr<Evoral::Control> rcontrol;
537 if ((tcontrol = boost::dynamic_pointer_cast<MidiTrack::MidiControl>(c->second)) &&
538 (rcontrol = region->control(tcontrol->parameter()))) {
539 const Evoral::Beats pos_beats = bfc.from(pos - origin);
540 if (rcontrol->list()->size() > 0) {
541 tcontrol->set_value(rcontrol->list()->eval(pos_beats.to_double()), Controllable::NoGroup);
548 MidiTrack::push_midi_input_to_step_edit_ringbuffer (framecnt_t nframes)
550 PortSet& ports (_input->ports());
552 for (PortSet::iterator p = ports.begin(DataType::MIDI); p != ports.end(DataType::MIDI); ++p) {
554 Buffer& b (p->get_buffer (nframes));
555 const MidiBuffer* const mb = dynamic_cast<MidiBuffer*>(&b);
558 for (MidiBuffer::const_iterator e = mb->begin(); e != mb->end(); ++e) {
560 const Evoral::Event<framepos_t> ev(*e, false);
562 /* note on, since for step edit, note length is determined
566 if (ev.is_note_on()) {
567 /* we don't care about the time for this purpose */
568 _step_edit_ring_buffer.write (0, ev.event_type(), ev.size(), ev.buffer());
575 MidiTrack::write_out_of_band_data (BufferSet& bufs, framepos_t /*start*/, framepos_t /*end*/, framecnt_t nframes)
577 MidiBuffer& buf (bufs.get_midi (0));
579 update_controls (bufs);
581 // Append immediate events
583 if (_immediate_events.read_space()) {
585 DEBUG_TRACE (DEBUG::MidiIO, string_compose ("%1 has %2 of immediate events to deliver\n",
586 name(), _immediate_events.read_space()));
588 /* write as many of the immediate events as we can, but give "true" as
589 * the last argument ("stop on overflow in destination") so that we'll
590 * ship the rest out next time.
592 * the Port::port_offset() + (nframes-1) argument puts all these events at the last
593 * possible position of the output buffer, so that we do not
594 * violate monotonicity when writing. Port::port_offset() will
595 * be non-zero if we're in a split process cycle.
597 _immediate_events.read (buf, 0, 1, Port::port_offset() + nframes - 1, true);
602 MidiTrack::export_stuff (BufferSet& buffers,
605 boost::shared_ptr<Processor> endpoint,
606 bool include_endpoint,
610 if (buffers.count().n_midi() == 0) {
614 boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream();
616 Glib::Threads::RWLock::ReaderLock rlock (_processor_lock);
618 boost::shared_ptr<MidiPlaylist> mpl = boost::dynamic_pointer_cast<MidiPlaylist>(diskstream->playlist());
623 buffers.get_midi(0).clear();
624 if (mpl->read(buffers.get_midi(0), start, nframes, 0) != nframes) {
628 //bounce_process (buffers, start, nframes, endpoint, include_endpoint, for_export, for_freeze);
633 boost::shared_ptr<Region>
634 MidiTrack::bounce (InterThreadInfo& itt)
636 return bounce_range (_session.current_start_frame(), _session.current_end_frame(), itt, main_outs(), false);
639 boost::shared_ptr<Region>
640 MidiTrack::bounce_range (framepos_t start,
642 InterThreadInfo& itt,
643 boost::shared_ptr<Processor> endpoint,
644 bool include_endpoint)
646 vector<boost::shared_ptr<Source> > srcs;
647 return _session.write_one_track (*this, start, end, false, srcs, itt, endpoint, include_endpoint, false, false);
651 MidiTrack::freeze_me (InterThreadInfo& /*itt*/)
653 std::cerr << "MIDI freeze currently unsupported" << std::endl;
657 MidiTrack::unfreeze ()
659 _freeze_record.state = UnFrozen;
660 FreezeChange (); /* EMIT SIGNAL */
664 MidiTrack::set_note_mode (NoteMode m)
667 midi_diskstream()->set_note_mode(m);
671 MidiTrack::describe_parameter (Evoral::Parameter param)
673 const std::string str(instrument_info().get_controller_name(param));
674 return str.empty() ? Automatable::describe_parameter(param) : str;
678 MidiTrack::midi_panic()
680 DEBUG_TRACE (DEBUG::MidiIO, string_compose ("%1 delivers panic data\n", name()));
681 for (uint8_t channel = 0; channel <= 0xF; channel++) {
682 uint8_t ev[3] = { ((uint8_t) (MIDI_CMD_CONTROL | channel)), ((uint8_t) MIDI_CTL_SUSTAIN), 0 };
683 write_immediate_event(3, ev);
684 ev[1] = MIDI_CTL_ALL_NOTES_OFF;
685 write_immediate_event(3, ev);
686 ev[1] = MIDI_CTL_RESET_CONTROLLERS;
687 write_immediate_event(3, ev);
691 /** \return true on success, false on failure (no buffer space left)
694 MidiTrack::write_immediate_event(size_t size, const uint8_t* buf)
696 if (!Evoral::midi_event_is_valid(buf, size)) {
697 cerr << "WARNING: Ignoring illegal immediate MIDI event" << endl;
700 return (_immediate_events.write (0, Evoral::MIDI_EVENT, size, buf) == size);
704 MidiTrack::set_parameter_automation_state (Evoral::Parameter param, AutoState state)
706 switch (param.type()) {
707 case MidiCCAutomation:
708 case MidiPgmChangeAutomation:
709 case MidiPitchBenderAutomation:
710 case MidiChannelPressureAutomation:
711 case MidiNotePressureAutomation:
712 case MidiSystemExclusiveAutomation:
713 /* The track control for MIDI parameters is for immediate events to act
714 as a control surface, write/touch for them is not currently
718 Automatable::set_parameter_automation_state(param, state);
723 MidiTrack::MidiControl::restore_value ()
725 actually_set_value (get_value(), Controllable::NoGroup);
729 MidiTrack::MidiControl::actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
731 const Evoral::Parameter ¶meter = _list ? _list->parameter() : Control::parameter();
732 const Evoral::ParameterDescriptor &desc = EventTypeMap::instance().descriptor(parameter);
735 if (isinf_local(val)) {
736 cerr << "MIDIControl value is infinity" << endl;
737 } else if (isnan_local(val)) {
738 cerr << "MIDIControl value is NaN" << endl;
739 } else if (val < desc.lower) {
740 cerr << "MIDIControl value is < " << desc.lower << endl;
741 } else if (val > desc.upper) {
742 cerr << "MIDIControl value is > " << desc.upper << endl;
751 assert(val <= desc.upper);
752 if ( ! _list || ! automation_playback()) {
754 uint8_t ev[3] = { parameter.channel(), uint8_t (val), 0 };
755 switch(parameter.type()) {
756 case MidiCCAutomation:
757 ev[0] += MIDI_CMD_CONTROL;
758 ev[1] = parameter.id();
762 case MidiPgmChangeAutomation:
764 ev[0] += MIDI_CMD_PGM_CHANGE;
768 case MidiChannelPressureAutomation:
770 ev[0] += MIDI_CMD_CHANNEL_PRESSURE;
774 case MidiNotePressureAutomation:
775 ev[0] += MIDI_CMD_NOTE_PRESSURE;
776 ev[1] = parameter.id();
780 case MidiPitchBenderAutomation:
781 ev[0] += MIDI_CMD_BENDER;
782 ev[1] = 0x7F & int(val);
783 ev[2] = 0x7F & (int(val) >> 7);
789 _route->write_immediate_event(size, ev);
792 AutomationControl::actually_set_value(val, group_override);
796 MidiTrack::set_step_editing (bool yn)
798 if (_session.record_status() != Session::Disabled) {
802 if (yn != _step_editing) {
804 StepEditStatusChange (yn);
808 boost::shared_ptr<SMFSource>
809 MidiTrack::write_source (uint32_t)
811 return midi_diskstream()->write_source ();
815 MidiTrack::set_playback_channel_mode(ChannelMode mode, uint16_t mask)
817 if (_playback_filter.set_channel_mode(mode, mask)) {
818 _session.set_dirty();
823 MidiTrack::set_capture_channel_mode(ChannelMode mode, uint16_t mask)
825 if (_capture_filter.set_channel_mode(mode, mask)) {
826 _session.set_dirty();
831 MidiTrack::set_playback_channel_mask (uint16_t mask)
833 if (_playback_filter.set_channel_mask(mask)) {
834 _session.set_dirty();
839 MidiTrack::set_capture_channel_mask (uint16_t mask)
841 if (_capture_filter.set_channel_mask(mask)) {
842 _session.set_dirty();
846 boost::shared_ptr<MidiPlaylist>
847 MidiTrack::midi_playlist ()
849 return midi_diskstream()->midi_playlist ();
853 MidiTrack::diskstream_data_recorded (boost::weak_ptr<MidiSource> src)
855 DataRecorded (src); /* EMIT SIGNAL */
859 MidiTrack::input_active () const
861 return _input_active;
865 MidiTrack::set_input_active (bool yn)
867 if (yn != _input_active) {
869 map_input_active (yn);
870 InputActiveChanged (); /* EMIT SIGNAL */
875 MidiTrack::map_input_active (bool yn)
881 PortSet& ports (_input->ports());
883 for (PortSet::iterator p = ports.begin(DataType::MIDI); p != ports.end(DataType::MIDI); ++p) {
884 boost::shared_ptr<MidiPort> mp = boost::dynamic_pointer_cast<MidiPort> (*p);
885 if (yn != mp->input_active()) {
886 mp->set_input_active (yn);
892 MidiTrack::track_input_active (IOChange change, void* /* src */)
894 if (change.type & IOChange::ConfigurationChanged) {
895 map_input_active (_input_active);
899 boost::shared_ptr<Diskstream>
900 MidiTrack::diskstream_factory (XMLNode const & node)
902 return boost::shared_ptr<Diskstream> (new MidiDiskstream (_session, node));
905 boost::shared_ptr<MidiBuffer>
906 MidiTrack::get_gui_feed_buffer () const
908 return midi_diskstream()->get_gui_feed_buffer ();
912 MidiTrack::act_on_mute ()
914 /* this is called right after our mute status has changed.
915 if we are now muted, send suitable output to shutdown
918 XXX we should should also stop all relevant note trackers.
921 /* If we haven't got a diskstream yet, there's nothing to worry about,
922 and we can't call get_channel_mask() anyway.
924 if (!midi_diskstream()) {
928 if (muted() || _mute_master->muted_by_others_soloing_at (MuteMaster::AllPoints)) {
929 /* only send messages for channels we are using */
931 uint16_t mask = _playback_filter.get_channel_mask();
933 for (uint8_t channel = 0; channel <= 0xF; channel++) {
935 if ((1<<channel) & mask) {
937 DEBUG_TRACE (DEBUG::MidiIO, string_compose ("%1 delivers mute message to channel %2\n", name(), channel+1));
938 uint8_t ev[3] = { ((uint8_t) (MIDI_CMD_CONTROL | channel)), MIDI_CTL_SUSTAIN, 0 };
939 write_immediate_event (3, ev);
941 /* Note we do not send MIDI_CTL_ALL_NOTES_OFF here, since this may
942 silence notes that came from another non-muted track. */
946 /* Resolve active notes. */
947 midi_diskstream()->resolve_tracker(_immediate_events, Port::port_offset());
952 MidiTrack::monitoring_changed (bool self, Controllable::GroupControlDisposition gcd)
954 Track::monitoring_changed (self, gcd);
956 /* monitoring state changed, so flush out any on notes at the
960 PortSet& ports (_output->ports());
962 for (PortSet::iterator p = ports.begin(); p != ports.end(); ++p) {
963 boost::shared_ptr<MidiPort> mp = boost::dynamic_pointer_cast<MidiPort> (*p);
965 mp->require_resolve ();
969 boost::shared_ptr<MidiDiskstream> md (midi_diskstream());
972 md->reset_tracker ();
977 MidiTrack::monitoring_state () const
979 MonitorState ms = Track::monitoring_state();
980 if (ms == MonitoringSilence) {
981 return MonitoringInput;