Actually added the code mentioned in my last commit. Whoops.
[ardour.git] / libs / ardour / midi_region.cc
1 /*
2     Copyright (C) 2006 Paul Davis 
3         Written by Dave Robillard, 2006
4
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.
9
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.
14
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.
18 */
19
20 #include <cmath>
21 #include <climits>
22 #include <cfloat>
23
24 #include <set>
25
26 #include <sigc++/bind.h>
27 #include <sigc++/class_slot.h>
28
29 #include <glibmm/thread.h>
30
31 #include <pbd/basename.h>
32 #include <pbd/xml++.h>
33
34 #include <ardour/midi_region.h>
35 #include <ardour/session.h>
36 #include <ardour/gain.h>
37 #include <ardour/dB.h>
38 #include <ardour/playlist.h>
39 #include <ardour/midi_source.h>
40
41 #include "i18n.h"
42 #include <locale.h>
43
44 using namespace std;
45 using namespace ARDOUR;
46
47 MidiRegionState::MidiRegionState (string why)
48         : RegionState (why)
49 {
50 }
51
52 MidiRegion::MidiRegion (MidiSource& src, jack_nframes_t start, jack_nframes_t length, bool announce)
53         : Region (start, length, PBD::basename_nosuffix(src.name()), 0,  Region::Flag(Region::DefaultFlags|Region::External))
54 {
55         /* basic MidiRegion constructor */
56
57         sources.push_back (&src);
58         master_sources.push_back (&src);
59         src.GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
60
61         save_state ("initial state");
62
63         if (announce) {
64                  CheckNewRegion (this); /* EMIT SIGNAL */
65         }
66 }
67
68 MidiRegion::MidiRegion (MidiSource& src, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce)
69         : Region (start, length, name, layer, flags)
70 {
71         /* basic MidiRegion constructor */
72
73         sources.push_back (&src);
74         master_sources.push_back (&src);
75         src.GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
76
77         save_state ("initial state");
78
79         if (announce) {
80                  CheckNewRegion (this); /* EMIT SIGNAL */
81         }
82 }
83
84 MidiRegion::MidiRegion (SourceList& srcs, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce)
85         : Region (start, length, name, layer, flags)
86 {
87         /* basic MidiRegion constructor */
88 #if 0
89         for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
90                 sources.push_back (*i);
91                 master_sources.push_back (*i);
92                 (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
93         }
94
95 {
96         /* create a new MidiRegion, that is part of an existing one */
97         
98         set<MidiSource*> unique_srcs;
99
100         for (SourceList::const_iterator i= other.sources.begin(); i != other.sources.end(); ++i) {
101                 sources.push_back (*i);
102                 (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
103                 unique_srcs.insert (*i);
104         }
105
106         for (SourceList::const_iterator i = other.master_sources.begin(); i != other.master_sources.end(); ++i) {
107                 if (unique_srcs.find (*i) == unique_srcs.end()) {
108                         (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
109                 }
110                 master_sources.push_back (*i);
111         }
112
113         save_state ("initial state");
114
115         if (announce) {
116                 CheckNewRegion (this); /* EMIT SIGNAL */
117         }
118 #endif
119 }
120
121 MidiRegion::MidiRegion (const MidiRegion &other)
122         : Region (other)
123 {
124         /* Pure copy constructor */
125
126         set<MidiSource*> unique_srcs;
127
128         for (SourceList::const_iterator i = other.sources.begin(); i != other.sources.end(); ++i) {
129                 sources.push_back (*i);
130                 (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
131                 unique_srcs.insert (*i);
132         }
133
134         for (SourceList::const_iterator i = other.master_sources.begin(); i != other.master_sources.end(); ++i) {
135                 master_sources.push_back (*i);
136                 if (unique_srcs.find (*i) == unique_srcs.end()) {
137                         (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
138                 }
139         }
140
141         save_state ("initial state");
142
143         /* NOTE: no CheckNewRegion signal emitted here. This is the copy constructor */
144 }
145
146 MidiRegion::MidiRegion (MidiSource& src, const XMLNode& node)
147         : Region (node)
148 {
149         sources.push_back (&src);
150         master_sources.push_back (&src);
151         src.GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
152
153         if (set_state (node)) {
154                 throw failed_constructor();
155         }
156
157         save_state ("initial state");
158
159         CheckNewRegion (this); /* EMIT SIGNAL */
160 }
161
162 MidiRegion::MidiRegion (SourceList& srcs, const XMLNode& node)
163         : Region (node)
164 {
165         /* basic MidiRegion constructor */
166
167         set<MidiSource*> unique_srcs;
168
169         for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
170                 sources.push_back (*i);
171                 (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
172                 unique_srcs.insert (*i);
173         }
174
175         for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
176                 master_sources.push_back (*i);
177                 if (unique_srcs.find (*i) == unique_srcs.end()) {
178                         (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
179                 }
180         }
181
182         if (set_state (node)) {
183                 throw failed_constructor();
184         }
185
186         save_state ("initial state");
187
188         CheckNewRegion (this); /* EMIT SIGNAL */
189 }
190
191 MidiRegion::~MidiRegion ()
192 {
193         GoingAway (this);
194 }
195
196 StateManager::State*
197 MidiRegion::state_factory (std::string why) const
198 {
199         MidiRegionState* state = new MidiRegionState (why);
200
201         Region::store_state (*state);
202
203         return state;
204 }       
205
206 Change
207 MidiRegion::restore_state (StateManager::State& sstate) 
208 {
209         MidiRegionState* state = dynamic_cast<MidiRegionState*> (&sstate);
210
211         Change what_changed = Region::restore_and_return_flags (*state);
212         
213         if (_flags != Flag (state->_flags)) {
214                 
215                 //uint32_t old_flags = _flags;
216                 
217                 _flags = Flag (state->_flags);
218                 
219         }
220                 
221         /* XXX need a way to test stored state versus current for envelopes */
222
223         what_changed = Change (what_changed);
224
225         return what_changed;
226 }
227
228 UndoAction
229 MidiRegion::get_memento() const
230 {
231         return sigc::bind (mem_fun (*(const_cast<MidiRegion *> (this)), &StateManager::use_state), _current_state_id);
232 }
233
234 bool
235 MidiRegion::verify_length (jack_nframes_t len)
236 {
237         for (uint32_t n=0; n < sources.size(); ++n) {
238                 if (_start > sources[n]->length() - len) {
239                         return false;
240                 }
241         }
242         return true;
243 }
244
245 bool
246 MidiRegion::verify_start_and_length (jack_nframes_t new_start, jack_nframes_t new_length)
247 {
248         for (uint32_t n=0; n < sources.size(); ++n) {
249                 if (new_length > sources[n]->length() - new_start) {
250                         return false;
251                 }
252         }
253         return true;
254 }
255 bool
256 MidiRegion::verify_start (jack_nframes_t pos)
257 {
258         for (uint32_t n=0; n < sources.size(); ++n) {
259                 if (pos > sources[n]->length() - _length) {
260                         return false;
261                 }
262         }
263         return true;
264 }
265
266 bool
267 MidiRegion::verify_start_mutable (jack_nframes_t& new_start)
268 {
269         for (uint32_t n=0; n < sources.size(); ++n) {
270                 if (new_start > sources[n]->length() - _length) {
271                         new_start = sources[n]->length() - _length;
272                 }
273         }
274         return true;
275 }
276
277 jack_nframes_t
278 MidiRegion::read_at (unsigned char *buf, unsigned char *mixdown_buffer, char * workbuf, jack_nframes_t position, 
279                       jack_nframes_t cnt, 
280                       uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const
281 {
282         return _read_at (sources, buf, mixdown_buffer, workbuf, position, cnt, chan_n, read_frames, skip_frames);
283 }
284
285 jack_nframes_t
286 MidiRegion::master_read_at (unsigned char *buf, unsigned char *mixdown_buffer, char * workbuf, jack_nframes_t position, 
287                              jack_nframes_t cnt, uint32_t chan_n) const
288 {
289         return _read_at (master_sources, buf, mixdown_buffer, workbuf, position, cnt, chan_n, 0, 0);
290 }
291
292 jack_nframes_t
293 MidiRegion::_read_at (const SourceList& srcs, unsigned char *buf, unsigned char *mixdown_buffer, char * workbuf,
294                        jack_nframes_t position, jack_nframes_t cnt, 
295                        uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const
296 {
297         jack_nframes_t internal_offset;
298         jack_nframes_t buf_offset;
299         jack_nframes_t to_read;
300         
301         /* precondition: caller has verified that we cover the desired section */
302
303         if (chan_n >= sources.size()) {
304                 return 0; /* read nothing */
305         }
306         
307         if (position < _position) {
308                 internal_offset = 0;
309                 buf_offset = _position - position;
310                 cnt -= buf_offset;
311         } else {
312                 internal_offset = position - _position;
313                 buf_offset = 0;
314         }
315
316         if (internal_offset >= _length) {
317                 return 0; /* read nothing */
318         }
319         
320
321         if ((to_read = min (cnt, _length - internal_offset)) == 0) {
322                 return 0; /* read nothing */
323         }
324
325         if (opaque()) {
326                 /* overwrite whatever is there */
327                 mixdown_buffer = buf + buf_offset;
328         } else {
329                 mixdown_buffer += buf_offset;
330         }
331
332         if (muted()) {
333                 return 0; /* read nothing */
334         }
335
336         _read_data_count = 0;
337
338         if (srcs[chan_n]->read (mixdown_buffer, _start + internal_offset, to_read, workbuf) != to_read) {
339                 return 0; /* "read nothing" */
340         }
341
342         _read_data_count += srcs[chan_n]->read_data_count();
343
344         if (!opaque()) {
345
346                 /* gack. the things we do for users.
347                  */
348
349                 buf += buf_offset;
350
351                 for (jack_nframes_t n = 0; n < to_read; ++n) {
352                         buf[n] += mixdown_buffer[n];
353                 }
354         } 
355         
356         return to_read;
357 }
358         
359 XMLNode&
360 MidiRegion::get_state ()
361 {
362         return state (true);
363 }
364
365 XMLNode&
366 MidiRegion::state (bool full)
367 {
368         XMLNode& node (Region::state (full));
369         //XMLNode *child;
370         char buf[64];
371         char buf2[64];
372         LocaleGuard lg (X_("POSIX"));
373         
374         snprintf (buf, sizeof (buf), "0x%x", (int) _flags);
375         node.add_property ("flags", buf);
376
377         for (uint32_t n=0; n < sources.size(); ++n) {
378                 snprintf (buf2, sizeof(buf2), "source-%d", n);
379                 snprintf (buf, sizeof(buf), "%" PRIu64, sources[n]->id());
380                 node.add_property (buf2, buf);
381         }
382
383         snprintf (buf, sizeof (buf), "%u", (uint32_t) sources.size());
384         node.add_property ("channels", buf);
385
386         if (full && _extra_xml) {
387                 node.add_child_copy (*_extra_xml);
388         }
389
390         return node;
391 }
392
393 int
394 MidiRegion::set_state (const XMLNode& node)
395 {
396         const XMLNodeList& nlist = node.children();
397         const XMLProperty *prop;
398         LocaleGuard lg (X_("POSIX"));
399
400         Region::set_state (node);
401
402         if ((prop = node.property ("flags")) != 0) {
403                 _flags = Flag (strtol (prop->value().c_str(), (char **) 0, 16));
404
405                 _flags = Flag (_flags & ~Region::LeftOfSplit);
406                 _flags = Flag (_flags & ~Region::RightOfSplit);
407         }
408
409         /* Now find envelope description and other misc child items */
410                                 
411         for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
412                 
413                 XMLNode *child;
414                 //XMLProperty *prop;
415                 
416                 child = (*niter);
417         }
418
419         return 0;
420 }
421
422 int
423 MidiRegion::separate_by_channel (Session& session, vector<MidiRegion*>& v) const
424 {
425         SourceList srcs;
426         string new_name;
427
428         for (SourceList::const_iterator i = master_sources.begin(); i != master_sources.end(); ++i) {
429
430                 srcs.clear ();
431                 srcs.push_back (*i);
432
433                 /* generate a new name */
434                 
435                 if (session.region_name (new_name, _name)) {
436                         return -1;
437                 }
438
439                 /* create a copy with just one source */
440
441                 v.push_back (new MidiRegion (srcs, _start, _length, new_name, _layer, _flags));
442         }
443
444         return 0;
445 }
446
447 void
448 MidiRegion::source_deleted (Source* ignored)
449 {
450         delete this;
451 }
452
453 void
454 MidiRegion::lock_sources ()
455 {
456         SourceList::iterator i;
457         set<MidiSource*> unique_srcs;
458
459         for (i = sources.begin(); i != sources.end(); ++i) {
460                 unique_srcs.insert (*i);
461                 (*i)->use ();
462         }
463
464         for (i = master_sources.begin(); i != master_sources.end(); ++i) {
465                 if (unique_srcs.find (*i) == unique_srcs.end()) {
466                         (*i)->use ();
467                 }
468         }
469 }
470
471 void
472 MidiRegion::unlock_sources ()
473 {
474         SourceList::iterator i;
475         set<MidiSource*> unique_srcs;
476
477         for (i = sources.begin(); i != sources.end(); ++i) {
478                 unique_srcs.insert (*i);
479                 (*i)->release ();
480         }
481
482         for (i = master_sources.begin(); i != master_sources.end(); ++i) {
483                 if (unique_srcs.find (*i) == unique_srcs.end()) {
484                         (*i)->release ();
485                 }
486         }
487 }
488
489 vector<string>
490 MidiRegion::master_source_names ()
491 {
492         SourceList::iterator i;
493
494         vector<string> names;
495         for (i = master_sources.begin(); i != master_sources.end(); ++i) {
496                 names.push_back((*i)->name());
497         }
498
499         return names;
500 }
501
502 bool
503 MidiRegion::region_list_equivalent (const MidiRegion& other) const
504 {
505         return size_equivalent (other) && source_equivalent (other) && _name == other._name;
506 }
507
508 bool
509 MidiRegion::source_equivalent (const MidiRegion& other) const
510 {
511         SourceList::const_iterator i;
512         SourceList::const_iterator io;
513
514         for (i = sources.begin(), io = other.sources.begin(); i != sources.end() && io != other.sources.end(); ++i, ++io) {
515                 if ((*i)->id() != (*io)->id()) {
516                         return false;
517                 }
518         }
519
520         for (i = master_sources.begin(), io = other.master_sources.begin(); i != master_sources.end() && io != other.master_sources.end(); ++i, ++io) {
521                 if ((*i)->id() != (*io)->id()) {
522                         return false;
523                 }
524         }
525
526         return true;
527 }
528
529 bool
530 MidiRegion::overlap_equivalent (const MidiRegion& other) const
531 {
532         return coverage (other.first_frame(), other.last_frame()) != OverlapNone;
533 }
534
535 bool
536 MidiRegion::equivalent (const MidiRegion& other) const
537 {
538         return _start == other._start &&
539                 _position == other._position &&
540                 _length == other._length;
541 }
542
543 bool
544 MidiRegion::size_equivalent (const MidiRegion& other) const
545 {
546         return _start == other._start &&
547                 _length == other._length;
548 }
549
550 #if 0
551 int
552 MidiRegion::exportme (Session& session, AudioExportSpecification& spec)
553 {
554         const jack_nframes_t blocksize = 4096;
555         jack_nframes_t to_read;
556         int status = -1;
557
558         spec.channels = sources.size();
559
560         if (spec.prepare (blocksize, session.frame_rate())) {
561                 goto out;
562         }
563
564         spec.pos = 0;
565         spec.total_frames = _length;
566
567         while (spec.pos < _length && !spec.stop) {
568                 
569                 
570                 /* step 1: interleave */
571                 
572                 to_read = min (_length - spec.pos, blocksize);
573                 
574                 if (spec.channels == 1) {
575
576                         if (sources.front()->read (spec.dataF, _start + spec.pos, to_read, 0) != to_read) {
577                                 goto out;
578                         }
579
580                 } else {
581
582                         Sample buf[blocksize];
583
584                         for (uint32_t chan = 0; chan < spec.channels; ++chan) {
585                                 
586                                 if (sources[chan]->read (buf, _start + spec.pos, to_read, 0) != to_read) {
587                                         goto out;
588                                 }
589                                 
590                                 for (jack_nframes_t x = 0; x < to_read; ++x) {
591                                         spec.dataF[chan+(x*spec.channels)] = buf[x];
592                                 }
593                         }
594                 }
595                 
596                 if (spec.process (to_read)) {
597                         goto out;
598                 }
599                 
600                 spec.pos += to_read;
601                 spec.progress = (double) spec.pos /_length;
602                 
603         }
604         
605         status = 0;
606
607   out:  
608         spec.running = false;
609         spec.status = status;
610         spec.clear();
611         
612         return status;
613 }
614 #endif
615
616 Region*
617 MidiRegion::get_parent()
618 {
619 #if 0
620         Region* r = 0;
621
622         if (_playlist) {
623                 r = _playlist->session().find_whole_file_parent (*this);
624         }
625         
626         return r;
627 #endif
628         return NULL;
629 }
630
631
632 bool
633 MidiRegion::speed_mismatch (float sr) const
634 {
635 #if 0
636         if (sources.empty()) {
637                 /* impossible, but ... */
638                 return false;
639         }
640
641         float fsr = sources.front()->sample_rate();
642
643         return fsr == sr;
644 #endif
645         return false;
646 }
647