diff options
Diffstat (limited to 'libs/ardour/midi_region.cc')
-rw-r--r-- | libs/ardour/midi_region.cc | 431 |
1 files changed, 75 insertions, 356 deletions
diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index d78506c1fc..0902337030 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -1,6 +1,5 @@ /* - Copyright (C) 2006 Paul Davis - Written by Dave Robillard, 2006 + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,6 +14,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: midiregion.cc 746 2006-08-02 02:44:23Z drobilla $ */ #include <cmath> @@ -37,6 +38,7 @@ #include <ardour/dB.h> #include <ardour/playlist.h> #include <ardour/midi_source.h> +#include <ardour/types.h> #include "i18n.h" #include <locale.h> @@ -44,20 +46,10 @@ using namespace std; using namespace ARDOUR; -MidiRegionState::MidiRegionState (string why) - : RegionState (why) -{ -} - +/** Basic MidiRegion constructor (one channel) */ MidiRegion::MidiRegion (MidiSource& src, jack_nframes_t start, jack_nframes_t length, bool announce) - : Region (start, length, PBD::basename_nosuffix(src.name()), 0, Region::Flag(Region::DefaultFlags|Region::External)) + : Region (src, start, length, PBD::basename_nosuffix(src.name()), 0, Region::Flag(Region::DefaultFlags|Region::External)) { - /* basic MidiRegion constructor */ - - sources.push_back (&src); - master_sources.push_back (&src); - src.GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - save_state ("initial state"); if (announce) { @@ -65,15 +57,10 @@ MidiRegion::MidiRegion (MidiSource& src, jack_nframes_t start, jack_nframes_t le } } +/* Basic MidiRegion constructor (one channel) */ MidiRegion::MidiRegion (MidiSource& src, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce) - : Region (start, length, name, layer, flags) + : Region (src, start, length, name, layer, flags) { - /* basic MidiRegion constructor */ - - sources.push_back (&src); - master_sources.push_back (&src); - src.GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - save_state ("initial state"); if (announce) { @@ -81,75 +68,40 @@ MidiRegion::MidiRegion (MidiSource& src, jack_nframes_t start, jack_nframes_t le } } +/* Basic MidiRegion constructor (many channels) */ MidiRegion::MidiRegion (SourceList& srcs, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce) - : Region (start, length, name, layer, flags) + : Region (srcs, start, length, name, layer, flags) { - /* basic MidiRegion constructor */ -#if 0 - for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) { - sources.push_back (*i); - master_sources.push_back (*i); - (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - } - -{ - /* create a new MidiRegion, that is part of an existing one */ - - set<MidiSource*> unique_srcs; + save_state ("initial state"); - for (SourceList::const_iterator i= other.sources.begin(); i != other.sources.end(); ++i) { - sources.push_back (*i); - (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - unique_srcs.insert (*i); + if (announce) { + CheckNewRegion (this); /* EMIT SIGNAL */ } +} - for (SourceList::const_iterator i = other.master_sources.begin(); i != other.master_sources.end(); ++i) { - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - } - master_sources.push_back (*i); - } +/** Create a new MidiRegion, that is part of an existing one */ +MidiRegion::MidiRegion (const MidiRegion& other, jack_nframes_t offset, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce) + : Region (other, offset, length, name, layer, flags) +{ save_state ("initial state"); if (announce) { CheckNewRegion (this); /* EMIT SIGNAL */ } -#endif } MidiRegion::MidiRegion (const MidiRegion &other) : Region (other) { - /* Pure copy constructor */ - - set<MidiSource*> unique_srcs; - - for (SourceList::const_iterator i = other.sources.begin(); i != other.sources.end(); ++i) { - sources.push_back (*i); - (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - unique_srcs.insert (*i); - } - - for (SourceList::const_iterator i = other.master_sources.begin(); i != other.master_sources.end(); ++i) { - master_sources.push_back (*i); - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - } - } - save_state ("initial state"); /* NOTE: no CheckNewRegion signal emitted here. This is the copy constructor */ } MidiRegion::MidiRegion (MidiSource& src, const XMLNode& node) - : Region (node) + : Region (src, node) { - sources.push_back (&src); - master_sources.push_back (&src); - src.GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - if (set_state (node)) { throw failed_constructor(); } @@ -160,25 +112,8 @@ MidiRegion::MidiRegion (MidiSource& src, const XMLNode& node) } MidiRegion::MidiRegion (SourceList& srcs, const XMLNode& node) - : Region (node) + : Region (srcs, node) { - /* basic MidiRegion constructor */ - - set<MidiSource*> unique_srcs; - - for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) { - sources.push_back (*i); - (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - unique_srcs.insert (*i); - } - - for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) { - master_sources.push_back (*i); - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - } - } - if (set_state (node)) { throw failed_constructor(); } @@ -196,7 +131,7 @@ MidiRegion::~MidiRegion () StateManager::State* MidiRegion::state_factory (std::string why) const { - MidiRegionState* state = new MidiRegionState (why); + RegionState* state = new RegionState (why); Region::store_state (*state); @@ -206,8 +141,7 @@ MidiRegion::state_factory (std::string why) const Change MidiRegion::restore_state (StateManager::State& sstate) { - MidiRegionState* state = dynamic_cast<MidiRegionState*> (&sstate); - + RegionState* state = dynamic_cast<RegionState*> (&sstate); Change what_changed = Region::restore_and_return_flags (*state); if (_flags != Flag (state->_flags)) { @@ -215,11 +149,8 @@ MidiRegion::restore_state (StateManager::State& sstate) //uint32_t old_flags = _flags; _flags = Flag (state->_flags); - } - /* XXX need a way to test stored state versus current for envelopes */ - what_changed = Change (what_changed); return what_changed; @@ -231,66 +162,23 @@ MidiRegion::get_memento() const return sigc::bind (mem_fun (*(const_cast<MidiRegion *> (this)), &StateManager::use_state), _current_state_id); } -bool -MidiRegion::verify_length (jack_nframes_t len) -{ - for (uint32_t n=0; n < sources.size(); ++n) { - if (_start > sources[n]->length() - len) { - return false; - } - } - return true; -} - -bool -MidiRegion::verify_start_and_length (jack_nframes_t new_start, jack_nframes_t new_length) -{ - for (uint32_t n=0; n < sources.size(); ++n) { - if (new_length > sources[n]->length() - new_start) { - return false; - } - } - return true; -} -bool -MidiRegion::verify_start (jack_nframes_t pos) -{ - for (uint32_t n=0; n < sources.size(); ++n) { - if (pos > sources[n]->length() - _length) { - return false; - } - } - return true; -} - -bool -MidiRegion::verify_start_mutable (jack_nframes_t& new_start) -{ - for (uint32_t n=0; n < sources.size(); ++n) { - if (new_start > sources[n]->length() - _length) { - new_start = sources[n]->length() - _length; - } - } - return true; -} - jack_nframes_t -MidiRegion::read_at (unsigned char *buf, unsigned char *mixdown_buffer, char * workbuf, jack_nframes_t position, +MidiRegion::read_at (RawMidi *out, RawMidi* mix_buf, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const { - return _read_at (sources, buf, mixdown_buffer, workbuf, position, cnt, chan_n, read_frames, skip_frames); + return _read_at (_sources, out, position, cnt, chan_n, read_frames, skip_frames); } jack_nframes_t -MidiRegion::master_read_at (unsigned char *buf, unsigned char *mixdown_buffer, char * workbuf, jack_nframes_t position, +MidiRegion::master_read_at (RawMidi *out, RawMidi* mix_buf, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n) const { - return _read_at (master_sources, buf, mixdown_buffer, workbuf, position, cnt, chan_n, 0, 0); + return _read_at (_master_sources, out, position, cnt, chan_n, 0, 0); } jack_nframes_t -MidiRegion::_read_at (const SourceList& srcs, unsigned char *buf, unsigned char *mixdown_buffer, char * workbuf, +MidiRegion::_read_at (const SourceList& srcs, RawMidi *buf, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const { @@ -300,9 +188,7 @@ MidiRegion::_read_at (const SourceList& srcs, unsigned char *buf, unsigned char /* precondition: caller has verified that we cover the desired section */ - if (chan_n >= sources.size()) { - return 0; /* read nothing */ - } + assert(chan_n == 0); if (position < _position) { internal_offset = 0; @@ -322,12 +208,8 @@ MidiRegion::_read_at (const SourceList& srcs, unsigned char *buf, unsigned char return 0; /* read nothing */ } - if (opaque()) { - /* overwrite whatever is there */ - mixdown_buffer = buf + buf_offset; - } else { - mixdown_buffer += buf_offset; - } + // FIXME: non-opaque MIDI regions not yet supported + assert(opaque()); if (muted()) { return 0; /* read nothing */ @@ -335,39 +217,21 @@ MidiRegion::_read_at (const SourceList& srcs, unsigned char *buf, unsigned char _read_data_count = 0; - if (srcs[chan_n]->read (mixdown_buffer, _start + internal_offset, to_read, workbuf) != to_read) { + MidiSource& src = midi_source(chan_n); + if (src.read (buf, _start + internal_offset, to_read) != to_read) { return 0; /* "read nothing" */ } - _read_data_count += srcs[chan_n]->read_data_count(); - - if (!opaque()) { + _read_data_count += src.read_data_count(); - /* gack. the things we do for users. - */ - - buf += buf_offset; - - for (jack_nframes_t n = 0; n < to_read; ++n) { - buf[n] += mixdown_buffer[n]; - } - } - return to_read; } XMLNode& -MidiRegion::get_state () -{ - return state (true); -} - -XMLNode& MidiRegion::state (bool full) { XMLNode& node (Region::state (full)); -#if 0 -//XMLNode *child; + XMLNode *child; char buf[64]; char buf2[64]; LocaleGuard lg (X_("POSIX")); @@ -375,19 +239,25 @@ MidiRegion::state (bool full) snprintf (buf, sizeof (buf), "0x%x", (int) _flags); node.add_property ("flags", buf); - for (uint32_t n=0; n < sources.size(); ++n) { + for (uint32_t n=0; n < _sources.size(); ++n) { snprintf (buf2, sizeof(buf2), "source-%d", n); - snprintf (buf, sizeof(buf), "%" PRIu64, sources[n]->id()); + _sources[n]->id().print (buf); node.add_property (buf2, buf); } - snprintf (buf, sizeof (buf), "%u", (uint32_t) sources.size()); + snprintf (buf, sizeof (buf), "%u", (uint32_t) _sources.size()); node.add_property ("channels", buf); + child = node.add_child ("Envelope"); + + if ( ! full) { + child->add_property ("default", "yes"); + } + if (full && _extra_xml) { node.add_child_copy (*_extra_xml); } -#endif + return node; } @@ -402,31 +272,51 @@ MidiRegion::set_state (const XMLNode& node) if ((prop = node.property ("flags")) != 0) { _flags = Flag (strtol (prop->value().c_str(), (char **) 0, 16)); - - _flags = Flag (_flags & ~Region::LeftOfSplit); - _flags = Flag (_flags & ~Region::RightOfSplit); } - /* Now find envelope description and other misc child items */ - + /* Now find child items */ for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) { XMLNode *child; //XMLProperty *prop; child = (*niter); + + /** Hello, children */ } return 0; } +void +MidiRegion::recompute_at_end () +{ + /* our length has changed + * (non destructively) "chop" notes that pass the end boundary, to + * prevent stuck notes. + */ +} + +void +MidiRegion::recompute_at_start () +{ + /* as above, but the shift was from the front + * maybe bump currently active note's note-ons up so they sound here? + * that could be undesireable in certain situations though.. maybe + * remove the note entirely, including it's note off? something needs to + * be done to keep the played MIDI sane to avoid messing up voices of + * polyhonic things etc........ + */ +} + int MidiRegion::separate_by_channel (Session& session, vector<MidiRegion*>& v) const { +#if 0 SourceList srcs; string new_name; - for (SourceList::const_iterator i = master_sources.begin(); i != master_sources.end(); ++i) { + for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) { srcs.clear (); srcs.push_back (*i); @@ -441,185 +331,14 @@ MidiRegion::separate_by_channel (Session& session, vector<MidiRegion*>& v) const v.push_back (new MidiRegion (srcs, _start, _length, new_name, _layer, _flags)); } - - return 0; -} - -void -MidiRegion::source_deleted (Source* ignored) -{ - delete this; -} - -void -MidiRegion::lock_sources () -{ - SourceList::iterator i; - set<MidiSource*> unique_srcs; - - for (i = sources.begin(); i != sources.end(); ++i) { - unique_srcs.insert (*i); - (*i)->use (); - } - - for (i = master_sources.begin(); i != master_sources.end(); ++i) { - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->use (); - } - } -} - -void -MidiRegion::unlock_sources () -{ - SourceList::iterator i; - set<MidiSource*> unique_srcs; - - for (i = sources.begin(); i != sources.end(); ++i) { - unique_srcs.insert (*i); - (*i)->release (); - } - - for (i = master_sources.begin(); i != master_sources.end(); ++i) { - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->release (); - } - } -} - -vector<string> -MidiRegion::master_source_names () -{ - SourceList::iterator i; - - vector<string> names; - for (i = master_sources.begin(); i != master_sources.end(); ++i) { - names.push_back((*i)->name()); - } - - return names; -} - -bool -MidiRegion::source_equivalent (const Region& o) const -{ - const MidiRegion* other = dynamic_cast<const MidiRegion*>(&o); - if (!other) - return false; - - SourceList::const_iterator i; - SourceList::const_iterator io; - - for (i = sources.begin(), io = other->sources.begin(); i != sources.end() && io != other->sources.end(); ++i, ++io) { - if ((*i)->id() != (*io)->id()) { - return false; - } - } - - for (i = master_sources.begin(), io = other->master_sources.begin(); i != master_sources.end() && io != other->master_sources.end(); ++i, ++io) { - if ((*i)->id() != (*io)->id()) { - return false; - } - } - - return true; -} - -#if 0 -int -MidiRegion::exportme (Session& session, AudioExportSpecification& spec) -{ - const jack_nframes_t blocksize = 4096; - jack_nframes_t to_read; - int status = -1; - - spec.channels = sources.size(); - - if (spec.prepare (blocksize, session.frame_rate())) { - goto out; - } - - spec.pos = 0; - spec.total_frames = _length; - - while (spec.pos < _length && !spec.stop) { - - - /* step 1: interleave */ - - to_read = min (_length - spec.pos, blocksize); - - if (spec.channels == 1) { - - if (sources.front()->read (spec.dataF, _start + spec.pos, to_read, 0) != to_read) { - goto out; - } - - } else { - - Sample buf[blocksize]; - - for (uint32_t chan = 0; chan < spec.channels; ++chan) { - - if (sources[chan]->read (buf, _start + spec.pos, to_read, 0) != to_read) { - goto out; - } - - for (jack_nframes_t x = 0; x < to_read; ++x) { - spec.dataF[chan+(x*spec.channels)] = buf[x]; - } - } - } - - if (spec.process (to_read)) { - goto out; - } - - spec.pos += to_read; - spec.progress = (double) spec.pos /_length; - - } - - status = 0; - - out: - spec.running = false; - spec.status = status; - spec.clear(); - - return status; -} -#endif - -Region* -MidiRegion::get_parent() -{ -#if 0 - Region* r = 0; - - if (_playlist) { - r = _playlist->session().find_whole_file_parent (*this); - } - - return r; #endif - return NULL; + return -1; } - -bool -MidiRegion::speed_mismatch (float sr) const +MidiSource& +MidiRegion::midi_source (uint32_t n) const { -#if 0 - if (sources.empty()) { - /* impossible, but ... */ - return false; - } - - float fsr = sources.front()->sample_rate(); - - return fsr == sr; -#endif - return false; + // Guaranteed to succeed (use a static cast?) + return dynamic_cast<MidiSource&>(source(n)); } |