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/pathscanner.h"
30 #include "pbd/stl_delete.h"
31 #include "pbd/strsplit.h"
33 #include <glibmm/miscutils.h>
34 #include <glibmm/fileutils.h>
36 #include "evoral/Control.hpp"
37 #include "evoral/evoral/SMF.hpp"
39 #include "ardour/event_type_map.h"
40 #include "ardour/midi_model.h"
41 #include "ardour/midi_ring_buffer.h"
42 #include "ardour/midi_state_tracker.h"
43 #include "ardour/session.h"
44 #include "ardour/smf_source.h"
45 #include "ardour/debug.h"
49 using namespace ARDOUR;
52 using namespace Evoral;
54 /** Constructor used for new internal-to-session files. File cannot exist. */
55 SMFSource::SMFSource (Session& s, const string& path, Source::Flag flags)
56 : Source(s, DataType::MIDI, path, flags)
57 , MidiSource(s, path, flags)
58 , FileSource(s, DataType::MIDI, path, string(), flags)
60 , _last_ev_time_beats(0.0)
61 , _last_ev_time_frames(0)
62 , _smf_last_read_end (0)
63 , _smf_last_read_time (0)
65 /* note that origin remains empty */
67 if (init (_path, false)) {
68 throw failed_constructor ();
71 assert (!Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
74 _flags = Source::Flag (_flags | Empty);
76 /* file is not opened until write */
78 if (flags & Writable) {
83 throw failed_constructor ();
89 /** Constructor used for external-to-session files. File must exist. */
90 SMFSource::SMFSource (Session& s, const string& path)
91 : Source(s, DataType::MIDI, path, Source::Flag (0))
92 , MidiSource(s, path, Source::Flag (0))
93 , FileSource(s, DataType::MIDI, path, string(), Source::Flag (0))
95 , _last_ev_time_beats(0.0)
96 , _last_ev_time_frames(0)
97 , _smf_last_read_end (0)
98 , _smf_last_read_time (0)
100 /* note that origin remains empty */
102 if (init (_path, true)) {
103 throw failed_constructor ();
106 assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
109 if (_flags & Writable) {
110 /* file is not opened until write */
115 throw failed_constructor ();
121 /** Constructor used for existing internal-to-session files. */
122 SMFSource::SMFSource (Session& s, const XMLNode& node, bool must_exist)
124 , MidiSource(s, node)
125 , FileSource(s, node, must_exist)
126 , _last_ev_time_beats(0.0)
127 , _last_ev_time_frames(0)
128 , _smf_last_read_end (0)
129 , _smf_last_read_time (0)
131 if (set_state(node, Stateful::loading_state_version)) {
132 throw failed_constructor ();
135 /* we expect the file to exist, but if no MIDI data was ever added
136 it will have been removed at last session close. so, we don't
137 require it to exist if it was marked Empty.
142 if (init (_path, true)) {
143 throw failed_constructor ();
146 } catch (MissingSource& err) {
148 if (_flags & Source::Empty) {
149 /* we don't care that the file was not found, because
150 it was empty. But FileSource::init() will have
151 failed to set our _path correctly, so we have to do
152 this ourselves. Use the first entry in the search
153 path for MIDI files, which is assumed to be the
154 correct "main" location.
156 std::vector<Glib::ustring> sdirs;
157 split (s.source_search_path (DataType::MIDI), sdirs, ':');
159 fatal << _("Empty MIDI source search path!") << endmsg;
162 _path = Glib::build_filename (sdirs.front(), _path);
163 /* This might be important, too */
171 if (!(_flags & Source::Empty)) {
172 assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
175 assert (_flags & Source::Writable);
176 /* file will be opened on write */
181 throw failed_constructor ();
187 SMFSource::~SMFSource ()
190 unlink (_path.c_str());
195 SMFSource::open_for_write ()
197 if (create (_path)) {
204 /** All stamps in audio frames */
206 SMFSource::read_unlocked (Evoral::EventSink<framepos_t>& destination,
207 framepos_t const source_start,
210 MidiStateTracker* tracker) const
213 uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
215 if (writable() && !_open) {
216 /* nothing to read since nothing has ben written */
220 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start %1 duration %2\n", start, duration));
222 // Output parameters for read_event (which will allocate scratch in buffer as needed)
223 uint32_t ev_delta_t = 0;
224 uint32_t ev_type = 0;
225 uint32_t ev_size = 0;
226 uint8_t* ev_buffer = 0;
228 size_t scratch_size = 0; // keep track of scratch to minimize reallocs
230 BeatsFramesConverter converter(_session.tempo_map(), source_start);
232 const uint64_t start_ticks = (uint64_t)(converter.from(start) * ppqn());
233 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start in ticks %1\n", start_ticks));
235 if (_smf_last_read_end == 0 || start != _smf_last_read_end) {
236 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: seek to %1\n", start));
237 Evoral::SMF::seek_to_start();
238 while (time < start_ticks) {
241 ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
242 if (ret == -1) { // EOF
243 _smf_last_read_end = start + duration;
246 time += ev_delta_t; // accumulate delta time
249 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: set time to %1\n", _smf_last_read_time));
250 time = _smf_last_read_time;
253 _smf_last_read_end = start + duration;
256 gint ignored; /* XXX don't ignore note id's ??*/
258 ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
259 if (ret == -1) { // EOF
263 time += ev_delta_t; // accumulate delta time
264 _smf_last_read_time = time;
266 if (ret == 0) { // meta-event (skipped, just accumulate time)
270 ev_type = EventTypeMap::instance().midi_event_type(ev_buffer[0]);
272 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked delta %1, time %2, buf[0] %3, type %4\n",
273 ev_delta_t, time, ev_buffer[0], ev_type));
275 assert(time >= start_ticks);
277 /* Note that we add on the source start time (in session frames) here so that ev_frame_time
278 is in session frames.
280 const framepos_t ev_frame_time = converter.to(time / (double)ppqn()) + source_start;
282 if (ev_frame_time < start + duration) {
283 destination.write (ev_frame_time, ev_type, ev_size, ev_buffer);
286 if (ev_buffer[0] & MIDI_CMD_NOTE_ON) {
287 tracker->add (ev_buffer[1], ev_buffer[0] & 0xf);
288 } else if (ev_buffer[0] & MIDI_CMD_NOTE_OFF) {
289 tracker->remove (ev_buffer[1], ev_buffer[0] & 0xf);
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 (MidiRingBuffer<framepos_t>& source,
311 mark_streaming_write_started ();
315 Evoral::EventType type;
318 size_t buf_capacity = 4;
319 uint8_t* buf = (uint8_t*)malloc(buf_capacity);
321 if (_model && !_model->writing()) {
322 _model->start_write();
325 Evoral::MIDIEvent<framepos_t> ev;
327 /* Get the event time, in frames since session start but ignoring looping. */
329 if (!(ret = source.peek ((uint8_t*)&time, sizeof (time)))) {
330 /* Ring is empty, no more events. */
334 if ((cnt != max_framecnt) &&
335 (time > position + _capture_length + cnt)) {
336 /* The diskstream doesn't want us to write everything, and this
337 event is past the end of this block, so we're done for now. */
341 /* Read the time, type, and size of the event. */
342 if (!(ret = source.read_prefix (&time, &type, &size))) {
343 error << _("Unable to read event prefix, corrupt MIDI ring") << endmsg;
347 /* Enlarge body buffer if necessary now that we know the size. */
348 if (size > buf_capacity) {
350 buf = (uint8_t*)realloc(buf, size);
353 /* Read the event body into buffer. */
354 ret = source.read_contents(size, buf);
356 error << _("Event has time and size but no body, corrupt MIDI ring") << endmsg;
360 /* Convert event time from absolute to source relative. */
361 if (time < position) {
362 error << _("Event time is before MIDI source position") << endmsg;
367 ev.set(buf, size, time);
368 ev.set_event_type(EventTypeMap::instance().midi_event_type(ev.buffer()[0]));
369 ev.set_id(Evoral::next_event_id());
371 if (!(ev.is_channel_event() || ev.is_smf_meta_event() || ev.is_sysex())) {
375 append_event_unlocked_frames(ev, position);
378 Evoral::SMF::flush ();
384 /** Append an event with a timestamp in beats (double) */
386 SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev)
388 if (!_writing || ev.size() == 0) {
392 /*printf("SMFSource: %s - append_event_unlocked_beats ID = %d time = %lf, size = %u, data = ",
393 name().c_str(), ev.id(), ev.time(), ev.size());
394 for (size_t i = 0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");*/
396 if (ev.time() < _last_ev_time_beats) {
397 warning << string_compose(_("Skipping event with unordered time %1"), ev.time())
402 Evoral::event_id_t event_id;
405 event_id = Evoral::next_event_id();
411 _model->append (ev, event_id);
414 _length_beats = max(_length_beats, ev.time());
416 const double delta_time_beats = ev.time() - _last_ev_time_beats;
417 const uint32_t delta_time_ticks = (uint32_t)lrint(delta_time_beats * (double)ppqn());
419 Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
420 _last_ev_time_beats = ev.time();
421 _flags = Source::Flag (_flags & ~Empty);
424 /** Append an event with a timestamp in frames (framepos_t) */
426 SMFSource::append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, framepos_t position)
428 if (!_writing || ev.size() == 0) {
432 // printf("SMFSource: %s - append_event_unlocked_frames ID = %d time = %u, size = %u, data = ",
433 // name().c_str(), ev.id(), ev.time(), ev.size());
434 // for (size_t i=0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");
436 if (ev.time() < _last_ev_time_frames) {
437 warning << string_compose(_("Skipping event with unordered time %1"), ev.time())
442 BeatsFramesConverter converter(_session.tempo_map(), position);
443 const double ev_time_beats = converter.from(ev.time());
444 Evoral::event_id_t event_id;
447 event_id = Evoral::next_event_id();
453 const Evoral::Event<double> beat_ev (ev.event_type(),
456 const_cast<uint8_t*>(ev.buffer()));
457 _model->append (beat_ev, event_id);
460 _length_beats = max(_length_beats, ev_time_beats);
462 const Evoral::MusicalTime last_time_beats = converter.from (_last_ev_time_frames);
463 const Evoral::MusicalTime delta_time_beats = ev_time_beats - last_time_beats;
464 const uint32_t delta_time_ticks = (uint32_t)(lrint(delta_time_beats * (double)ppqn()));
466 Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
467 _last_ev_time_frames = ev.time();
468 _flags = Source::Flag (_flags & ~Empty);
472 SMFSource::get_state ()
474 XMLNode& node = MidiSource::get_state();
475 node.add_property (X_("origin"), _origin);
480 SMFSource::set_state (const XMLNode& node, int version)
482 if (Source::set_state (node, version)) {
486 if (MidiSource::set_state (node, version)) {
490 if (FileSource::set_state (node, version)) {
498 SMFSource::mark_streaming_midi_write_started (NoteMode mode)
500 /* CALLER MUST HOLD LOCK */
502 if (!_open && open_for_write()) {
503 error << string_compose (_("cannot open MIDI file %1 for write"), _path) << endmsg;
504 /* XXX should probably throw or return something */
508 MidiSource::mark_streaming_midi_write_started (mode);
509 Evoral::SMF::begin_write ();
510 _last_ev_time_beats = 0.0;
511 _last_ev_time_frames = 0;
515 SMFSource::mark_streaming_write_completed ()
517 mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::DeleteStuckNotes);
521 SMFSource::mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption stuck_notes_option, Evoral::MusicalTime when)
523 Glib::Threads::Mutex::Lock lm (_lock);
524 MidiSource::mark_midi_streaming_write_completed (stuck_notes_option, when);
527 warning << string_compose ("attempt to write to unwritable SMF file %1", _path) << endmsg;
532 _model->set_edited(false);
535 Evoral::SMF::end_write ();
537 /* data in the file now, not removable */
539 mark_nonremovable ();
543 SMFSource::valid_midi_file (const string& file)
545 if (safe_midi_file_extension (file) ) {
546 return (SMF::test (file) );
552 SMFSource::safe_midi_file_extension (const string& file)
554 static regex_t compiled_pattern;
555 static bool compile = true;
556 const int nmatches = 2;
557 regmatch_t matches[nmatches];
559 if (Glib::file_test (file, Glib::FILE_TEST_EXISTS)) {
560 if (!Glib::file_test (file, Glib::FILE_TEST_IS_REGULAR)) {
561 /* exists but is not a regular file */
566 if (compile && regcomp (&compiled_pattern, "\\.[mM][iI][dD][iI]?$", REG_EXTENDED)) {
572 if (regexec (&compiled_pattern, file.c_str(), nmatches, matches, 0)) {
579 static bool compare_eventlist (
580 const std::pair< Evoral::Event<double>*, gint >& a,
581 const std::pair< Evoral::Event<double>*, gint >& b) {
582 return ( a.first->time() < b.first->time() );
586 SMFSource::load_model (bool lock, bool force_reload)
592 boost::shared_ptr<Glib::Threads::Mutex::Lock> lm;
594 lm = boost::shared_ptr<Glib::Threads::Mutex::Lock>(new Glib::Threads::Mutex::Lock(_lock));
596 if (_model && !force_reload) {
601 _model = boost::shared_ptr<MidiModel> (new MidiModel (shared_from_this ()));
606 if (writable() && !_open) {
610 _model->start_write();
611 Evoral::SMF::seek_to_start();
613 uint64_t time = 0; /* in SMF ticks */
614 Evoral::Event<double> ev;
616 uint32_t scratch_size = 0; // keep track of scratch and minimize reallocs
618 uint32_t delta_t = 0;
625 // TODO simplify event allocation
626 std::list< std::pair< Evoral::Event<double>*, gint > > eventlist;
628 for (unsigned i = 1; i <= num_tracks(); ++i) {
629 if (seek_to_track(i)) continue;
632 have_event_id = false;
634 while ((ret = read_event (&delta_t, &size, &buf, &event_id)) >= 0) {
639 /* meta-event : did we get an event ID ? */
641 have_event_id = true;
647 /* not a meta-event */
649 if (!have_event_id) {
650 event_id = Evoral::next_event_id();
652 uint32_t event_type = EventTypeMap::instance().midi_event_type(buf[0]);
653 double event_time = time / (double) ppqn();
657 for (uint32_t xx = 0; xx < size; ++xx) {
659 snprintf (b, sizeof (b), "0x%x ", buf[xx]);
663 DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF %6 load model delta %1, time %2, size %3 buf %4, type %5\n",
664 delta_t, time, size, ss , event_type, name()));
667 eventlist.push_back(make_pair (
668 new Evoral::Event<double> (
669 event_type, event_time,
673 // Set size to max capacity to minimize allocs in read_event
674 scratch_size = std::max(size, scratch_size);
677 _length_beats = max(_length_beats, event_time);
680 /* event ID's must immediately precede the event they are for */
681 have_event_id = false;
685 eventlist.sort(compare_eventlist);
687 std::list< std::pair< Evoral::Event<double>*, gint > >::iterator it;
688 for (it=eventlist.begin(); it!=eventlist.end(); ++it) {
689 _model->append (*it->first, it->second);
693 _model->end_write (Evoral::Sequence<Evoral::MusicalTime>::ResolveStuckNotes, _length_beats);
694 _model->set_edited (false);
696 _model_iter = _model->begin();
702 SMFSource::destroy_model ()
704 //cerr << _name << " destroying model " << _model.get() << endl;
709 SMFSource::flush_midi ()
711 if (!writable() || _length_beats == 0.0) {
717 Evoral::SMF::end_write ();
718 /* data in the file means its no longer removable */
719 mark_nonremovable ();
723 SMFSource::set_path (const string& p)
725 FileSource::set_path (p);
726 SMF::set_path (_path);
729 /** Ensure that this source has some file on disk, even if it's just a SMF header */
731 SMFSource::ensure_disk_file ()
738 /* We have a model, so write it to disk; see MidiSource::session_saved
739 for an explanation of what we are doing here.
741 boost::shared_ptr<MidiModel> mm = _model;
743 mm->sync_to_source ();
746 /* No model; if it's not already open, it's an empty source, so create
747 and open it for writing.
756 SMFSource::prevent_deletion ()
758 /* Unlike the audio case, the MIDI file remains mutable (because we can
762 _flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy));