2 Copyright (C) 2006 Paul Davis
3 Written by Dave Robillard, 2006
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.
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.
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.
26 #include <sigc++/bind.h>
27 #include <sigc++/class_slot.h>
29 #include <glibmm/thread.h>
31 #include <pbd/basename.h>
32 #include <pbd/xml++.h>
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>
45 using namespace ARDOUR;
47 MidiRegionState::MidiRegionState (string why)
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))
55 /* basic MidiRegion constructor */
57 sources.push_back (&src);
58 master_sources.push_back (&src);
59 src.GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
61 save_state ("initial state");
64 CheckNewRegion (this); /* EMIT SIGNAL */
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)
71 /* basic MidiRegion constructor */
73 sources.push_back (&src);
74 master_sources.push_back (&src);
75 src.GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
77 save_state ("initial state");
80 CheckNewRegion (this); /* EMIT SIGNAL */
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)
87 /* basic MidiRegion constructor */
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));
96 /* create a new MidiRegion, that is part of an existing one */
98 set<MidiSource*> unique_srcs;
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);
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));
110 master_sources.push_back (*i);
113 save_state ("initial state");
116 CheckNewRegion (this); /* EMIT SIGNAL */
121 MidiRegion::MidiRegion (const MidiRegion &other)
124 /* Pure copy constructor */
126 set<MidiSource*> unique_srcs;
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);
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));
141 save_state ("initial state");
143 /* NOTE: no CheckNewRegion signal emitted here. This is the copy constructor */
146 MidiRegion::MidiRegion (MidiSource& src, const XMLNode& node)
149 sources.push_back (&src);
150 master_sources.push_back (&src);
151 src.GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
153 if (set_state (node)) {
154 throw failed_constructor();
157 save_state ("initial state");
159 CheckNewRegion (this); /* EMIT SIGNAL */
162 MidiRegion::MidiRegion (SourceList& srcs, const XMLNode& node)
165 /* basic MidiRegion constructor */
167 set<MidiSource*> unique_srcs;
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);
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));
182 if (set_state (node)) {
183 throw failed_constructor();
186 save_state ("initial state");
188 CheckNewRegion (this); /* EMIT SIGNAL */
191 MidiRegion::~MidiRegion ()
197 MidiRegion::state_factory (std::string why) const
199 MidiRegionState* state = new MidiRegionState (why);
201 Region::store_state (*state);
207 MidiRegion::restore_state (StateManager::State& sstate)
209 MidiRegionState* state = dynamic_cast<MidiRegionState*> (&sstate);
211 Change what_changed = Region::restore_and_return_flags (*state);
213 if (_flags != Flag (state->_flags)) {
215 //uint32_t old_flags = _flags;
217 _flags = Flag (state->_flags);
221 /* XXX need a way to test stored state versus current for envelopes */
223 what_changed = Change (what_changed);
229 MidiRegion::get_memento() const
231 return sigc::bind (mem_fun (*(const_cast<MidiRegion *> (this)), &StateManager::use_state), _current_state_id);
235 MidiRegion::verify_length (jack_nframes_t len)
237 for (uint32_t n=0; n < sources.size(); ++n) {
238 if (_start > sources[n]->length() - len) {
246 MidiRegion::verify_start_and_length (jack_nframes_t new_start, jack_nframes_t new_length)
248 for (uint32_t n=0; n < sources.size(); ++n) {
249 if (new_length > sources[n]->length() - new_start) {
256 MidiRegion::verify_start (jack_nframes_t pos)
258 for (uint32_t n=0; n < sources.size(); ++n) {
259 if (pos > sources[n]->length() - _length) {
267 MidiRegion::verify_start_mutable (jack_nframes_t& new_start)
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;
278 MidiRegion::read_at (unsigned char *buf, unsigned char *mixdown_buffer, char * workbuf, jack_nframes_t position,
280 uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const
282 return _read_at (sources, buf, mixdown_buffer, workbuf, position, cnt, chan_n, read_frames, skip_frames);
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
289 return _read_at (master_sources, buf, mixdown_buffer, workbuf, position, cnt, chan_n, 0, 0);
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
297 jack_nframes_t internal_offset;
298 jack_nframes_t buf_offset;
299 jack_nframes_t to_read;
301 /* precondition: caller has verified that we cover the desired section */
303 if (chan_n >= sources.size()) {
304 return 0; /* read nothing */
307 if (position < _position) {
309 buf_offset = _position - position;
312 internal_offset = position - _position;
316 if (internal_offset >= _length) {
317 return 0; /* read nothing */
321 if ((to_read = min (cnt, _length - internal_offset)) == 0) {
322 return 0; /* read nothing */
326 /* overwrite whatever is there */
327 mixdown_buffer = buf + buf_offset;
329 mixdown_buffer += buf_offset;
333 return 0; /* read nothing */
336 _read_data_count = 0;
338 if (srcs[chan_n]->read (mixdown_buffer, _start + internal_offset, to_read, workbuf) != to_read) {
339 return 0; /* "read nothing" */
342 _read_data_count += srcs[chan_n]->read_data_count();
346 /* gack. the things we do for users.
351 for (jack_nframes_t n = 0; n < to_read; ++n) {
352 buf[n] += mixdown_buffer[n];
360 MidiRegion::get_state ()
366 MidiRegion::state (bool full)
368 XMLNode& node (Region::state (full));
372 LocaleGuard lg (X_("POSIX"));
374 snprintf (buf, sizeof (buf), "0x%x", (int) _flags);
375 node.add_property ("flags", buf);
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);
383 snprintf (buf, sizeof (buf), "%u", (uint32_t) sources.size());
384 node.add_property ("channels", buf);
386 if (full && _extra_xml) {
387 node.add_child_copy (*_extra_xml);
394 MidiRegion::set_state (const XMLNode& node)
396 const XMLNodeList& nlist = node.children();
397 const XMLProperty *prop;
398 LocaleGuard lg (X_("POSIX"));
400 Region::set_state (node);
402 if ((prop = node.property ("flags")) != 0) {
403 _flags = Flag (strtol (prop->value().c_str(), (char **) 0, 16));
405 _flags = Flag (_flags & ~Region::LeftOfSplit);
406 _flags = Flag (_flags & ~Region::RightOfSplit);
409 /* Now find envelope description and other misc child items */
411 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
423 MidiRegion::separate_by_channel (Session& session, vector<MidiRegion*>& v) const
428 for (SourceList::const_iterator i = master_sources.begin(); i != master_sources.end(); ++i) {
433 /* generate a new name */
435 if (session.region_name (new_name, _name)) {
439 /* create a copy with just one source */
441 v.push_back (new MidiRegion (srcs, _start, _length, new_name, _layer, _flags));
448 MidiRegion::source_deleted (Source* ignored)
454 MidiRegion::lock_sources ()
456 SourceList::iterator i;
457 set<MidiSource*> unique_srcs;
459 for (i = sources.begin(); i != sources.end(); ++i) {
460 unique_srcs.insert (*i);
464 for (i = master_sources.begin(); i != master_sources.end(); ++i) {
465 if (unique_srcs.find (*i) == unique_srcs.end()) {
472 MidiRegion::unlock_sources ()
474 SourceList::iterator i;
475 set<MidiSource*> unique_srcs;
477 for (i = sources.begin(); i != sources.end(); ++i) {
478 unique_srcs.insert (*i);
482 for (i = master_sources.begin(); i != master_sources.end(); ++i) {
483 if (unique_srcs.find (*i) == unique_srcs.end()) {
490 MidiRegion::master_source_names ()
492 SourceList::iterator i;
494 vector<string> names;
495 for (i = master_sources.begin(); i != master_sources.end(); ++i) {
496 names.push_back((*i)->name());
503 MidiRegion::region_list_equivalent (const MidiRegion& other) const
505 return size_equivalent (other) && source_equivalent (other) && _name == other._name;
509 MidiRegion::source_equivalent (const MidiRegion& other) const
511 SourceList::const_iterator i;
512 SourceList::const_iterator io;
514 for (i = sources.begin(), io = other.sources.begin(); i != sources.end() && io != other.sources.end(); ++i, ++io) {
515 if ((*i)->id() != (*io)->id()) {
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()) {
530 MidiRegion::overlap_equivalent (const MidiRegion& other) const
532 return coverage (other.first_frame(), other.last_frame()) != OverlapNone;
536 MidiRegion::equivalent (const MidiRegion& other) const
538 return _start == other._start &&
539 _position == other._position &&
540 _length == other._length;
544 MidiRegion::size_equivalent (const MidiRegion& other) const
546 return _start == other._start &&
547 _length == other._length;
552 MidiRegion::exportme (Session& session, AudioExportSpecification& spec)
554 const jack_nframes_t blocksize = 4096;
555 jack_nframes_t to_read;
558 spec.channels = sources.size();
560 if (spec.prepare (blocksize, session.frame_rate())) {
565 spec.total_frames = _length;
567 while (spec.pos < _length && !spec.stop) {
570 /* step 1: interleave */
572 to_read = min (_length - spec.pos, blocksize);
574 if (spec.channels == 1) {
576 if (sources.front()->read (spec.dataF, _start + spec.pos, to_read, 0) != to_read) {
582 Sample buf[blocksize];
584 for (uint32_t chan = 0; chan < spec.channels; ++chan) {
586 if (sources[chan]->read (buf, _start + spec.pos, to_read, 0) != to_read) {
590 for (jack_nframes_t x = 0; x < to_read; ++x) {
591 spec.dataF[chan+(x*spec.channels)] = buf[x];
596 if (spec.process (to_read)) {
601 spec.progress = (double) spec.pos /_length;
608 spec.running = false;
609 spec.status = status;
617 MidiRegion::get_parent()
623 r = _playlist->session().find_whole_file_parent (*this);
633 MidiRegion::speed_mismatch (float sr) const
636 if (sources.empty()) {
637 /* impossible, but ... */
641 float fsr = sources.front()->sample_rate();