X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fmidi_diskstream.cc;h=fa2cdce0140e8664149e8a0fea55cf94785d0414;hb=932d6c79d01be93f491415ef1491bca17d92671f;hp=262a29d1df4336fe52dd2747421a2ae4788dbe9f;hpb=e76d325bd00be4cb04dbbf96a6afb1927cf04a31;p=ardour.git diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index 262a29d1df..fa2cdce014 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -35,11 +35,14 @@ #include "pbd/xml++.h" #include "pbd/memento_command.h" #include "pbd/enumwriter.h" +#include "pbd/stateful_diff_command.h" #include "ardour/ardour.h" #include "ardour/audioengine.h" +#include "ardour/butler.h" #include "ardour/configuration.h" #include "ardour/cycle_timer.h" +#include "ardour/debug.h" #include "ardour/io.h" #include "ardour/midi_diskstream.h" #include "ardour/midi_playlist.h" @@ -51,6 +54,8 @@ #include "ardour/session.h" #include "ardour/smf_source.h" #include "ardour/utils.h" +#include "ardour/session_playlists.h" +#include "ardour/route.h" #include "midi++/types.h" @@ -77,7 +82,7 @@ MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::F in_set_state = true; - init(flag); + init (); use_new_playlist (); in_set_state = false; @@ -96,7 +101,7 @@ MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node) , _frames_read_from_ringbuffer(0) { in_set_state = true; - init (Recordable); + init (); if (set_state (node, Stateful::loading_state_version)) { in_set_state = false; @@ -111,10 +116,8 @@ MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node) } void -MidiDiskstream::init (Diskstream::Flag f) +MidiDiskstream::init () { - Diskstream::init(f); - /* there are no channels at this point, so these two calls just get speed_buffer_size and wrap_buffer size setup without duplicating their code. @@ -123,7 +126,7 @@ MidiDiskstream::init (Diskstream::Flag f) set_block_size (_session.get_block_size()); allocate_temporary_buffers (); - const size_t size = _session.midi_diskstream_buffer_size(); + const size_t size = _session.butler()->midi_diskstream_buffer_size(); _playback_buf = new MidiRingBuffer(size); _capture_buf = new MidiRingBuffer(size); @@ -218,7 +221,7 @@ MidiDiskstream::find_and_use_playlist (const string& name) { boost::shared_ptr playlist; - if ((playlist = boost::dynamic_pointer_cast (_session.playlist_by_name (name))) == 0) { + if ((playlist = boost::dynamic_pointer_cast (_session.playlists->by_name (name))) == 0) { playlist = boost::dynamic_pointer_cast (PlaylistFactory::create (DataType::MIDI, _session, name)); } @@ -483,7 +486,7 @@ trace_midi (ostream& o, MIDI::byte *msg, size_t len) #endif int -MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input) +MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input, bool& need_butler) { int ret = -1; nframes_t rec_offset = 0; @@ -491,39 +494,22 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_ bool nominally_recording; bool re = record_enabled (); - /* if we've already processed the frames corresponding to this call, - just return. this allows multiple routes that are taking input - from this diskstream to call our ::process() method, but have - this stuff only happen once. more commonly, it allows both - the AudioTrack that is using this AudioDiskstream *and* the Session - to call process() without problems. - */ - - if (_processed) { - return 0; - } - - commit_should_unlock = false; + playback_distance = 0; check_record_status (transport_frame, nframes, can_record); nominally_recording = (can_record && re); if (nframes == 0) { - _processed = true; return 0; } - /* This lock is held until the end of ::commit, so these two functions - must always be called as a pair. The only exception is if this function - returns a non-zero value, in which case, ::commit should not be called. - */ + Glib::Mutex::Lock sm (state_lock, Glib::TRY_LOCK); - // If we can't take the state lock return. - if (!state_lock.trylock()) { + if (!sm.locked()) { return 1; } - commit_should_unlock = true; + adjust_capture_position = 0; if (nominally_recording || (_session.get_record_enabled() && _session.config.get_punch_in())) { @@ -582,17 +568,9 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_ ret = 0; - _processed = true; - - if (ret) { - - /* we're exiting with failure, so ::commit will not - be called. unlock the state lock. - */ - - commit_should_unlock = false; - state_lock.unlock(); - } + if (commit (nframes)) { + need_butler = true; + } return ret; } @@ -623,12 +601,6 @@ MidiDiskstream::commit (nframes_t nframes) " = " << frames_written - frames_read << " + " << nframes << " < " << midi_readahead << " = " << need_butler << ")" << endl;*/ - if (commit_should_unlock) { - state_lock.unlock(); - } - - _processed = false; - return need_butler; } @@ -637,7 +609,7 @@ MidiDiskstream::set_pending_overwrite (bool yn) { /* called from audio thread, so we can use the read ptr and playback sample as we wish */ - pending_overwrite = yn; + _pending_overwrite = yn; overwrite_frame = playback_sample; } @@ -647,7 +619,7 @@ MidiDiskstream::overwrite_existing_buffers () { //read(overwrite_frame, disk_io_chunk_frames, false); overwrite_queued = false; - pending_overwrite = false; + _pending_overwrite = false; return 0; } @@ -700,10 +672,12 @@ MidiDiskstream::read (nframes_t& start, nframes_t dur, bool reversed) bool reloop = false; nframes_t loop_end = 0; nframes_t loop_start = 0; - nframes_t loop_length = 0; Location *loc = 0; if (!reversed) { + + nframes_t loop_length = 0; + /* Make the use of a Location atomic for this read operation. Note: Locations don't get deleted, so all we care about @@ -909,13 +883,11 @@ out: } void -MidiDiskstream::transport_stopped (struct tm& /*when*/, time_t /*twhen*/, bool abort_capture) +MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen*/, bool abort_capture) { - uint32_t buffer_position; bool more_work = true; int err = 0; boost::shared_ptr region; - nframes_t total_capture; MidiRegion::SourceList srcs; MidiRegion::SourceList::iterator src; vector::iterator ci; @@ -952,7 +924,6 @@ MidiDiskstream::transport_stopped (struct tm& /*when*/, time_t /*twhen*/, bool a if (_write_source) { _write_source->mark_for_remove (); - _write_source->drop_references (); _write_source.reset(); } @@ -962,7 +933,8 @@ MidiDiskstream::transport_stopped (struct tm& /*when*/, time_t /*twhen*/, bool a assert(_write_source); - for (total_capture = 0, ci = capture_info.begin(); ci != capture_info.end(); ++ci) { + nframes_t total_capture = 0; + for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) { total_capture += (*ci)->frames; } @@ -982,9 +954,16 @@ MidiDiskstream::transport_stopped (struct tm& /*when*/, time_t /*twhen*/, bool a */ try { - boost::shared_ptr rx (RegionFactory::create (srcs, 0, - total_capture, whole_file_region_name, 0, - Region::Flag (Region::DefaultFlags|Region::Automatic|Region::WholeFile))); + PropertyList plist; + + plist.add (Properties::name, whole_file_region_name); + plist.add (Properties::whole_file, true); + plist.add (Properties::automatic, true); + plist.add (Properties::start, 0); + plist.add (Properties::length, total_capture); + plist.add (Properties::layer, 0); + + boost::shared_ptr rx (RegionFactory::create (srcs, plist)); region = boost::dynamic_pointer_cast (rx); region->special_set_position (capture_info.front()->start); @@ -1000,19 +979,26 @@ MidiDiskstream::transport_stopped (struct tm& /*when*/, time_t /*twhen*/, bool a // cerr << _name << ": there are " << capture_info.size() << " capture_info records\n"; - XMLNode &before = _playlist->get_state(); + _playlist->clear_history (); _playlist->freeze (); + uint32_t buffer_position = 0; for (buffer_position = 0, ci = capture_info.begin(); ci != capture_info.end(); ++ci) { string region_name; - _session.region_name (region_name, _write_source->name(), false); + RegionFactory::region_name (region_name, _write_source->name(), false); // cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add a region\n"; try { - boost::shared_ptr rx (RegionFactory::create (srcs, buffer_position, (*ci)->frames, region_name)); + PropertyList plist; + + plist.add (Properties::start, buffer_position); + plist.add (Properties::length, (*ci)->frames); + plist.add (Properties::name, region_name); + + boost::shared_ptr rx (RegionFactory::create (srcs, plist)); region = boost::dynamic_pointer_cast (rx); } @@ -1021,7 +1007,7 @@ MidiDiskstream::transport_stopped (struct tm& /*when*/, time_t /*twhen*/, bool a continue; /* XXX is this OK? */ } - region->GoingAway.connect (bind (mem_fun (*this, &Diskstream::remove_region_from_last_capture), boost::weak_ptr(region))); + region->DropReferences.connect_same_thread (*this, boost::bind (&Diskstream::remove_region_from_last_capture, this, boost::weak_ptr(region))); _last_capture_regions.push_back (region); @@ -1035,8 +1021,7 @@ MidiDiskstream::transport_stopped (struct tm& /*when*/, time_t /*twhen*/, bool a } _playlist->thaw (); - XMLNode &after = _playlist->get_state(); - _session.add_command (new MementoCommand(*_playlist, &before, &after)); + _session.add_command (new StatefulDiffCommand(_playlist)); } @@ -1048,6 +1033,10 @@ MidiDiskstream::transport_stopped (struct tm& /*when*/, time_t /*twhen*/, bool a delete *ci; } + if (_playlist) { + midi_playlist()->clear_note_trackers (); + } + capture_info.clear (); capture_start_frame = 0; } @@ -1122,15 +1111,6 @@ MidiDiskstream::set_record_enabled (bool yn) assert(!destructive()); - if (yn && _source_port == 0) { - - /* pick up connections not initiated *from* the IO object - we're associated with. - */ - - get_input_sources (); - } - /* yes, i know that this not proof against race conditions, but its good enough. i think. */ @@ -1180,7 +1160,7 @@ MidiDiskstream::disengage_record_enable () XMLNode& MidiDiskstream::get_state () { - XMLNode* node = new XMLNode ("MidiDiskstream"); + XMLNode* node = new XMLNode ("Diskstream"); char buf[64]; LocaleGuard lg (X_("POSIX")); @@ -1217,7 +1197,7 @@ MidiDiskstream::get_state () if (_session.config.get_punch_in() && ((pi = _session.locations()->auto_punch_location()) != 0)) { snprintf (buf, sizeof (buf), "%" PRId64, pi->start()); } else { - snprintf (buf, sizeof (buf), "%" PRIu32, _session.transport_frame()); + snprintf (buf, sizeof (buf), "%" PRId64, _session.transport_frame()); } cs_child->add_property (X_("at"), buf); @@ -1237,7 +1217,6 @@ MidiDiskstream::set_state (const XMLNode& node, int /*version*/) const XMLProperty* prop; XMLNodeList nlist = node.children(); XMLNodeIterator niter; - uint32_t nchans = 1; XMLNode* capture_pending_node = 0; LocaleGuard lg (X_("POSIX")); @@ -1285,10 +1264,6 @@ MidiDiskstream::set_state (const XMLNode& node, int /*version*/) set_channel_mode(channel_mode, channel_mask); - if ((prop = node.property ("channels")) != 0) { - nchans = atoi (prop->value().c_str()); - } - if ((prop = node.property ("playlist")) == 0) { return -1; } @@ -1301,7 +1276,7 @@ MidiDiskstream::set_state (const XMLNode& node, int /*version*/) } if (!had_playlist) { - _playlist->set_orig_diskstream_id (_id); + _playlist->set_orig_diskstream_id (id()); } if (capture_pending_node) { @@ -1346,7 +1321,12 @@ MidiDiskstream::use_new_write_source (uint32_t n) if (_write_source) { if (_write_source->is_empty ()) { + /* remove any region that is using this empty source; they can result when MIDI recordings + are made, but no MIDI data is received. + */ + _playlist->remove_region_by_source (_write_source); _write_source->mark_for_remove (); + _write_source->drop_references (); _write_source.reset(); } else { _write_source.reset(); @@ -1354,7 +1334,7 @@ MidiDiskstream::use_new_write_source (uint32_t n) } try { - _write_source = boost::dynamic_pointer_cast(_session.create_midi_source_for_session (*this)); + _write_source = boost::dynamic_pointer_cast(_session.create_midi_source_for_session (name ())); if (!_write_source) { throw failed_constructor(); } @@ -1390,7 +1370,7 @@ int MidiDiskstream::rename_write_sources () { if (_write_source != 0) { - _write_source->set_source_name (_name, destructive()); + _write_source->set_source_name (_name.val(), destructive()); /* XXX what to do if this fails ? */ } return 0; @@ -1472,14 +1452,13 @@ MidiDiskstream::get_playback (MidiBuffer& dst, nframes_t start, nframes_t end) // Translates stamps to be relative to start - _playback_buf->read(dst, start, end); -#if 0 +#ifndef NDEBUG const size_t events_read = _playback_buf->read(dst, start, end); - cout << _name << ": MDS events read = " << events_read - << " start = " << start << " end = " << end - << " readspace " << _playback_buf->read_space() - << " writespace " << _playback_buf->write_space() << endl; + DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("%1 MDS events read %2 range %3 .. %4 rspace %5 wspace %6\n", _name, events_read, start, end, + _playback_buf->read_space(), _playback_buf->write_space())); +#else + _playback_buf->read(dst, start, end); #endif gint32 frames_read = end - start;