lots of details relating to MIDI file management; try to ignore ALSA sequencer MIDI ports named "Midi-Through"

git-svn-id: svn://localhost/ardour2/branches/3.0@7305 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2010-06-26 13:45:59 +00:00
parent ecb0cd5d11
commit 37978aa214
17 changed files with 126 additions and 82 deletions

View File

@ -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") ||

View File

@ -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; }

View File

@ -353,7 +353,7 @@ class Region
void register_properties ();
private:
protected:
void use_sources (SourceList const &);
};

View File

@ -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; }

View File

@ -1917,8 +1917,6 @@ AudioDiskstream::reset_write_sources (bool mark_write_complete, bool /*force*/)
boost::shared_ptr<ChannelList> c = channels.reader();
uint32_t n;
cerr << name() << " resetting write sources, recrodable " << recordable() << " chans = " << c->size() << endl;
if (!_session.writable() || !recordable()) {
return;
}

View File

@ -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<string>& 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<string>& 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);

View File

@ -417,6 +417,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)
{

View File

@ -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<SMFSource>(_session.create_midi_source_for_session (0, name ()));

View File

@ -780,7 +780,7 @@ MidiModel::DiffCommand::side_effect_remove(const NotePtr note)
source->mark_streaming_write_completed();
set_edited(false);
return true;
}

View File

@ -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<const MidiRegion> 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<Source> 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));
}

View File

@ -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<MidiSource> newsrc = clone ();
if (newsrc) {
@ -298,6 +308,7 @@ MidiSource::session_saved()
Switched (newsrc); /* EMIT SIGNAL */
}
}
#endif
}
void

View File

@ -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 ();
}

View File

@ -73,7 +73,6 @@ RegionFactory::create (boost::shared_ptr<const Region> 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> 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> 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<Region> r)
boost::bind (&RegionFactory::region_changed, _1, boost::weak_ptr<Region> (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<Region> 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<Region> 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);
}

View File

@ -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();
}

View File

@ -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
}

View File

@ -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<Source> ret (src);

View File

@ -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();