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:
parent
ecb0cd5d11
commit
37978aa214
|
@ -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") ||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -353,7 +353,7 @@ class Region
|
|||
|
||||
void register_properties ();
|
||||
|
||||
private:
|
||||
protected:
|
||||
void use_sources (SourceList const &);
|
||||
};
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 ()));
|
||||
|
|
|
@ -780,7 +780,7 @@ MidiModel::DiffCommand::side_effect_remove(const NotePtr note)
|
|||
source->mark_streaming_write_completed();
|
||||
|
||||
set_edited(false);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue
Block a user