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));
373 LocaleGuard lg (X_("POSIX"));
375 snprintf (buf, sizeof (buf), "0x%x", (int) _flags);
376 node.add_property ("flags", buf);
378 for (uint32_t n=0; n < sources.size(); ++n) {
379 snprintf (buf2, sizeof(buf2), "source-%d", n);
380 snprintf (buf, sizeof(buf), "%" PRIu64, sources[n]->id());
381 node.add_property (buf2, buf);
384 snprintf (buf, sizeof (buf), "%u", (uint32_t) sources.size());
385 node.add_property ("channels", buf);
387 if (full && _extra_xml) {
388 node.add_child_copy (*_extra_xml);
395 MidiRegion::set_state (const XMLNode& node)
397 const XMLNodeList& nlist = node.children();
398 const XMLProperty *prop;
399 LocaleGuard lg (X_("POSIX"));
401 Region::set_state (node);
403 if ((prop = node.property ("flags")) != 0) {
404 _flags = Flag (strtol (prop->value().c_str(), (char **) 0, 16));
406 _flags = Flag (_flags & ~Region::LeftOfSplit);
407 _flags = Flag (_flags & ~Region::RightOfSplit);
410 /* Now find envelope description and other misc child items */
412 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
424 MidiRegion::separate_by_channel (Session& session, vector<MidiRegion*>& v) const
429 for (SourceList::const_iterator i = master_sources.begin(); i != master_sources.end(); ++i) {
434 /* generate a new name */
436 if (session.region_name (new_name, _name)) {
440 /* create a copy with just one source */
442 v.push_back (new MidiRegion (srcs, _start, _length, new_name, _layer, _flags));
449 MidiRegion::source_deleted (Source* ignored)
455 MidiRegion::lock_sources ()
457 SourceList::iterator i;
458 set<MidiSource*> unique_srcs;
460 for (i = sources.begin(); i != sources.end(); ++i) {
461 unique_srcs.insert (*i);
465 for (i = master_sources.begin(); i != master_sources.end(); ++i) {
466 if (unique_srcs.find (*i) == unique_srcs.end()) {
473 MidiRegion::unlock_sources ()
475 SourceList::iterator i;
476 set<MidiSource*> unique_srcs;
478 for (i = sources.begin(); i != sources.end(); ++i) {
479 unique_srcs.insert (*i);
483 for (i = master_sources.begin(); i != master_sources.end(); ++i) {
484 if (unique_srcs.find (*i) == unique_srcs.end()) {
491 MidiRegion::master_source_names ()
493 SourceList::iterator i;
495 vector<string> names;
496 for (i = master_sources.begin(); i != master_sources.end(); ++i) {
497 names.push_back((*i)->name());
504 MidiRegion::source_equivalent (const Region& o) const
506 const MidiRegion* other = dynamic_cast<const MidiRegion*>(&o);
510 SourceList::const_iterator i;
511 SourceList::const_iterator io;
513 for (i = sources.begin(), io = other->sources.begin(); i != sources.end() && io != other->sources.end(); ++i, ++io) {
514 if ((*i)->id() != (*io)->id()) {
519 for (i = master_sources.begin(), io = other->master_sources.begin(); i != master_sources.end() && io != other->master_sources.end(); ++i, ++io) {
520 if ((*i)->id() != (*io)->id()) {
530 MidiRegion::exportme (Session& session, AudioExportSpecification& spec)
532 const jack_nframes_t blocksize = 4096;
533 jack_nframes_t to_read;
536 spec.channels = sources.size();
538 if (spec.prepare (blocksize, session.frame_rate())) {
543 spec.total_frames = _length;
545 while (spec.pos < _length && !spec.stop) {
548 /* step 1: interleave */
550 to_read = min (_length - spec.pos, blocksize);
552 if (spec.channels == 1) {
554 if (sources.front()->read (spec.dataF, _start + spec.pos, to_read, 0) != to_read) {
560 Sample buf[blocksize];
562 for (uint32_t chan = 0; chan < spec.channels; ++chan) {
564 if (sources[chan]->read (buf, _start + spec.pos, to_read, 0) != to_read) {
568 for (jack_nframes_t x = 0; x < to_read; ++x) {
569 spec.dataF[chan+(x*spec.channels)] = buf[x];
574 if (spec.process (to_read)) {
579 spec.progress = (double) spec.pos /_length;
586 spec.running = false;
587 spec.status = status;
595 MidiRegion::get_parent()
601 r = _playlist->session().find_whole_file_parent (*this);
611 MidiRegion::speed_mismatch (float sr) const
614 if (sources.empty()) {
615 /* impossible, but ... */
619 float fsr = sources.front()->sample_rate();