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
This commit is contained in:
Paul Davis 2013-01-08 21:36:42 +00:00
parent 1d8b951500
commit d89f209f4a
14 changed files with 100 additions and 105 deletions

View file

@ -46,7 +46,7 @@ LXVSTPluginUI::~LXVSTPluginUI ()
bool
LXVSTPluginUI::start_updating (GdkEventAny* ignored)
LXVSTPluginUI::start_updating (GdkEventAny*)
{
_screen_update_connection.disconnect();
_screen_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect (mem_fun(*this, &LXVSTPluginUI::resize_callback));
@ -54,7 +54,7 @@ LXVSTPluginUI::start_updating (GdkEventAny* ignored)
}
bool
LXVSTPluginUI::stop_updating (GdkEventAny* ignored)
LXVSTPluginUI::stop_updating (GdkEventAny*)
{
_screen_update_connection.disconnect();
return false;
@ -116,7 +116,7 @@ LXVSTPluginUI::package (Gtk::Window& win)
}
void
LXVSTPluginUI::forward_key_event (GdkEventKey* ev)
LXVSTPluginUI::forward_key_event (GdkEventKey*)
{
std::cerr << "LXVSTPluginUI : keypress forwarding to linuxVSTs unsupported" << std::endl;
}
@ -163,7 +163,7 @@ static error_handler_t vstfx_error_handler;
static error_handler_t gtk_error_handler;
static int
gtk_xerror_handler (Display* disp, XErrorEvent* ev)
gtk_xerror_handler (Display*, XErrorEvent*)
{
std::cerr << "** ERROR ** LXVSTPluginUI : Trapped an X Window System Error" << std::endl;

View file

@ -941,7 +941,7 @@ MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
}
void
MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const & current)
MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
{
using namespace Menu_Helpers;
@ -969,7 +969,7 @@ MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR:
}
void
MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const & current)
MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
{
using namespace Menu_Helpers;

View file

@ -79,7 +79,7 @@ VSTPluginUI::package (Gtk::Window& win)
}
bool
VSTPluginUI::configure_handler (GdkEventConfigure* ev)
VSTPluginUI::configure_handler (GdkEventConfigure*)
{
XEvent event;
gint x, y;

View file

@ -50,10 +50,6 @@ private:
static EventTypeMap event_type_map;
};
enum InternalEventType {
LoopEventType = 1000
};
} // namespace ARDOUR
#endif /* __ardour_event_type_map_h__ */

View file

@ -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

View file

@ -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);

View file

@ -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),

View file

@ -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)

View file

@ -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
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";
Location* loc = loop_location;
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,
(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);
}

View file

@ -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 "

View file

@ -45,93 +45,42 @@ MidiRingBuffer<T>::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<T>::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<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
template<typename T>
void
MidiRingBuffer<T>::flush (framepos_t start, framepos_t end)
MidiRingBuffer<T>::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<T>::reset_tracker ()
_tracker.reset ();
}
template<typename T>
void
MidiRingBuffer<T>::loop_resolve (MidiBuffer& dst, framepos_t t)
{
_tracker.resolve_notes (dst, t);
}
template class MidiRingBuffer<framepos_t>;
} // namespace ARDOUR

View file

@ -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<MidiBuffer::TimeType> ev(*i, false);
if (ev.event_type() == LoopEventType) {
looped = true;
continue;
}
/* catch AllNotesOff message and turn off all notes
*/

View file

@ -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) */

View file

@ -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 ();