1 /*
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>
9 *
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.
14 *
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.
19 *
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.
23 */
24
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <float.h>
29 #include <cerrno>
30 #include <ctime>
31 #include <cmath>
32 #include <iomanip>
33 #include <algorithm>
34
35 #include <glibmm/fileutils.h>
36 #include <glibmm/miscutils.h>
37
38 #include "pbd/xml++.h"
39 #include "pbd/pthread_utils.h"
40 #include "pbd/basename.h"
41 #include "pbd/timing.h"
42
43 #include "evoral/Control.h"
44 #include "evoral/EventSink.h"
45
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"
57
58 #include "pbd/i18n.h"
59
60 namespace ARDOUR { template <typename T> class MidiRingBuffer; }
61
62 using namespace std;
63 using namespace ARDOUR;
64 using namespace PBD;
65
MidiSource(Session & s,string name,Source::Flag flags)66 MidiSource::MidiSource (Session& s, string name, Source::Flag flags)
67 : Source(s, DataType::MIDI, name, flags)
68 , _writing(false)
69 , _length_beats(0.0)
70 , _capture_length(0)
71 , _capture_loop_length(0)
72 {
73 }
74
MidiSource(Session & s,const XMLNode & node)75 MidiSource::MidiSource (Session& s, const XMLNode& node)
76 : Source(s, node)
77 , _writing(false)
78 , _length_beats(0.0)
79 , _capture_length(0)
80 , _capture_loop_length(0)
81 {
82 if (set_state (node, Stateful::loading_state_version)) {
83 throw failed_constructor();
84 }
85 }
86
~MidiSource()87 MidiSource::~MidiSource ()
88 {
89 /* invalidate any existing iterators */
90 Invalidated (false);
91 }
92
93 XMLNode&
get_state()94 MidiSource::get_state ()
95 {
96 XMLNode& node (Source::get_state());
97
98 if (_captured_for.length()) {
99 node.set_property ("captured-for", _captured_for);
100 }
101
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));
106 }
107
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));
112 }
113
114 return node;
115 }
116
117 int
set_state(const XMLNode & node,int)118 MidiSource::set_state (const XMLNode& node, int /*version*/)
119 {
120 node.get_property ("captured-for", _captured_for);
121
122 std::string str;
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;
128 return -1;
129 }
130 Evoral::Parameter p = EventTypeMap::instance().from_symbol (str);
131
132 switch (p.type()) {
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";
140 continue;
141 default:
142 cerr << "Parameter \"" << str << "\" found for MIDI source ... not legal; ignoring this parameter\n";
143 continue;
144 }
145
146 if (!(*i)->get_property (X_("style"), str)) {
147 error << _("Missing style property on InterpolationStyle") << endmsg;
148 return -1;
149 }
150 Evoral::ControlList::InterpolationStyle s =
151 static_cast<Evoral::ControlList::InterpolationStyle>(string_2_enum (str, s));
152 set_interpolation_of (p, s);
153
154 } else if ((*i)->name() == X_("AutomationState")) {
155 if (!(*i)->get_property (X_("parameter"), str)) {
156 error << _("Missing parameter property on AutomationState") << endmsg;
157 return -1;
158 }
159 Evoral::Parameter p = EventTypeMap::instance().from_symbol (str);
160
161 if (!(*i)->get_property (X_("state"), str)) {
162 error << _("Missing state property on AutomationState") << endmsg;
163 return -1;
164 }
165 AutoState s = static_cast<AutoState>(string_2_enum (str, s));
166 set_automation_state_of (p, s);
167 }
168 }
169
170 return 0;
171 }
172
173 bool
empty() const174 MidiSource::empty () const
175 {
176 return !_length_beats;
177 }
178
179 samplecnt_t
length(samplepos_t pos) const180 MidiSource::length (samplepos_t pos) const
181 {
182 if (!_length_beats) {
183 return 0;
184 }
185
186 BeatsSamplesConverter converter(_session.tempo_map(), pos);
187 return converter.to(_length_beats);
188 }
189
190 void
update_length(samplecnt_t)191 MidiSource::update_length (samplecnt_t)
192 {
193 // You're not the boss of me!
194 }
195
196 void
invalidate(const Lock & lock)197 MidiSource::invalidate (const Lock& lock)
198 {
199 Invalidated(_session.transport_rolling());
200 }
201
202 samplecnt_t
midi_read(const Lock & lm,Evoral::EventSink<samplepos_t> & dst,samplepos_t source_start,samplepos_t start,samplecnt_t cnt,Evoral::Range<samplepos_t> * loop_range,MidiCursor & cursor,MidiStateTracker * tracker,MidiChannelFilter * filter,const std::set<Evoral::Parameter> & filtered,const double pos_beats,const double start_beats) const203 MidiSource::midi_read (const Lock& lm,
204 Evoral::EventSink<samplepos_t>& dst,
205 samplepos_t source_start,
206 samplepos_t start,
207 samplecnt_t cnt,
208 Evoral::Range<samplepos_t>* loop_range,
209 MidiCursor& cursor,
210 MidiStateTracker* tracker,
211 MidiChannelFilter* filter,
212 const std::set<Evoral::Parameter>& filtered,
213 const double pos_beats,
214 const double start_beats) const
215 {
216 BeatsSamplesConverter converter(_session.tempo_map(), source_start);
217
218 const double start_qn = pos_beats - start_beats;
219
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()));
223
224 if (!_model) {
225 return read_unlocked (lm, dst, source_start, start, cnt, loop_range, tracker, filter);
226 }
227
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
237 */
238 cursor.connect(Invalidated);
239 cursor.iter = _model->begin(converter.from(start), false, filtered, &cursor.active_notes);
240 cursor.active_notes.clear();
241 }
242
243 cursor.last_read_end = start + cnt;
244
245 // Copy events in [start, start + cnt) into dst
246 for (; i != _model->end(); ++i) {
247
248 // Offset by source start to convert event time to session time
249
250 samplepos_t time_samples = _session.tempo_map().sample_at_quarter_note (i->time().to_double() + start_qn);
251
252 if (time_samples < start + source_start) {
253 /* event too early */
254
255 continue;
256
257 } else if (time_samples >= start + cnt + source_start) {
258
259 DEBUG_TRACE (DEBUG::MidiSourceIO,
260 string_compose ("%1: reached end with event @ %2 vs. %3\n",
261 _name, time_samples, start+cnt));
262 break;
263
264 } else {
265
266 /* in range */
267
268 if (loop_range) {
269 time_samples = loop_range->squish (time_samples);
270 }
271
272 const uint8_t status = i->buffer()[0];
273 const bool is_channel_event = (0x80 <= (status & 0xF0)) && (status <= 0xE0);
274 if (filter && is_channel_event) {
275 /* Copy event so the filter can modify the channel. I'm not
276 sure if this is necessary here (channels are mapped later in
277 buffers anyway), but it preserves existing behaviour without
278 destroying events in the model during read. */
279 Evoral::Event<Temporal::Beats> ev(*i, true);
280 if (!filter->filter(ev.buffer(), ev.size())) {
281 dst.write (time_samples, ev.event_type(), ev.size(), ev.buffer());
282 } else {
283 DEBUG_TRACE (DEBUG::MidiSourceIO,
284 string_compose ("%1: filter event @ %2 type %3 size %4\n",
285 _name, time_samples, i->event_type(), i->size()));
286 }
287 } else {
288 dst.write (time_samples, i->event_type(), i->size(), i->buffer());
289 }
290
291 #ifndef NDEBUG
292 if (DEBUG_ENABLED(DEBUG::MidiSourceIO)) {
293 DEBUG_STR_DECL(a);
294 DEBUG_STR_APPEND(a, string_compose ("%1 added event @ %2 sz %3 within %4 .. %5 ",
295 _name, time_samples, i->size(),
296 start + source_start, start + cnt + source_start));
297 for (size_t n=0; n < i->size(); ++n) {
298 DEBUG_STR_APPEND(a,hex);
299 DEBUG_STR_APPEND(a,"0x");
300 DEBUG_STR_APPEND(a,(int)i->buffer()[n]);
301 DEBUG_STR_APPEND(a,' ');
302 }
303 DEBUG_STR_APPEND(a,'\n');
304 DEBUG_TRACE (DEBUG::MidiSourceIO, DEBUG_STR(a).str());
305 }
306 #endif
307
308 if (tracker) {
309 tracker->track (*i);
310 }
311 }
312 }
313
314 return cnt;
315 }
316
317 samplecnt_t
midi_write(const Lock & lm,MidiRingBuffer<samplepos_t> & source,samplepos_t source_start,samplecnt_t cnt)318 MidiSource::midi_write (const Lock& lm,
319 MidiRingBuffer<samplepos_t>& source,
320 samplepos_t source_start,
321 samplecnt_t cnt)
322 {
323 const samplecnt_t ret = write_unlocked (lm, source, source_start, cnt);
324
325 if (cnt == max_samplecnt) {
326 invalidate(lm);
327 } else {
328 _capture_length += cnt;
329 }
330
331 return ret;
332 }
333
334 void
mark_streaming_midi_write_started(const Lock & lock,NoteMode mode)335 MidiSource::mark_streaming_midi_write_started (const Lock& lock, NoteMode mode)
336 {
337 if (_model) {
338 _model->set_note_mode (mode);
339 _model->start_write ();
340 }
341
342 _writing = true;
343 }
344
345 void
mark_write_starting_now(samplecnt_t position,samplecnt_t capture_length,samplecnt_t loop_length)346 MidiSource::mark_write_starting_now (samplecnt_t position,
347 samplecnt_t capture_length,
348 samplecnt_t loop_length)
349 {
350 /* I'm not sure if this is the best way to approach this, but
351 _capture_length needs to be set up with the transport sample
352 when a record actually starts, as it is used by
353 SMFSource::write_unlocked to decide whether incoming notes
354 are within the correct time range.
355 mark_streaming_midi_write_started (perhaps a more logical
356 place to do this) is not called at exactly the time when
357 record starts, and I don't think it necessarily can be
358 because it is not RT-safe.
359 */
360
361 set_natural_position (position);
362 _capture_length = capture_length;
363 _capture_loop_length = loop_length;
364
365 TempoMap& map (_session.tempo_map());
366 BeatsSamplesConverter converter(map, position);
367 _length_beats = converter.from(capture_length);
368 }
369
370 void
mark_streaming_write_started(const Lock & lock)371 MidiSource::mark_streaming_write_started (const Lock& lock)
372 {
373 NoteMode note_mode = _model ? _model->note_mode() : Sustained;
374 mark_streaming_midi_write_started (lock, note_mode);
375 }
376
377 void
mark_midi_streaming_write_completed(const Lock & lock,Evoral::Sequence<Temporal::Beats>::StuckNoteOption option,Temporal::Beats end)378 MidiSource::mark_midi_streaming_write_completed (const Lock& lock,
379 Evoral::Sequence<Temporal::Beats>::StuckNoteOption option,
380 Temporal::Beats end)
381 {
382 if (_model) {
383 _model->end_write (option, end);
384
385 /* Make captured controls discrete to play back user input exactly. */
386 for (MidiModel::Controls::iterator i = _model->controls().begin(); i != _model->controls().end(); ++i) {
387 if (i->second->list()) {
388 i->second->list()->set_interpolation(Evoral::ControlList::Discrete);
389 _interpolation_style.insert(std::make_pair(i->second->parameter(), Evoral::ControlList::Discrete));
390 }
391 }
392 }
393
394 invalidate(lock);
395 _writing = false;
396 }
397
398 void
mark_streaming_write_completed(const Lock & lock)399 MidiSource::mark_streaming_write_completed (const Lock& lock)
400 {
401 mark_midi_streaming_write_completed (lock, Evoral::Sequence<Temporal::Beats>::DeleteStuckNotes);
402 }
403
404 int
export_write_to(const Lock & lock,boost::shared_ptr<MidiSource> newsrc,Temporal::Beats begin,Temporal::Beats end)405 MidiSource::export_write_to (const Lock& lock, boost::shared_ptr<MidiSource> newsrc, Temporal::Beats begin, Temporal::Beats end)
406 {
407 Lock newsrc_lock (newsrc->mutex ());
408
409 if (!_model) {
410 error << string_compose (_("programming error: %1"), X_("no model for MidiSource during export"));
411 return -1;
412 }
413
414 _model->write_section_to (newsrc, newsrc_lock, begin, end, true);
415
416 newsrc->flush_midi(newsrc_lock);
417
418 return 0;
419 }
420
421 int
write_to(const Lock & lock,boost::shared_ptr<MidiSource> newsrc,Temporal::Beats begin,Temporal::Beats end)422 MidiSource::write_to (const Lock& lock, boost::shared_ptr<MidiSource> newsrc, Temporal::Beats begin, Temporal::Beats end)
423 {
424 Lock newsrc_lock (newsrc->mutex ());
425
426 newsrc->set_natural_position (_natural_position);
427 newsrc->copy_interpolation_from (this);
428 newsrc->copy_automation_state_from (this);
429
430 if (_model) {
431 if (begin == Temporal::Beats() && end == std::numeric_limits<Temporal::Beats>::max()) {
432 _model->write_to (newsrc, newsrc_lock);
433 } else {
434 _model->write_section_to (newsrc, newsrc_lock, begin, end);
435 }
436 } else {
437 error << string_compose (_("programming error: %1"), X_("no model for MidiSource during ::clone()"));
438 return -1;
439 }
440
441 newsrc->flush_midi(newsrc_lock);
442
443
444 if (begin != Temporal::Beats() || end != std::numeric_limits<Temporal::Beats>::max()) {
445 /* force a reload of the model if the range is partial */
446 newsrc->load_model (newsrc_lock, true);
447 } else {
448 /* re-create model */
449 newsrc->destroy_model (newsrc_lock);
450 newsrc->load_model (newsrc_lock);
451 }
452
453 /* this file is not removable (but since it is MIDI, it is mutable) */
454
455 boost::dynamic_pointer_cast<FileSource> (newsrc)->prevent_deletion ();
456
457 return 0;
458 }
459
460 void
session_saved()461 MidiSource::session_saved()
462 {
463 Lock lm (_lock);
464
465 /* this writes a copy of the data to disk.
466 XXX do we need to do this every time?
467 */
468
469 if (_model && _model->edited()) {
470 /* The model is edited, write its contents into the current source
471 file (overwiting previous contents). */
472
473 /* Temporarily drop our reference to the model so that as the model
474 pushes its current state to us, we don't try to update it. */
475 boost::shared_ptr<MidiModel> mm = _model;
476 _model.reset ();
477
478 /* Flush model contents to disk. */
479 mm->sync_to_source (lm);
480
481 /* Reacquire model. */
482 _model = mm;
483
484 } else {
485 flush_midi(lm);
486 }
487 }
488
489 void
set_note_mode(const Lock & lock,NoteMode mode)490 MidiSource::set_note_mode(const Lock& lock, NoteMode mode)
491 {
492 if (_model) {
493 _model->set_note_mode(mode);
494 }
495 }
496
497 void
drop_model(const Lock & lock)498 MidiSource::drop_model (const Lock& lock)
499 {
500 _model.reset();
501 invalidate(lock);
502 ModelChanged (); /* EMIT SIGNAL */
503 }
504
505 void
set_model(const Lock & lock,boost::shared_ptr<MidiModel> m)506 MidiSource::set_model (const Lock& lock, boost::shared_ptr<MidiModel> m)
507 {
508 _model = m;
509 invalidate(lock);
510 ModelChanged (); /* EMIT SIGNAL */
511 }
512
513 Evoral::ControlList::InterpolationStyle
interpolation_of(Evoral::Parameter p) const514 MidiSource::interpolation_of (Evoral::Parameter p) const
515 {
516 InterpolationStyleMap::const_iterator i = _interpolation_style.find (p);
517 if (i == _interpolation_style.end()) {
518 return EventTypeMap::instance().interpolation_of (p);
519 }
520
521 return i->second;
522 }
523
524 AutoState
automation_state_of(Evoral::Parameter p) const525 MidiSource::automation_state_of (Evoral::Parameter p) const
526 {
527 AutomationStateMap::const_iterator i = _automation_state.find (p);
528 if (i == _automation_state.end()) {
529 /* default to `play', otherwise if MIDI is recorded /
530 imported with controllers etc. they are by default
531 not played back, which is a little surprising.
532 */
533 return Play;
534 }
535
536 return i->second;
537 }
538
539 /** Set interpolation style to be used for a given parameter. This change will be
540 * propagated to anyone who needs to know.
541 */
542 void
set_interpolation_of(Evoral::Parameter p,Evoral::ControlList::InterpolationStyle s)543 MidiSource::set_interpolation_of (Evoral::Parameter p, Evoral::ControlList::InterpolationStyle s)
544 {
545 if (interpolation_of (p) == s) {
546 return;
547 }
548
549 if (EventTypeMap::instance().interpolation_of (p) == s) {
550 /* interpolation type is being set to the default, so we don't need a note in our map */
551 _interpolation_style.erase (p);
552 } else {
553 _interpolation_style[p] = s;
554 }
555
556 InterpolationChanged (p, s); /* EMIT SIGNAL */
557 }
558
559 void
set_automation_state_of(Evoral::Parameter p,AutoState s)560 MidiSource::set_automation_state_of (Evoral::Parameter p, AutoState s)
561 {
562 if (automation_state_of (p) == s) {
563 return;
564 }
565
566 if (s == Play) {
567 /* automation state is being set to the default, so we don't need a note in our map */
568 _automation_state.erase (p);
569 } else {
570 _automation_state[p] = s;
571 }
572
573 AutomationStateChanged (p, s); /* EMIT SIGNAL */
574 }
575
576 void
copy_interpolation_from(boost::shared_ptr<MidiSource> s)577 MidiSource::copy_interpolation_from (boost::shared_ptr<MidiSource> s)
578 {
579 copy_interpolation_from (s.get ());
580 }
581
582 void
copy_automation_state_from(boost::shared_ptr<MidiSource> s)583 MidiSource::copy_automation_state_from (boost::shared_ptr<MidiSource> s)
584 {
585 copy_automation_state_from (s.get ());
586 }
587
588 void
copy_interpolation_from(MidiSource * s)589 MidiSource::copy_interpolation_from (MidiSource* s)
590 {
591 _interpolation_style = s->_interpolation_style;
592
593 /* XXX: should probably emit signals here */
594 }
595
596 void
copy_automation_state_from(MidiSource * s)597 MidiSource::copy_automation_state_from (MidiSource* s)
598 {
599 _automation_state = s->_automation_state;
600
601 /* XXX: should probably emit signals here */
602 }
603