13
0

Add a new ::render() method to MidiSource that writes to an EventSink

This commit is contained in:
Paul Davis 2024-06-25 22:03:00 -06:00
parent 0986b8d1e8
commit b693d07fcb
3 changed files with 59 additions and 0 deletions

View File

@ -109,6 +109,7 @@ class LIBARDOUR_API MidiSource : virtual public Source
MidiNoteTracker* tracker,
MidiChannelFilter* filter,
const std::set<Evoral::Parameter>& filtered);
virtual void render (const ReaderLock& lock, Evoral::EventSink<Temporal::Beats>& dst) = 0;
/** Write data from a MidiRingBuffer to this source.
* @param lock Reference to the Mutex to lock before modification

View File

@ -79,6 +79,8 @@ public:
/** Query the smf file for its channel info */
SMF::UsedChannels used_midi_channels();
void render (const ReaderLock& lock, Evoral::EventSink<Temporal::Beats>& dst);
protected:
void close ();
void flush_midi (const WriterLock& lock);

View File

@ -217,6 +217,62 @@ SMFSource::close ()
extern PBD::Timing minsert;
void
SMFSource::render (const ReaderLock& lock, Evoral::EventSink<Temporal::Beats>& destination)
{
int ret = 0;
Temporal::Beats time; // in SMF ticks, 1 tick per _ppqn
if (writable() && !_open) {
/* nothing to read since nothing has ben written */
return;
}
// Output parameters for read_event (which will allocate scratch in buffer as needed)
uint32_t ev_delta_t = 0;
uint32_t ev_size = 0;
uint8_t* ev_buffer = 0;
size_t scratch_size = 0; // keep track of scratch to minimize reallocs
/* start of read in SMF ticks (which may differ from our own musical ticks */
Evoral::SMF::seek_to_start();
while (true) {
Evoral::event_id_t ignored; /* XXX don't ignore note id's ??*/
ret = read_event (&ev_delta_t, &ev_size, &ev_buffer, &ignored);
if (ret == -1) { // EOF
break;
}
if (ret == 0) { // meta-event (skipped, just accumulate time)
continue;
}
time += Temporal::Beats::ticks_at_rate (ev_delta_t, ppqn()); // accumulate delta time
DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF render delta %1, time %2, buf[0] %3\n",
ev_delta_t, time, ev_buffer[0]));
/* Note that we add on the source start time (in session samples) here so that ev_sample_time
is in session samples.
*/
destination.write (time, Evoral::MIDI_EVENT, ev_size, ev_buffer);
if (ev_size > scratch_size) {
scratch_size = ev_size;
}
ev_size = scratch_size; // ensure read_event only allocates if necessary
}
_smf_last_read_end = time;
_smf_last_read_time = time;
}
timecnt_t
SMFSource::read_unlocked (const ReaderLock& lock,
Evoral::EventSink<samplepos_t>& destination,