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 "pbd/gstdio_compat.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)) {
208 /* nothing to do: file descriptor is never kept open */
211 /** All stamps in audio frames */
213 SMFSource::read_unlocked (const Lock& lock,
214 Evoral::EventSink<framepos_t>& destination,
215 framepos_t const source_start,
218 Evoral::Range<framepos_t>* loop_range,
219 MidiStateTracker* tracker,
220 MidiChannelFilter* filter) const
223 uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
225 if (writable() && !_open) {
226 /* nothing to read since nothing has ben written */
230 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start %1 duration %2\n", start, duration));
232 // Output parameters for read_event (which will allocate scratch in buffer as needed)
233 uint32_t ev_delta_t = 0;
234 uint32_t ev_type = 0;
235 uint32_t ev_size = 0;
236 uint8_t* ev_buffer = 0;
238 size_t scratch_size = 0; // keep track of scratch to minimize reallocs
240 BeatsFramesConverter converter(_session.tempo_map(), source_start);
242 const uint64_t start_ticks = converter.from(start).to_ticks();
243 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start in ticks %1\n", start_ticks));
245 if (_smf_last_read_end == 0 || start != _smf_last_read_end) {
246 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: seek to %1\n", start));
247 Evoral::SMF::seek_to_start();
248 while (time < start_ticks) {
251 ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
252 if (ret == -1) { // EOF
253 _smf_last_read_end = start + duration;
256 time += ev_delta_t; // accumulate delta time
259 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: set time to %1\n", _smf_last_read_time));
260 time = _smf_last_read_time;
263 _smf_last_read_end = start + duration;
266 gint ignored; /* XXX don't ignore note id's ??*/
268 ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
269 if (ret == -1) { // EOF
273 time += ev_delta_t; // accumulate delta time
274 _smf_last_read_time = time;
276 if (ret == 0) { // meta-event (skipped, just accumulate time)
280 ev_type = midi_parameter_type(ev_buffer[0]);
282 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked delta %1, time %2, buf[0] %3, type %4\n",
283 ev_delta_t, time, ev_buffer[0], ev_type));
285 assert(time >= start_ticks);
287 /* Note that we add on the source start time (in session frames) here so that ev_frame_time
288 is in session frames.
290 const framepos_t ev_frame_time = converter.to(Evoral::Beats::ticks_at_rate(time, ppqn())) + source_start;
293 loop_range->squish (ev_frame_time);
296 if (ev_frame_time < start + duration) {
297 if (!filter || !filter->filter(ev_buffer, ev_size)) {
298 destination.write (ev_frame_time, ev_type, ev_size, ev_buffer);
300 tracker->track(ev_buffer);
307 if (ev_size > scratch_size) {
308 scratch_size = ev_size;
310 ev_size = scratch_size; // ensure read_event only allocates if necessary
317 SMFSource::write_unlocked (const Lock& lock,
318 MidiRingBuffer<framepos_t>& source,
323 mark_streaming_write_started (lock);
327 Evoral::EventType type;
330 size_t buf_capacity = 4;
331 uint8_t* buf = (uint8_t*)malloc(buf_capacity);
333 if (_model && !_model->writing()) {
334 _model->start_write();
337 Evoral::MIDIEvent<framepos_t> ev;
339 /* Get the event time, in frames since session start but ignoring looping. */
341 if (!(ret = source.peek ((uint8_t*)&time, sizeof (time)))) {
342 /* Ring is empty, no more events. */
346 if ((cnt != max_framecnt) &&
347 (time > position + _capture_length + cnt)) {
348 /* The diskstream doesn't want us to write everything, and this
349 event is past the end of this block, so we're done for now. */
353 /* Read the time, type, and size of the event. */
354 if (!(ret = source.read_prefix (&time, &type, &size))) {
355 error << _("Unable to read event prefix, corrupt MIDI ring") << endmsg;
359 /* Enlarge body buffer if necessary now that we know the size. */
360 if (size > buf_capacity) {
362 buf = (uint8_t*)realloc(buf, size);
365 /* Read the event body into buffer. */
366 ret = source.read_contents(size, buf);
368 error << _("Event has time and size but no body, corrupt MIDI ring") << endmsg;
372 /* Convert event time from absolute to source relative. */
373 if (time < position) {
374 error << _("Event time is before MIDI source position") << endmsg;
379 ev.set(buf, size, time);
380 ev.set_event_type(midi_parameter_type(ev.buffer()[0]));
381 ev.set_id(Evoral::next_event_id());
383 if (!(ev.is_channel_event() || ev.is_smf_meta_event() || ev.is_sysex())) {
387 append_event_frames(lock, ev, position);
390 Evoral::SMF::flush ();
396 /** Append an event with a timestamp in beats */
398 SMFSource::append_event_beats (const Glib::Threads::Mutex::Lock& lock,
399 const Evoral::Event<Evoral::Beats>& ev)
401 if (!_writing || ev.size() == 0) {
406 printf("SMFSource: %s - append_event_beats ID = %d time = %lf, size = %u, data = ",
407 name().c_str(), ev.id(), ev.time(), ev.size());
408 for (size_t i = 0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");
411 Evoral::Beats time = ev.time();
412 if (time < _last_ev_time_beats) {
413 const Evoral::Beats difference = _last_ev_time_beats - time;
414 if (difference.to_double() / (double)ppqn() < 1.0) {
415 /* Close enough. This problem occurs because Sequence is not
416 actually ordered due to fuzzy time comparison. I'm pretty sure
417 this is inherently a bad idea which causes problems all over the
418 place, but tolerate it here for now anyway. */
419 time = _last_ev_time_beats;
421 /* Out of order by more than a tick. */
422 warning << string_compose(_("Skipping event with unordered beat time %1 < %2 (off by %3 beats, %4 ticks)"),
423 ev.time(), _last_ev_time_beats, difference, difference.to_double() / (double)ppqn())
429 Evoral::event_id_t event_id;
432 event_id = Evoral::next_event_id();
438 _model->append (ev, event_id);
441 _length_beats = max(_length_beats, time);
443 const Evoral::Beats delta_time_beats = time - _last_ev_time_beats;
444 const uint32_t delta_time_ticks = delta_time_beats.to_ticks(ppqn());
446 Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
447 _last_ev_time_beats = time;
448 _flags = Source::Flag (_flags & ~Empty);
451 /** Append an event with a timestamp in frames (framepos_t) */
453 SMFSource::append_event_frames (const Glib::Threads::Mutex::Lock& lock,
454 const Evoral::Event<framepos_t>& ev,
457 if (!_writing || ev.size() == 0) {
461 // printf("SMFSource: %s - append_event_frames ID = %d time = %u, size = %u, data = ",
462 // name().c_str(), ev.id(), ev.time(), ev.size());
463 // for (size_t i=0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");
465 if (ev.time() < _last_ev_time_frames) {
466 warning << string_compose(_("Skipping event with unordered frame time %1 < %2"),
467 ev.time(), _last_ev_time_frames)
472 BeatsFramesConverter converter(_session.tempo_map(), position);
473 const Evoral::Beats ev_time_beats = converter.from(ev.time());
474 Evoral::event_id_t event_id;
477 event_id = Evoral::next_event_id();
483 const Evoral::Event<Evoral::Beats> beat_ev (ev.event_type(),
486 const_cast<uint8_t*>(ev.buffer()));
487 _model->append (beat_ev, event_id);
490 _length_beats = max(_length_beats, ev_time_beats);
492 const Evoral::Beats last_time_beats = converter.from (_last_ev_time_frames);
493 const Evoral::Beats delta_time_beats = ev_time_beats - last_time_beats;
494 const uint32_t delta_time_ticks = delta_time_beats.to_ticks(ppqn());
496 Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
497 _last_ev_time_frames = ev.time();
498 _flags = Source::Flag (_flags & ~Empty);
502 SMFSource::get_state ()
504 XMLNode& node = MidiSource::get_state();
505 node.add_property (X_("origin"), _origin);
510 SMFSource::set_state (const XMLNode& node, int version)
512 if (Source::set_state (node, version)) {
516 if (MidiSource::set_state (node, version)) {
520 if (FileSource::set_state (node, version)) {
528 SMFSource::mark_streaming_midi_write_started (const Lock& lock, NoteMode mode)
530 if (!_open && open_for_write()) {
531 error << string_compose (_("cannot open MIDI file %1 for write"), _path) << endmsg;
532 /* XXX should probably throw or return something */
536 MidiSource::mark_streaming_midi_write_started (lock, mode);
537 Evoral::SMF::begin_write ();
538 _last_ev_time_beats = Evoral::Beats();
539 _last_ev_time_frames = 0;
543 SMFSource::mark_streaming_write_completed (const Lock& lock)
545 mark_midi_streaming_write_completed (lock, Evoral::Sequence<Evoral::Beats>::DeleteStuckNotes);
549 SMFSource::mark_midi_streaming_write_completed (const Lock& lm, Evoral::Sequence<Evoral::Beats>::StuckNoteOption stuck_notes_option, Evoral::Beats when)
551 MidiSource::mark_midi_streaming_write_completed (lm, stuck_notes_option, when);
554 warning << string_compose ("attempt to write to unwritable SMF file %1", _path) << endmsg;
559 _model->set_edited(false);
562 Evoral::SMF::end_write (_path);
564 /* data in the file now, not removable */
566 mark_nonremovable ();
570 SMFSource::valid_midi_file (const string& file)
572 if (safe_midi_file_extension (file) ) {
573 return (SMF::test (file) );
579 SMFSource::safe_midi_file_extension (const string& file)
581 static regex_t compiled_pattern;
582 static bool compile = true;
583 const int nmatches = 2;
584 regmatch_t matches[nmatches];
586 if (Glib::file_test (file, Glib::FILE_TEST_EXISTS)) {
587 if (!Glib::file_test (file, Glib::FILE_TEST_IS_REGULAR)) {
588 /* exists but is not a regular file */
593 if (compile && regcomp (&compiled_pattern, "\\.[mM][iI][dD][iI]?$", REG_EXTENDED)) {
599 if (regexec (&compiled_pattern, file.c_str(), nmatches, matches, 0)) {
606 static bool compare_eventlist (
607 const std::pair< const Evoral::Event<Evoral::Beats>*, gint >& a,
608 const std::pair< const Evoral::Event<Evoral::Beats>*, gint >& b) {
609 return ( a.first->time() < b.first->time() );
613 SMFSource::load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload)
619 if (_model && !force_reload) {
624 _model = boost::shared_ptr<MidiModel> (new MidiModel (shared_from_this ()));
631 if (writable() && !_open) {
635 _model->start_write();
636 Evoral::SMF::seek_to_start();
638 uint64_t time = 0; /* in SMF ticks */
639 Evoral::Event<Evoral::Beats> ev;
641 uint32_t scratch_size = 0; // keep track of scratch and minimize reallocs
643 uint32_t delta_t = 0;
650 // TODO simplify event allocation
651 std::list< std::pair< Evoral::Event<Evoral::Beats>*, gint > > eventlist;
653 for (unsigned i = 1; i <= num_tracks(); ++i) {
654 if (seek_to_track(i)) continue;
657 have_event_id = false;
659 while ((ret = read_event (&delta_t, &size, &buf, &event_id)) >= 0) {
664 /* meta-event : did we get an event ID ? */
666 have_event_id = true;
672 /* not a meta-event */
674 if (!have_event_id) {
675 event_id = Evoral::next_event_id();
677 const uint32_t event_type = midi_parameter_type(buf[0]);
678 const Evoral::Beats event_time = Evoral::Beats::ticks_at_rate(time, ppqn());
682 for (uint32_t xx = 0; xx < size; ++xx) {
684 snprintf (b, sizeof (b), "0x%x ", buf[xx]);
688 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF %7 load model delta %1, time %2, size %3 buf %4, type %5 id %6\n",
689 delta_t, time, size, ss , event_type, event_id, name()));
692 eventlist.push_back(make_pair (
693 new Evoral::Event<Evoral::Beats> (
694 event_type, event_time,
698 // Set size to max capacity to minimize allocs in read_event
699 scratch_size = std::max(size, scratch_size);
702 _length_beats = max(_length_beats, event_time);
705 /* event ID's must immediately precede the event they are for */
706 have_event_id = false;
710 eventlist.sort(compare_eventlist);
712 std::list< std::pair< Evoral::Event<Evoral::Beats>*, gint > >::iterator it;
713 for (it=eventlist.begin(); it!=eventlist.end(); ++it) {
714 _model->append (*it->first, it->second);
718 // cerr << "----SMF-SRC-----\n";
719 // _playback_buf->dump (cerr);
720 // cerr << "----------------\n";
722 _model->end_write (Evoral::Sequence<Evoral::Beats>::ResolveStuckNotes, _length_beats);
723 _model->set_edited (false);
730 SMFSource::destroy_model (const Glib::Threads::Mutex::Lock& lock)
732 //cerr << _name << " destroying model " << _model.get() << endl;
738 SMFSource::flush_midi (const Lock& lock)
740 if (!writable() || _length_beats == 0.0) {
744 ensure_disk_file (lock);
746 Evoral::SMF::end_write (_path);
747 /* data in the file means its no longer removable */
748 mark_nonremovable ();
754 SMFSource::set_path (const string& p)
756 FileSource::set_path (p);
759 /** Ensure that this source has some file on disk, even if it's just a SMF header */
761 SMFSource::ensure_disk_file (const Lock& lock)
768 /* We have a model, so write it to disk; see MidiSource::session_saved
769 for an explanation of what we are doing here.
771 boost::shared_ptr<MidiModel> mm = _model;
773 mm->sync_to_source (lock);
777 /* No model; if it's not already open, it's an empty source, so create
778 and open it for writing.
787 SMFSource::prevent_deletion ()
789 /* Unlike the audio case, the MIDI file remains mutable (because we can
793 _flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy));