mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-06 06:44:57 +01:00
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:
parent
1d8b951500
commit
d89f209f4a
14 changed files with 100 additions and 105 deletions
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ VSTPluginUI::package (Gtk::Window& win)
|
|||
}
|
||||
|
||||
bool
|
||||
VSTPluginUI::configure_handler (GdkEventConfigure* ev)
|
||||
VSTPluginUI::configure_handler (GdkEventConfigure*)
|
||||
{
|
||||
XEvent event;
|
||||
gint x, y;
|
||||
|
|
|
|||
|
|
@ -50,10 +50,6 @@ private:
|
|||
static EventTypeMap event_type_map;
|
||||
};
|
||||
|
||||
enum InternalEventType {
|
||||
LoopEventType = 1000
|
||||
};
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
#endif /* __ardour_event_type_map_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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 "
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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) */
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue