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);
442 /* midi is in quarter note format as distinct from ardour beat */
443 _length_pulse = _length_beats.to_double() / 4.0;
445 const Evoral::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 frames (framepos_t) */
455 SMFSource::append_event_frames (const Glib::Threads::Mutex::Lock& lock,
456 const Evoral::Event<framepos_t>& ev,
459 if (!_writing || ev.size() == 0) {
463 // printf("SMFSource: %s - append_event_frames 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_frames) {
468 warning << string_compose(_("Skipping event with unordered frame time %1 < %2"),
469 ev.time(), _last_ev_time_frames)
474 BeatsFramesConverter converter(_session.tempo_map(), position);
475 const Evoral::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<Evoral::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);
493 /* midi is in quarter note format as distinct from ardour beat */
494 _length_pulse = _length_beats.to_double() / 4.0;
496 const Evoral::Beats last_time_beats = converter.from (_last_ev_time_frames);
497 const Evoral::Beats delta_time_beats = ev_time_beats - last_time_beats;
498 const uint32_t delta_time_ticks = delta_time_beats.to_ticks(ppqn());
500 Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
501 _last_ev_time_frames = ev.time();
502 _flags = Source::Flag (_flags & ~Empty);
506 SMFSource::get_state ()
508 XMLNode& node = MidiSource::get_state();
509 node.add_property (X_("origin"), _origin);
514 SMFSource::set_state (const XMLNode& node, int version)
516 if (Source::set_state (node, version)) {
520 if (MidiSource::set_state (node, version)) {
524 if (FileSource::set_state (node, version)) {
532 SMFSource::mark_streaming_midi_write_started (const Lock& lock, NoteMode mode)
534 if (!_open && open_for_write()) {
535 error << string_compose (_("cannot open MIDI file %1 for write"), _path) << endmsg;
536 /* XXX should probably throw or return something */
540 MidiSource::mark_streaming_midi_write_started (lock, mode);
541 Evoral::SMF::begin_write ();
542 _last_ev_time_beats = Evoral::Beats();
543 _last_ev_time_frames = 0;
547 SMFSource::mark_streaming_write_completed (const Lock& lock)
549 mark_midi_streaming_write_completed (lock, Evoral::Sequence<Evoral::Beats>::DeleteStuckNotes);
553 SMFSource::mark_midi_streaming_write_completed (const Lock& lm, Evoral::Sequence<Evoral::Beats>::StuckNoteOption stuck_notes_option, Evoral::Beats when)
555 MidiSource::mark_midi_streaming_write_completed (lm, stuck_notes_option, when);
558 warning << string_compose ("attempt to write to unwritable SMF file %1", _path) << endmsg;
563 _model->set_edited(false);
566 Evoral::SMF::end_write (_path);
568 /* data in the file now, not removable */
570 mark_nonremovable ();
574 SMFSource::valid_midi_file (const string& file)
576 if (safe_midi_file_extension (file) ) {
577 return (SMF::test (file) );
583 SMFSource::safe_midi_file_extension (const string& file)
585 static regex_t compiled_pattern;
586 static bool compile = true;
587 const int nmatches = 2;
588 regmatch_t matches[nmatches];
590 if (Glib::file_test (file, Glib::FILE_TEST_EXISTS)) {
591 if (!Glib::file_test (file, Glib::FILE_TEST_IS_REGULAR)) {
592 /* exists but is not a regular file */
597 if (compile && regcomp (&compiled_pattern, "\\.[mM][iI][dD][iI]?$", REG_EXTENDED)) {
603 if (regexec (&compiled_pattern, file.c_str(), nmatches, matches, 0)) {
610 static bool compare_eventlist (
611 const std::pair< Evoral::Event<Evoral::Beats>*, gint >& a,
612 const std::pair< Evoral::Event<Evoral::Beats>*, gint >& b) {
613 return ( a.first->time() < b.first->time() );
617 SMFSource::load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload)
623 if (_model && !force_reload) {
628 _model = boost::shared_ptr<MidiModel> (new MidiModel (shared_from_this ()));
635 if (writable() && !_open) {
639 _model->start_write();
640 Evoral::SMF::seek_to_start();
642 uint64_t time = 0; /* in SMF ticks */
643 Evoral::Event<Evoral::Beats> ev;
645 uint32_t scratch_size = 0; // keep track of scratch and minimize reallocs
647 uint32_t delta_t = 0;
654 // TODO simplify event allocation
655 std::list< std::pair< Evoral::Event<Evoral::Beats>*, gint > > eventlist;
657 for (unsigned i = 1; i <= num_tracks(); ++i) {
658 if (seek_to_track(i)) continue;
661 have_event_id = false;
663 while ((ret = read_event (&delta_t, &size, &buf, &event_id)) >= 0) {
668 /* meta-event : did we get an event ID ? */
670 have_event_id = true;
676 /* not a meta-event */
678 if (!have_event_id) {
679 event_id = Evoral::next_event_id();
681 const uint32_t event_type = midi_parameter_type(buf[0]);
682 const Evoral::Beats event_time = Evoral::Beats::ticks_at_rate(time, ppqn());
686 for (uint32_t xx = 0; xx < size; ++xx) {
688 snprintf (b, sizeof (b), "0x%x ", buf[xx]);
692 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF %7 load model delta %1, time %2, size %3 buf %4, type %5 id %6\n",
693 delta_t, time, size, ss , event_type, event_id, name()));
696 eventlist.push_back(make_pair (
697 new Evoral::Event<Evoral::Beats> (
698 event_type, event_time,
702 // Set size to max capacity to minimize allocs in read_event
703 scratch_size = std::max(size, scratch_size);
706 _length_beats = max(_length_beats, event_time);
707 /* midi is in quarter note format as distinct from ardour beat */
708 _length_pulse = _length_beats.to_double() / 4.0;
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<Evoral::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<Evoral::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));