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 MidiStateTracker* tracker,
219 MidiChannelFilter* filter) const
222 uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
224 if (writable() && !_open) {
225 /* nothing to read since nothing has ben written */
229 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start %1 duration %2\n", start, duration));
231 // Output parameters for read_event (which will allocate scratch in buffer as needed)
232 uint32_t ev_delta_t = 0;
233 uint32_t ev_type = 0;
234 uint32_t ev_size = 0;
235 uint8_t* ev_buffer = 0;
237 size_t scratch_size = 0; // keep track of scratch to minimize reallocs
239 BeatsFramesConverter converter(_session.tempo_map(), source_start);
241 const uint64_t start_ticks = converter.from(start).to_ticks();
242 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start in ticks %1\n", start_ticks));
244 if (_smf_last_read_end == 0 || start != _smf_last_read_end) {
245 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: seek to %1\n", start));
246 Evoral::SMF::seek_to_start();
247 while (time < start_ticks) {
250 ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
251 if (ret == -1) { // EOF
252 _smf_last_read_end = start + duration;
255 time += ev_delta_t; // accumulate delta time
258 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: set time to %1\n", _smf_last_read_time));
259 time = _smf_last_read_time;
262 _smf_last_read_end = start + duration;
265 gint ignored; /* XXX don't ignore note id's ??*/
267 ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
268 if (ret == -1) { // EOF
272 time += ev_delta_t; // accumulate delta time
273 _smf_last_read_time = time;
275 if (ret == 0) { // meta-event (skipped, just accumulate time)
279 ev_type = midi_parameter_type(ev_buffer[0]);
281 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked delta %1, time %2, buf[0] %3, type %4\n",
282 ev_delta_t, time, ev_buffer[0], ev_type));
284 assert(time >= start_ticks);
286 /* Note that we add on the source start time (in session frames) here so that ev_frame_time
287 is in session frames.
289 const framepos_t ev_frame_time = converter.to(Evoral::Beats::ticks_at_rate(time, ppqn())) + source_start;
291 if (ev_frame_time < start + duration) {
292 if (!filter || !filter->filter(ev_buffer, ev_size)) {
293 destination.write (ev_frame_time, ev_type, ev_size, ev_buffer);
295 tracker->track(ev_buffer);
302 if (ev_size > scratch_size) {
303 scratch_size = ev_size;
305 ev_size = scratch_size; // ensure read_event only allocates if necessary
312 SMFSource::write_unlocked (const Lock& lock,
313 MidiRingBuffer<framepos_t>& source,
318 mark_streaming_write_started (lock);
322 Evoral::EventType type;
325 size_t buf_capacity = 4;
326 uint8_t* buf = (uint8_t*)malloc(buf_capacity);
328 if (_model && !_model->writing()) {
329 _model->start_write();
332 Evoral::MIDIEvent<framepos_t> ev;
334 /* Get the event time, in frames since session start but ignoring looping. */
336 if (!(ret = source.peek ((uint8_t*)&time, sizeof (time)))) {
337 /* Ring is empty, no more events. */
341 if ((cnt != max_framecnt) &&
342 (time > position + _capture_length + cnt)) {
343 /* The diskstream doesn't want us to write everything, and this
344 event is past the end of this block, so we're done for now. */
348 /* Read the time, type, and size of the event. */
349 if (!(ret = source.read_prefix (&time, &type, &size))) {
350 error << _("Unable to read event prefix, corrupt MIDI ring") << endmsg;
354 /* Enlarge body buffer if necessary now that we know the size. */
355 if (size > buf_capacity) {
357 buf = (uint8_t*)realloc(buf, size);
360 /* Read the event body into buffer. */
361 ret = source.read_contents(size, buf);
363 error << _("Event has time and size but no body, corrupt MIDI ring") << endmsg;
367 /* Convert event time from absolute to source relative. */
368 if (time < position) {
369 error << _("Event time is before MIDI source position") << endmsg;
374 ev.set(buf, size, time);
375 ev.set_event_type(midi_parameter_type(ev.buffer()[0]));
376 ev.set_id(Evoral::next_event_id());
378 if (!(ev.is_channel_event() || ev.is_smf_meta_event() || ev.is_sysex())) {
382 append_event_frames(lock, ev, position);
385 Evoral::SMF::flush ();
391 /** Append an event with a timestamp in beats */
393 SMFSource::append_event_beats (const Glib::Threads::Mutex::Lock& lock,
394 const Evoral::Event<Evoral::Beats>& ev)
396 if (!_writing || ev.size() == 0) {
401 printf("SMFSource: %s - append_event_beats ID = %d time = %lf, size = %u, data = ",
402 name().c_str(), ev.id(), ev.time(), ev.size());
403 for (size_t i = 0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");
406 Evoral::Beats time = ev.time();
407 if (time < _last_ev_time_beats) {
408 const Evoral::Beats difference = _last_ev_time_beats - time;
409 if (difference.to_double() / (double)ppqn() < 1.0) {
410 /* Close enough. This problem occurs because Sequence is not
411 actually ordered due to fuzzy time comparison. I'm pretty sure
412 this is inherently a bad idea which causes problems all over the
413 place, but tolerate it here for now anyway. */
414 time = _last_ev_time_beats;
416 /* Out of order by more than a tick. */
417 warning << string_compose(_("Skipping event with unordered beat time %1 < %2 (off by %3 beats, %4 ticks)"),
418 ev.time(), _last_ev_time_beats, difference, difference.to_double() / (double)ppqn())
424 Evoral::event_id_t event_id;
427 event_id = Evoral::next_event_id();
433 _model->append (ev, event_id);
436 _length_beats = max(_length_beats, time);
437 /* midi is in quarter note format as distinct from ardour beat */
438 _length_pulse = _length_beats.to_double() / 4.0;
440 const Evoral::Beats delta_time_beats = time - _last_ev_time_beats;
441 const uint32_t delta_time_ticks = delta_time_beats.to_ticks(ppqn());
443 Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
444 _last_ev_time_beats = time;
445 _flags = Source::Flag (_flags & ~Empty);
448 /** Append an event with a timestamp in frames (framepos_t) */
450 SMFSource::append_event_frames (const Glib::Threads::Mutex::Lock& lock,
451 const Evoral::Event<framepos_t>& ev,
454 if (!_writing || ev.size() == 0) {
458 // printf("SMFSource: %s - append_event_frames ID = %d time = %u, size = %u, data = ",
459 // name().c_str(), ev.id(), ev.time(), ev.size());
460 // for (size_t i=0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");
462 if (ev.time() < _last_ev_time_frames) {
463 warning << string_compose(_("Skipping event with unordered frame time %1 < %2"),
464 ev.time(), _last_ev_time_frames)
469 BeatsFramesConverter converter(_session.tempo_map(), position);
470 const Evoral::Beats ev_time_beats = converter.from(ev.time());
471 Evoral::event_id_t event_id;
474 event_id = Evoral::next_event_id();
480 const Evoral::Event<Evoral::Beats> beat_ev (ev.event_type(),
483 const_cast<uint8_t*>(ev.buffer()));
484 _model->append (beat_ev, event_id);
487 _length_beats = max(_length_beats, ev_time_beats);
488 /* midi is in quarter note format as distinct from ardour beat */
489 _length_pulse = _length_beats.to_double() / 4.0;
491 const Evoral::Beats last_time_beats = converter.from (_last_ev_time_frames);
492 const Evoral::Beats delta_time_beats = ev_time_beats - last_time_beats;
493 const uint32_t delta_time_ticks = delta_time_beats.to_ticks(ppqn());
495 Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
496 _last_ev_time_frames = ev.time();
497 _flags = Source::Flag (_flags & ~Empty);
501 SMFSource::get_state ()
503 XMLNode& node = MidiSource::get_state();
504 node.add_property (X_("origin"), _origin);
509 SMFSource::set_state (const XMLNode& node, int version)
511 if (Source::set_state (node, version)) {
515 if (MidiSource::set_state (node, version)) {
519 if (FileSource::set_state (node, version)) {
527 SMFSource::mark_streaming_midi_write_started (const Lock& lock, NoteMode mode)
529 if (!_open && open_for_write()) {
530 error << string_compose (_("cannot open MIDI file %1 for write"), _path) << endmsg;
531 /* XXX should probably throw or return something */
535 MidiSource::mark_streaming_midi_write_started (lock, mode);
536 Evoral::SMF::begin_write ();
537 _last_ev_time_beats = Evoral::Beats();
538 _last_ev_time_frames = 0;
542 SMFSource::mark_streaming_write_completed (const Lock& lock)
544 mark_midi_streaming_write_completed (lock, Evoral::Sequence<Evoral::Beats>::DeleteStuckNotes);
548 SMFSource::mark_midi_streaming_write_completed (const Lock& lm, Evoral::Sequence<Evoral::Beats>::StuckNoteOption stuck_notes_option, Evoral::Beats when)
550 MidiSource::mark_midi_streaming_write_completed (lm, stuck_notes_option, when);
553 warning << string_compose ("attempt to write to unwritable SMF file %1", _path) << endmsg;
558 _model->set_edited(false);
561 Evoral::SMF::end_write (_path);
563 /* data in the file now, not removable */
565 mark_nonremovable ();
569 SMFSource::valid_midi_file (const string& file)
571 if (safe_midi_file_extension (file) ) {
572 return (SMF::test (file) );
578 SMFSource::safe_midi_file_extension (const string& file)
580 static regex_t compiled_pattern;
581 static bool compile = true;
582 const int nmatches = 2;
583 regmatch_t matches[nmatches];
585 if (Glib::file_test (file, Glib::FILE_TEST_EXISTS)) {
586 if (!Glib::file_test (file, Glib::FILE_TEST_IS_REGULAR)) {
587 /* exists but is not a regular file */
592 if (compile && regcomp (&compiled_pattern, "\\.[mM][iI][dD][iI]?$", REG_EXTENDED)) {
598 if (regexec (&compiled_pattern, file.c_str(), nmatches, matches, 0)) {
605 static bool compare_eventlist (
606 const std::pair< Evoral::Event<Evoral::Beats>*, gint >& a,
607 const std::pair< Evoral::Event<Evoral::Beats>*, gint >& b) {
608 return ( a.first->time() < b.first->time() );
612 SMFSource::load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload)
618 if (_model && !force_reload) {
623 _model = boost::shared_ptr<MidiModel> (new MidiModel (shared_from_this ()));
630 if (writable() && !_open) {
634 _model->start_write();
635 Evoral::SMF::seek_to_start();
637 uint64_t time = 0; /* in SMF ticks */
638 Evoral::Event<Evoral::Beats> ev;
640 uint32_t scratch_size = 0; // keep track of scratch and minimize reallocs
642 uint32_t delta_t = 0;
649 // TODO simplify event allocation
650 std::list< std::pair< Evoral::Event<Evoral::Beats>*, gint > > eventlist;
652 for (unsigned i = 1; i <= num_tracks(); ++i) {
653 if (seek_to_track(i)) continue;
656 have_event_id = false;
658 while ((ret = read_event (&delta_t, &size, &buf, &event_id)) >= 0) {
663 /* meta-event : did we get an event ID ? */
665 have_event_id = true;
671 /* not a meta-event */
673 if (!have_event_id) {
674 event_id = Evoral::next_event_id();
676 const uint32_t event_type = midi_parameter_type(buf[0]);
677 const Evoral::Beats event_time = Evoral::Beats::ticks_at_rate(time, ppqn());
681 for (uint32_t xx = 0; xx < size; ++xx) {
683 snprintf (b, sizeof (b), "0x%x ", buf[xx]);
687 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF %7 load model delta %1, time %2, size %3 buf %4, type %5 id %6\n",
688 delta_t, time, size, ss , event_type, event_id, name()));
691 eventlist.push_back(make_pair (
692 new Evoral::Event<Evoral::Beats> (
693 event_type, event_time,
697 // Set size to max capacity to minimize allocs in read_event
698 scratch_size = std::max(size, scratch_size);
701 _length_beats = max(_length_beats, event_time);
702 /* midi is in quarter note format as distinct from ardour beat */
703 _length_pulse = _length_beats.to_double() / 4.0;
706 /* event ID's must immediately precede the event they are for */
707 have_event_id = false;
711 eventlist.sort(compare_eventlist);
713 std::list< std::pair< Evoral::Event<Evoral::Beats>*, gint > >::iterator it;
714 for (it=eventlist.begin(); it!=eventlist.end(); ++it) {
715 _model->append (*it->first, it->second);
719 // cerr << "----SMF-SRC-----\n";
720 // _playback_buf->dump (cerr);
721 // cerr << "----------------\n";
723 _model->end_write (Evoral::Sequence<Evoral::Beats>::ResolveStuckNotes, _length_beats);
724 _model->set_edited (false);
731 SMFSource::destroy_model (const Glib::Threads::Mutex::Lock& lock)
733 //cerr << _name << " destroying model " << _model.get() << endl;
739 SMFSource::flush_midi (const Lock& lock)
741 if (!writable() || _length_beats == 0.0) {
745 ensure_disk_file (lock);
747 Evoral::SMF::end_write (_path);
748 /* data in the file means its no longer removable */
749 mark_nonremovable ();
755 SMFSource::set_path (const string& p)
757 FileSource::set_path (p);
760 /** Ensure that this source has some file on disk, even if it's just a SMF header */
762 SMFSource::ensure_disk_file (const Lock& lock)
769 /* We have a model, so write it to disk; see MidiSource::session_saved
770 for an explanation of what we are doing here.
772 boost::shared_ptr<MidiModel> mm = _model;
774 mm->sync_to_source (lock);
778 /* No model; if it's not already open, it's an empty source, so create
779 and open it for writing.
788 SMFSource::prevent_deletion ()
790 /* Unlike the audio case, the MIDI file remains mutable (because we can
794 _flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy));