X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fmidi_track.cc;h=d07076ea65b8d2988513e01af50203ce73097b77;hb=16a8762dd494adb68756b8d549f349ed7bdccd9b;hp=2226574e6a5f31b489374ebb56abd0e94505fa0f;hpb=0bf7323df3e28f108fea525549ba2f8edbfc432d;p=ardour.git diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index 2226574e6a..d07076ea65 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -17,6 +17,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include // for ffs(3) + #include "pbd/enumwriter.h" #include "pbd/convert.h" #include "evoral/midi_util.h" @@ -55,6 +57,8 @@ MidiTrack::MidiTrack (Session& sess, string name, Route::Flag flag, TrackMode mo , _note_mode(Sustained) , _step_editing (false) , _input_active (true) + , _playback_channel_mask(0x0000ffff) + , _capture_channel_mask(0x0000ffff) { } @@ -77,13 +81,7 @@ MidiTrack::init () boost::shared_ptr MidiTrack::create_diskstream () { - MidiDiskstream::Flag dflags = MidiDiskstream::Flag (0); - - if (_flags & Hidden) { - dflags = MidiDiskstream::Flag (dflags | MidiDiskstream::Hidden); - } else { - dflags = MidiDiskstream::Flag (dflags | MidiDiskstream::Recordable); - } + MidiDiskstream::Flag dflags = MidiDiskstream::Flag (MidiDiskstream::Recordable); assert(_mode != Destructive); @@ -158,6 +156,38 @@ MidiTrack::set_state (const XMLNode& node, int version) set_input_active (string_is_affirmative (prop->value())); } + ChannelMode playback_channel_mode = AllChannels; + ChannelMode capture_channel_mode = AllChannels; + + if ((prop = node.property ("playback-channel-mode")) != 0) { + playback_channel_mode = ChannelMode (string_2_enum(prop->value(), playback_channel_mode)); + } + if ((prop = node.property ("capture-channel-mode")) != 0) { + capture_channel_mode = ChannelMode (string_2_enum(prop->value(), capture_channel_mode)); + } + if ((prop = node.property ("channel-mode")) != 0) { + /* 3.0 behaviour where capture and playback modes were not separated */ + playback_channel_mode = ChannelMode (string_2_enum(prop->value(), playback_channel_mode)); + capture_channel_mode = playback_channel_mode; + } + + unsigned int playback_channel_mask = 0xffff; + unsigned int capture_channel_mask = 0xffff; + + if ((prop = node.property ("playback-channel-mask")) != 0) { + sscanf (prop->value().c_str(), "0x%x", &playback_channel_mask); + } + if ((prop = node.property ("capture-channel-mask")) != 0) { + sscanf (prop->value().c_str(), "0x%x", &capture_channel_mask); + } + if ((prop = node.property ("channel-mask")) != 0) { + sscanf (prop->value().c_str(), "0x%x", &playback_channel_mask); + capture_channel_mask = playback_channel_mask; + } + + set_playback_channel_mode (playback_channel_mode, playback_channel_mask); + set_capture_channel_mode (capture_channel_mode, capture_channel_mask); + pending_state = const_cast (&node); if (_session.state_of_the_state() & Session::Loading) { @@ -196,6 +226,13 @@ MidiTrack::state(bool full_state) root.add_child_nocopy (*freeze_node); } + root.add_property("playback_channel-mode", enum_2_string(get_playback_channel_mode())); + root.add_property("capture_channel-mode", enum_2_string(get_capture_channel_mode())); + snprintf (buf, sizeof(buf), "0x%x", get_playback_channel_mask()); + root.add_property("playback-channel-mask", buf); + snprintf (buf, sizeof(buf), "0x%x", get_capture_channel_mask()); + root.add_property("capture-channel-mask", buf); + root.add_property ("note-mode", enum_2_string (_note_mode)); root.add_property ("step-editing", (_step_editing ? "yes" : "no")); root.add_property ("input-active", (_input_active ? "yes" : "no")); @@ -276,6 +313,12 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame { Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK); if (!lm.locked()) { + boost::shared_ptr diskstream = midi_diskstream(); + framecnt_t playback_distance = diskstream->calculate_playback_distance(nframes); + if (can_internal_playback_seek(std::llabs(playback_distance))) { + /* TODO should declick, and/or note-off */ + internal_playback_seek(playback_distance); + } return 0; } @@ -287,6 +330,9 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame if (!_active) { silence (nframes); + if (_meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled())) { + _meter->reset(); + } return 0; } @@ -300,25 +346,36 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame playback distance to zero, thus causing diskstream::commit to do nothing. */ - dret = diskstream->process (transport_frame, 0, playback_distance); + BufferSet bufs; /* empty set - is OK, since nothing will happen */ + + dret = diskstream->process (bufs, transport_frame, 0, playback_distance, false); need_butler = diskstream->commit (playback_distance); return dret; } + BufferSet& bufs = _session.get_route_buffers (n_process_buffers()); + + fill_buffers_with_input (bufs, _input, nframes); + + if (_meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled())) { + _meter->run (bufs, start_frame, end_frame, nframes, true); + } + + /* filter captured data before the diskstream sees it */ + + filter_channels (bufs, get_capture_channel_mode(), get_capture_channel_mask()); _silent = false; - if ((dret = diskstream->process (transport_frame, nframes, playback_distance)) != 0) { + if ((dret = diskstream->process (bufs, transport_frame, nframes, playback_distance, (monitoring_state() == MonitoringDisk))) != 0) { need_butler = diskstream->commit (playback_distance); silence (nframes); return dret; } - /* special condition applies */ - - if (_meter_point == MeterInput) { - _input->process_input (_meter, start_frame, end_frame, nframes); - } + /* filter playback data before we do anything else */ + + filter_channels (bufs, get_playback_channel_mode(), get_playback_channel_mask ()); if (monitoring_state() == MonitoringInput) { @@ -334,43 +391,17 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame diskstream->flush_playback (start_frame, end_frame); - passthru (start_frame, end_frame, nframes, 0); - - } else { - - /* - XXX is it true that the earlier test on n_outputs() - means that we can avoid checking it again here? i think - so, because changing the i/o configuration of an IO - requires holding the AudioEngine lock, which we hold - while in the process() tree. - */ - - - /* copy the diskstream data to all output buffers */ - - BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers()); - MidiBuffer& mbuf (bufs.get_midi (0)); - - /* we are a MIDI track, so we always start the chain with a single-channel diskstream */ - ChanCount c; - c.set_audio (0); - c.set_midi (1); - bufs.set_count (c); - - diskstream->get_playback (mbuf, nframes); - - /* append immediate messages to the first MIDI buffer (thus sending it to the first output port) */ - - write_out_of_band_data (bufs, start_frame, end_frame, nframes); + } - /* final argument: don't waste time with automation if we're recording or we've just stopped (yes it can happen) */ - - process_output_buffers ( - bufs, start_frame, end_frame, nframes, - declick, (!diskstream->record_enabled() && !_session.transport_stopped()) - ); - } + + /* append immediate messages to the first MIDI buffer (thus sending it to the first output port) */ + + write_out_of_band_data (bufs, start_frame, end_frame, nframes); + + /* final argument: don't waste time with automation if we're not recording or rolling */ + + process_output_buffers (bufs, start_frame, end_frame, nframes, + declick, (!diskstream->record_enabled() && !_session.transport_stopped())); for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { boost::shared_ptr d = boost::dynamic_pointer_cast (*i); @@ -453,6 +484,43 @@ MidiTrack::push_midi_input_to_step_edit_ringbuffer (framecnt_t nframes) } } +void +MidiTrack::filter_channels (BufferSet& bufs, ChannelMode mode, uint32_t mask) +{ + if (mode == AllChannels) { + return; + } + + MidiBuffer& buf (bufs.get_midi (0)); + + for (MidiBuffer::iterator e = buf.begin(); e != buf.end(); ) { + + Evoral::MIDIEvent ev(*e, false); + + if (ev.is_channel_event()) { + switch (mode) { + case FilterChannels: + if (0 == ((1<set_note_mode(m); } +std::string +MidiTrack::describe_parameter (Evoral::Parameter param) +{ + const std::string str(instrument_info().get_controller_name(param)); + return str.empty() ? Automatable::describe_parameter(param) : str; +} + void MidiTrack::midi_panic() { @@ -626,21 +701,53 @@ MidiTrack::write_source (uint32_t) } void -MidiTrack::set_channel_mode (ChannelMode mode, uint16_t mask) +MidiTrack::set_playback_channel_mode(ChannelMode mode, uint16_t mask) { - midi_diskstream()->set_channel_mode (mode, mask); + ChannelMode old = get_playback_channel_mode (); + uint16_t old_mask = get_playback_channel_mask (); + + if (old != mode || mask != old_mask) { + _set_playback_channel_mode (mode, mask); + PlaybackChannelModeChanged (); + _session.set_dirty (); + } } -ChannelMode -MidiTrack::get_channel_mode () +void +MidiTrack::set_capture_channel_mode(ChannelMode mode, uint16_t mask) { - return midi_diskstream()->get_channel_mode (); + ChannelMode old = get_capture_channel_mode (); + uint16_t old_mask = get_capture_channel_mask (); + + if (old != mode || mask != old_mask) { + _set_capture_channel_mode (mode, mask); + CaptureChannelModeChanged (); + _session.set_dirty (); + } } -uint16_t -MidiTrack::get_channel_mask () +void +MidiTrack::set_playback_channel_mask (uint16_t mask) { - return midi_diskstream()->get_channel_mask (); + uint16_t old = get_playback_channel_mask(); + + if (old != mask) { + _set_playback_channel_mask (mask); + PlaybackChannelMaskChanged (); + _session.set_dirty (); + } +} + +void +MidiTrack::set_capture_channel_mask (uint16_t mask) +{ + uint16_t old = get_capture_channel_mask(); + + if (old != mask) { + _set_capture_channel_mask (mask); + CaptureChannelMaskChanged (); + _session.set_dirty (); + } } boost::shared_ptr @@ -728,7 +835,7 @@ MidiTrack::act_on_mute () if (muted()) { /* only send messages for channels we are using */ - uint16_t mask = get_channel_mask(); + uint16_t mask = get_playback_channel_mask(); for (uint8_t channel = 0; channel <= 0xF; channel++) { @@ -772,3 +879,13 @@ MidiTrack::set_monitoring (MonitorChoice mc) } } +MonitorState +MidiTrack::monitoring_state () const +{ + MonitorState ms = Track::monitoring_state(); + if (ms == MonitoringSilence) { + return MonitoringInput; + } + return ms; +} +