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;
56 /** Constructor used for new internal-to-session files. File cannot exist. */
57 SMFSource::SMFSource (Session& s, const string& path, Source::Flag flags)
58 : Source(s, DataType::MIDI, path, flags)
59 , MidiSource(s, path, flags)
60 , FileSource(s, DataType::MIDI, path, string(), flags)
63 , _last_ev_time_beats(0.0)
64 , _last_ev_time_frames(0)
65 , _smf_last_read_end (0)
66 , _smf_last_read_time (0)
68 /* note that origin remains empty */
70 if (init (_path, false)) {
71 throw failed_constructor ();
74 assert (!Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
77 _flags = Source::Flag (_flags | Empty);
79 /* file is not opened until write */
81 if (flags & Writable) {
86 throw failed_constructor ();
92 /** Constructor used for external-to-session files. File must exist. */
93 SMFSource::SMFSource (Session& s, const string& path)
94 : Source(s, DataType::MIDI, path, Source::Flag (0))
95 , MidiSource(s, path, Source::Flag (0))
96 , FileSource(s, DataType::MIDI, path, string(), Source::Flag (0))
99 , _last_ev_time_beats(0.0)
100 , _last_ev_time_frames(0)
101 , _smf_last_read_end (0)
102 , _smf_last_read_time (0)
104 /* note that origin remains empty */
106 if (init (_path, true)) {
107 throw failed_constructor ();
110 assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
113 if (_flags & Writable) {
114 /* file is not opened until write */
119 throw failed_constructor ();
125 /** Constructor used for existing internal-to-session files. */
126 SMFSource::SMFSource (Session& s, const XMLNode& node, bool must_exist)
128 , MidiSource(s, node)
129 , FileSource(s, node, must_exist)
131 , _last_ev_time_beats(0.0)
132 , _last_ev_time_frames(0)
133 , _smf_last_read_end (0)
134 , _smf_last_read_time (0)
136 if (set_state(node, Stateful::loading_state_version)) {
137 throw failed_constructor ();
140 /* we expect the file to exist, but if no MIDI data was ever added
141 it will have been removed at last session close. so, we don't
142 require it to exist if it was marked Empty.
147 if (init (_path, true)) {
148 throw failed_constructor ();
151 } catch (MissingSource& err) {
153 if (_flags & Source::Empty) {
154 /* we don't care that the file was not found, because
155 it was empty. But FileSource::init() will have
156 failed to set our _path correctly, so we have to do
157 this ourselves. Use the first entry in the search
158 path for MIDI files, which is assumed to be the
159 correct "main" location.
161 std::vector<string> sdirs = s.source_search_path (DataType::MIDI);
162 _path = Glib::build_filename (sdirs.front(), _path);
163 /* This might be important, too */
171 if (!(_flags & Source::Empty)) {
172 assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
175 assert (_flags & Source::Writable);
176 /* file will be opened on write */
181 throw failed_constructor ();
187 SMFSource::~SMFSource ()
190 ::g_unlink (_path.c_str());
195 SMFSource::open_for_write ()
197 if (create (_path)) {
204 /** All stamps in audio frames */
206 SMFSource::read_unlocked (const Lock& lock,
207 Evoral::EventSink<framepos_t>& destination,
208 framepos_t const source_start,
211 MidiStateTracker* tracker) const
214 uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
216 if (writable() && !_open) {
217 /* nothing to read since nothing has ben written */
221 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start %1 duration %2\n", start, duration));
223 // Output parameters for read_event (which will allocate scratch in buffer as needed)
224 uint32_t ev_delta_t = 0;
225 uint32_t ev_type = 0;
226 uint32_t ev_size = 0;
227 uint8_t* ev_buffer = 0;
229 size_t scratch_size = 0; // keep track of scratch to minimize reallocs
231 BeatsFramesConverter converter(_session.tempo_map(), source_start);
233 const uint64_t start_ticks = converter.from(start).to_ticks();
234 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start in ticks %1\n", start_ticks));
236 if (_smf_last_read_end == 0 || start != _smf_last_read_end) {
237 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: seek to %1\n", start));
238 Evoral::SMF::seek_to_start();
239 while (time < start_ticks) {
242 ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
243 if (ret == -1) { // EOF
244 _smf_last_read_end = start + duration;
247 time += ev_delta_t; // accumulate delta time
250 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: set time to %1\n", _smf_last_read_time));
251 time = _smf_last_read_time;
254 _smf_last_read_end = start + duration;
257 gint ignored; /* XXX don't ignore note id's ??*/
259 ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
260 if (ret == -1) { // EOF
264 time += ev_delta_t; // accumulate delta time
265 _smf_last_read_time = time;
267 if (ret == 0) { // meta-event (skipped, just accumulate time)
271 ev_type = midi_parameter_type(ev_buffer[0]);
273 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked delta %1, time %2, buf[0] %3, type %4\n",
274 ev_delta_t, time, ev_buffer[0], ev_type));
276 assert(time >= start_ticks);
278 /* Note that we add on the source start time (in session frames) here so that ev_frame_time
279 is in session frames.
281 const framepos_t ev_frame_time = converter.to(Evoral::MusicalTime::ticks_at_rate(time, ppqn())) + source_start;
283 if (ev_frame_time < start + duration) {
284 destination.write (ev_frame_time, ev_type, ev_size, ev_buffer);
286 tracker->track(ev_buffer);
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 (const Lock& lock,
303 MidiRingBuffer<framepos_t>& source,
308 mark_streaming_write_started (lock);
312 Evoral::EventType type;
315 size_t buf_capacity = 4;
316 uint8_t* buf = (uint8_t*)malloc(buf_capacity);
318 if (_model && !_model->writing()) {
319 _model->start_write();
322 Evoral::MIDIEvent<framepos_t> ev;
324 /* Get the event time, in frames since session start but ignoring looping. */
326 if (!(ret = source.peek ((uint8_t*)&time, sizeof (time)))) {
327 /* Ring is empty, no more events. */
331 if ((cnt != max_framecnt) &&
332 (time > position + _capture_length + cnt)) {
333 /* The diskstream doesn't want us to write everything, and this
334 event is past the end of this block, so we're done for now. */
338 /* Read the time, type, and size of the event. */
339 if (!(ret = source.read_prefix (&time, &type, &size))) {
340 error << _("Unable to read event prefix, corrupt MIDI ring") << endmsg;
344 /* Enlarge body buffer if necessary now that we know the size. */
345 if (size > buf_capacity) {
347 buf = (uint8_t*)realloc(buf, size);
350 /* Read the event body into buffer. */
351 ret = source.read_contents(size, buf);
353 error << _("Event has time and size but no body, corrupt MIDI ring") << endmsg;
357 /* Convert event time from absolute to source relative. */
358 if (time < position) {
359 error << _("Event time is before MIDI source position") << endmsg;
364 ev.set(buf, size, time);
365 ev.set_event_type(midi_parameter_type(ev.buffer()[0]));
366 ev.set_id(Evoral::next_event_id());
368 if (!(ev.is_channel_event() || ev.is_smf_meta_event() || ev.is_sysex())) {
372 append_event_frames(lock, ev, position);
375 Evoral::SMF::flush ();
381 /** Append an event with a timestamp in beats */
383 SMFSource::append_event_beats (const Glib::Threads::Mutex::Lock& lock,
384 const Evoral::Event<Evoral::MusicalTime>& ev)
386 if (!_writing || ev.size() == 0) {
390 /*printf("SMFSource: %s - append_event_beats ID = %d time = %lf, size = %u, data = ",
391 name().c_str(), ev.id(), ev.time(), ev.size());
392 for (size_t i = 0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");*/
394 Evoral::MusicalTime time = ev.time();
395 if (time < _last_ev_time_beats) {
396 const Evoral::MusicalTime difference = _last_ev_time_beats - time;
397 if (difference.to_double() / (double)ppqn() < 1.0) {
398 /* Close enough. This problem occurs because Sequence is not
399 actually ordered due to fuzzy time comparison. I'm pretty sure
400 this is inherently a bad idea which causes problems all over the
401 place, but tolerate it here for now anyway. */
402 time = _last_ev_time_beats;
404 /* Out of order by more than a tick. */
405 warning << string_compose(_("Skipping event with unordered beat time %1 < %2 (off by %3 beats, %4 ticks)"),
406 ev.time(), _last_ev_time_beats, difference, difference.to_double() / (double)ppqn())
412 Evoral::event_id_t event_id;
415 event_id = Evoral::next_event_id();
421 _model->append (ev, event_id);
424 _length_beats = max(_length_beats, time);
426 const Evoral::MusicalTime delta_time_beats = time - _last_ev_time_beats;
427 const uint32_t delta_time_ticks = delta_time_beats.to_ticks(ppqn());
429 Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
430 _last_ev_time_beats = time;
431 _flags = Source::Flag (_flags & ~Empty);
434 /** Append an event with a timestamp in frames (framepos_t) */
436 SMFSource::append_event_frames (const Glib::Threads::Mutex::Lock& lock,
437 const Evoral::Event<framepos_t>& ev,
440 if (!_writing || ev.size() == 0) {
444 // printf("SMFSource: %s - append_event_frames ID = %d time = %u, size = %u, data = ",
445 // name().c_str(), ev.id(), ev.time(), ev.size());
446 // for (size_t i=0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");
448 if (ev.time() < _last_ev_time_frames) {
449 warning << string_compose(_("Skipping event with unordered frame time %1 < %2"),
450 ev.time(), _last_ev_time_frames)
455 BeatsFramesConverter converter(_session.tempo_map(), position);
456 const Evoral::MusicalTime ev_time_beats = converter.from(ev.time());
457 Evoral::event_id_t event_id;
460 event_id = Evoral::next_event_id();
466 const Evoral::Event<Evoral::MusicalTime> beat_ev (ev.event_type(),
469 const_cast<uint8_t*>(ev.buffer()));
470 _model->append (beat_ev, event_id);
473 _length_beats = max(_length_beats, ev_time_beats);
475 const Evoral::MusicalTime last_time_beats = converter.from (_last_ev_time_frames);
476 const Evoral::MusicalTime delta_time_beats = ev_time_beats - last_time_beats;
477 const uint32_t delta_time_ticks = delta_time_beats.to_ticks(ppqn());
479 Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
480 _last_ev_time_frames = ev.time();
481 _flags = Source::Flag (_flags & ~Empty);
485 SMFSource::get_state ()
487 XMLNode& node = MidiSource::get_state();
488 node.add_property (X_("origin"), _origin);
493 SMFSource::set_state (const XMLNode& node, int version)
495 if (Source::set_state (node, version)) {
499 if (MidiSource::set_state (node, version)) {
503 if (FileSource::set_state (node, version)) {
511 SMFSource::mark_streaming_midi_write_started (const Lock& lock, NoteMode mode)
513 if (!_open && open_for_write()) {
514 error << string_compose (_("cannot open MIDI file %1 for write"), _path) << endmsg;
515 /* XXX should probably throw or return something */
519 MidiSource::mark_streaming_midi_write_started (lock, mode);
520 Evoral::SMF::begin_write ();
521 _last_ev_time_beats = Evoral::MusicalTime();
522 _last_ev_time_frames = 0;
526 SMFSource::mark_streaming_write_completed (const Lock& lock)
528 mark_midi_streaming_write_completed (lock, Evoral::Sequence<Evoral::MusicalTime>::DeleteStuckNotes);
532 SMFSource::mark_midi_streaming_write_completed (const Lock& lm, Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption stuck_notes_option, Evoral::MusicalTime when)
534 MidiSource::mark_midi_streaming_write_completed (lm, stuck_notes_option, when);
537 warning << string_compose ("attempt to write to unwritable SMF file %1", _path) << endmsg;
542 _model->set_edited(false);
545 Evoral::SMF::end_write ();
547 /* data in the file now, not removable */
549 mark_nonremovable ();
553 SMFSource::valid_midi_file (const string& file)
555 if (safe_midi_file_extension (file) ) {
556 return (SMF::test (file) );
562 SMFSource::safe_midi_file_extension (const string& file)
564 static regex_t compiled_pattern;
565 static bool compile = true;
566 const int nmatches = 2;
567 regmatch_t matches[nmatches];
569 if (Glib::file_test (file, Glib::FILE_TEST_EXISTS)) {
570 if (!Glib::file_test (file, Glib::FILE_TEST_IS_REGULAR)) {
571 /* exists but is not a regular file */
576 if (compile && regcomp (&compiled_pattern, "\\.[mM][iI][dD][iI]?$", REG_EXTENDED)) {
582 if (regexec (&compiled_pattern, file.c_str(), nmatches, matches, 0)) {
589 static bool compare_eventlist (
590 const std::pair< Evoral::Event<Evoral::MusicalTime>*, gint >& a,
591 const std::pair< Evoral::Event<Evoral::MusicalTime>*, gint >& b) {
592 return ( a.first->time() < b.first->time() );
596 SMFSource::load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload)
602 if (_model && !force_reload) {
607 _model = boost::shared_ptr<MidiModel> (new MidiModel (shared_from_this ()));
614 if (writable() && !_open) {
618 _model->start_write();
619 Evoral::SMF::seek_to_start();
621 uint64_t time = 0; /* in SMF ticks */
622 Evoral::Event<Evoral::MusicalTime> ev;
624 uint32_t scratch_size = 0; // keep track of scratch and minimize reallocs
626 uint32_t delta_t = 0;
633 // TODO simplify event allocation
634 std::list< std::pair< Evoral::Event<Evoral::MusicalTime>*, gint > > eventlist;
636 for (unsigned i = 1; i <= num_tracks(); ++i) {
637 if (seek_to_track(i)) continue;
640 have_event_id = false;
642 while ((ret = read_event (&delta_t, &size, &buf, &event_id)) >= 0) {
647 /* meta-event : did we get an event ID ? */
649 have_event_id = true;
655 /* not a meta-event */
657 if (!have_event_id) {
658 event_id = Evoral::next_event_id();
660 const uint32_t event_type = midi_parameter_type(buf[0]);
661 const Evoral::MusicalTime event_time = Evoral::MusicalTime::ticks_at_rate(time, ppqn());
665 for (uint32_t xx = 0; xx < size; ++xx) {
667 snprintf (b, sizeof (b), "0x%x ", buf[xx]);
671 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF %6 load model delta %1, time %2, size %3 buf %4, type %5\n",
672 delta_t, time, size, ss , event_type, name()));
675 eventlist.push_back(make_pair (
676 new Evoral::Event<Evoral::MusicalTime> (
677 event_type, event_time,
681 // Set size to max capacity to minimize allocs in read_event
682 scratch_size = std::max(size, scratch_size);
685 _length_beats = max(_length_beats, event_time);
688 /* event ID's must immediately precede the event they are for */
689 have_event_id = false;
693 eventlist.sort(compare_eventlist);
695 std::list< std::pair< Evoral::Event<Evoral::MusicalTime>*, gint > >::iterator it;
696 for (it=eventlist.begin(); it!=eventlist.end(); ++it) {
697 _model->append (*it->first, it->second);
701 _model->end_write (Evoral::Sequence<Evoral::MusicalTime>::ResolveStuckNotes, _length_beats);
702 _model->set_edited (false);
709 SMFSource::destroy_model (const Glib::Threads::Mutex::Lock& lock)
711 //cerr << _name << " destroying model " << _model.get() << endl;
717 SMFSource::flush_midi (const Lock& lock)
719 if (!writable() || _length_beats == 0.0) {
723 ensure_disk_file (lock);
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 (const Lock& lock)
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 (lock);
757 /* No model; if it's not already open, it's an empty source, so create
758 and open it for writing.
767 SMFSource::prevent_deletion ()
769 /* Unlike the audio case, the MIDI file remains mutable (because we can
773 _flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy));