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/debug.h"
41 #include "ardour/midi_channel_filter.h"
42 #include "ardour/midi_model.h"
43 #include "ardour/midi_ring_buffer.h"
44 #include "ardour/midi_state_tracker.h"
45 #include "ardour/parameter_types.h"
46 #include "ardour/session.h"
47 #include "ardour/smf_source.h"
51 using namespace ARDOUR;
54 using namespace Evoral;
57 /** Constructor used for new internal-to-session files. File cannot exist. */
58 SMFSource::SMFSource (Session& s, const string& path, Source::Flag flags)
59 : Source(s, DataType::MIDI, path, flags)
60 , MidiSource(s, path, flags)
61 , FileSource(s, DataType::MIDI, path, string(), flags)
64 , _last_ev_time_beats(0.0)
65 , _last_ev_time_frames(0)
66 , _smf_last_read_end (0)
67 , _smf_last_read_time (0)
69 /* note that origin remains empty */
71 if (init (_path, false)) {
72 throw failed_constructor ();
75 assert (!Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
78 _flags = Source::Flag (_flags | Empty);
80 /* file is not opened until write */
82 if (flags & Writable) {
87 throw failed_constructor ();
93 /** Constructor used for external-to-session files. File must exist. */
94 SMFSource::SMFSource (Session& s, const string& path)
95 : Source(s, DataType::MIDI, path, Source::Flag (0))
96 , MidiSource(s, path, Source::Flag (0))
97 , FileSource(s, DataType::MIDI, path, string(), Source::Flag (0))
100 , _last_ev_time_beats(0.0)
101 , _last_ev_time_frames(0)
102 , _smf_last_read_end (0)
103 , _smf_last_read_time (0)
105 /* note that origin remains empty */
107 if (init (_path, true)) {
108 throw failed_constructor ();
111 assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
114 if (_flags & Writable) {
115 /* file is not opened until write */
120 throw failed_constructor ();
126 /** Constructor used for existing internal-to-session files. */
127 SMFSource::SMFSource (Session& s, const XMLNode& node, bool must_exist)
129 , MidiSource(s, node)
130 , FileSource(s, node, must_exist)
132 , _last_ev_time_beats(0.0)
133 , _last_ev_time_frames(0)
134 , _smf_last_read_end (0)
135 , _smf_last_read_time (0)
137 if (set_state(node, Stateful::loading_state_version)) {
138 throw failed_constructor ();
141 /* we expect the file to exist, but if no MIDI data was ever added
142 it will have been removed at last session close. so, we don't
143 require it to exist if it was marked Empty.
148 if (init (_path, true)) {
149 throw failed_constructor ();
152 } catch (MissingSource& err) {
154 if (_flags & Source::Empty) {
155 /* we don't care that the file was not found, because
156 it was empty. But FileSource::init() will have
157 failed to set our _path correctly, so we have to do
158 this ourselves. Use the first entry in the search
159 path for MIDI files, which is assumed to be the
160 correct "main" location.
162 std::vector<string> sdirs = s.source_search_path (DataType::MIDI);
163 _path = Glib::build_filename (sdirs.front(), _path);
164 /* This might be important, too */
172 if (!(_flags & Source::Empty)) {
173 assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
176 assert (_flags & Source::Writable);
177 /* file will be opened on write */
182 throw failed_constructor ();
188 SMFSource::~SMFSource ()
191 ::g_unlink (_path.c_str());
196 SMFSource::open_for_write ()
198 if (create (_path)) {
205 /** All stamps in audio frames */
207 SMFSource::read_unlocked (const Lock& lock,
208 Evoral::EventSink<framepos_t>& destination,
209 framepos_t const source_start,
212 MidiStateTracker* tracker,
213 MidiChannelFilter* filter) const
216 uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
218 if (writable() && !_open) {
219 /* nothing to read since nothing has ben written */
223 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start %1 duration %2\n", start, duration));
225 // Output parameters for read_event (which will allocate scratch in buffer as needed)
226 uint32_t ev_delta_t = 0;
227 uint32_t ev_type = 0;
228 uint32_t ev_size = 0;
229 uint8_t* ev_buffer = 0;
231 size_t scratch_size = 0; // keep track of scratch to minimize reallocs
233 BeatsFramesConverter converter(_session.tempo_map(), source_start);
235 const uint64_t start_ticks = converter.from(start).to_ticks();
236 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start in ticks %1\n", start_ticks));
238 if (_smf_last_read_end == 0 || start != _smf_last_read_end) {
239 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: seek to %1\n", start));
240 Evoral::SMF::seek_to_start();
241 while (time < start_ticks) {
244 ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
245 if (ret == -1) { // EOF
246 _smf_last_read_end = start + duration;
249 time += ev_delta_t; // accumulate delta time
252 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: set time to %1\n", _smf_last_read_time));
253 time = _smf_last_read_time;
256 _smf_last_read_end = start + duration;
259 gint ignored; /* XXX don't ignore note id's ??*/
261 ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
262 if (ret == -1) { // EOF
266 time += ev_delta_t; // accumulate delta time
267 _smf_last_read_time = time;
269 if (ret == 0) { // meta-event (skipped, just accumulate time)
273 ev_type = midi_parameter_type(ev_buffer[0]);
275 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked delta %1, time %2, buf[0] %3, type %4\n",
276 ev_delta_t, time, ev_buffer[0], ev_type));
278 assert(time >= start_ticks);
280 /* Note that we add on the source start time (in session frames) here so that ev_frame_time
281 is in session frames.
283 const framepos_t ev_frame_time = converter.to(Evoral::Beats::ticks_at_rate(time, ppqn())) + source_start;
285 if (ev_frame_time < start + duration) {
286 if (!filter || !filter->filter(ev_buffer, ev_size)) {
287 destination.write (ev_frame_time, ev_type, ev_size, ev_buffer);
289 tracker->track(ev_buffer);
296 if (ev_size > scratch_size) {
297 scratch_size = ev_size;
299 ev_size = scratch_size; // ensure read_event only allocates if necessary
306 SMFSource::write_unlocked (const Lock& lock,
307 MidiRingBuffer<framepos_t>& source,
312 mark_streaming_write_started (lock);
316 Evoral::EventType type;
319 size_t buf_capacity = 4;
320 uint8_t* buf = (uint8_t*)malloc(buf_capacity);
322 if (_model && !_model->writing()) {
323 _model->start_write();
326 Evoral::MIDIEvent<framepos_t> ev;
328 /* Get the event time, in frames since session start but ignoring looping. */
330 if (!(ret = source.peek ((uint8_t*)&time, sizeof (time)))) {
331 /* Ring is empty, no more events. */
335 if ((cnt != max_framecnt) &&
336 (time > position + _capture_length + cnt)) {
337 /* The diskstream doesn't want us to write everything, and this
338 event is past the end of this block, so we're done for now. */
342 /* Read the time, type, and size of the event. */
343 if (!(ret = source.read_prefix (&time, &type, &size))) {
344 error << _("Unable to read event prefix, corrupt MIDI ring") << endmsg;
348 /* Enlarge body buffer if necessary now that we know the size. */
349 if (size > buf_capacity) {
351 buf = (uint8_t*)realloc(buf, size);
354 /* Read the event body into buffer. */
355 ret = source.read_contents(size, buf);
357 error << _("Event has time and size but no body, corrupt MIDI ring") << endmsg;
361 /* Convert event time from absolute to source relative. */
362 if (time < position) {
363 error << _("Event time is before MIDI source position") << endmsg;
368 ev.set(buf, size, time);
369 ev.set_event_type(midi_parameter_type(ev.buffer()[0]));
370 ev.set_id(Evoral::next_event_id());
372 if (!(ev.is_channel_event() || ev.is_smf_meta_event() || ev.is_sysex())) {
376 append_event_frames(lock, ev, position);
379 Evoral::SMF::flush ();
385 /** Append an event with a timestamp in beats */
387 SMFSource::append_event_beats (const Glib::Threads::Mutex::Lock& lock,
388 const Evoral::Event<Evoral::Beats>& ev)
390 if (!_writing || ev.size() == 0) {
394 /*printf("SMFSource: %s - append_event_beats ID = %d time = %lf, size = %u, data = ",
395 name().c_str(), ev.id(), ev.time(), ev.size());
396 for (size_t i = 0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");*/
398 Evoral::Beats time = ev.time();
399 if (time < _last_ev_time_beats) {
400 const Evoral::Beats difference = _last_ev_time_beats - time;
401 if (difference.to_double() / (double)ppqn() < 1.0) {
402 /* Close enough. This problem occurs because Sequence is not
403 actually ordered due to fuzzy time comparison. I'm pretty sure
404 this is inherently a bad idea which causes problems all over the
405 place, but tolerate it here for now anyway. */
406 time = _last_ev_time_beats;
408 /* Out of order by more than a tick. */
409 warning << string_compose(_("Skipping event with unordered beat time %1 < %2 (off by %3 beats, %4 ticks)"),
410 ev.time(), _last_ev_time_beats, difference, difference.to_double() / (double)ppqn())
416 Evoral::event_id_t event_id;
419 event_id = Evoral::next_event_id();
425 _model->append (ev, event_id);
428 _length_beats = max(_length_beats, time);
430 const Evoral::Beats delta_time_beats = time - _last_ev_time_beats;
431 const uint32_t delta_time_ticks = delta_time_beats.to_ticks(ppqn());
433 Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
434 _last_ev_time_beats = time;
435 _flags = Source::Flag (_flags & ~Empty);
438 /** Append an event with a timestamp in frames (framepos_t) */
440 SMFSource::append_event_frames (const Glib::Threads::Mutex::Lock& lock,
441 const Evoral::Event<framepos_t>& ev,
444 if (!_writing || ev.size() == 0) {
448 // printf("SMFSource: %s - append_event_frames ID = %d time = %u, size = %u, data = ",
449 // name().c_str(), ev.id(), ev.time(), ev.size());
450 // for (size_t i=0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");
452 if (ev.time() < _last_ev_time_frames) {
453 warning << string_compose(_("Skipping event with unordered frame time %1 < %2"),
454 ev.time(), _last_ev_time_frames)
459 BeatsFramesConverter converter(_session.tempo_map(), position);
460 const Evoral::Beats ev_time_beats = converter.from(ev.time());
461 Evoral::event_id_t event_id;
464 event_id = Evoral::next_event_id();
470 const Evoral::Event<Evoral::Beats> beat_ev (ev.event_type(),
473 const_cast<uint8_t*>(ev.buffer()));
474 _model->append (beat_ev, event_id);
477 _length_beats = max(_length_beats, ev_time_beats);
479 const Evoral::Beats last_time_beats = converter.from (_last_ev_time_frames);
480 const Evoral::Beats delta_time_beats = ev_time_beats - last_time_beats;
481 const uint32_t delta_time_ticks = delta_time_beats.to_ticks(ppqn());
483 Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
484 _last_ev_time_frames = ev.time();
485 _flags = Source::Flag (_flags & ~Empty);
489 SMFSource::get_state ()
491 XMLNode& node = MidiSource::get_state();
492 node.add_property (X_("origin"), _origin);
497 SMFSource::set_state (const XMLNode& node, int version)
499 if (Source::set_state (node, version)) {
503 if (MidiSource::set_state (node, version)) {
507 if (FileSource::set_state (node, version)) {
515 SMFSource::mark_streaming_midi_write_started (const Lock& lock, NoteMode mode)
517 if (!_open && open_for_write()) {
518 error << string_compose (_("cannot open MIDI file %1 for write"), _path) << endmsg;
519 /* XXX should probably throw or return something */
523 MidiSource::mark_streaming_midi_write_started (lock, mode);
524 Evoral::SMF::begin_write ();
525 _last_ev_time_beats = Evoral::Beats();
526 _last_ev_time_frames = 0;
530 SMFSource::mark_streaming_write_completed (const Lock& lock)
532 mark_midi_streaming_write_completed (lock, Evoral::Sequence<Evoral::Beats>::DeleteStuckNotes);
536 SMFSource::mark_midi_streaming_write_completed (const Lock& lm, Evoral::Sequence<Evoral::Beats>::StuckNoteOption stuck_notes_option, Evoral::Beats when)
538 MidiSource::mark_midi_streaming_write_completed (lm, stuck_notes_option, when);
541 warning << string_compose ("attempt to write to unwritable SMF file %1", _path) << endmsg;
546 _model->set_edited(false);
549 Evoral::SMF::end_write (_path);
551 /* data in the file now, not removable */
553 mark_nonremovable ();
557 SMFSource::valid_midi_file (const string& file)
559 if (safe_midi_file_extension (file) ) {
560 return (SMF::test (file) );
566 SMFSource::safe_midi_file_extension (const string& file)
568 static regex_t compiled_pattern;
569 static bool compile = true;
570 const int nmatches = 2;
571 regmatch_t matches[nmatches];
573 if (Glib::file_test (file, Glib::FILE_TEST_EXISTS)) {
574 if (!Glib::file_test (file, Glib::FILE_TEST_IS_REGULAR)) {
575 /* exists but is not a regular file */
580 if (compile && regcomp (&compiled_pattern, "\\.[mM][iI][dD][iI]?$", REG_EXTENDED)) {
586 if (regexec (&compiled_pattern, file.c_str(), nmatches, matches, 0)) {
593 static bool compare_eventlist (
594 const std::pair< Evoral::Event<Evoral::Beats>*, gint >& a,
595 const std::pair< Evoral::Event<Evoral::Beats>*, gint >& b) {
596 return ( a.first->time() < b.first->time() );
600 SMFSource::load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload)
606 if (_model && !force_reload) {
611 _model = boost::shared_ptr<MidiModel> (new MidiModel (shared_from_this ()));
618 if (writable() && !_open) {
622 _model->start_write();
623 Evoral::SMF::seek_to_start();
625 uint64_t time = 0; /* in SMF ticks */
626 Evoral::Event<Evoral::Beats> ev;
628 uint32_t scratch_size = 0; // keep track of scratch and minimize reallocs
630 uint32_t delta_t = 0;
637 // TODO simplify event allocation
638 std::list< std::pair< Evoral::Event<Evoral::Beats>*, gint > > eventlist;
640 for (unsigned i = 1; i <= num_tracks(); ++i) {
641 if (seek_to_track(i)) continue;
644 have_event_id = false;
646 while ((ret = read_event (&delta_t, &size, &buf, &event_id)) >= 0) {
651 /* meta-event : did we get an event ID ? */
653 have_event_id = true;
659 /* not a meta-event */
661 if (!have_event_id) {
662 event_id = Evoral::next_event_id();
664 const uint32_t event_type = midi_parameter_type(buf[0]);
665 const Evoral::Beats event_time = Evoral::Beats::ticks_at_rate(time, ppqn());
669 for (uint32_t xx = 0; xx < size; ++xx) {
671 snprintf (b, sizeof (b), "0x%x ", buf[xx]);
675 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF %6 load model delta %1, time %2, size %3 buf %4, type %5\n",
676 delta_t, time, size, ss , event_type, name()));
679 eventlist.push_back(make_pair (
680 new Evoral::Event<Evoral::Beats> (
681 event_type, event_time,
685 // Set size to max capacity to minimize allocs in read_event
686 scratch_size = std::max(size, scratch_size);
689 _length_beats = max(_length_beats, event_time);
692 /* event ID's must immediately precede the event they are for */
693 have_event_id = false;
697 eventlist.sort(compare_eventlist);
699 std::list< std::pair< Evoral::Event<Evoral::Beats>*, gint > >::iterator it;
700 for (it=eventlist.begin(); it!=eventlist.end(); ++it) {
701 _model->append (*it->first, it->second);
705 _model->end_write (Evoral::Sequence<Evoral::Beats>::ResolveStuckNotes, _length_beats);
706 _model->set_edited (false);
713 SMFSource::destroy_model (const Glib::Threads::Mutex::Lock& lock)
715 //cerr << _name << " destroying model " << _model.get() << endl;
721 SMFSource::flush_midi (const Lock& lock)
723 if (!writable() || _length_beats == 0.0) {
727 ensure_disk_file (lock);
729 Evoral::SMF::end_write (_path);
730 /* data in the file means its no longer removable */
731 mark_nonremovable ();
737 SMFSource::set_path (const string& p)
739 FileSource::set_path (p);
742 /** Ensure that this source has some file on disk, even if it's just a SMF header */
744 SMFSource::ensure_disk_file (const Lock& lock)
751 /* We have a model, so write it to disk; see MidiSource::session_saved
752 for an explanation of what we are doing here.
754 boost::shared_ptr<MidiModel> mm = _model;
756 mm->sync_to_source (lock);
760 /* No model; if it's not already open, it's an empty source, so create
761 and open it for writing.
770 SMFSource::prevent_deletion ()
772 /* Unlike the audio case, the MIDI file remains mutable (because we can
776 _flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy));