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-2012 Carl Hetherington <carl@carlh.net>
6 * Copyright (C) 2012-2016 Tim Mayberry <mojofunk@gmail.com>
7 * Copyright (C) 2015-2019 Robin Gareus <robin@gareus.org>
8 * Copyright (C) 2016 Nick Mainsbridge <mainsbridge@gmail.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
35 #include <glibmm/fileutils.h>
36 #include <glibmm/miscutils.h>
38 #include "pbd/xml++.h"
39 #include "pbd/pthread_utils.h"
40 #include "pbd/basename.h"
41 #include "pbd/timing.h"
43 #include "evoral/Control.hpp"
44 #include "evoral/EventSink.hpp"
46 #include "ardour/debug.h"
47 #include "ardour/file_source.h"
48 #include "ardour/midi_channel_filter.h"
49 #include "ardour/midi_cursor.h"
50 #include "ardour/midi_model.h"
51 #include "ardour/midi_source.h"
52 #include "ardour/midi_state_tracker.h"
53 #include "ardour/session.h"
54 #include "ardour/session_directory.h"
55 #include "ardour/source_factory.h"
56 #include "ardour/tempo.h"
60 namespace ARDOUR { template <typename T> class MidiRingBuffer; }
63 using namespace ARDOUR;
66 MidiSource::MidiSource (Session& s, string name, Source::Flag flags)
67 : Source(s, DataType::MIDI, name, flags)
71 , _capture_loop_length(0)
75 MidiSource::MidiSource (Session& s, const XMLNode& node)
80 , _capture_loop_length(0)
82 if (set_state (node, Stateful::loading_state_version)) {
83 throw failed_constructor();
87 MidiSource::~MidiSource ()
89 /* invalidate any existing iterators */
94 MidiSource::get_state ()
96 XMLNode& node (Source::get_state());
98 if (_captured_for.length()) {
99 node.set_property ("captured-for", _captured_for);
102 for (InterpolationStyleMap::const_iterator i = _interpolation_style.begin(); i != _interpolation_style.end(); ++i) {
103 XMLNode* child = node.add_child (X_("InterpolationStyle"));
104 child->set_property (X_("parameter"), EventTypeMap::instance().to_symbol (i->first));
105 child->set_property (X_("style"), enum_2_string (i->second));
108 for (AutomationStateMap::const_iterator i = _automation_state.begin(); i != _automation_state.end(); ++i) {
109 XMLNode* child = node.add_child (X_("AutomationState"));
110 child->set_property (X_("parameter"), EventTypeMap::instance().to_symbol (i->first));
111 child->set_property (X_("state"), enum_2_string (i->second));
118 MidiSource::set_state (const XMLNode& node, int /*version*/)
120 node.get_property ("captured-for", _captured_for);
123 XMLNodeList children = node.children ();
124 for (XMLNodeConstIterator i = children.begin(); i != children.end(); ++i) {
125 if ((*i)->name() == X_("InterpolationStyle")) {
126 if (!(*i)->get_property (X_("parameter"), str)) {
127 error << _("Missing parameter property on InterpolationStyle") << endmsg;
130 Evoral::Parameter p = EventTypeMap::instance().from_symbol (str);
133 case MidiCCAutomation:
134 case MidiPgmChangeAutomation: break;
135 case MidiChannelPressureAutomation: break;
136 case MidiNotePressureAutomation: break;
137 case MidiPitchBenderAutomation: break;
138 case MidiSystemExclusiveAutomation:
139 cerr << "Parameter \"" << str << "\" is system exclusive - no automation possible!\n";
142 cerr << "Parameter \"" << str << "\" found for MIDI source ... not legal; ignoring this parameter\n";
146 if (!(*i)->get_property (X_("style"), str)) {
147 error << _("Missing style property on InterpolationStyle") << endmsg;
150 Evoral::ControlList::InterpolationStyle s =
151 static_cast<Evoral::ControlList::InterpolationStyle>(string_2_enum (str, s));
152 set_interpolation_of (p, s);
154 } else if ((*i)->name() == X_("AutomationState")) {
155 if (!(*i)->get_property (X_("parameter"), str)) {
156 error << _("Missing parameter property on AutomationState") << endmsg;
159 Evoral::Parameter p = EventTypeMap::instance().from_symbol (str);
161 if (!(*i)->get_property (X_("state"), str)) {
162 error << _("Missing state property on AutomationState") << endmsg;
165 AutoState s = static_cast<AutoState>(string_2_enum (str, s));
166 set_automation_state_of (p, s);
174 MidiSource::empty () const
176 return !_length_beats;
180 MidiSource::length (samplepos_t pos) const
182 if (!_length_beats) {
186 BeatsSamplesConverter converter(_session.tempo_map(), pos);
187 return converter.to(_length_beats);
191 MidiSource::update_length (samplecnt_t)
193 // You're not the boss of me!
197 MidiSource::invalidate (const Lock& lock)
199 Invalidated(_session.transport_rolling());
203 MidiSource::midi_read (const Lock& lm,
204 Evoral::EventSink<samplepos_t>& dst,
205 samplepos_t source_start,
208 Evoral::Range<samplepos_t>* loop_range,
210 MidiStateTracker* tracker,
211 MidiChannelFilter* filter,
212 const std::set<Evoral::Parameter>& filtered,
213 const double pos_beats,
214 const double start_beats) const
216 BeatsSamplesConverter converter(_session.tempo_map(), source_start);
218 const double start_qn = pos_beats - start_beats;
220 DEBUG_TRACE (DEBUG::MidiSourceIO,
221 string_compose ("MidiSource::midi_read() %5 sstart %1 start %2 cnt %3 tracker %4\n",
222 source_start, start, cnt, tracker, name()));
225 return read_unlocked (lm, dst, source_start, start, cnt, loop_range, tracker, filter);
228 // Find appropriate model iterator
229 Evoral::Sequence<Temporal::Beats>::const_iterator& i = cursor.iter;
230 const bool linear_read = cursor.last_read_end != 0 && start == cursor.last_read_end;
231 if (!linear_read || !i.valid()) {
232 /* Cached iterator is invalid, search for the first event past start.
233 Note that multiple tracks can use a MidiSource simultaneously, so
234 all playback state must be in parameters (the cursor) and must not
235 be cached in the source of model itself.
236 See http://tracker.ardour.org/view.php?id=6541
238 cursor.connect(Invalidated);
239 cursor.iter = _model->begin(converter.from(start), false, filtered, &cursor.active_notes);
240 cursor.active_notes.clear();
243 cursor.last_read_end = start + cnt;
245 samplepos_t time_samples = 0;
246 // Copy events in [start, start + cnt) into dst
247 for (; i != _model->end(); ++i) {
249 // Offset by source start to convert event time to session time
251 samplepos_t time_samples = _session.tempo_map().sample_at_quarter_note (i->time().to_double() + start_qn);
253 if (time_samples < start + source_start) {
254 /* event too early */
258 } else if (time_samples >= start + cnt + source_start) {
260 DEBUG_TRACE (DEBUG::MidiSourceIO,
261 string_compose ("%1: reached end with event @ %2 vs. %3\n",
262 _name, time_samples, start+cnt));
270 time_samples = loop_range->squish (time_samples);
273 const uint8_t status = i->buffer()[0];
274 const bool is_channel_event = (0x80 <= (status & 0xF0)) && (status <= 0xE0);
275 if (filter && is_channel_event) {
276 /* Copy event so the filter can modify the channel. I'm not
277 sure if this is necessary here (channels are mapped later in
278 buffers anyway), but it preserves existing behaviour without
279 destroying events in the model during read. */
280 Evoral::Event<Temporal::Beats> ev(*i, true);
281 if (!filter->filter(ev.buffer(), ev.size())) {
282 dst.write (time_samples, ev.event_type(), ev.size(), ev.buffer());
284 DEBUG_TRACE (DEBUG::MidiSourceIO,
285 string_compose ("%1: filter event @ %2 type %3 size %4\n",
286 _name, time_samples, i->event_type(), i->size()));
289 dst.write (time_samples, i->event_type(), i->size(), i->buffer());
293 if (DEBUG_ENABLED(DEBUG::MidiSourceIO)) {
295 DEBUG_STR_APPEND(a, string_compose ("%1 added event @ %2 sz %3 within %4 .. %5 ",
296 _name, time_samples, i->size(),
297 start + source_start, start + cnt + source_start));
298 for (size_t n=0; n < i->size(); ++n) {
299 DEBUG_STR_APPEND(a,hex);
300 DEBUG_STR_APPEND(a,"0x");
301 DEBUG_STR_APPEND(a,(int)i->buffer()[n]);
302 DEBUG_STR_APPEND(a,' ');
304 DEBUG_STR_APPEND(a,'\n');
305 DEBUG_TRACE (DEBUG::MidiSourceIO, DEBUG_STR(a).str());
319 MidiSource::midi_write (const Lock& lm,
320 MidiRingBuffer<samplepos_t>& source,
321 samplepos_t source_start,
324 const samplecnt_t ret = write_unlocked (lm, source, source_start, cnt);
326 if (cnt == max_samplecnt) {
329 _capture_length += cnt;
336 MidiSource::mark_streaming_midi_write_started (const Lock& lock, NoteMode mode)
339 _model->set_note_mode (mode);
340 _model->start_write ();
347 MidiSource::mark_write_starting_now (samplecnt_t position,
348 samplecnt_t capture_length,
349 samplecnt_t loop_length)
351 /* I'm not sure if this is the best way to approach this, but
352 _capture_length needs to be set up with the transport sample
353 when a record actually starts, as it is used by
354 SMFSource::write_unlocked to decide whether incoming notes
355 are within the correct time range.
356 mark_streaming_midi_write_started (perhaps a more logical
357 place to do this) is not called at exactly the time when
358 record starts, and I don't think it necessarily can be
359 because it is not RT-safe.
362 set_natural_position (position);
363 _capture_length = capture_length;
364 _capture_loop_length = loop_length;
366 TempoMap& map (_session.tempo_map());
367 BeatsSamplesConverter converter(map, position);
368 _length_beats = converter.from(capture_length);
372 MidiSource::mark_streaming_write_started (const Lock& lock)
374 NoteMode note_mode = _model ? _model->note_mode() : Sustained;
375 mark_streaming_midi_write_started (lock, note_mode);
379 MidiSource::mark_midi_streaming_write_completed (const Lock& lock,
380 Evoral::Sequence<Temporal::Beats>::StuckNoteOption option,
384 _model->end_write (option, end);
386 /* Make captured controls discrete to play back user input exactly. */
387 for (MidiModel::Controls::iterator i = _model->controls().begin(); i != _model->controls().end(); ++i) {
388 if (i->second->list()) {
389 i->second->list()->set_interpolation(Evoral::ControlList::Discrete);
390 _interpolation_style.insert(std::make_pair(i->second->parameter(), Evoral::ControlList::Discrete));
400 MidiSource::mark_streaming_write_completed (const Lock& lock)
402 mark_midi_streaming_write_completed (lock, Evoral::Sequence<Temporal::Beats>::DeleteStuckNotes);
406 MidiSource::export_write_to (const Lock& lock, boost::shared_ptr<MidiSource> newsrc, Temporal::Beats begin, Temporal::Beats end)
408 Lock newsrc_lock (newsrc->mutex ());
411 error << string_compose (_("programming error: %1"), X_("no model for MidiSource during export"));
415 _model->write_section_to (newsrc, newsrc_lock, begin, end, true);
417 newsrc->flush_midi(newsrc_lock);
423 MidiSource::write_to (const Lock& lock, boost::shared_ptr<MidiSource> newsrc, Temporal::Beats begin, Temporal::Beats end)
425 Lock newsrc_lock (newsrc->mutex ());
427 newsrc->set_natural_position (_natural_position);
428 newsrc->copy_interpolation_from (this);
429 newsrc->copy_automation_state_from (this);
432 if (begin == Temporal::Beats() && end == std::numeric_limits<Temporal::Beats>::max()) {
433 _model->write_to (newsrc, newsrc_lock);
435 _model->write_section_to (newsrc, newsrc_lock, begin, end);
438 error << string_compose (_("programming error: %1"), X_("no model for MidiSource during ::clone()"));
442 newsrc->flush_midi(newsrc_lock);
444 /* force a reload of the model if the range is partial */
446 if (begin != Temporal::Beats() || end != std::numeric_limits<Temporal::Beats>::max()) {
447 newsrc->load_model (newsrc_lock, true);
449 newsrc->set_model (newsrc_lock, _model);
452 /* this file is not removable (but since it is MIDI, it is mutable) */
454 boost::dynamic_pointer_cast<FileSource> (newsrc)->prevent_deletion ();
460 MidiSource::session_saved()
464 /* this writes a copy of the data to disk.
465 XXX do we need to do this every time?
468 if (_model && _model->edited()) {
469 /* The model is edited, write its contents into the current source
470 file (overwiting previous contents). */
472 /* Temporarily drop our reference to the model so that as the model
473 pushes its current state to us, we don't try to update it. */
474 boost::shared_ptr<MidiModel> mm = _model;
477 /* Flush model contents to disk. */
478 mm->sync_to_source (lm);
480 /* Reacquire model. */
489 MidiSource::set_note_mode(const Lock& lock, NoteMode mode)
492 _model->set_note_mode(mode);
497 MidiSource::drop_model (const Lock& lock)
501 ModelChanged (); /* EMIT SIGNAL */
505 MidiSource::set_model (const Lock& lock, boost::shared_ptr<MidiModel> m)
509 ModelChanged (); /* EMIT SIGNAL */
512 Evoral::ControlList::InterpolationStyle
513 MidiSource::interpolation_of (Evoral::Parameter p) const
515 InterpolationStyleMap::const_iterator i = _interpolation_style.find (p);
516 if (i == _interpolation_style.end()) {
517 return EventTypeMap::instance().interpolation_of (p);
524 MidiSource::automation_state_of (Evoral::Parameter p) const
526 AutomationStateMap::const_iterator i = _automation_state.find (p);
527 if (i == _automation_state.end()) {
528 /* default to `play', otherwise if MIDI is recorded /
529 imported with controllers etc. they are by default
530 not played back, which is a little surprising.
538 /** Set interpolation style to be used for a given parameter. This change will be
539 * propagated to anyone who needs to know.
542 MidiSource::set_interpolation_of (Evoral::Parameter p, Evoral::ControlList::InterpolationStyle s)
544 if (interpolation_of (p) == s) {
548 if (EventTypeMap::instance().interpolation_of (p) == s) {
549 /* interpolation type is being set to the default, so we don't need a note in our map */
550 _interpolation_style.erase (p);
552 _interpolation_style[p] = s;
555 InterpolationChanged (p, s); /* EMIT SIGNAL */
559 MidiSource::set_automation_state_of (Evoral::Parameter p, AutoState s)
561 if (automation_state_of (p) == s) {
566 /* automation state is being set to the default, so we don't need a note in our map */
567 _automation_state.erase (p);
569 _automation_state[p] = s;
572 AutomationStateChanged (p, s); /* EMIT SIGNAL */
576 MidiSource::copy_interpolation_from (boost::shared_ptr<MidiSource> s)
578 copy_interpolation_from (s.get ());
582 MidiSource::copy_automation_state_from (boost::shared_ptr<MidiSource> s)
584 copy_automation_state_from (s.get ());
588 MidiSource::copy_interpolation_from (MidiSource* s)
590 _interpolation_style = s->_interpolation_style;
592 /* XXX: should probably emit signals here */
596 MidiSource::copy_automation_state_from (MidiSource* s)
598 _automation_state = s->_automation_state;
600 /* XXX: should probably emit signals here */