const correctness.
[ardour.git] / libs / ardour / midi_diskstream.cc
index 8db5a277db7dfcd78fb4bffd006425e7d27e554e..95e242e6714384816f432461305ab8411fd857c3 100644 (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 */
 
@@ -373,7 +375,7 @@ trace_midi (ostream& o, MIDI::byte *msg, size_t len)
                o << trace_prefix
                   << "Channel "
                   << (msg[0]&0xF)+1
-                  <<  " Program PropertyChange ProgNum "
+                  <<  " Program Change ProgNum "
                   << (int) msg[1]
                   << endl;
                break;
@@ -524,8 +526,8 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_
        }
 
 
-       if (can_record && !_last_capture_regions.empty()) {
-               _last_capture_regions.clear ();
+       if (can_record && !_last_capture_sources.empty()) {
+               _last_capture_sources.clear ();
        }
 
        if (nominally_recording || rec_nframes) {
@@ -938,96 +940,109 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
                        total_capture += (*ci)->frames;
                }
 
-               /* 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);
-
-               string whole_file_region_name;
-               whole_file_region_name = region_name_from_path (_write_source->name(), true);
-
-               /* Register a new region with the Session that
-                  describes the entire source. Do this first
-                  so that any sub-regions will obviously be
-                  children of this one (later!)
-                  */
-
-               try {
-                       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<Region> rx (RegionFactory::create (srcs, plist));
-
-                       region = boost::dynamic_pointer_cast<MidiRegion> (rx);
-                       region->special_set_position (capture_info.front()->start);
-               }
-
-
-               catch (failed_constructor& err) {
-                       error << string_compose(_("%1: could not create region for complete midi file"), _name) << endmsg;
-                       /* XXX what now? */
-               }
-
-               _last_capture_regions.push_back (region);
-
-               // cerr << _name << ": there are " << capture_info.size() << " capture_info records\n";
-
-               _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;
-
-                       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 {
-                               PropertyList plist;
+                if (_write_source->length (capture_info.front()->start) != 0) {
+                        
+                        /* phew, we have data */
+                        
+                        /* 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);
+                        
+                        /* Register a new region with the Session that
+                           describes the entire source. Do this first
+                           so that any sub-regions will obviously be
+                           children of this one (later!)
+                        */
+                        
+                        try {
+                                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<Region> rx (RegionFactory::create (srcs, plist));
+
+                                region = boost::dynamic_pointer_cast<MidiRegion> (rx);
+                                region->special_set_position (capture_info.front()->start);
+                        }
+
+
+                        catch (failed_constructor& err) {
+                                error << string_compose(_("%1: could not create region for complete midi file"), _name) << endmsg;
+                                /* XXX what now? */
+                        }
+
+                        _last_capture_sources.insert (_last_capture_sources.end(), srcs.begin(), srcs.end());
+
+                        _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;
+
+                                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 {
+                                        PropertyList plist;
                                
-                               plist.add (Properties::start, buffer_position);
-                               plist.add (Properties::length, (*ci)->frames);
-                               plist.add (Properties::name, region_name);
+                                        plist.add (Properties::start, buffer_position);
+                                        plist.add (Properties::length, (*ci)->frames);
+                                        plist.add (Properties::name, region_name);
                                
-                               boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist));
-                               region = boost::dynamic_pointer_cast<MidiRegion> (rx);
-                       }
+                                        boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist));
+                                        region = boost::dynamic_pointer_cast<MidiRegion> (rx);
+                                }
 
-                       catch (failed_constructor& err) {
-                               error << _("MidiDiskstream: could not create region for captured midi!") << endmsg;
-                               continue; /* XXX is this OK? */
-                       }
+                                catch (failed_constructor& err) {
+                                        error << _("MidiDiskstream: could not create region for captured midi!") << endmsg;
+                                        continue; /* XXX is this OK? */
+                                }
 
-                       region->DropReferences.connect_same_thread (*this, boost::bind (&Diskstream::remove_region_from_last_capture, this, boost::weak_ptr<Region>(region)));
+                                // cerr << "add new region, buffer position = " << buffer_position << " @ " << (*ci)->start << endl;
 
-                       _last_capture_regions.push_back (region);
+                                i_am_the_modifier++;
+                                _playlist->add_region (region, (*ci)->start);
+                                i_am_the_modifier--;
 
-                       // cerr << "add new region, buffer position = " << buffer_position << " @ " << (*ci)->start << endl;
+                                buffer_position += (*ci)->frames;
+                        }
 
-                       i_am_the_modifier++;
-                       _playlist->add_region (region, (*ci)->start);
-                       i_am_the_modifier--;
-
-                       buffer_position += (*ci)->frames;
-               }
-
-               _playlist->thaw ();
-               _session.add_command (new StatefulDiffCommand(_playlist));
+                        _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;
@@ -1135,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 */
@@ -1295,17 +1306,6 @@ 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;
 }
 
@@ -1318,19 +1318,10 @@ MidiDiskstream::use_new_write_source (uint32_t n)
 
        assert(n == 0);
 
-       if (_write_source) {
-
-               if (_write_source->is_empty ()) {
-                       _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 (name ()));
+               _write_source = boost::dynamic_pointer_cast<SMFSource>(_session.create_midi_source_for_session (0, name ()));
                if (!_write_source) {
                        throw failed_constructor();
                }
@@ -1348,6 +1339,15 @@ MidiDiskstream::use_new_write_source (uint32_t n)
        return 0;
 }
 
+list<boost::shared_ptr<Source> > 
+MidiDiskstream::steal_write_sources()
+{
+        list<boost::shared_ptr<Source> > ret;
+        ret.push_back (_write_source);
+        reset_write_sources (false);
+        return ret;
+}
+
 void
 MidiDiskstream::reset_write_sources (bool mark_write_complete, bool /*force*/)
 {