diff options
author | David Robillard <d@drobilla.net> | 2013-01-21 06:00:15 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2013-01-21 06:00:15 +0000 |
commit | e781c1cf0d4d16cd08b8dc2d9aedb2b6b9d8cf71 (patch) | |
tree | 7c0cce1bef5968dfef0ca666344a61a58e415f05 /libs/ardour/smf_source.cc | |
parent | 76547b5c4b7fb2d4fbb7db9f12427b439da34a43 (diff) |
Fix MIDI loop recording.
This changes how things work a bit, but I am committing it for 3.0 since the
previous revision often crashed (and never worked), this one seems to work
fine, and the code is quite a bit more cogent.
I have tested the following use cases with live input and audible output:
* Non-loop recording, armed before roll
* Non-loop recording, arm while rolling
* Loop recording, armed before roll
* Loop recording, arm during roll
In the last case, the source/region is created starting at the loop start
rather than the current transport frame as usual so time makes sense when it
wraps around.
See the documentation added to the code for details, but the basic idea here is
to simply push MIDI events to the source with increasing monotonic time,
ignoring looping altogether. Essentially we pretend the loop does not exist,
but the source knows all the details so it can implement whatever behaviour is
appropriate.
Currently, this is simply recording a complete non-destructive copy of the
input, which is a good thing. Perhaps not what the user expects of loop
recording, but at least it works and is one sensible option. We will need to
add more later.
Display while recording is a little bit wacky, but whatever.
git-svn-id: svn://localhost/ardour2/branches/3.0@13940 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour/smf_source.cc')
-rw-r--r-- | libs/ardour/smf_source.cc | 59 |
1 files changed, 27 insertions, 32 deletions
diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index 2b4c7ef7c9..5b42852923 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -211,14 +211,10 @@ SMFSource::read_unlocked (Evoral::EventSink<framepos_t>& destination, return duration; } -/** Write data to this source from a MidiRingBuffer. - * @param source Buffer to read from. - * @param position This source's start position in session frames. - */ framecnt_t SMFSource::write_unlocked (MidiRingBuffer<framepos_t>& source, framepos_t position, - framecnt_t duration) + framecnt_t cnt) { if (!_writing) { mark_streaming_write_started (); @@ -231,55 +227,57 @@ SMFSource::write_unlocked (MidiRingBuffer<framepos_t>& source, size_t buf_capacity = 4; uint8_t* buf = (uint8_t*)malloc(buf_capacity); - if (_model && ! _model->writing()) { + if (_model && !_model->writing()) { _model->start_write(); } Evoral::MIDIEvent<framepos_t> ev; - - // cerr << "SMFSource::write unlocked, begins writing from src buffer with _last_write_end = " << _last_write_end << " dur = " << duration << endl; - while (true) { + /* Get the event time, in frames since session start but ignoring looping. */ bool ret; - if (!(ret = source.peek ((uint8_t*)&time, sizeof (time)))) { - /* no more events to consider */ + /* Ring is empty, no more events. */ break; } - if ((duration != max_framecnt) && (time > (_last_write_end + duration))) { - DEBUG_TRACE (DEBUG::MidiIO, string_compose ("SMFSource::write_unlocked: dropping event @ %1 because it is later than %2 + %3\n", - time, _last_write_end, duration)); + if ((cnt != max_framecnt) && + (time > position + _capture_length + cnt)) { + /* The diskstream doesn't want us to write everything, and this + event is past the end of this block, so we're done for now. */ break; } + /* Read the time, type, and size of the event. */ if (!(ret = source.read_prefix (&time, &type, &size))) { - error << _("Unable to read event prefix, corrupt MIDI ring buffer") << endmsg; + error << _("Unable to read event prefix, corrupt MIDI ring") << endmsg; break; } + /* Enlarge body buffer if necessary now that we know the size. */ if (size > buf_capacity) { buf_capacity = size; buf = (uint8_t*)realloc(buf, size); } + /* Read the event body into buffer. */ ret = source.read_contents(size, buf); if (!ret) { - error << _("Read time/size but not buffer, corrupt MIDI ring buffer") << endmsg; + error << _("Event has time and size but no body, corrupt MIDI ring") << endmsg; break; } - /* convert from session time to time relative to the source start */ - assert(time >= position); + /* Convert event time from absolute to source relative. */ + if (time < position) { + error << _("Event time is before MIDI source position") << endmsg; + break; + } time -= position; - + ev.set(buf, size, time); ev.set_event_type(EventTypeMap::instance().midi_event_type(ev.buffer()[0])); - ev.set_id (Evoral::next_event_id()); + ev.set_id(Evoral::next_event_id()); if (!(ev.is_channel_event() || ev.is_smf_meta_event() || ev.is_sysex())) { - /*cerr << "SMFSource: WARNING: caller tried to write non SMF-Event of type " - << std::hex << int(ev.buffer()[0]) << endl;*/ continue; } @@ -289,16 +287,14 @@ SMFSource::write_unlocked (MidiRingBuffer<framepos_t>& source, Evoral::SMF::flush (); free (buf); - return duration; + return cnt; } - /** Append an event with a timestamp in beats (double) */ void SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev) { - assert(_writing); - if (ev.size() == 0) { + if (!_writing || ev.size() == 0) { return; } @@ -306,9 +302,9 @@ SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev) name().c_str(), ev.id(), ev.time(), ev.size()); for (size_t i = 0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");*/ - assert(ev.time() >= 0); if (ev.time() < _last_ev_time_beats) { - cerr << "SMFSource: Warning: Skipping event with non-monotonic time" << endl; + warning << string_compose(_("Skipping event with unordered time %1"), ev.time()) + << endmsg; return; } @@ -337,9 +333,7 @@ SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev) void SMFSource::append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, framepos_t position) { - assert(_writing); - if (ev.size() == 0) { - cerr << "SMFSource: asked to append zero-size event\n"; + if (!_writing || ev.size() == 0) { return; } @@ -348,7 +342,8 @@ SMFSource::append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, fr // for (size_t i=0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n"); if (ev.time() < _last_ev_time_frames) { - cerr << "SMFSource: Warning: Skipping event with non-monotonic time" << endl; + warning << string_compose(_("Skipping event with unordered time %1"), ev.time()) + << endmsg; return; } |