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/midi_model.h"
41 #include "ardour/midi_ring_buffer.h"
42 #include "ardour/midi_state_tracker.h"
43 #include "ardour/parameter_types.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, true)) {
104 throw failed_constructor ();
107 assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
110 if (_flags & Writable) {
111 /* file is not opened until write */
116 throw failed_constructor ();
122 /** Constructor used for existing internal-to-session files. */
123 SMFSource::SMFSource (Session& s, const XMLNode& node, bool must_exist)
125 , MidiSource(s, node)
126 , FileSource(s, node, must_exist)
127 , _last_ev_time_beats(0.0)
128 , _last_ev_time_frames(0)
129 , _smf_last_read_end (0)
130 , _smf_last_read_time (0)
132 if (set_state(node, Stateful::loading_state_version)) {
133 throw failed_constructor ();
136 /* we expect the file to exist, but if no MIDI data was ever added
137 it will have been removed at last session close. so, we don't
138 require it to exist if it was marked Empty.
143 if (init (_path, true)) {
144 throw failed_constructor ();
147 } catch (MissingSource& err) {
149 if (_flags & Source::Empty) {
150 /* we don't care that the file was not found, because
151 it was empty. But FileSource::init() will have
152 failed to set our _path correctly, so we have to do
153 this ourselves. Use the first entry in the search
154 path for MIDI files, which is assumed to be the
155 correct "main" location.
157 std::vector<string> sdirs = s.source_search_path (DataType::MIDI);
158 _path = Glib::build_filename (sdirs.front(), _path);
159 /* This might be important, too */
167 if (!(_flags & Source::Empty)) {
168 assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
171 assert (_flags & Source::Writable);
172 /* file will be opened on write */
177 throw failed_constructor ();
183 SMFSource::~SMFSource ()
186 ::g_unlink (_path.c_str());
191 SMFSource::open_for_write ()
193 if (create (_path)) {
200 /** All stamps in audio frames */
202 SMFSource::read_unlocked (Evoral::EventSink<framepos_t>& destination,
203 framepos_t const source_start,
206 MidiStateTracker* tracker) const
209 uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
211 if (writable() && !_open) {
212 /* nothing to read since nothing has ben written */
216 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start %1 duration %2\n", start, duration));
218 // Output parameters for read_event (which will allocate scratch in buffer as needed)
219 uint32_t ev_delta_t = 0;
220 uint32_t ev_type = 0;
221 uint32_t ev_size = 0;
222 uint8_t* ev_buffer = 0;
224 size_t scratch_size = 0; // keep track of scratch to minimize reallocs
226 BeatsFramesConverter converter(_session.tempo_map(), source_start);
228 const uint64_t start_ticks = (uint64_t)(converter.from(start) * ppqn());
229 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start in ticks %1\n", start_ticks));
231 if (_smf_last_read_end == 0 || start != _smf_last_read_end) {
232 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: seek to %1\n", start));
233 Evoral::SMF::seek_to_start();
234 while (time < start_ticks) {
237 ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
238 if (ret == -1) { // EOF
239 _smf_last_read_end = start + duration;
242 time += ev_delta_t; // accumulate delta time
245 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: set time to %1\n", _smf_last_read_time));
246 time = _smf_last_read_time;
249 _smf_last_read_end = start + duration;
252 gint ignored; /* XXX don't ignore note id's ??*/
254 ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
255 if (ret == -1) { // EOF
259 time += ev_delta_t; // accumulate delta time
260 _smf_last_read_time = time;
262 if (ret == 0) { // meta-event (skipped, just accumulate time)
266 ev_type = midi_parameter_type(ev_buffer[0]);
268 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked delta %1, time %2, buf[0] %3, type %4\n",
269 ev_delta_t, time, ev_buffer[0], ev_type));
271 assert(time >= start_ticks);
273 /* Note that we add on the source start time (in session frames) here so that ev_frame_time
274 is in session frames.
276 const framepos_t ev_frame_time = converter.to(time / (double)ppqn()) + source_start;
278 if (ev_frame_time < start + duration) {
279 destination.write (ev_frame_time, ev_type, ev_size, ev_buffer);
282 if (ev_buffer[0] & MIDI_CMD_NOTE_ON) {
283 tracker->add (ev_buffer[1], ev_buffer[0] & 0xf);
284 } else if (ev_buffer[0] & MIDI_CMD_NOTE_OFF) {
285 tracker->remove (ev_buffer[1], ev_buffer[0] & 0xf);
292 if (ev_size > scratch_size) {
293 scratch_size = ev_size;
295 ev_size = scratch_size; // ensure read_event only allocates if necessary
302 SMFSource::write_unlocked (MidiRingBuffer<framepos_t>& source,
307 mark_streaming_write_started ();
311 Evoral::EventType type;
314 size_t buf_capacity = 4;
315 uint8_t* buf = (uint8_t*)malloc(buf_capacity);
317 if (_model && !_model->writing()) {
318 _model->start_write();
321 Evoral::MIDIEvent<framepos_t> ev;
323 /* Get the event time, in frames since session start but ignoring looping. */
325 if (!(ret = source.peek ((uint8_t*)&time, sizeof (time)))) {
326 /* Ring is empty, no more events. */
330 if ((cnt != max_framecnt) &&
331 (time > position + _capture_length + cnt)) {
332 /* The diskstream doesn't want us to write everything, and this
333 event is past the end of this block, so we're done for now. */
337 /* Read the time, type, and size of the event. */
338 if (!(ret = source.read_prefix (&time, &type, &size))) {
339 error << _("Unable to read event prefix, corrupt MIDI ring") << endmsg;
343 /* Enlarge body buffer if necessary now that we know the size. */
344 if (size > buf_capacity) {
346 buf = (uint8_t*)realloc(buf, size);
349 /* Read the event body into buffer. */
350 ret = source.read_contents(size, buf);
352 error << _("Event has time and size but no body, corrupt MIDI ring") << endmsg;
356 /* Convert event time from absolute to source relative. */
357 if (time < position) {
358 error << _("Event time is before MIDI source position") << endmsg;
363 ev.set(buf, size, time);
364 ev.set_event_type(midi_parameter_type(ev.buffer()[0]));
365 ev.set_id(Evoral::next_event_id());
367 if (!(ev.is_channel_event() || ev.is_smf_meta_event() || ev.is_sysex())) {
371 append_event_unlocked_frames(ev, position);
374 Evoral::SMF::flush ();
380 /** Append an event with a timestamp in beats (double) */
382 SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev)
384 if (!_writing || ev.size() == 0) {
388 /*printf("SMFSource: %s - append_event_unlocked_beats ID = %d time = %lf, size = %u, data = ",
389 name().c_str(), ev.id(), ev.time(), ev.size());
390 for (size_t i = 0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");*/
392 double time = ev.time();
393 if (time < _last_ev_time_beats) {
394 const double difference = _last_ev_time_beats - time;
395 if (difference / (double)ppqn() < 1.0) {
396 /* Close enough. This problem occurs because Sequence is not
397 actually ordered due to fuzzy time comparison. I'm pretty sure
398 this is inherently a bad idea which causes problems all over the
399 place, but tolerate it here for now anyway. */
400 time = _last_ev_time_beats;
402 /* Out of order by more than a tick. */
403 warning << string_compose(_("Skipping event with unordered beat time %1 < %2 (off by %3 beats, %4 ticks)"),
404 ev.time(), _last_ev_time_beats, difference, difference / (double)ppqn())
410 Evoral::event_id_t event_id;
413 event_id = Evoral::next_event_id();
419 _model->append (ev, event_id);
422 _length_beats = max(_length_beats, time);
424 const double delta_time_beats = time - _last_ev_time_beats;
425 const uint32_t delta_time_ticks = (uint32_t)lrint(delta_time_beats * (double)ppqn());
427 Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
428 _last_ev_time_beats = time;
429 _flags = Source::Flag (_flags & ~Empty);
432 /** Append an event with a timestamp in frames (framepos_t) */
434 SMFSource::append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, framepos_t position)
436 if (!_writing || ev.size() == 0) {
440 // printf("SMFSource: %s - append_event_unlocked_frames ID = %d time = %u, size = %u, data = ",
441 // name().c_str(), ev.id(), ev.time(), ev.size());
442 // for (size_t i=0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");
444 if (ev.time() < _last_ev_time_frames) {
445 warning << string_compose(_("Skipping event with unordered frame time %1 < %2"),
446 ev.time(), _last_ev_time_frames)
451 BeatsFramesConverter converter(_session.tempo_map(), position);
452 const double ev_time_beats = converter.from(ev.time());
453 Evoral::event_id_t event_id;
456 event_id = Evoral::next_event_id();
462 const Evoral::Event<double> beat_ev (ev.event_type(),
465 const_cast<uint8_t*>(ev.buffer()));
466 _model->append (beat_ev, event_id);
469 _length_beats = max(_length_beats, ev_time_beats);
471 const Evoral::MusicalTime last_time_beats = converter.from (_last_ev_time_frames);
472 const Evoral::MusicalTime delta_time_beats = ev_time_beats - last_time_beats;
473 const uint32_t delta_time_ticks = (uint32_t)(lrint(delta_time_beats * (double)ppqn()));
475 Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
476 _last_ev_time_frames = ev.time();
477 _flags = Source::Flag (_flags & ~Empty);
481 SMFSource::get_state ()
483 XMLNode& node = MidiSource::get_state();
484 node.add_property (X_("origin"), _origin);
489 SMFSource::set_state (const XMLNode& node, int version)
491 if (Source::set_state (node, version)) {
495 if (MidiSource::set_state (node, version)) {
499 if (FileSource::set_state (node, version)) {
507 SMFSource::mark_streaming_midi_write_started (NoteMode mode)
509 /* CALLER MUST HOLD LOCK */
511 if (!_open && open_for_write()) {
512 error << string_compose (_("cannot open MIDI file %1 for write"), _path) << endmsg;
513 /* XXX should probably throw or return something */
517 MidiSource::mark_streaming_midi_write_started (mode);
518 Evoral::SMF::begin_write ();
519 _last_ev_time_beats = 0.0;
520 _last_ev_time_frames = 0;
524 SMFSource::mark_streaming_write_completed ()
526 mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::DeleteStuckNotes);
530 SMFSource::mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption stuck_notes_option, Evoral::MusicalTime when)
532 Glib::Threads::Mutex::Lock lm (_lock);
533 MidiSource::mark_midi_streaming_write_completed (stuck_notes_option, when);
536 warning << string_compose ("attempt to write to unwritable SMF file %1", _path) << endmsg;
541 _model->set_edited(false);
544 Evoral::SMF::end_write ();
546 /* data in the file now, not removable */
548 mark_nonremovable ();
552 SMFSource::valid_midi_file (const string& file)
554 if (safe_midi_file_extension (file) ) {
555 return (SMF::test (file) );
561 SMFSource::safe_midi_file_extension (const string& file)
563 static regex_t compiled_pattern;
564 static bool compile = true;
565 const int nmatches = 2;
566 regmatch_t matches[nmatches];
568 if (Glib::file_test (file, Glib::FILE_TEST_EXISTS)) {
569 if (!Glib::file_test (file, Glib::FILE_TEST_IS_REGULAR)) {
570 /* exists but is not a regular file */
575 if (compile && regcomp (&compiled_pattern, "\\.[mM][iI][dD][iI]?$", REG_EXTENDED)) {
581 if (regexec (&compiled_pattern, file.c_str(), nmatches, matches, 0)) {
588 static bool compare_eventlist (
589 const std::pair< Evoral::Event<double>*, gint >& a,
590 const std::pair< Evoral::Event<double>*, gint >& b) {
591 return ( a.first->time() < b.first->time() );
595 SMFSource::load_model (bool lock, bool force_reload)
601 boost::shared_ptr<Glib::Threads::Mutex::Lock> lm;
603 lm = boost::shared_ptr<Glib::Threads::Mutex::Lock>(new Glib::Threads::Mutex::Lock(_lock));
605 if (_model && !force_reload) {
610 _model = boost::shared_ptr<MidiModel> (new MidiModel (shared_from_this ()));
615 if (writable() && !_open) {
619 _model->start_write();
620 Evoral::SMF::seek_to_start();
622 uint64_t time = 0; /* in SMF ticks */
623 Evoral::Event<double> ev;
625 uint32_t scratch_size = 0; // keep track of scratch and minimize reallocs
627 uint32_t delta_t = 0;
634 // TODO simplify event allocation
635 std::list< std::pair< Evoral::Event<double>*, gint > > eventlist;
637 for (unsigned i = 1; i <= num_tracks(); ++i) {
638 if (seek_to_track(i)) continue;
641 have_event_id = false;
643 while ((ret = read_event (&delta_t, &size, &buf, &event_id)) >= 0) {
648 /* meta-event : did we get an event ID ? */
650 have_event_id = true;
656 /* not a meta-event */
658 if (!have_event_id) {
659 event_id = Evoral::next_event_id();
661 uint32_t event_type = midi_parameter_type(buf[0]);
662 double event_time = time / (double) ppqn();
666 for (uint32_t xx = 0; xx < size; ++xx) {
668 snprintf (b, sizeof (b), "0x%x ", buf[xx]);
672 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF %6 load model delta %1, time %2, size %3 buf %4, type %5\n",
673 delta_t, time, size, ss , event_type, name()));
676 eventlist.push_back(make_pair (
677 new Evoral::Event<double> (
678 event_type, event_time,
682 // Set size to max capacity to minimize allocs in read_event
683 scratch_size = std::max(size, scratch_size);
686 _length_beats = max(_length_beats, event_time);
689 /* event ID's must immediately precede the event they are for */
690 have_event_id = false;
694 eventlist.sort(compare_eventlist);
696 std::list< std::pair< Evoral::Event<double>*, gint > >::iterator it;
697 for (it=eventlist.begin(); it!=eventlist.end(); ++it) {
698 _model->append (*it->first, it->second);
702 _model->end_write (Evoral::Sequence<Evoral::MusicalTime>::ResolveStuckNotes, _length_beats);
703 _model->set_edited (false);
710 SMFSource::destroy_model ()
712 //cerr << _name << " destroying model " << _model.get() << endl;
717 SMFSource::flush_midi ()
719 if (!writable() || _length_beats == 0.0) {
725 Evoral::SMF::end_write ();
726 /* data in the file means its no longer removable */
727 mark_nonremovable ();
733 SMFSource::set_path (const string& p)
735 FileSource::set_path (p);
736 SMF::set_path (_path);
739 /** Ensure that this source has some file on disk, even if it's just a SMF header */
741 SMFSource::ensure_disk_file ()
748 /* We have a model, so write it to disk; see MidiSource::session_saved
749 for an explanation of what we are doing here.
751 boost::shared_ptr<MidiModel> mm = _model;
753 mm->sync_to_source ();
756 /* No model; if it's not already open, it's an empty source, so create
757 and open it for writing.
766 SMFSource::prevent_deletion ()
768 /* Unlike the audio case, the MIDI file remains mutable (because we can
772 _flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy));