From d89f209f4a8e94c06de2895ff6fd1830c0e5419d Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 8 Jan 2013 21:36:42 +0000 Subject: tentative redesign of MIDI looping, will probably fix #5050 but needs more extensive testing; remove several unused parameter names git-svn-id: svn://localhost/ardour2/branches/3.0@13810 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/event_type_map.h | 4 -- libs/ardour/ardour/midi_ring_buffer.h | 3 +- libs/ardour/ardour/midi_state_tracker.h | 2 +- libs/ardour/automation_list.cc | 2 +- libs/ardour/lv2_plugin.cc | 2 +- libs/ardour/midi_diskstream.cc | 78 +++++++++++++++++++++++++++------ libs/ardour/midi_port.cc | 5 --- libs/ardour/midi_ring_buffer.cc | 76 +++++++------------------------- libs/ardour/midi_state_tracker.cc | 10 +---- libs/ardour/midi_track.cc | 2 + libs/ardour/plugin.cc | 5 +-- 11 files changed, 92 insertions(+), 97 deletions(-) (limited to 'libs') diff --git a/libs/ardour/ardour/event_type_map.h b/libs/ardour/ardour/event_type_map.h index 5068029db7..02852e9711 100644 --- a/libs/ardour/ardour/event_type_map.h +++ b/libs/ardour/ardour/event_type_map.h @@ -50,10 +50,6 @@ private: static EventTypeMap event_type_map; }; -enum InternalEventType { - LoopEventType = 1000 -}; - } // namespace ARDOUR #endif /* __ardour_event_type_map_h__ */ diff --git a/libs/ardour/ardour/midi_ring_buffer.h b/libs/ardour/ardour/midi_ring_buffer.h index f4580b37a6..7f5774054a 100644 --- a/libs/ardour/ardour/midi_ring_buffer.h +++ b/libs/ardour/ardour/midi_ring_buffer.h @@ -79,7 +79,8 @@ public: } void reset_tracker (); - + void loop_resolve (MidiBuffer& dst, framepos_t); + protected: inline bool is_channel_event(uint8_t event_type_byte) { // mask out channel information diff --git a/libs/ardour/ardour/midi_state_tracker.h b/libs/ardour/ardour/midi_state_tracker.h index 64e4aace2d..24d3ab73a1 100644 --- a/libs/ardour/ardour/midi_state_tracker.h +++ b/libs/ardour/ardour/midi_state_tracker.h @@ -37,7 +37,7 @@ class MidiStateTracker public: MidiStateTracker(); - void track (const MidiBuffer::iterator& from, const MidiBuffer::iterator& to, bool& looped); + void track (const MidiBuffer::iterator& from, const MidiBuffer::iterator& to); void add (uint8_t note, uint8_t chn); void remove (uint8_t note, uint8_t chn); void resolve_notes (MidiBuffer& buffer, framepos_t time); diff --git a/libs/ardour/automation_list.cc b/libs/ardour/automation_list.cc index 00d9f624ed..83df92488b 100644 --- a/libs/ardour/automation_list.cc +++ b/libs/ardour/automation_list.cc @@ -204,7 +204,7 @@ AutomationList::start_touch (double when) } void -AutomationList::stop_touch (bool mark, double when) +AutomationList::stop_touch (bool mark, double) { if (g_atomic_int_get (&_touching) == 0) { /* this touch has already been stopped (probably by Automatable::transport_stopped), diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc index 3c557b7d2f..85605d346a 100644 --- a/libs/ardour/lv2_plugin.cc +++ b/libs/ardour/lv2_plugin.cc @@ -175,7 +175,7 @@ work_respond(LV2_Worker_Respond_Handle handle, /* log extension */ static int -log_vprintf(LV2_Log_Handle handle, +log_vprintf(LV2_Log_Handle /*handle*/, LV2_URID type, const char* fmt, va_list args) diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index ede50370de..c151b776c2 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -613,7 +613,7 @@ MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed) id(), this_read, start) << endmsg; return -1; } - + g_atomic_int_add (&_frames_written_to_ringbuffer, this_read); if (reversed) { @@ -625,11 +625,9 @@ MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed) } else { /* if we read to the end of the loop, go back to the beginning */ - if (reloop) { // Synthesize LoopEvent here, because the next events // written will have non-monotonic timestamps. - _playback_buf->write(loop_end - 1, LoopEventType, sizeof (framepos_t), (uint8_t *) &loop_start); start = loop_start; } else { start += this_read; @@ -1297,23 +1295,77 @@ MidiDiskstream::get_playback (MidiBuffer& dst, framecnt_t nframes) dst.clear(); assert(dst.size() == 0); -#ifndef NDEBUG + Location* loc = loop_location; + DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ( - "%1 MDS pre-read read %4..%5 from %2 write to %3\n", _name, - _playback_buf->get_read_ptr(), _playback_buf->get_write_ptr(), playback_sample, playback_sample + nframes)); -// cerr << "================\n"; -// _playback_buf->dump (cerr); -// cerr << "----------------\n"; + "%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, + (loc ? loc->start() : -1), (loc ? loc->end() : -1), nframes)); + + // cerr << "================\n"; + // _playback_buf->dump (cerr); + // cerr << "----------------\n"; + + size_t events_read = 0; + + if (loc) { + framepos_t effective_start; + + if (playback_sample >= loc->end()) { + effective_start = loc->start() + ((playback_sample - loc->end()) % loc->length()); + } 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()) { + /* We need to turn off notes that may extend + beyond the loop end. + */ + + _playback_buf->loop_resolve (dst, 0); + } + + 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 + for the 2nd read + */ + framecnt_t first, second; + + first = loc->end() - effective_start; + second = nframes - first; + + DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("loop read for eff %1 end %2: %3 and %4\n", + effective_start, loc->end(), first, second)); + + 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); + } + + 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); + } + + } 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); + } + } else { + events_read = _playback_buf->read (dst, playback_sample, playback_sample + nframes); + } - const size_t events_read = _playback_buf->read (dst, playback_sample, playback_sample + nframes); DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ( "%1 MDS events read %2 range %3 .. %4 rspace %5 wspace %6 r@%7 w@%8\n", _name, events_read, playback_sample, playback_sample + nframes, _playback_buf->read_space(), _playback_buf->write_space(), _playback_buf->get_read_ptr(), _playback_buf->get_write_ptr())); -#else - _playback_buf->read (dst, playback_sample, playback_sample + nframes); -#endif g_atomic_int_add (&_frames_read_from_ringbuffer, nframes); } diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc index 63004f658b..0856666159 100644 --- a/libs/ardour/midi_port.cc +++ b/libs/ardour/midi_port.cc @@ -170,11 +170,6 @@ MidiPort::flush_buffers (pframes_t nframes) assert (ev.time() < (nframes + _global_port_buffer_offset + _port_buffer_offset)); - if (ev.event_type() == LoopEventType) { - resolve_notes (jack_buffer, ev.time()); - continue; - } - if (ev.time() >= _global_port_buffer_offset + _port_buffer_offset) { if (jack_midi_event_write (jack_buffer, (jack_nframes_t) ev.time(), ev.buffer(), ev.size()) != 0) { cerr << "write failed, drop flushed note off on the floor, time " diff --git a/libs/ardour/midi_ring_buffer.cc b/libs/ardour/midi_ring_buffer.cc index 786ed3c080..0f08247cb9 100644 --- a/libs/ardour/midi_ring_buffer.cc +++ b/libs/ardour/midi_ring_buffer.cc @@ -45,93 +45,42 @@ MidiRingBuffer::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame T ev_time; Evoral::EventType ev_type; uint32_t ev_size; - - /* If we see the end of a loop during this read, we must write the events after it - to the MidiBuffer with adjusted times. The situation is as follows: - - session frames-----------------------------> - - | | | - start_of_loop start end_of_loop - - The MidiDiskstream::read method which will have happened before this checks for - loops ending, and helpfully inserts a magic LoopEvent into the ringbuffer. After this, - the MidiDiskstream continues to write events with their proper session frame times, - so after the LoopEvent event times will go backwards (ie non-monotonically). - - Once we hit end_of_loop, we need to fake it to make it look as though the loop has been - immediately repeated. Say that an event E after the end_of_loop in the ringbuffer - has time E_t, which is a time in session frames. Its offset from the start - of the loop will be E_t - start_of_loop. Its `faked' time will therefore be - end_of_loop + E_t - start_of_loop. And so its port-buffer-relative time (for - writing to the MidiBuffer) will be end_of_loop + E_t - start_of_loop - start. - - The subtraction of start is already taken care of, so if we see a LoopEvent, we'll - set up loop_offset to equal end_of_loop - start_of_loop, so that given an event - time E_t in the ringbuffer we can get the port-buffer-relative time as - E_t + offset - start. - */ - - frameoffset_t loop_offset = 0; - - size_t count = 0; - - const size_t prefix_size = sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t); + size_t count = 0; + const size_t prefix_size = sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t); while (this->read_space() >= prefix_size) { uint8_t peekbuf[prefix_size]; - bool success; - success = this->peek (peekbuf, prefix_size); /* this cannot fail, because we've already verified that there is prefix_space to read */ - assert (success); + assert (this->peek (peekbuf, prefix_size)); ev_time = *((T*) peekbuf); ev_type = *((Evoral::EventType*)(peekbuf + sizeof (T))); ev_size = *((uint32_t*)(peekbuf + sizeof(T) + sizeof (Evoral::EventType))); - if (ev_time + loop_offset >= end) { + if (ev_time >= end) { DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 past end @ %2\n", ev_time, end)); break; - } else if (ev_time + loop_offset < start) { + } else if (ev_time < start) { DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 before start @ %2\n", ev_time, start)); - this->increment_read_ptr (prefix_size); - this->increment_read_ptr (ev_size); - continue; + break; } else { DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 in range %2 .. %3\n", ev_time, start, end)); } - assert(ev_time >= start); - ev_time -= start; ev_time += offset; - // This event marks a loop end (i.e. the next event's timestamp - // will be non-monotonic). Don't write it into the buffer - the - // significance of this event ends here. - - if (ev_type == LoopEventType) { - assert (ev_size == sizeof (framepos_t)); - framepos_t loop_start; - read_contents (ev_size, (uint8_t *) &loop_start); - loop_offset = ev_time - loop_start; - _tracker.resolve_notes (dst, ev_time); - continue; - } - /* we're good to go ahead and read the data now but since we * have the prefix data already, just skip over that */ this->increment_read_ptr (prefix_size); - ev_time += loop_offset; uint8_t status; - success = this->peek (&status, sizeof(uint8_t)); - assert(success); // If this failed, buffer is corrupt, all hope is lost + assert (this->peek (&status, sizeof(uint8_t))); // If this failed, buffer is corrupt, all hope is lost // Ignore event if it doesn't match channel filter if (is_channel_event(status) && get_channel_mode() == FilterChannels) { @@ -158,7 +107,7 @@ MidiRingBuffer::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame } // write MIDI buffer contents - success = read_contents (ev_size, write_loc); + bool success = read_contents (ev_size, write_loc); #ifndef NDEBUG if (DEBUG::MidiDiskstreamIO && PBD::debug_bits) { @@ -197,7 +146,7 @@ MidiRingBuffer::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame template void -MidiRingBuffer::flush (framepos_t start, framepos_t end) +MidiRingBuffer::flush (framepos_t /*start*/, framepos_t end) { const size_t prefix_size = sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t); @@ -310,6 +259,13 @@ MidiRingBuffer::reset_tracker () _tracker.reset (); } +template +void +MidiRingBuffer::loop_resolve (MidiBuffer& dst, framepos_t t) +{ + _tracker.resolve_notes (dst, t); +} + template class MidiRingBuffer; } // namespace ARDOUR diff --git a/libs/ardour/midi_state_tracker.cc b/libs/ardour/midi_state_tracker.cc index 99a6cd991d..73b6fb639e 100644 --- a/libs/ardour/midi_state_tracker.cc +++ b/libs/ardour/midi_state_tracker.cc @@ -94,18 +94,12 @@ MidiStateTracker::remove (uint8_t note, uint8_t chn) } void -MidiStateTracker::track (const MidiBuffer::iterator &from, const MidiBuffer::iterator &to, bool& looped) +MidiStateTracker::track (const MidiBuffer::iterator &from, const MidiBuffer::iterator &to) { - looped = false; - - // DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1 track notes, looped = %2\n", this, looped)); + // DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1 track notes\n", this)); for (MidiBuffer::iterator i = from; i != to; ++i) { const Evoral::MIDIEvent ev(*i, false); - if (ev.event_type() == LoopEventType) { - looped = true; - continue; - } /* catch AllNotesOff message and turn off all notes */ diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index 7f2bb641e1..525db3ab96 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -360,6 +360,8 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame c.set_midi (1); bufs.set_count (c); + assert (nframes > 0); + diskstream->get_playback (mbuf, nframes); /* append immediate messages to the first MIDI buffer (thus sending it to the first output port) */ diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc index 9f39e06787..57198475d7 100644 --- a/libs/ardour/plugin.cc +++ b/libs/ardour/plugin.cc @@ -256,9 +256,8 @@ Plugin::connect_and_run (BufferSet& bufs, /* Track notes that we are sending to the plugin */ MidiBuffer& b = bufs.get_midi (0); - bool looped; - _tracker.track (b.begin(), b.end(), looped); + _tracker.track (b.begin(), b.end()); if (_have_pending_stop_events) { /* Transmit note-offs that are pending from the last transport stop */ @@ -339,7 +338,7 @@ Plugin::clear_preset () /** @param val `plugin' value */ void -Plugin::set_parameter (uint32_t which, float val) +Plugin::set_parameter (uint32_t which, float) { _parameter_changed_since_last_preset = true; _session.set_dirty (); -- cgit v1.2.3