From 75af744dd0f717a64f177fbf47624ce64208de24 Mon Sep 17 00:00:00 2001 From: paul Date: Sat, 26 Jun 2010 13:45:59 +0000 Subject: [PATCH] lots of details relating to MIDI file management; try to ignore ALSA sequencer MIDI ports named "Midi-Through" git-svn-id: http://subversion.ardour.org/svn/ardour2/ardour2/branches/3.0@7305 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/port_group.cc | 10 ++++++ libs/ardour/ardour/file_source.h | 1 + libs/ardour/ardour/region.h | 2 +- libs/ardour/ardour/source.h | 10 +----- libs/ardour/audio_diskstream.cc | 2 -- libs/ardour/audioengine.cc | 41 ++++++++++++++++++------ libs/ardour/file_source.cc | 6 ++++ libs/ardour/midi_diskstream.cc | 69 ++++++++++++++++------------------------ libs/ardour/midi_model.cc | 2 +- libs/ardour/midi_region.cc | 13 +++++--- libs/ardour/midi_source.cc | 11 +++++++ libs/ardour/region.cc | 3 ++ libs/ardour/region_factory.cc | 9 ------ libs/ardour/smf_source.cc | 7 ++++ libs/ardour/source.cc | 14 ++++++++ libs/ardour/source_factory.cc | 4 +-- libs/evoral/src/SMF.cpp | 4 +-- 17 files changed, 126 insertions(+), 82 deletions(-) diff --git a/gtk2_ardour/port_group.cc b/gtk2_ardour/port_group.cc index 8dc91edb3..a010b3c18 100644 --- a/gtk2_ardour/port_group.cc +++ b/gtk2_ardour/port_group.cc @@ -422,6 +422,16 @@ PortGroupList::gather (ARDOUR::Session* session, bool inputs, bool allow_dups) !track->has_port(p) && !ardour->has_port(p) && !other->has_port(p)) { + + /* special hack: ignore MIDI ports labelled Midi-Through. these + are basically useless and mess things up for default + connections. + */ + + if (p.find ("MIDI-Through") != string::npos) { + ++n; + continue; + } if (port_has_prefix (p, "system:") || port_has_prefix (p, "alsa_pcm") || diff --git a/libs/ardour/ardour/file_source.h b/libs/ardour/ardour/file_source.h index 76c3c57e3..38449def2 100644 --- a/libs/ardour/ardour/file_source.h +++ b/libs/ardour/ardour/file_source.h @@ -41,6 +41,7 @@ public: int move_to_trash (const Glib::ustring& trash_dir_name); void mark_take (const Glib::ustring& id); void mark_immutable (); + void mark_nonremovable (); const Glib::ustring& take_id () const { return _take_id; } bool within_session () const { return _within_session; } diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h index a30bb8660..9d85c5b43 100644 --- a/libs/ardour/ardour/region.h +++ b/libs/ardour/ardour/region.h @@ -353,7 +353,7 @@ class Region void register_properties (); -private: +protected: void use_sources (SourceList const &); }; diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h index 9abf7ff8f..6f750e6fd 100644 --- a/libs/ardour/ardour/source.h +++ b/libs/ardour/ardour/source.h @@ -106,15 +106,7 @@ class Source : public SessionObject Flag flags() const { return _flags; } void inc_use_count () { g_atomic_int_inc (&_use_count); } - void dec_use_count () { -#ifndef NDEBUG - gint oldval = g_atomic_int_exchange_and_add (&_use_count, -1); - assert (oldval > 0); -#else - g_atomic_int_exchange_and_add (&_use_count, -1); -#endif - } - + void dec_use_count (); int use_count() const { return g_atomic_int_get (&_use_count); } bool used() const { return use_count() > 0; } diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index d3e19dac9..6dc29a510 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -1917,8 +1917,6 @@ AudioDiskstream::reset_write_sources (bool mark_write_complete, bool /*force*/) boost::shared_ptr c = channels.reader(); uint32_t n; - cerr << name() << " resetting write sources, recrodable " << recordable() << " chans = " << c->size() << endl; - if (!_session.writable() || !recordable()) { return; } diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 2282a2080..79aa5d9ff 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -1109,16 +1109,21 @@ AudioEngine::n_physical_outputs (DataType type) const { GET_PRIVATE_JACK_POINTER_RET (_jack,0); const char ** ports; - uint32_t i = 0; + uint32_t cnt = 0; if ((ports = jack_get_ports (_priv_jack, NULL, type.to_jack_type(), JackPortIsPhysical|JackPortIsInput)) == 0) { return 0; } - for (i = 0; ports[i]; ++i) {} + for (uint32_t i = 0; ports[i]; ++i) { + if (!strstr (ports[i], "Midi-Through")) { + cnt++; + } + } + free (ports); - return i; + return cnt; } uint32_t @@ -1126,16 +1131,21 @@ AudioEngine::n_physical_inputs (DataType type) const { GET_PRIVATE_JACK_POINTER_RET (_jack,0); const char ** ports; - uint32_t i = 0; - + uint32_t cnt = 0; + if ((ports = jack_get_ports (_priv_jack, NULL, type.to_jack_type(), JackPortIsPhysical|JackPortIsOutput)) == 0) { return 0; } - for (i = 0; ports[i]; ++i) {} + for (uint32_t i = 0; ports[i]; ++i) { + if (!strstr (ports[i], "Midi-Through")) { + cnt++; + } + } + free (ports); - return i; + return cnt; } void @@ -1150,6 +1160,9 @@ AudioEngine::get_physical_inputs (DataType type, vector& ins) if (ports) { for (uint32_t i = 0; ports[i]; ++i) { + if (strstr (ports[i], "Midi-Through")) { + continue; + } ins.push_back (ports[i]); } free (ports); @@ -1168,6 +1181,9 @@ AudioEngine::get_physical_outputs (DataType type, vector& outs) } for (i = 0; ports[i]; ++i) { + if (strstr (ports[i], "Midi-Through")) { + continue; + } outs.push_back (ports[i]); } free (ports); @@ -1179,6 +1195,7 @@ AudioEngine::get_nth_physical (DataType type, uint32_t n, int flag) GET_PRIVATE_JACK_POINTER_RET (_jack,""); const char ** ports; uint32_t i; + uint32_t idx; string ret; assert(type != DataType::NIL); @@ -1187,10 +1204,14 @@ AudioEngine::get_nth_physical (DataType type, uint32_t n, int flag) return ret; } - for (i = 0; i < n && ports[i]; ++i) {} + for (i = 0, idx = 0; idx < n && ports[i]; ++i) { + if (!strstr (ports[i], "Midi-Through")) { + ++idx; + } + } - if (ports[i]) { - ret = ports[i]; + if (ports[idx]) { + ret = ports[idx]; } free ((const char **) ports); diff --git a/libs/ardour/file_source.cc b/libs/ardour/file_source.cc index fd66a7a16..be68c0c40 100644 --- a/libs/ardour/file_source.cc +++ b/libs/ardour/file_source.cc @@ -418,6 +418,12 @@ FileSource::mark_immutable () } void +FileSource::mark_nonremovable () +{ + _flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy)); +} + +void FileSource::set_within_session_from_path (const std::string& path) { _within_session = _session.path_is_within_session (path); diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index f9ece16ae..95e242e67 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -36,6 +36,7 @@ #include "pbd/memento_command.h" #include "pbd/enumwriter.h" #include "pbd/stateful_diff_command.h" +#include "pbd/stacktrace.h" #include "ardour/ardour.h" #include "ardour/audioengine.h" @@ -84,6 +85,7 @@ MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::F init (); use_new_playlist (); + use_new_write_source (0); in_set_state = false; @@ -101,6 +103,7 @@ MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node) , _frames_read_from_ringbuffer(0) { in_set_state = true; + init (); if (set_state (node, Stateful::loading_state_version)) { @@ -108,11 +111,9 @@ MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node) throw failed_constructor(); } - in_set_state = false; + use_new_write_source (0); - if (destructive()) { - use_destructive_playlist (); - } + in_set_state = false; } void @@ -183,9 +184,10 @@ MidiDiskstream::non_realtime_input_change () /* implicit unlock */ } - /* reset capture files */ - - reset_write_sources (false); + /* unlike with audio, there is never any need to reset write sources + based on input configuration changes because ... a MIDI track + has just 1 MIDI port as input, always. + */ /* now refill channel buffers */ @@ -945,8 +947,23 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen /* figure out the name for this take */ srcs.push_back (_write_source); + _write_source->set_timeline_position (capture_info.front()->start); _write_source->set_captured_for (_name); + + /* flush to disk: this step differs from the audio path, + where all the data is already on disk. + */ + + _write_source->mark_streaming_write_completed (); + + /* we will want to be able to keep (over)writing the source + but we don't want it to be removable. this also differs + from the audio situation, where the source at this point + must be considered immutable + */ + + _write_source->mark_nonremovable (); string whole_file_region_name; whole_file_region_name = region_name_from_path (_write_source->name(), true); @@ -1021,11 +1038,11 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen _playlist->thaw (); _session.add_command (new StatefulDiffCommand(_playlist)); } - } - mark_write_completed = true; + mark_write_completed = true; + } - reset_write_sources (mark_write_completed); + use_new_write_source (0); for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) { delete *ci; @@ -1133,10 +1150,6 @@ MidiDiskstream::engage_record_enable () _source_port->request_monitor_input (!(_session.config.get_auto_input() && rolling)); } - // FIXME: Why is this necessary? Isn't needed for AudioDiskstream... - if (!_write_source) - use_new_write_source(); - _write_source->mark_streaming_midi_write_started (_note_mode, _session.transport_frame()); RecordEnableChanged (); /* EMIT SIGNAL */ @@ -1293,45 +1306,19 @@ MidiDiskstream::set_state (const XMLNode& node, int /*version*/) in_set_state = false; - /* make sure this is clear before we do anything else */ - - // FIXME? - //_capturing_source = 0; - - /* write sources are handled when we handle the input set - up of the IO that owns this DS (::non_realtime_input_change()) - */ - - in_set_state = false; - return 0; } int MidiDiskstream::use_new_write_source (uint32_t n) { - cerr << name() << " use new write source for n = " << n << " recordable ? " << recordable() << endl; - if (!recordable()) { return 1; } assert(n == 0); - 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(); - } - } + _write_source.reset(); try { _write_source = boost::dynamic_pointer_cast(_session.create_midi_source_for_session (0, name ())); diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index 57cbb70cf..5926d403c 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -780,7 +780,7 @@ MidiModel::DiffCommand::side_effect_remove(const NotePtr note) source->mark_streaming_write_completed(); set_edited(false); - + return true; } diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index fe49547bf..aad4bdfc6 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -51,7 +51,7 @@ using namespace PBD; MidiRegion::MidiRegion (const SourceList& srcs) : Region (srcs) { - midi_source(0)->Switched.connect_same_thread (*this, boost::bind (&MidiRegion::switch_source, this, _1)); + // midi_source(0)->Switched.connect_same_thread (*this, boost::bind (&MidiRegion::switch_source, this, _1)); midi_source(0)->ModelChanged.connect_same_thread (_source_connection, boost::bind (&MidiRegion::model_changed, this)); model_changed (); assert(_name.val().find("/") == string::npos); @@ -63,7 +63,7 @@ MidiRegion::MidiRegion (boost::shared_ptr other, frameoffset_t : Region (other, offset, offset_relative) { assert(_name.val().find("/") == string::npos); - midi_source(0)->Switched.connect_same_thread (*this, boost::bind (&MidiRegion::switch_source, this, _1)); + // midi_source(0)->Switched.connect_same_thread (*this, boost::bind (&MidiRegion::switch_source, this, _1)); midi_source(0)->ModelChanged.connect_same_thread (_source_connection, boost::bind (&MidiRegion::model_changed, this)); model_changed (); } @@ -258,10 +258,13 @@ MidiRegion::switch_source(boost::shared_ptr src) } // MIDI regions have only one source - _sources.clear(); - _sources.push_back(msrc); + SourceList srcs; + srcs.push_back (msrc); - set_name(msrc->name()); + drop_sources (); + use_sources (srcs); + + set_name (msrc->name()); msrc->ModelChanged.connect_same_thread (_source_connection, boost::bind (&MidiRegion::model_changed, this)); } diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc index 2e549b6fc..36cd36795 100644 --- a/libs/ardour/midi_source.cc +++ b/libs/ardour/midi_source.cc @@ -288,9 +288,19 @@ MidiSource::clone (Evoral::MusicalTime begin, Evoral::MusicalTime end) void MidiSource::session_saved() { + /* this writes a copy of the data to disk. + XXX do we need to do this every time? + */ + flush_midi(); + cerr << name() << " @ " << this << " length at save = " << _length_beats << endl; + +#if 0 // old style: clone the source if necessary on every session save + // and switch to the new source if (_model && _model->edited()) { + cerr << "Model exists and is edited\n"; + boost::shared_ptr newsrc = clone (); if (newsrc) { @@ -298,6 +308,7 @@ MidiSource::session_saved() Switched (newsrc); /* EMIT SIGNAL */ } } +#endif } void diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index e62031963..0ae947063 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -1381,6 +1381,7 @@ void Region::set_master_sources (const SourceList& srcs) { for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) { + cerr << name() << " " << id() << " DEC M SMS\n"; (*i)->dec_use_count (); } @@ -1535,12 +1536,14 @@ void Region::drop_sources () { for (SourceList::const_iterator i = _sources.begin (); i != _sources.end(); ++i) { + cerr << name() << " " << id() << " DEC DS\n"; (*i)->dec_use_count (); } _sources.clear (); for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) { + cerr << name() << " " << id() << " DEC MDS \n"; (*i)->dec_use_count (); } diff --git a/libs/ardour/region_factory.cc b/libs/ardour/region_factory.cc index 65649ad8f..b4beddfb6 100644 --- a/libs/ardour/region_factory.cc +++ b/libs/ardour/region_factory.cc @@ -73,7 +73,6 @@ RegionFactory::create (boost::shared_ptr region) } if (ret) { - cerr << "Pure copy constructor region " << ret << " named " << ret->name() << endl; map_add (ret); /* pure copy constructor - no property list */ @@ -125,7 +124,6 @@ RegionFactory::create (boost::shared_ptr region, frameoffset_t offset, b if (ret) { ret->set_properties (plist); - cerr << "Partial copy constructor region\n"; map_add (ret); if (announce) { @@ -165,7 +163,6 @@ RegionFactory::create (boost::shared_ptr region, const SourceList& srcs, if (ret) { ret->set_properties (plist); - cerr << "New sources copy constructor region\n"; map_add (ret); if (announce) { @@ -211,7 +208,6 @@ RegionFactory::create (const SourceList& srcs, const PropertyList& plist, bool a if (ret) { ret->set_properties (plist); - cerr << "de-novo constructor region " << ret << " named " << ret->name() << endl; map_add (ret); if (announce) { @@ -285,8 +281,6 @@ RegionFactory::map_add (boost::shared_ptr r) boost::bind (&RegionFactory::region_changed, _1, boost::weak_ptr (r)) ); - cerr << "Added region with ID = " << r->id() << " named " << r->name() << endl; - update_region_name_map (r); } @@ -298,7 +292,6 @@ RegionFactory::map_remove (boost::shared_ptr r) if (i != region_map.end()) { region_map.erase (i); - cerr << "Removed region with ID = " << r->id() << " named " << r->name() << endl;; } } @@ -313,10 +306,8 @@ RegionFactory::map_remove_with_equivalents (boost::shared_ptr r) ++tmp; if (r->region_list_equivalent (i->second)) { - cerr << "Removed equivalent region " << i->second->name() << '/' << i->first << endl; region_map.erase (i); } else if (r == i->second) { - cerr << "Removed actual region " << i->second->name() << '/' << i->first << endl; region_map.erase (i); } diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index 99d0e8c5e..bf038326d 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -99,6 +99,7 @@ SMFSource::SMFSource (Session& s, const XMLNode& node, bool must_exist) SMFSource::~SMFSource () { if (removable()) { + cerr << name() << " is removable, empty ? " << empty() << " UC " << use_count() << endl; unlink (_path.c_str()); } } @@ -383,6 +384,7 @@ SMFSource::mark_streaming_write_completed () MidiSource::mark_streaming_write_completed(); if (!writable()) { + cerr << "\n\n\n[[[[[[[[[ This SMFS is not writable! ]]]]]]]]]]]\n\n\n"; return; } @@ -495,6 +497,11 @@ SMFSource::destroy_model () void SMFSource::flush_midi () { + if (!writable()) { + cerr << "\n\n\n\n " << name() << " CANNOT FLUSH - not writable\n\n\n\n"; + return; + } + Evoral::SMF::end_write(); } diff --git a/libs/ardour/source.cc b/libs/ardour/source.cc index 55ce9f8be..894233f43 100644 --- a/libs/ardour/source.cc +++ b/libs/ardour/source.cc @@ -272,3 +272,17 @@ Source::set_allow_remove_if_empty (bool yn) } } +void +Source::dec_use_count () +{ +#ifndef NDEBUG + gint oldval = g_atomic_int_exchange_and_add (&_use_count, -1); + cerr << "Bad use dec for " << name() << endl; + if (oldval <= 0) { + abort (); + } + assert (oldval > 0); +#else + g_atomic_int_exchange_and_add (&_use_count, -1); +#endif +} diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc index 05e7513da..357dbbadf 100644 --- a/libs/ardour/source_factory.cc +++ b/libs/ardour/source_factory.cc @@ -285,8 +285,8 @@ SourceFactory::createWritable (DataType type, Session& s, const std::string& pat return ret; } else if (type == DataType::MIDI) { - - Source* src = new SMFSource (s, path, Source::Flag(0)); + // XXX writable flags should belong to MidiSource too + Source* src = new SMFSource (s, path, SndFileSource::default_writable_flags); // boost_debug_shared_ptr_mark_interesting (src, "Source"); boost::shared_ptr ret (src); diff --git a/libs/evoral/src/SMF.cpp b/libs/evoral/src/SMF.cpp index cf838455c..5768b1cae 100644 --- a/libs/evoral/src/SMF.cpp +++ b/libs/evoral/src/SMF.cpp @@ -275,7 +275,6 @@ SMF::begin_write() void SMF::end_write() THROW_FILE_ERROR { -#if 0 /* don't create empty MIDI files */ @@ -283,13 +282,14 @@ SMF::end_write() THROW_FILE_ERROR if (smf_peek_next_event (_smf) == 0) { return; } -#endif PBD::StdioFileDescriptor d (_file_path, "w+"); FILE* f = d.allocate (); if (f == 0) { throw FileError (); } + + cerr << "\n\n\nSAVE SMF to " << _file_path << "\n\n"; if (smf_save(_smf, f) != 0) { throw FileError(); -- 2.11.4.GIT