X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fmidi_diskstream.cc;h=485967b2a3ad3b5cea3edd1222117de6502e480b;hb=3aade3801d5ff2c8314eefc4375475f46e913fac;hp=9795d57b5c65d96b7a1dc8cea0e5d11fa6c229f1;hpb=b622bc18fc21de974f08a663996077ac91c98ccb;p=ardour.git diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index 9795d57b5c..485967b2a3 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -16,7 +16,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include @@ -403,17 +402,10 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t } if (nominally_recording || rec_nframes) { - - // Pump entire port buffer into the ring buffer (FIXME: split cycles?) - MidiBuffer& buf = sp->get_midi_buffer(nframes); - ChannelMode mode = AllChannels; - uint32_t mask = 0xffff; - - MidiTrack * mt = dynamic_cast (_track); - if (mt) { - mode = mt->get_capture_channel_mode (); - mask = mt->get_capture_channel_mask (); - } + // Pump entire port buffer into the ring buffer (TODO: split cycles?) + MidiBuffer& buf = sp->get_midi_buffer(nframes); + MidiTrack* mt = dynamic_cast(_track); + MidiChannelFilter* filter = mt ? &mt->capture_filter() : NULL; for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) { Evoral::MIDIEvent ev(*i, false); @@ -421,7 +413,7 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t break; } #ifndef NDEBUG - if (DEBUG::MidiIO & PBD::debug_bits) { + if (DEBUG_ENABLED(DEBUG::MidiIO)) { const uint8_t* __data = ev.buffer(); DEBUG_STR_DECL(a); DEBUG_STR_APPEND(a, string_compose ("mididiskstream %1 capture event @ %2 + %3 sz %4 ", this, ev.time(), transport_frame, ev.size())); @@ -447,31 +439,12 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t const framecnt_t loop_offset = _num_captured_loops * loop_length; const framepos_t event_time = transport_frame + loop_offset - _accumulated_capture_offset + ev.time(); if (event_time < 0 || event_time < first_recordable_frame) { + /* Event out of range, skip */ continue; } - switch (mode) { - case AllChannels: - _capture_buf->write(event_time, - ev.type(), ev.size(), ev.buffer()); - break; - case FilterChannels: - if (ev.is_channel_event()) { - if ((1<write(event_time, - ev.type(), ev.size(), ev.buffer()); - } - } else { - _capture_buf->write(event_time, - ev.type(), ev.size(), ev.buffer()); - } - break; - case ForceChannel: - if (ev.is_channel_event()) { - ev.set_channel (PBD::ffs(mask) - 1); - } - _capture_buf->write(event_time, - ev.type(), ev.size(), ev.buffer()); - break; + + if (!filter || !filter->filter(ev.buffer(), ev.size())) { + _capture_buf->write(event_time, ev.type(), ev.size(), ev.buffer()); } } g_atomic_int_add(const_cast(&_frames_pending_write), nframes); @@ -484,7 +457,7 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t that it can read it if it likes. */ _gui_feed_buffer.clear (); - + for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) { /* This may fail if buf is larger than _gui_feed_buffer, but it's not really the end of the world if it does. @@ -535,7 +508,7 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t if (need_disk_signal) { /* copy the diskstream data to all output buffers */ - + MidiBuffer& mbuf (bufs.get_midi (0)); get_playback (mbuf, playback_distance); @@ -609,7 +582,7 @@ MidiDiskstream::commit (framecnt_t playback_distance) * but we do need to check so that the decision on whether or not we * need the butler is done correctly. */ - + /* furthermore.. * * Doing heavy GUI operations[1] can stall also the butler. @@ -736,6 +709,9 @@ MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed) framecnt_t loop_length = 0; Location* loc = 0; + MidiTrack* mt = dynamic_cast(_track); + MidiChannelFilter* filter = mt ? &mt->playback_filter() : NULL; + if (!reversed) { loc = loop_location; @@ -772,13 +748,13 @@ MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed) this_read = min(dur,this_read); - if (midi_playlist()->read (*_playback_buf, start, this_read) != this_read) { + if (midi_playlist()->read (*_playback_buf, start, this_read, 0, filter) != this_read) { error << string_compose( _("MidiDiskstream %1: cannot read %2 from playlist at frame %3"), id(), this_read, start) << endmsg; return -1; } - + g_atomic_int_add (&_frames_written_to_ringbuffer, this_read); if (reversed) { @@ -807,7 +783,7 @@ MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed) } int -MidiDiskstream::do_refill_with_alloc () +MidiDiskstream::_do_refill_with_alloc (bool /* partial_fill */) { return do_refill(); } @@ -880,8 +856,8 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush) const framecnt_t total = g_atomic_int_get(const_cast (&_frames_pending_write)); - if (total == 0 || - _capture_buf->read_space() == 0 || + if (total == 0 || + _capture_buf->read_space() == 0 || (!force_flush && (total < disk_write_chunk_frames) && was_recording)) { goto out; } @@ -913,7 +889,7 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush) if (_write_source->midi_write (lm, *_capture_buf, get_capture_start_frame (0), to_write) != to_write) { error << string_compose(_("MidiDiskstream %1: cannot write to disk"), id()) << endmsg; return -1; - } + } g_atomic_int_add(const_cast (&_frames_pending_write), -to_write); } @@ -1166,7 +1142,7 @@ MidiDiskstream::finish_capture () void MidiDiskstream::set_record_enabled (bool yn) { - if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_midi() == 0) { + if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_midi() == 0 || record_safe ()) { return; } @@ -1180,22 +1156,44 @@ MidiDiskstream::set_record_enabled (bool yn) } else { disengage_record_enable (); } - + RecordEnableChanged (); /* EMIT SIGNAL */ } } +void +MidiDiskstream::set_record_safe (bool yn) +{ + if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_midi() == 0) { // REQUIRES REVIEW + return; + } + + /* yes, i know that this not proof against race conditions, but its + good enough. i think. + */ + + if (record_safe () != yn) { + if (yn) { + engage_record_safe (); + } else { + disengage_record_safe (); + } + + RecordSafeChanged (); /* EMIT SIGNAL */ + } +} + bool MidiDiskstream::prep_record_enable () { - if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_midi() == 0) { + if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_midi() == 0 || record_safe ()) { // REQUIRES REVIEW "|| record_safe ()" return false; } bool const rolling = _session.transport_speed() != 0.0f; boost::shared_ptr sp = _source_port.lock (); - + if (sp && Config->get_monitoring_model() == HardwareMonitoring) { sp->request_input_monitoring (!(_session.config.get_auto_input() && rolling)); } @@ -1322,14 +1320,14 @@ MidiDiskstream::steal_write_source_name () try { string new_path = _session.new_midi_source_path (name()); - + if (_write_source->rename (new_path)) { return string(); } } catch (...) { return string (); } - + return our_old_name; } @@ -1361,7 +1359,7 @@ void MidiDiskstream::ensure_input_monitoring (bool yn) { boost::shared_ptr sp = _source_port.lock (); - + if (sp) { sp->ensure_input_monitoring (yn); } @@ -1386,7 +1384,7 @@ float MidiDiskstream::playback_buffer_load () const { /* For MIDI it's not trivial to differentiate the following two cases: - + 1. The playback buffer is empty because the system has run out of time to fill it. 2. The playback buffer is empty because there is no more data on the playlist. @@ -1394,7 +1392,7 @@ MidiDiskstream::playback_buffer_load () const cannot keep up when #2 happens, when in fact it can. Since MIDI data rates are so low compared to audio, just give a pretend answer here. */ - + return 1; } @@ -1402,7 +1400,7 @@ float MidiDiskstream::capture_buffer_load () const { /* We don't report playback buffer load, so don't report capture load either */ - + return 1; } @@ -1431,14 +1429,15 @@ MidiDiskstream::get_playback (MidiBuffer& dst, framecnt_t nframes) DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ( "%1 MDS pre-read read %8 @ %4..%5 from %2 write to %3, LOOPED ? %6-%7\n", _name, - _playback_buf->get_read_ptr(), _playback_buf->get_write_ptr(), playback_sample, playback_sample + nframes, + _playback_buf->get_read_ptr(), _playback_buf->get_write_ptr(), playback_sample, playback_sample + nframes, (loc ? loc->start() : -1), (loc ? loc->end() : -1), nframes)); // cerr << "================\n"; // _playback_buf->dump (cerr); // cerr << "----------------\n"; - size_t events_read = 0; + size_t events_read = 0; + const size_t split_cycle_offset = Port::port_offset (); if (loc) { framepos_t effective_start; @@ -1448,7 +1447,7 @@ MidiDiskstream::get_playback (MidiBuffer& dst, framecnt_t nframes) } else { effective_start = playback_sample; } - + DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("looped, effective start adjusted to %1\n", effective_start)); if (effective_start == loc->start()) { @@ -1456,11 +1455,13 @@ MidiDiskstream::get_playback (MidiBuffer& dst, framecnt_t nframes) beyond the loop end. */ - _playback_buf->resolve_tracker (dst, 0); + _playback_buf->resolve_tracker (dst, split_cycle_offset); } _playback_buf->skip_to (effective_start); + /* for split-cycles we need to offset the events */ + if (loc->end() >= effective_start && loc->end() < effective_start + nframes) { /* end of loop is within the range we are reading, so split the read in two, and lie about the location @@ -1477,23 +1478,23 @@ MidiDiskstream::get_playback (MidiBuffer& dst, framecnt_t nframes) if (first) { DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("loop read #1, from %1 for %2\n", effective_start, first)); - events_read = _playback_buf->read (dst, effective_start, first); - } + events_read = _playback_buf->read (dst, effective_start, first, split_cycle_offset); + } if (second) { DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("loop read #2, from %1 for %2\n", loc->start(), second)); - events_read += _playback_buf->read (dst, loc->start(), second); + events_read += _playback_buf->read (dst, loc->start(), second, split_cycle_offset); } - + } else { DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("loop read #3, adjusted start as %1 for %2\n", effective_start, nframes)); - events_read = _playback_buf->read (dst, effective_start, effective_start + nframes); + events_read = _playback_buf->read (dst, effective_start, effective_start + nframes, split_cycle_offset); } } else { _playback_buf->skip_to (playback_sample); - events_read = _playback_buf->read (dst, playback_sample, playback_sample + nframes); + events_read = _playback_buf->read (dst, playback_sample, playback_sample + nframes, split_cycle_offset); } DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ( @@ -1536,7 +1537,7 @@ boost::shared_ptr MidiDiskstream::get_gui_feed_buffer () const { boost::shared_ptr b (new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI))); - + Glib::Threads::Mutex::Lock lm (_gui_feed_buffer_mutex); b->copy (_gui_feed_buffer); return b; @@ -1554,6 +1555,19 @@ MidiDiskstream::reset_tracker () } } +void +MidiDiskstream::resolve_tracker (Evoral::EventSink& buffer, framepos_t time) +{ + _playback_buf->resolve_tracker(buffer, time); + + boost::shared_ptr mp (midi_playlist()); + + if (mp) { + mp->reset_note_trackers (); + } +} + + boost::shared_ptr MidiDiskstream::midi_playlist () {