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