Fixup prev commit (LV2 X11 UI) -- #7837
[ardour.git] / libs / ardour / midi_playlist.cc
1 /*
2  * Copyright (C) 2006-2016 David Robillard <d@drobilla.net>
3  * Copyright (C) 2007-2017 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
5  * Copyright (C) 2015-2017 Robin Gareus <robin@gareus.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include <algorithm>
23 #include <cassert>
24 #include <cstdlib>
25 #include <iostream>
26 #include <utility>
27
28 #include "evoral/EventList.hpp"
29 #include "evoral/Control.hpp"
30
31 #include "ardour/beats_samples_converter.h"
32 #include "ardour/debug.h"
33 #include "ardour/midi_model.h"
34 #include "ardour/midi_playlist.h"
35 #include "ardour/midi_region.h"
36 #include "ardour/midi_source.h"
37 #include "ardour/midi_state_tracker.h"
38 #include "ardour/region_factory.h"
39 #include "ardour/session.h"
40 #include "ardour/tempo.h"
41 #include "ardour/types.h"
42
43 #include "pbd/i18n.h"
44
45 using namespace ARDOUR;
46 using namespace PBD;
47 using namespace std;
48
49 MidiPlaylist::MidiPlaylist (Session& session, const XMLNode& node, bool hidden)
50         : Playlist (session, node, DataType::MIDI, hidden)
51         , _note_mode(Sustained)
52         , _read_end(0)
53 {
54 #ifndef NDEBUG
55         XMLProperty const * prop = node.property("type");
56         assert(prop && DataType(prop->value()) == DataType::MIDI);
57 #endif
58
59         in_set_state++;
60         if (set_state (node, Stateful::loading_state_version)) {
61                 throw failed_constructor ();
62         }
63         in_set_state--;
64
65         relayer ();
66 }
67
68 MidiPlaylist::MidiPlaylist (Session& session, string name, bool hidden)
69         : Playlist (session, name, DataType::MIDI, hidden)
70         , _note_mode(Sustained)
71         , _read_end(0)
72 {
73 }
74
75 MidiPlaylist::MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other, string name, bool hidden)
76         : Playlist (other, name, hidden)
77         , _note_mode(other->_note_mode)
78         , _read_end(0)
79 {
80 }
81
82 MidiPlaylist::MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other,
83                             samplepos_t                            start,
84                             samplecnt_t                            dur,
85                             string                                name,
86                             bool                                  hidden)
87         : Playlist (other, start, dur, name, hidden)
88         , _note_mode(other->_note_mode)
89         , _read_end(0)
90 {
91 }
92
93 MidiPlaylist::~MidiPlaylist ()
94 {
95 }
96
97 template<typename Time>
98 struct EventsSortByTimeAndType {
99     bool operator() (const Evoral::Event<Time>* a, const Evoral::Event<Time>* b) {
100             if (a->time() == b->time()) {
101                     if (parameter_is_midi ((AutomationType)a->event_type()) &&
102                         parameter_is_midi ((AutomationType)b->event_type())) {
103                             /* negate return value since we must return whether
104                              * or not a should sort before b, not b before a
105                              */
106                             return !MidiBuffer::second_simultaneous_midi_byte_is_first (a->buffer()[0], b->buffer()[0]);
107                     }
108             }
109             return a->time() < b->time();
110     }
111 };
112
113 samplecnt_t
114 MidiPlaylist::read (Evoral::EventSink<samplepos_t>& dst,
115                     samplepos_t                     start,
116                     samplecnt_t                     dur,
117                     Evoral::Range<samplepos_t>*     loop_range,
118                     unsigned                       chan_n,
119                     MidiChannelFilter*             filter)
120 {
121         typedef pair<MidiStateTracker*,samplepos_t> TrackerInfo;
122
123         Playlist::RegionReadLock rl (this);
124
125         DEBUG_TRACE (DEBUG::MidiPlaylistIO,
126                      string_compose ("---- MidiPlaylist::read %1 .. %2 (%3 trackers) ----\n",
127                                      start, start + dur, _note_trackers.size()));
128
129         /* First, emit any queued edit fixup events at start. */
130         for (NoteTrackers::iterator t = _note_trackers.begin(); t != _note_trackers.end(); ++t) {
131                 t->second->fixer.emit(dst, _read_end, t->second->tracker);
132         }
133
134         /* Find relevant regions that overlap [start..end] */
135         const samplepos_t                         end = start + dur - 1;
136         std::vector< boost::shared_ptr<Region> > regs;
137         std::vector< boost::shared_ptr<Region> > ended;
138         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
139
140                 /* check for the case of solo_selection */
141                 bool force_transparent = ( _session.solo_selection_active() && SoloSelectedActive() && !SoloSelectedListIncludes( (const Region*) &(**i) ) );
142                 if ( force_transparent )
143                         continue;
144
145                 switch ((*i)->coverage (start, end)) {
146                 case Evoral::OverlapStart:
147                 case Evoral::OverlapInternal:
148                         regs.push_back (*i);
149                         break;
150
151                 case Evoral::OverlapExternal:
152                         /* this region is entirely contained in the read range */
153                         regs.push_back (*i);
154                         ended.push_back (*i);
155                         break;
156
157                 case Evoral::OverlapEnd:
158                         /* this region ends within the read range */
159                         regs.push_back (*i);
160                         ended.push_back (*i);
161                         break;
162
163                 default:
164                         /* we don't care */
165                         break;
166                 }
167         }
168
169         /* If we are reading from a single region, we can read directly into dst.  Otherwise,
170            we read into a temporarily list, sort it, then write that to dst. */
171         const bool direct_read = regs.size() == 1 &&
172                 (ended.empty() || (ended.size() == 1 && ended.front() == regs.front()));
173
174         Evoral::EventList<samplepos_t>  evlist;
175         Evoral::EventSink<samplepos_t>& tgt = direct_read ? dst : evlist;
176
177         DEBUG_TRACE (DEBUG::MidiPlaylistIO,
178                      string_compose ("\t%1 regions to read, direct: %2\n", regs.size(), direct_read));
179
180         for (vector<boost::shared_ptr<Region> >::iterator i = regs.begin(); i != regs.end(); ++i) {
181                 boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(*i);
182                 if (!mr) {
183                         continue;
184                 }
185
186                 /* Get the existing note tracker for this region, or create a new one. */
187                 NoteTrackers::iterator           t           = _note_trackers.find (mr.get());
188                 bool                             new_tracker = false;
189                 boost::shared_ptr<RegionTracker> tracker;
190                 if (t == _note_trackers.end()) {
191                         tracker     = boost::shared_ptr<RegionTracker>(new RegionTracker);
192                         new_tracker = true;
193                         DEBUG_TRACE (DEBUG::MidiPlaylistIO,
194                                      string_compose ("\tPre-read %1 (%2 .. %3): new tracker\n",
195                                                      mr->name(), mr->position(), mr->last_sample()));
196                 } else {
197                         tracker = t->second;
198                         DEBUG_TRACE (DEBUG::MidiPlaylistIO,
199                                      string_compose ("\tPre-read %1 (%2 .. %3): %4 active notes\n",
200                                                      mr->name(), mr->position(), mr->last_sample(), tracker->tracker.on()));
201                 }
202
203                 /* Read from region into target. */
204                 DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("read from %1 at %2 for %3 LR %4 .. %5\n",
205                                                                     mr->name(), start, dur, 
206                                                                     (loop_range ? loop_range->from : -1),
207                                                                     (loop_range ? loop_range->to : -1)));
208                 mr->read_at (tgt, start, dur, loop_range, tracker->cursor, chan_n, _note_mode, &tracker->tracker, filter);
209                 DEBUG_TRACE (DEBUG::MidiPlaylistIO,
210                              string_compose ("\tPost-read: %1 active notes\n", tracker->tracker.on()));
211
212                 if (find (ended.begin(), ended.end(), *i) != ended.end()) {
213                         /* Region ended within the read range, so resolve any active notes
214                            (either stuck notes in the data, or notes that end after the end
215                            of the region). */
216                         DEBUG_TRACE (DEBUG::MidiPlaylistIO,
217                                      string_compose ("\t%1 ended, resolve notes and delete (%2) tracker\n",
218                                                      mr->name(), ((new_tracker) ? "new" : "old")));
219
220                         tracker->tracker.resolve_notes (tgt, loop_range ? loop_range->squish ((*i)->last_sample()) : (*i)->last_sample());
221                         tracker->cursor.invalidate (false);
222                         if (!new_tracker) {
223                                 _note_trackers.erase (t);
224                         }
225
226                 } else {
227
228                         if (new_tracker) {
229                                 _note_trackers.insert (make_pair (mr.get(), tracker));
230                                 DEBUG_TRACE (DEBUG::MidiPlaylistIO, "\tadded tracker to trackers\n");
231                         }
232                 }
233         }
234
235         if (!direct_read && !evlist.empty()) {
236                 /* We've read from multiple regions, sort the event list by time. */
237                 EventsSortByTimeAndType<samplepos_t> cmp;
238                 evlist.sort (cmp);
239
240                 /* Copy ordered events from event list to dst. */
241                 for (Evoral::EventList<samplepos_t>::iterator e = evlist.begin(); e != evlist.end(); ++e) {
242                         Evoral::Event<samplepos_t>* ev (*e);
243                         dst.write (ev->time(), ev->event_type(), ev->size(), ev->buffer());
244                         delete ev;
245                 }
246         }
247
248         DEBUG_TRACE (DEBUG::MidiPlaylistIO, "---- End MidiPlaylist::read ----\n");
249         _read_end = start + dur;
250         return dur;
251 }
252
253 void
254 MidiPlaylist::region_edited(boost::shared_ptr<Region>         region,
255                             const MidiModel::NoteDiffCommand* cmd)
256 {
257         typedef MidiModel::NoteDiffCommand Command;
258
259         boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(region);
260         if (!mr || !_session.transport_rolling()) {
261                 return;
262         }
263
264         /* Take write lock to prevent concurrency with read(). */
265         Playlist::RegionWriteLock lock(this);
266
267         NoteTrackers::iterator t = _note_trackers.find(mr.get());
268         if (t == _note_trackers.end()) {
269                 return; /* Region is not currently active, nothing to do. */
270         }
271
272         /* Queue any necessary edit compensation events. */
273         t->second->fixer.prepare(
274                 _session.tempo_map(), cmd, mr->position() - mr->start(),
275                 _read_end, t->second->cursor.active_notes);
276 }
277
278 void
279 MidiPlaylist::reset_note_trackers ()
280 {
281         Playlist::RegionWriteLock rl (this, false);
282
283         DEBUG_TRACE (DEBUG::MidiTrackers, string_compose ("%1 reset all note trackers\n", name()));
284         _note_trackers.clear ();
285 }
286
287 void
288 MidiPlaylist::resolve_note_trackers (Evoral::EventSink<samplepos_t>& dst, samplepos_t time)
289 {
290         Playlist::RegionWriteLock rl (this, false);
291
292         for (NoteTrackers::iterator n = _note_trackers.begin(); n != _note_trackers.end(); ++n) {
293                 n->second->tracker.resolve_notes(dst, time);
294         }
295         DEBUG_TRACE (DEBUG::MidiTrackers, string_compose ("%1 resolve all note trackers\n", name()));
296         _note_trackers.clear ();
297 }
298
299 void
300 MidiPlaylist::remove_dependents (boost::shared_ptr<Region> region)
301 {
302         /* MIDI regions have no dependents (crossfades) but we might be tracking notes */
303         _note_trackers.erase(region.get());
304 }
305
306 void
307 MidiPlaylist::region_going_away (boost::weak_ptr<Region> region)
308 {
309         boost::shared_ptr<Region> r = region.lock();
310         if (r) {
311                 remove_dependents(r);
312         }
313 }
314
315 int
316 MidiPlaylist::set_state (const XMLNode& node, int version)
317 {
318         in_set_state++;
319         freeze ();
320
321         if (Playlist::set_state (node, version)) {
322                 return -1;
323         }
324
325         thaw();
326         in_set_state--;
327
328         return 0;
329 }
330
331 void
332 MidiPlaylist::dump () const
333 {
334         boost::shared_ptr<Region> r;
335
336         cerr << "Playlist \"" << _name << "\" " << endl
337         << regions.size() << " regions "
338         << endl;
339
340         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
341                 r = *i;
342                 cerr << "  " << r->name() << " @ " << r << " ["
343                 << r->start() << "+" << r->length()
344                 << "] at "
345                 << r->position()
346                 << " on layer "
347                 << r->layer ()
348                 << endl;
349         }
350 }
351
352 bool
353 MidiPlaylist::destroy_region (boost::shared_ptr<Region> region)
354 {
355         boost::shared_ptr<MidiRegion> r = boost::dynamic_pointer_cast<MidiRegion> (region);
356
357         if (!r) {
358                 return false;
359         }
360
361         bool changed = false;
362
363         {
364                 RegionWriteLock rlock (this);
365                 RegionList::iterator i;
366                 RegionList::iterator tmp;
367
368                 for (i = regions.begin(); i != regions.end(); ) {
369
370                         tmp = i;
371                         ++tmp;
372
373                         if ((*i) == region) {
374                                 regions.erase (i);
375                                 changed = true;
376                         }
377
378                         i = tmp;
379                 }
380
381                 NoteTrackers::iterator t = _note_trackers.find(region.get());
382                 if (t != _note_trackers.end()) {
383                         _note_trackers.erase(t);
384                 }
385         }
386
387         if (changed) {
388                 /* overload this, it normally means "removed", not destroyed */
389                 notify_region_removed (region);
390         }
391
392         return changed;
393 }
394 void
395 MidiPlaylist::_split_region (boost::shared_ptr<Region> region, const MusicSample& playlist_position)
396 {
397         if (!region->covers (playlist_position.sample)) {
398                 return;
399         }
400
401         if (region->position() == playlist_position.sample ||
402             region->last_sample() == playlist_position.sample) {
403                 return;
404         }
405
406         boost::shared_ptr<const MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(region);
407
408         if (mr == 0) {
409                 return;
410         }
411
412         boost::shared_ptr<Region> left;
413         boost::shared_ptr<Region> right;
414
415         string before_name;
416         string after_name;
417         const double before_qn = _session.tempo_map().exact_qn_at_sample (playlist_position.sample, playlist_position.division) - region->quarter_note();
418         const double after_qn = mr->length_beats() - before_qn;
419         MusicSample before (playlist_position.sample - region->position(), playlist_position.division);
420         MusicSample after (region->length() - before.sample, playlist_position.division);
421
422         /* split doesn't change anything about length, so don't try to splice */
423         bool old_sp = _splicing;
424         _splicing = true;
425
426         RegionFactory::region_name (before_name, region->name(), false);
427
428         {
429                 PropertyList plist;
430
431                 plist.add (Properties::length, before.sample);
432                 plist.add (Properties::length_beats, before_qn);
433                 plist.add (Properties::name, before_name);
434                 plist.add (Properties::left_of_split, true);
435                 plist.add (Properties::layering_index, region->layering_index ());
436                 plist.add (Properties::layer, region->layer ());
437
438                 /* note: we must use the version of ::create with an offset here,
439                    since it supplies that offset to the Region constructor, which
440                    is necessary to get audio region gain envelopes right.
441                 */
442                 left = RegionFactory::create (region, MusicSample (0, 0), plist, true);
443         }
444
445         RegionFactory::region_name (after_name, region->name(), false);
446
447         {
448                 PropertyList plist;
449
450                 plist.add (Properties::length, after.sample);
451                 plist.add (Properties::length_beats, after_qn);
452                 plist.add (Properties::name, after_name);
453                 plist.add (Properties::right_of_split, true);
454                 plist.add (Properties::layering_index, region->layering_index ());
455                 plist.add (Properties::layer, region->layer ());
456
457                 /* same note as above */
458                 right = RegionFactory::create (region, before, plist, true);
459         }
460
461         add_region_internal (left, region->position(), 0, region->quarter_note(), true);
462         add_region_internal (right, region->position() + before.sample, before.division, region->quarter_note() + before_qn, true);
463
464         remove_region_internal (region);
465
466         _splicing = old_sp;
467 }
468
469 set<Evoral::Parameter>
470 MidiPlaylist::contained_automation()
471 {
472         /* this function is never called from a realtime thread, so
473            its OK to block (for short intervals).
474         */
475
476         Playlist::RegionReadLock rl (this);
477         set<Evoral::Parameter> ret;
478
479         for (RegionList::const_iterator r = regions.begin(); r != regions.end(); ++r) {
480                 boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(*r);
481
482                 for (Automatable::Controls::iterator c = mr->model()->controls().begin();
483                                 c != mr->model()->controls().end(); ++c) {
484                         if (c->second->list()->size() > 0) {
485                                 ret.insert(c->first);
486                         }
487                 }
488         }
489
490         return ret;
491 }