2 * Copyright (C) 2006-2016 David Robillard <d@drobilla.net>
3 * Copyright (C) 2007-2018 Paul Davis <paul@linuxaudiosystems.com>
4 * Copyright (C) 2008-2009 Hans Baier <hansfbaier@googlemail.com>
5 * Copyright (C) 2009-2011 Carl Hetherington <carl@carlh.net>
6 * Copyright (C) 2012-2016 Tim Mayberry <mojofunk@gmail.com>
7 * Copyright (C) 2014-2015 Robin Gareus <robin@gareus.org>
8 * Copyright (C) 2014-2016 John Emmas <john@creativepost.co.uk>
9 * Copyright (C) 2016 Nick Mainsbridge <mainsbridge@gmail.com>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
34 #include "pbd/file_utils.h"
35 #include "pbd/stl_delete.h"
36 #include "pbd/strsplit.h"
38 #include "pbd/gstdio_compat.h"
39 #include <glibmm/miscutils.h>
40 #include <glibmm/fileutils.h>
42 #include "evoral/Control.hpp"
43 #include "evoral/SMF.hpp"
45 #include "ardour/debug.h"
46 #include "ardour/midi_channel_filter.h"
47 #include "ardour/midi_model.h"
48 #include "ardour/midi_ring_buffer.h"
49 #include "ardour/midi_state_tracker.h"
50 #include "ardour/parameter_types.h"
51 #include "ardour/session.h"
52 #include "ardour/smf_source.h"
56 using namespace ARDOUR;
59 using namespace Evoral;
62 /** Constructor used for new internal-to-session files. File cannot exist. */
63 SMFSource::SMFSource (Session& s, const string& path, Source::Flag flags)
64 : Source(s, DataType::MIDI, path, flags)
65 , MidiSource(s, path, flags)
66 , FileSource(s, DataType::MIDI, path, string(), flags)
69 , _last_ev_time_beats(0.0)
70 , _last_ev_time_samples(0)
71 , _smf_last_read_end (0)
72 , _smf_last_read_time (0)
74 /* note that origin remains empty */
76 if (init (_path, false)) {
77 throw failed_constructor ();
80 assert (!Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
83 _flags = Source::Flag (_flags | Empty);
85 /* file is not opened until write */
87 if (flags & Writable) {
92 throw failed_constructor ();
98 /** Constructor used for external-to-session files. File must exist. */
99 SMFSource::SMFSource (Session& s, const string& path)
100 : Source(s, DataType::MIDI, path, Source::Flag (0))
101 , MidiSource(s, path, Source::Flag (0))
102 , FileSource(s, DataType::MIDI, path, string(), Source::Flag (0))
105 , _last_ev_time_beats(0.0)
106 , _last_ev_time_samples(0)
107 , _smf_last_read_end (0)
108 , _smf_last_read_time (0)
110 /* note that origin remains empty */
112 if (init (_path, true)) {
113 throw failed_constructor ();
116 assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
119 if (_flags & Writable) {
120 /* file is not opened until write */
125 throw failed_constructor ();
131 /** Constructor used for existing internal-to-session files. */
132 SMFSource::SMFSource (Session& s, const XMLNode& node, bool must_exist)
134 , MidiSource(s, node)
135 , FileSource(s, node, must_exist)
137 , _last_ev_time_beats(0.0)
138 , _last_ev_time_samples(0)
139 , _smf_last_read_end (0)
140 , _smf_last_read_time (0)
142 if (set_state(node, Stateful::loading_state_version)) {
143 throw failed_constructor ();
146 /* we expect the file to exist, but if no MIDI data was ever added
147 it will have been removed at last session close. so, we don't
148 require it to exist if it was marked Empty.
153 if (init (_path, true)) {
154 throw failed_constructor ();
157 } catch (MissingSource& err) {
159 if (_flags & Source::Empty) {
160 /* we don't care that the file was not found, because
161 it was empty. But FileSource::init() will have
162 failed to set our _path correctly, so we have to do
163 this ourselves. Use the first entry in the search
164 path for MIDI files, which is assumed to be the
165 correct "main" location.
167 std::vector<string> sdirs = s.source_search_path (DataType::MIDI);
168 _path = Glib::build_filename (sdirs.front(), _path);
169 /* This might be important, too */
177 if (!(_flags & Source::Empty)) {
178 assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
181 assert (_flags & Source::Writable);
182 /* file will be opened on write */
187 throw failed_constructor ();
193 SMFSource::~SMFSource ()
196 ::g_unlink (_path.c_str());
201 SMFSource::open_for_write ()
203 if (create (_path)) {
213 /* nothing to do: file descriptor is never kept open */
216 /** All stamps in audio samples */
218 SMFSource::read_unlocked (const Lock& lock,
219 Evoral::EventSink<samplepos_t>& destination,
220 samplepos_t const source_start,
222 samplecnt_t duration,
223 Evoral::Range<samplepos_t>* loop_range,
224 MidiStateTracker* tracker,
225 MidiChannelFilter* filter) const
228 uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
230 if (writable() && !_open) {
231 /* nothing to read since nothing has ben written */
235 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start %1 duration %2\n", start, duration));
237 // Output parameters for read_event (which will allocate scratch in buffer as needed)
238 uint32_t ev_delta_t = 0;
239 uint32_t ev_size = 0;
240 uint8_t* ev_buffer = 0;
242 size_t scratch_size = 0; // keep track of scratch to minimize reallocs
244 BeatsSamplesConverter converter(_session.tempo_map(), source_start);
246 const uint64_t start_ticks = converter.from(start).to_ticks();
247 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start in ticks %1\n", start_ticks));
249 if (_smf_last_read_end == 0 || start != _smf_last_read_end) {
250 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: seek to %1\n", start));
251 Evoral::SMF::seek_to_start();
252 while (time < start_ticks) {
255 ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
256 if (ret == -1) { // EOF
257 _smf_last_read_end = start + duration;
260 time += ev_delta_t; // accumulate delta time
263 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: set time to %1\n", _smf_last_read_time));
264 time = _smf_last_read_time;
267 _smf_last_read_end = start + duration;
270 gint ignored; /* XXX don't ignore note id's ??*/
272 ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
273 if (ret == -1) { // EOF
277 time += ev_delta_t; // accumulate delta time
278 _smf_last_read_time = time;
280 if (ret == 0) { // meta-event (skipped, just accumulate time)
284 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked delta %1, time %2, buf[0] %3\n",
285 ev_delta_t, time, ev_buffer[0]));
287 assert(time >= start_ticks);
289 /* Note that we add on the source start time (in session samples) here so that ev_sample_time
290 is in session samples.
292 const samplepos_t ev_sample_time = converter.to(Temporal::Beats::ticks_at_rate(time, ppqn())) + source_start;
295 loop_range->squish (ev_sample_time);
298 if (ev_sample_time < start + duration) {
299 if (!filter || !filter->filter(ev_buffer, ev_size)) {
300 destination.write (ev_sample_time, Evoral::MIDI_EVENT, ev_size, ev_buffer);
302 tracker->track(ev_buffer);
309 if (ev_size > scratch_size) {
310 scratch_size = ev_size;
312 ev_size = scratch_size; // ensure read_event only allocates if necessary
319 SMFSource::write_unlocked (const Lock& lock,
320 MidiRingBuffer<samplepos_t>& source,
321 samplepos_t position,
325 mark_streaming_write_started (lock);
329 Evoral::EventType type;
332 size_t buf_capacity = 4;
333 uint8_t* buf = (uint8_t*)malloc(buf_capacity);
335 if (_model && !_model->writing()) {
336 _model->start_write();
339 Evoral::Event<samplepos_t> ev;
341 /* Get the event time, in samples since session start but ignoring looping. */
343 if (!(ret = source.peek ((uint8_t*)&time, sizeof (time)))) {
344 /* Ring is empty, no more events. */
348 if ((cnt != max_samplecnt) &&
349 (time > position + _capture_length + cnt)) {
350 /* The diskstream doesn't want us to write everything, and this
351 event is past the end of this block, so we're done for now. */
355 /* Read the time, type, and size of the event. */
356 if (!(ret = source.read_prefix (&time, &type, &size))) {
357 error << _("Unable to read event prefix, corrupt MIDI ring") << endmsg;
361 /* Enlarge body buffer if necessary now that we know the size. */
362 if (size > buf_capacity) {
364 buf = (uint8_t*)realloc(buf, size);
367 /* Read the event body into buffer. */
368 ret = source.read_contents(size, buf);
370 error << _("Event has time and size but no body, corrupt MIDI ring") << endmsg;
374 /* Convert event time from absolute to source relative. */
375 if (time < position) {
376 error << _("Event time is before MIDI source position") << endmsg;
381 ev.set(buf, size, time);
382 ev.set_event_type(Evoral::MIDI_EVENT);
383 ev.set_id(Evoral::next_event_id());
385 if (!(ev.is_channel_event() || ev.is_smf_meta_event() || ev.is_sysex())) {
389 append_event_samples(lock, ev, position);
392 Evoral::SMF::flush ();
398 /** Append an event with a timestamp in beats */
400 SMFSource::append_event_beats (const Glib::Threads::Mutex::Lock& lock,
401 const Evoral::Event<Temporal::Beats>& ev)
403 if (!_writing || ev.size() == 0) {
408 printf("SMFSource: %s - append_event_beats ID = %d time = %lf, size = %u, data = ",
409 name().c_str(), ev.id(), ev.time(), ev.size());
410 for (size_t i = 0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");
413 Temporal::Beats time = ev.time();
414 if (time < _last_ev_time_beats) {
415 const Temporal::Beats difference = _last_ev_time_beats - time;
416 if (difference.to_double() / (double)ppqn() < 1.0) {
417 /* Close enough. This problem occurs because Sequence is not
418 actually ordered due to fuzzy time comparison. I'm pretty sure
419 this is inherently a bad idea which causes problems all over the
420 place, but tolerate it here for now anyway. */
421 time = _last_ev_time_beats;
423 /* Out of order by more than a tick. */
424 warning << string_compose(_("Skipping event with unordered beat time %1 < %2 (off by %3 beats, %4 ticks)"),
425 ev.time(), _last_ev_time_beats, difference, difference.to_double() / (double)ppqn())
431 Evoral::event_id_t event_id;
434 event_id = Evoral::next_event_id();
440 _model->append (ev, event_id);
443 _length_beats = max(_length_beats, time);
445 const Temporal::Beats delta_time_beats = time - _last_ev_time_beats;
446 const uint32_t delta_time_ticks = delta_time_beats.to_ticks(ppqn());
448 Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
449 _last_ev_time_beats = time;
450 _flags = Source::Flag (_flags & ~Empty);
453 /** Append an event with a timestamp in samples (samplepos_t) */
455 SMFSource::append_event_samples (const Glib::Threads::Mutex::Lock& lock,
456 const Evoral::Event<samplepos_t>& ev,
457 samplepos_t position)
459 if (!_writing || ev.size() == 0) {
463 // printf("SMFSource: %s - append_event_samples ID = %d time = %u, size = %u, data = ",
464 // name().c_str(), ev.id(), ev.time(), ev.size());
465 // for (size_t i=0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");
467 if (ev.time() < _last_ev_time_samples) {
468 warning << string_compose(_("Skipping event with unordered sample time %1 < %2"),
469 ev.time(), _last_ev_time_samples)
474 BeatsSamplesConverter converter(_session.tempo_map(), position);
475 const Temporal::Beats ev_time_beats = converter.from(ev.time());
476 Evoral::event_id_t event_id;
479 event_id = Evoral::next_event_id();
485 const Evoral::Event<Temporal::Beats> beat_ev (ev.event_type(),
488 const_cast<uint8_t*>(ev.buffer()));
489 _model->append (beat_ev, event_id);
492 _length_beats = max(_length_beats, ev_time_beats);
494 const Temporal::Beats last_time_beats = converter.from (_last_ev_time_samples);
495 const Temporal::Beats delta_time_beats = ev_time_beats - last_time_beats;
496 const uint32_t delta_time_ticks = delta_time_beats.to_ticks(ppqn());
498 Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
499 _last_ev_time_samples = ev.time();
500 _flags = Source::Flag (_flags & ~Empty);
504 SMFSource::get_state ()
506 XMLNode& node = MidiSource::get_state();
507 node.set_property (X_("origin"), _origin);
512 SMFSource::set_state (const XMLNode& node, int version)
514 if (Source::set_state (node, version)) {
518 if (MidiSource::set_state (node, version)) {
522 if (FileSource::set_state (node, version)) {
530 SMFSource::mark_streaming_midi_write_started (const Lock& lock, NoteMode mode)
532 if (!_open && open_for_write()) {
533 error << string_compose (_("cannot open MIDI file %1 for write"), _path) << endmsg;
534 /* XXX should probably throw or return something */
538 MidiSource::mark_streaming_midi_write_started (lock, mode);
539 Evoral::SMF::begin_write ();
540 _last_ev_time_beats = Temporal::Beats();
541 _last_ev_time_samples = 0;
545 SMFSource::mark_streaming_write_completed (const Lock& lock)
547 mark_midi_streaming_write_completed (lock, Evoral::Sequence<Temporal::Beats>::DeleteStuckNotes);
551 SMFSource::mark_midi_streaming_write_completed (const Lock& lm, Evoral::Sequence<Temporal::Beats>::StuckNoteOption stuck_notes_option, Temporal::Beats when)
553 MidiSource::mark_midi_streaming_write_completed (lm, stuck_notes_option, when);
556 warning << string_compose ("attempt to write to unwritable SMF file %1", _path) << endmsg;
561 _model->set_edited(false);
565 Evoral::SMF::end_write (_path);
566 } catch (std::exception & e) {
567 error << string_compose (_("Exception while writing %1, file may be corrupt/unusable"), _path) << endmsg;
570 /* data in the file now, not removable */
572 mark_nonremovable ();
576 SMFSource::valid_midi_file (const string& file)
578 if (safe_midi_file_extension (file) ) {
579 return (SMF::test (file) );
585 SMFSource::safe_midi_file_extension (const string& file)
587 static regex_t compiled_pattern;
588 static bool compile = true;
589 const int nmatches = 2;
590 regmatch_t matches[nmatches];
592 if (Glib::file_test (file, Glib::FILE_TEST_EXISTS)) {
593 if (!Glib::file_test (file, Glib::FILE_TEST_IS_REGULAR)) {
594 /* exists but is not a regular file */
599 if (compile && regcomp (&compiled_pattern, "\\.[mM][iI][dD][iI]?$", REG_EXTENDED)) {
605 if (regexec (&compiled_pattern, file.c_str(), nmatches, matches, 0)) {
612 static bool compare_eventlist (
613 const std::pair< const Evoral::Event<Temporal::Beats>*, gint >& a,
614 const std::pair< const Evoral::Event<Temporal::Beats>*, gint >& b) {
615 return ( a.first->time() < b.first->time() );
619 SMFSource::load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload)
625 if (_model && !force_reload) {
630 boost::shared_ptr<SMFSource> smf = boost::dynamic_pointer_cast<SMFSource> ( shared_from_this () );
631 _model = boost::shared_ptr<MidiModel> (new MidiModel (smf));
638 if (writable() && !_open) {
642 _model->start_write();
643 Evoral::SMF::seek_to_start();
645 uint64_t time = 0; /* in SMF ticks */
646 Evoral::Event<Temporal::Beats> ev;
648 uint32_t scratch_size = 0; // keep track of scratch and minimize reallocs
650 uint32_t delta_t = 0;
657 // TODO simplify event allocation
658 std::list< std::pair< Evoral::Event<Temporal::Beats>*, gint > > eventlist;
660 for (unsigned i = 1; i <= num_tracks(); ++i) {
661 if (seek_to_track(i)) continue;
664 have_event_id = false;
666 while ((ret = read_event (&delta_t, &size, &buf, &event_id)) >= 0) {
671 /* meta-event : did we get an event ID ? */
673 have_event_id = true;
679 /* not a meta-event */
681 if (!have_event_id) {
682 event_id = Evoral::next_event_id();
684 const Temporal::Beats event_time = Temporal::Beats::ticks_at_rate(time, ppqn());
688 for (uint32_t xx = 0; xx < size; ++xx) {
690 snprintf (b, sizeof (b), "0x%x ", buf[xx]);
694 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF %7 load model delta %1, time %2, size %3 buf %4, id %6\n",
695 delta_t, time, size, ss, event_id, name()));
698 eventlist.push_back(make_pair (
699 new Evoral::Event<Temporal::Beats> (
700 Evoral::MIDI_EVENT, event_time,
704 // Set size to max capacity to minimize allocs in read_event
705 scratch_size = std::max(size, scratch_size);
708 _length_beats = max(_length_beats, event_time);
711 /* event ID's must immediately precede the event they are for */
712 have_event_id = false;
716 eventlist.sort(compare_eventlist);
718 std::list< std::pair< Evoral::Event<Temporal::Beats>*, gint > >::iterator it;
719 for (it=eventlist.begin(); it!=eventlist.end(); ++it) {
720 _model->append (*it->first, it->second);
724 // cerr << "----SMF-SRC-----\n";
725 // _playback_buf->dump (cerr);
726 // cerr << "----------------\n";
728 _model->end_write (Evoral::Sequence<Temporal::Beats>::ResolveStuckNotes, _length_beats);
729 _model->set_edited (false);
736 SMFSource::destroy_model (const Glib::Threads::Mutex::Lock& lock)
738 //cerr << _name << " destroying model " << _model.get() << endl;
744 SMFSource::flush_midi (const Lock& lock)
746 if (!writable() || _length_beats == 0.0) {
750 ensure_disk_file (lock);
752 Evoral::SMF::end_write (_path);
753 /* data in the file means its no longer removable */
754 mark_nonremovable ();
760 SMFSource::set_path (const string& p)
762 FileSource::set_path (p);
765 /** Ensure that this source has some file on disk, even if it's just a SMF header */
767 SMFSource::ensure_disk_file (const Lock& lock)
774 /* We have a model, so write it to disk; see MidiSource::session_saved
775 for an explanation of what we are doing here.
777 boost::shared_ptr<MidiModel> mm = _model;
779 mm->sync_to_source (lock);
783 /* No model; if it's not already open, it's an empty source, so create
784 and open it for writing.
793 SMFSource::prevent_deletion ()
795 /* Unlike the audio case, the MIDI file remains mutable (because we can
799 _flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy));