Apply MIDI looping patch from torbenh, with minor changes.
General idea: use internal events to mark loop boundaries in MIDI buffers so readers can make sense of timestamps. git-svn-id: svn://localhost/ardour2/branches/3.0@3905 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
c64e96b6a8
commit
15cdf454ea
|
@ -262,9 +262,9 @@ def fetch_git_revision (path):
|
||||||
cmd += "git log --abbrev HEAD^..HEAD "
|
cmd += "git log --abbrev HEAD^..HEAD "
|
||||||
cmd += path
|
cmd += path
|
||||||
output = commands.getoutput (cmd)
|
output = commands.getoutput (cmd)
|
||||||
output = output.splitlines()
|
output = output.splitlines ()
|
||||||
|
|
||||||
rev = output[0].replace( "commit", "git")[0:7]
|
rev = output[0].replace ("commit", "git")[0:10]
|
||||||
for line in output:
|
for line in output:
|
||||||
try:
|
try:
|
||||||
if "git-svn-id" in line:
|
if "git-svn-id" in line:
|
||||||
|
|
|
@ -110,6 +110,7 @@ midi_playlist.cc
|
||||||
midi_port.cc
|
midi_port.cc
|
||||||
midi_region.cc
|
midi_region.cc
|
||||||
midi_source.cc
|
midi_source.cc
|
||||||
|
midi_state_tracker.cc
|
||||||
midi_stretch.cc
|
midi_stretch.cc
|
||||||
midi_track.cc
|
midi_track.cc
|
||||||
mix.cc
|
mix.cc
|
||||||
|
|
|
@ -46,6 +46,10 @@ private:
|
||||||
static EventTypeMap event_type_map;
|
static EventTypeMap event_type_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum InternalEventType {
|
||||||
|
LoopEventType = 1000
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace ARDOUR
|
} // namespace ARDOUR
|
||||||
|
|
||||||
#endif /* __ardour_event_type_map_h__ */
|
#endif /* __ardour_event_type_map_h__ */
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include <ardour/diskstream.h>
|
#include <ardour/diskstream.h>
|
||||||
#include <ardour/midi_playlist.h>
|
#include <ardour/midi_playlist.h>
|
||||||
#include <ardour/midi_ring_buffer.h>
|
#include <ardour/midi_ring_buffer.h>
|
||||||
|
#include <ardour/midi_state_tracker.h>
|
||||||
|
|
||||||
struct tm;
|
struct tm;
|
||||||
|
|
||||||
|
@ -68,7 +69,7 @@ class MidiDiskstream : public Diskstream
|
||||||
float playback_buffer_load() const;
|
float playback_buffer_load() const;
|
||||||
float capture_buffer_load() const;
|
float capture_buffer_load() const;
|
||||||
|
|
||||||
void get_playback(MidiBuffer& dst, nframes_t start, nframes_t end);
|
void get_playback(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t offset);
|
||||||
|
|
||||||
void set_record_enabled (bool yn);
|
void set_record_enabled (bool yn);
|
||||||
|
|
||||||
|
@ -170,13 +171,16 @@ class MidiDiskstream : public Diskstream
|
||||||
|
|
||||||
void engage_record_enable ();
|
void engage_record_enable ();
|
||||||
void disengage_record_enable ();
|
void disengage_record_enable ();
|
||||||
|
void check_note_onoffs(Evoral::MIDIEvent &event);
|
||||||
|
void emit_pending_note_offs(MidiBuffer &dst, nframes_t time);
|
||||||
|
|
||||||
MidiRingBuffer* _playback_buf;
|
MidiRingBuffer* _playback_buf;
|
||||||
MidiRingBuffer* _capture_buf;
|
MidiRingBuffer* _capture_buf;
|
||||||
MidiPort* _source_port;
|
MidiPort* _source_port;
|
||||||
boost::shared_ptr<SMFSource> _write_source;
|
boost::shared_ptr<SMFSource> _write_source;
|
||||||
nframes_t _last_flush_frame;
|
nframes_t _last_flush_frame;
|
||||||
NoteMode _note_mode;
|
NoteMode _note_mode;
|
||||||
|
MidiStateTracker _midistate_tracker;
|
||||||
};
|
};
|
||||||
|
|
||||||
}; /* namespace ARDOUR */
|
}; /* namespace ARDOUR */
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <ardour/types.h>
|
#include <ardour/types.h>
|
||||||
#include <ardour/buffer.h>
|
#include <ardour/buffer.h>
|
||||||
|
#include <ardour/event_type_map.h>
|
||||||
#include <evoral/EventSink.hpp>
|
#include <evoral/EventSink.hpp>
|
||||||
#include <evoral/EventRingBuffer.hpp>
|
#include <evoral/EventRingBuffer.hpp>
|
||||||
|
|
||||||
|
@ -148,6 +149,18 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This event marks a loop happening. this means that
|
||||||
|
// the next events timestamp will be non-monotonic.
|
||||||
|
if (ev_type == LoopEventType) {
|
||||||
|
ev_time -= start;
|
||||||
|
Evoral::MIDIEvent loopevent(LoopEventType, ev_time);
|
||||||
|
dst.push_back(loopevent);
|
||||||
|
|
||||||
|
// We can safely return, without reading the data, because
|
||||||
|
// a LoopEvent does not have data.
|
||||||
|
return count + 1;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
success = full_peek(sizeof(uint8_t), &status);
|
success = full_peek(sizeof(uint8_t), &status);
|
||||||
assert(success); // If this failed, buffer is corrupt, all hope is lost
|
assert(success); // If this failed, buffer is corrupt, all hope is lost
|
||||||
|
@ -168,6 +181,7 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t
|
||||||
|
|
||||||
assert(ev_time >= start);
|
assert(ev_time >= start);
|
||||||
ev_time -= start;
|
ev_time -= start;
|
||||||
|
ev_time += offset;
|
||||||
|
|
||||||
uint8_t* write_loc = dst.reserve(ev_time, ev_size);
|
uint8_t* write_loc = dst.reserve(ev_time, ev_size);
|
||||||
if (write_loc == NULL) {
|
if (write_loc == NULL) {
|
||||||
|
|
|
@ -110,6 +110,7 @@ JackMidiPort::cycle_end (nframes_t nframes, nframes_t offset)
|
||||||
|
|
||||||
for (MidiBuffer::iterator i = _buffer->begin(); i != _buffer->end(); ++i) {
|
for (MidiBuffer::iterator i = _buffer->begin(); i != _buffer->end(); ++i) {
|
||||||
const Evoral::Event& ev = *i;
|
const Evoral::Event& ev = *i;
|
||||||
|
|
||||||
// event times should be frames, relative to cycle start
|
// event times should be frames, relative to cycle start
|
||||||
assert(ev.time() >= 0);
|
assert(ev.time() >= 0);
|
||||||
assert(ev.time() < nframes);
|
assert(ev.time() < nframes);
|
||||||
|
@ -133,7 +134,8 @@ JackMidiPort::flush_buffers (nframes_t nframes, nframes_t offset)
|
||||||
const Evoral::Event& ev = *i;
|
const Evoral::Event& ev = *i;
|
||||||
// event times should be frames, relative to cycle start
|
// event times should be frames, relative to cycle start
|
||||||
assert(ev.time() >= 0);
|
assert(ev.time() >= 0);
|
||||||
assert(ev.time() < nframes);
|
assert(ev.time() < (nframes+offset));
|
||||||
jack_midi_event_write (jack_buffer, (jack_nframes_t) ev.time(), ev.buffer(), ev.size());
|
if (ev.time() >= offset)
|
||||||
|
jack_midi_event_write (jack_buffer, (jack_nframes_t) ev.time(), ev.buffer(), ev.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,13 +110,17 @@ MidiBuffer::read_from(const Buffer& src, nframes_t nframes, nframes_t offset)
|
||||||
|
|
||||||
assert(_capacity >= msrc.size());
|
assert(_capacity >= msrc.size());
|
||||||
|
|
||||||
clear();
|
if (offset == 0) {
|
||||||
assert(_size == 0);
|
clear();
|
||||||
|
assert(_size == 0);
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: slow
|
// FIXME: slow
|
||||||
for (size_t i=0; i < msrc.size(); ++i) {
|
for (size_t i=0; i < msrc.size(); ++i) {
|
||||||
const Evoral::MIDIEvent& ev = msrc[i];
|
const Evoral::MIDIEvent& ev = msrc[i];
|
||||||
if (ev.time() >= offset && ev.time() < offset+nframes) {
|
if (ev.time() < offset)
|
||||||
|
continue;
|
||||||
|
if (ev.time() < (nframes + offset)) {
|
||||||
//cout << "MidiBuffer::read_from got event, " << int(ev.type()) << " time: " << ev.time() << " buffer size: " << _size << endl;
|
//cout << "MidiBuffer::read_from got event, " << int(ev.type()) << " time: " << ev.time() << " buffer size: " << _size << endl;
|
||||||
push_back(ev);
|
push_back(ev);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -728,7 +728,7 @@ MidiDiskstream::read (nframes_t& start, nframes_t dur, bool reversed)
|
||||||
position within the loop.
|
position within the loop.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (loc && start >= loop_end) {
|
if (loc && (start >= loop_end)) {
|
||||||
//cerr << "start adjusted from " << start;
|
//cerr << "start adjusted from " << start;
|
||||||
start = loop_start + ((start - loop_start) % loop_length);
|
start = loop_start + ((start - loop_start) % loop_length);
|
||||||
//cerr << "to " << start << endl;
|
//cerr << "to " << start << endl;
|
||||||
|
@ -774,6 +774,9 @@ MidiDiskstream::read (nframes_t& start, nframes_t dur, bool reversed)
|
||||||
/* if we read to the end of the loop, go back to the beginning */
|
/* if we read to the end of the loop, go back to the beginning */
|
||||||
|
|
||||||
if (reloop) {
|
if (reloop) {
|
||||||
|
// Synthesize LoopEvent here, because the next events
|
||||||
|
// written will have non-monotonic timestamps.
|
||||||
|
_playback_buf->write(loop_end - 1, LoopEventType, 0, 0);
|
||||||
start = loop_start;
|
start = loop_start;
|
||||||
} else {
|
} else {
|
||||||
start += this_read;
|
start += this_read;
|
||||||
|
@ -1435,7 +1438,6 @@ MidiDiskstream::capture_buffer_load () const
|
||||||
(double) _capture_buf->capacity());
|
(double) _capture_buf->capacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
MidiDiskstream::use_pending_capture_data (XMLNode& node)
|
MidiDiskstream::use_pending_capture_data (XMLNode& node)
|
||||||
{
|
{
|
||||||
|
@ -1446,16 +1448,29 @@ MidiDiskstream::use_pending_capture_data (XMLNode& node)
|
||||||
* so that an event at \a start has time = 0
|
* so that an event at \a start has time = 0
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
MidiDiskstream::get_playback(MidiBuffer& dst, nframes_t start, nframes_t end)
|
MidiDiskstream::get_playback(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t offset)
|
||||||
{
|
{
|
||||||
dst.clear();
|
if (offset == 0) {
|
||||||
assert(dst.size() == 0);
|
dst.clear();
|
||||||
|
assert(dst.size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
// Reverse. ... We just don't do reverse, ok? Back off.
|
// Reverse. ... We just don't do reverse, ok? Back off.
|
||||||
if (end <= start) {
|
if (end <= start) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translates stamps to be relative to start
|
// Check only events added this offset cycle
|
||||||
_playback_buf->read(dst, start, end);
|
MidiBuffer::iterator this_cycle_start = dst.end();
|
||||||
|
|
||||||
|
// Translates stamps to be relative to start, but add offset.
|
||||||
|
_playback_buf->read(dst, start, end, offset);
|
||||||
|
|
||||||
|
|
||||||
|
// Now feed the data through the MidiStateTracker.
|
||||||
|
// In case it detects a LoopEvent it will add necessary note
|
||||||
|
// offs.
|
||||||
|
|
||||||
|
if (_midistate_tracker.track(this_cycle_start, dst.end()))
|
||||||
|
_midistate_tracker.resolve_notes(dst, end-start - 1 + offset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -510,7 +510,7 @@ MidiTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
|
||||||
//const size_t limit = n_process_buffers().n_audio();
|
//const size_t limit = n_process_buffers().n_audio();
|
||||||
BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
|
BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
|
||||||
|
|
||||||
diskstream->get_playback(bufs.get_midi(0), start_frame, end_frame);
|
diskstream->get_playback(bufs.get_midi(0), start_frame, end_frame, offset);
|
||||||
|
|
||||||
process_output_buffers (bufs, start_frame, end_frame, nframes, offset,
|
process_output_buffers (bufs, start_frame, end_frame, nframes, offset,
|
||||||
(!_session.get_record_enabled() || !Config->get_do_not_record_plugins()), declick, (_meter_point != MeterInput));
|
(!_session.get_record_enabled() || !Config->get_do_not_record_plugins()), declick, (_meter_point != MeterInput));
|
||||||
|
|
|
@ -970,12 +970,6 @@ Panner::state (bool full)
|
||||||
node.add_property (X_("link_direction"), enum_2_string (_link_direction));
|
node.add_property (X_("link_direction"), enum_2_string (_link_direction));
|
||||||
node.add_property (X_("bypassed"), (bypassed() ? "yes" : "no"));
|
node.add_property (X_("bypassed"), (bypassed() ? "yes" : "no"));
|
||||||
|
|
||||||
snprintf (buf, sizeof (buf), "%d", _streampanners.size());
|
|
||||||
node.add_property (X_("ins"), buf);
|
|
||||||
snprintf (buf, sizeof (buf), "%d", outputs.size());
|
|
||||||
node.add_property (X_("outs"), buf);
|
|
||||||
/* add each output */
|
|
||||||
|
|
||||||
for (vector<Panner::Output>::iterator o = outputs.begin(); o != outputs.end(); ++o) {
|
for (vector<Panner::Output>::iterator o = outputs.begin(); o != outputs.end(); ++o) {
|
||||||
XMLNode* onode = new XMLNode (X_("Output"));
|
XMLNode* onode = new XMLNode (X_("Output"));
|
||||||
snprintf (buf, sizeof (buf), "%.12g", (*o).x);
|
snprintf (buf, sizeof (buf), "%.12g", (*o).x);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user