2 Copyright (C) 2006 Paul Davis
3 Author: David Robillard
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include "pbd/file_utils.h"
30 #include "pbd/stl_delete.h"
31 #include "pbd/strsplit.h"
33 #include <glib/gstdio.h>
34 #include <glibmm/miscutils.h>
35 #include <glibmm/fileutils.h>
37 #include "evoral/Control.hpp"
38 #include "evoral/SMF.hpp"
40 #include "ardour/event_type_map.h"
41 #include "ardour/midi_model.h"
42 #include "ardour/midi_ring_buffer.h"
43 #include "ardour/midi_state_tracker.h"
44 #include "ardour/session.h"
45 #include "ardour/smf_source.h"
46 #include "ardour/debug.h"
50 using namespace ARDOUR;
53 using namespace Evoral;
55 /** Constructor used for new internal-to-session files. File cannot exist. */
56 SMFSource::SMFSource (Session& s, const string& path, Source::Flag flags)
57 : Source(s, DataType::MIDI, path, flags)
58 , MidiSource(s, path, flags)
59 , FileSource(s, DataType::MIDI, path, string(), flags)
61 , _last_ev_time_beats(0.0)
62 , _last_ev_time_frames(0)
63 , _smf_last_read_end (0)
64 , _smf_last_read_time (0)
66 /* note that origin remains empty */
68 if (init (_path, false)) {
69 throw failed_constructor ();
72 assert (!Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
75 _flags = Source::Flag (_flags | Empty);
77 /* file is not opened until write */
79 if (flags & Writable) {
84 throw failed_constructor ();
90 /** Constructor used for external-to-session files. File must exist. */
91 SMFSource::SMFSource (Session& s, const string& path)
92 : Source(s, DataType::MIDI, path, Source::Flag (0))
93 , MidiSource(s, path, Source::Flag (0))
94 , FileSource(s, DataType::MIDI, path, string(), Source::Flag (0))
96 , _last_ev_time_beats(0.0)
97 , _last_ev_time_frames(0)
98 , _smf_last_read_end (0)
99 , _smf_last_read_time (0)
101 /* note that origin remains empty */
103 if (init (_path, false)) {
104 throw failed_constructor ();
107 assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
110 /* file is not opened until write */
112 if (_flags & Writable) {
117 throw failed_constructor ();
123 /** Constructor used for existing internal-to-session files. */
124 SMFSource::SMFSource (Session& s, const XMLNode& node, bool must_exist)
126 , MidiSource(s, node)
127 , FileSource(s, node, must_exist)
128 , _last_ev_time_beats(0.0)
129 , _last_ev_time_frames(0)
130 , _smf_last_read_end (0)
131 , _smf_last_read_time (0)
133 if (set_state(node, Stateful::loading_state_version)) {
134 throw failed_constructor ();
137 /* we expect the file to exist, but if no MIDI data was ever added
138 it will have been removed at last session close. so, we don't
139 require it to exist if it was marked Empty.
142 if (init (_path, !(_flags & Source::Empty))) {
143 throw failed_constructor ();
146 if (!(_flags & Source::Empty)) {
147 assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
150 assert (_flags & Source::Writable);
151 /* file will be opened on write */
156 throw failed_constructor ();
162 SMFSource::~SMFSource ()
165 ::g_unlink (_path.c_str());
170 SMFSource::open_for_write ()
172 if (create (_path)) {
179 /** All stamps in audio frames */
181 SMFSource::read_unlocked (Evoral::EventSink<framepos_t>& destination,
182 framepos_t const source_start,
185 MidiStateTracker* tracker) const
188 uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
190 if (writable() && !_open) {
191 /* nothing to read since nothing has ben written */
195 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start %1 duration %2\n", start, duration));
197 // Output parameters for read_event (which will allocate scratch in buffer as needed)
198 uint32_t ev_delta_t = 0;
199 uint32_t ev_type = 0;
200 uint32_t ev_size = 0;
201 uint8_t* ev_buffer = 0;
203 size_t scratch_size = 0; // keep track of scratch to minimize reallocs
205 BeatsFramesConverter converter(_session.tempo_map(), source_start);
207 const uint64_t start_ticks = (uint64_t)(converter.from(start) * ppqn());
208 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start in ticks %1\n", start_ticks));
210 if (_smf_last_read_end == 0 || start != _smf_last_read_end) {
211 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: seek to %1\n", start));
212 Evoral::SMF::seek_to_start();
213 while (time < start_ticks) {
216 ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
217 if (ret == -1) { // EOF
218 _smf_last_read_end = start + duration;
221 time += ev_delta_t; // accumulate delta time
224 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: set time to %1\n", _smf_last_read_time));
225 time = _smf_last_read_time;
228 _smf_last_read_end = start + duration;
231 gint ignored; /* XXX don't ignore note id's ??*/
233 ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
234 if (ret == -1) { // EOF
238 time += ev_delta_t; // accumulate delta time
239 _smf_last_read_time = time;
241 if (ret == 0) { // meta-event (skipped, just accumulate time)
245 ev_type = EventTypeMap::instance().midi_event_type(ev_buffer[0]);
247 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked delta %1, time %2, buf[0] %3, type %4\n",
248 ev_delta_t, time, ev_buffer[0], ev_type));
250 assert(time >= start_ticks);
252 /* Note that we add on the source start time (in session frames) here so that ev_frame_time
253 is in session frames.
255 const framepos_t ev_frame_time = converter.to(time / (double)ppqn()) + source_start;
257 if (ev_frame_time < start + duration) {
258 destination.write (ev_frame_time, ev_type, ev_size, ev_buffer);
261 if (ev_buffer[0] & MIDI_CMD_NOTE_ON) {
262 tracker->add (ev_buffer[1], ev_buffer[0] & 0xf);
263 } else if (ev_buffer[0] & MIDI_CMD_NOTE_OFF) {
264 tracker->remove (ev_buffer[1], ev_buffer[0] & 0xf);
271 if (ev_size > scratch_size) {
272 scratch_size = ev_size;
274 ev_size = scratch_size; // ensure read_event only allocates if necessary
281 SMFSource::write_unlocked (MidiRingBuffer<framepos_t>& source,
286 mark_streaming_write_started ();
290 Evoral::EventType type;
293 size_t buf_capacity = 4;
294 uint8_t* buf = (uint8_t*)malloc(buf_capacity);
296 if (_model && !_model->writing()) {
297 _model->start_write();
300 Evoral::MIDIEvent<framepos_t> ev;
302 /* Get the event time, in frames since session start but ignoring looping. */
304 if (!(ret = source.peek ((uint8_t*)&time, sizeof (time)))) {
305 /* Ring is empty, no more events. */
309 if ((cnt != max_framecnt) &&
310 (time > position + _capture_length + cnt)) {
311 /* The diskstream doesn't want us to write everything, and this
312 event is past the end of this block, so we're done for now. */
316 /* Read the time, type, and size of the event. */
317 if (!(ret = source.read_prefix (&time, &type, &size))) {
318 error << _("Unable to read event prefix, corrupt MIDI ring") << endmsg;
322 /* Enlarge body buffer if necessary now that we know the size. */
323 if (size > buf_capacity) {
325 buf = (uint8_t*)realloc(buf, size);
328 /* Read the event body into buffer. */
329 ret = source.read_contents(size, buf);
331 error << _("Event has time and size but no body, corrupt MIDI ring") << endmsg;
335 /* Convert event time from absolute to source relative. */
336 if (time < position) {
337 error << _("Event time is before MIDI source position") << endmsg;
342 ev.set(buf, size, time);
343 ev.set_event_type(EventTypeMap::instance().midi_event_type(ev.buffer()[0]));
344 ev.set_id(Evoral::next_event_id());
346 if (!(ev.is_channel_event() || ev.is_smf_meta_event() || ev.is_sysex())) {
350 append_event_unlocked_frames(ev, position);
353 Evoral::SMF::flush ();
359 /** Append an event with a timestamp in beats (double) */
361 SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev)
363 if (!_writing || ev.size() == 0) {
367 /*printf("SMFSource: %s - append_event_unlocked_beats ID = %d time = %lf, size = %u, data = ",
368 name().c_str(), ev.id(), ev.time(), ev.size());
369 for (size_t i = 0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");*/
371 if (ev.time() < _last_ev_time_beats) {
372 warning << string_compose(_("Skipping event with unordered time %1"), ev.time())
377 Evoral::event_id_t event_id;
380 event_id = Evoral::next_event_id();
386 _model->append (ev, event_id);
389 _length_beats = max(_length_beats, ev.time());
391 const double delta_time_beats = ev.time() - _last_ev_time_beats;
392 const uint32_t delta_time_ticks = (uint32_t)lrint(delta_time_beats * (double)ppqn());
394 Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
395 _last_ev_time_beats = ev.time();
396 _flags = Source::Flag (_flags & ~Empty);
399 /** Append an event with a timestamp in frames (framepos_t) */
401 SMFSource::append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, framepos_t position)
403 if (!_writing || ev.size() == 0) {
407 // printf("SMFSource: %s - append_event_unlocked_frames ID = %d time = %u, size = %u, data = ",
408 // name().c_str(), ev.id(), ev.time(), ev.size());
409 // for (size_t i=0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");
411 if (ev.time() < _last_ev_time_frames) {
412 warning << string_compose(_("Skipping event with unordered time %1"), ev.time())
417 BeatsFramesConverter converter(_session.tempo_map(), position);
418 const double ev_time_beats = converter.from(ev.time());
419 Evoral::event_id_t event_id;
422 event_id = Evoral::next_event_id();
428 const Evoral::Event<double> beat_ev (ev.event_type(),
431 const_cast<uint8_t*>(ev.buffer()));
432 _model->append (beat_ev, event_id);
435 _length_beats = max(_length_beats, ev_time_beats);
437 const Evoral::MusicalTime last_time_beats = converter.from (_last_ev_time_frames);
438 const Evoral::MusicalTime delta_time_beats = ev_time_beats - last_time_beats;
439 const uint32_t delta_time_ticks = (uint32_t)(lrint(delta_time_beats * (double)ppqn()));
441 Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
442 _last_ev_time_frames = ev.time();
443 _flags = Source::Flag (_flags & ~Empty);
447 SMFSource::get_state ()
449 XMLNode& node = MidiSource::get_state();
450 node.add_property (X_("origin"), _origin);
455 SMFSource::set_state (const XMLNode& node, int version)
457 if (Source::set_state (node, version)) {
461 if (MidiSource::set_state (node, version)) {
465 if (FileSource::set_state (node, version)) {
473 SMFSource::mark_streaming_midi_write_started (NoteMode mode)
475 /* CALLER MUST HOLD LOCK */
477 if (!_open && open_for_write()) {
478 error << string_compose (_("cannot open MIDI file %1 for write"), _path) << endmsg;
479 /* XXX should probably throw or return something */
483 MidiSource::mark_streaming_midi_write_started (mode);
484 Evoral::SMF::begin_write ();
485 _last_ev_time_beats = 0.0;
486 _last_ev_time_frames = 0;
490 SMFSource::mark_streaming_write_completed ()
492 mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::DeleteStuckNotes);
496 SMFSource::mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption stuck_notes_option, Evoral::MusicalTime when)
498 Glib::Threads::Mutex::Lock lm (_lock);
499 MidiSource::mark_midi_streaming_write_completed (stuck_notes_option, when);
502 warning << string_compose ("attempt to write to unwritable SMF file %1", _path) << endmsg;
507 _model->set_edited(false);
510 Evoral::SMF::end_write ();
512 /* data in the file now, not removable */
514 mark_nonremovable ();
518 SMFSource::valid_midi_file (const string& file)
520 if (safe_midi_file_extension (file) ) {
521 return (SMF::test (file) );
527 SMFSource::safe_midi_file_extension (const string& file)
529 static regex_t compiled_pattern;
530 static bool compile = true;
531 const int nmatches = 2;
532 regmatch_t matches[nmatches];
534 if (Glib::file_test (file, Glib::FILE_TEST_EXISTS)) {
535 if (!Glib::file_test (file, Glib::FILE_TEST_IS_REGULAR)) {
536 /* exists but is not a regular file */
541 if (compile && regcomp (&compiled_pattern, "\\.[mM][iI][dD][iI]?$", REG_EXTENDED)) {
547 if (regexec (&compiled_pattern, file.c_str(), nmatches, matches, 0)) {
554 static bool compare_eventlist (
555 const std::pair< Evoral::Event<double>*, gint >& a,
556 const std::pair< Evoral::Event<double>*, gint >& b) {
557 return ( a.first->time() < b.first->time() );
561 SMFSource::load_model (bool lock, bool force_reload)
567 boost::shared_ptr<Glib::Threads::Mutex::Lock> lm;
569 lm = boost::shared_ptr<Glib::Threads::Mutex::Lock>(new Glib::Threads::Mutex::Lock(_lock));
571 if (_model && !force_reload) {
576 _model = boost::shared_ptr<MidiModel> (new MidiModel (shared_from_this ()));
581 if (writable() && !_open) {
585 _model->start_write();
586 Evoral::SMF::seek_to_start();
588 uint64_t time = 0; /* in SMF ticks */
589 Evoral::Event<double> ev;
591 uint32_t scratch_size = 0; // keep track of scratch and minimize reallocs
593 uint32_t delta_t = 0;
600 // TODO simplify event allocation
601 std::list< std::pair< Evoral::Event<double>*, gint > > eventlist;
603 for (unsigned i = 1; i <= num_tracks(); ++i) {
604 if (seek_to_track(i)) continue;
607 have_event_id = false;
609 while ((ret = read_event (&delta_t, &size, &buf, &event_id)) >= 0) {
614 /* meta-event : did we get an event ID ? */
616 have_event_id = true;
622 /* not a meta-event */
624 if (!have_event_id) {
625 event_id = Evoral::next_event_id();
627 uint32_t event_type = EventTypeMap::instance().midi_event_type(buf[0]);
628 double event_time = time / (double) ppqn();
632 for (uint32_t xx = 0; xx < size; ++xx) {
634 snprintf (b, sizeof (b), "0x%x ", buf[xx]);
638 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF %6 load model delta %1, time %2, size %3 buf %4, type %5\n",
639 delta_t, time, size, ss , event_type, name()));
642 eventlist.push_back(make_pair (
643 new Evoral::Event<double> (
644 event_type, event_time,
648 // Set size to max capacity to minimize allocs in read_event
649 scratch_size = std::max(size, scratch_size);
652 _length_beats = max(_length_beats, event_time);
655 /* event ID's must immediately precede the event they are for */
656 have_event_id = false;
660 eventlist.sort(compare_eventlist);
662 std::list< std::pair< Evoral::Event<double>*, gint > >::iterator it;
663 for (it=eventlist.begin(); it!=eventlist.end(); ++it) {
664 _model->append (*it->first, it->second);
668 _model->end_write (Evoral::Sequence<Evoral::MusicalTime>::ResolveStuckNotes, _length_beats);
669 _model->set_edited (false);
671 _model_iter = _model->begin();
677 SMFSource::destroy_model ()
679 //cerr << _name << " destroying model " << _model.get() << endl;
684 SMFSource::flush_midi ()
686 if (!writable() || _length_beats == 0.0) {
692 Evoral::SMF::end_write ();
693 /* data in the file means its no longer removable */
694 mark_nonremovable ();
698 SMFSource::set_path (const string& p)
700 FileSource::set_path (p);
701 SMF::set_path (_path);
704 /** Ensure that this source has some file on disk, even if it's just a SMF header */
706 SMFSource::ensure_disk_file ()
709 /* We have a model, so write it to disk; see MidiSource::session_saved
710 for an explanation of what we are doing here.
712 boost::shared_ptr<MidiModel> mm = _model;
714 mm->sync_to_source ();
717 /* No model; if it's not already open, it's an empty source, so create
718 and open it for writing.
727 SMFSource::prevent_deletion ()
729 /* Unlike the audio case, the MIDI file remains mutable (because we can
733 _flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy));