(1) push a locate all the way through the processing heirarchy so that MIDI output...
[ardour.git] / libs / ardour / midi_diskstream.cc
index c3f85438dbd84474e120e72c1780bef604a03c56..a99feec465f704baccad8daa91bfbc8fd4bc9e6e 100644 (file)
@@ -79,8 +79,6 @@ MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::F
        , _frames_written_to_ringbuffer(0)
        , _frames_read_from_ringbuffer(0)
 {
-       /* prevent any write sources from being created */
-
        in_set_state = true;
 
        init ();
@@ -148,7 +146,7 @@ MidiDiskstream::non_realtime_locate (framepos_t position)
        if (_write_source) {
                _write_source->set_timeline_position (position);
        }
-       seek(position, false);
+       seek (position, false);
 }
 
 
@@ -163,19 +161,25 @@ MidiDiskstream::non_realtime_input_change ()
                }
 
                if (input_change_pending.type & IOChange::ConfigurationChanged) {
-                       if (_io->n_ports().n_midi() != _n_channels.n_midi()) {
-                               error << "Can not feed IO " << _io->n_ports()
-                                       << " with diskstream " << _n_channels << endl;
+                       uint32_t ni = _io->n_ports().n_midi();
+
+                       if (ni != _n_channels.n_midi()) {
+                               error << string_compose (_("%1: I/O configuration change %4 requested to use %2, but channel setup is %3"),
+                                                        name(),
+                                                        _io->n_ports(),
+                                                        _n_channels, input_change_pending.type)
+                                     << endmsg;
+                       }
+                       
+                       if (ni == 0) {
+                               _source_port = 0;
+                       } else {
+                               _source_port = _io->midi(0);
                        }
                }
 
-               get_input_sources ();
-               set_capture_offset ();
-
-               if (first_input_change) {
-                       set_align_style (_persistent_alignment_style);
-                       first_input_change = false;
-               } else {
+               if (input_change_pending.type & IOChange::ConnectionsChanged) {
+                       set_capture_offset ();
                        set_align_style_from_io ();
                }
 
@@ -201,23 +205,6 @@ MidiDiskstream::non_realtime_input_change ()
        _last_flush_frame = _session.transport_frame();
 }
 
-void
-MidiDiskstream::get_input_sources ()
-{
-       uint32_t ni = _io->n_ports().n_midi();
-
-       if (ni == 0) {
-               return;
-       }
-
-       // This is all we do for now at least
-       assert(ni == 1);
-
-       _source_port = _io->midi(0);
-
-       // do... stuff?
-}
-
 int
 MidiDiskstream::find_and_use_playlist (const string& name)
 {
@@ -506,6 +493,10 @@ MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool can
                return 0;
        }
 
+       if (_source_port == 0) {
+               return 1;
+       }
+
        Glib::Mutex::Lock sm (state_lock, Glib::TRY_LOCK);
 
        if (!sm.locked()) {
@@ -520,18 +511,18 @@ MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool can
                calculate_record_range(ot, transport_frame, nframes, rec_nframes, rec_offset);
 
                if (rec_nframes && !was_recording) {
+                       _write_source->mark_write_starting_now ();
                        capture_captured = 0;
                        was_recording = true;
                }
        }
 
-
        if (can_record && !_last_capture_sources.empty()) {
                _last_capture_sources.clear ();
        }
 
        if (nominally_recording || rec_nframes) {
-
+               
                // Pump entire port buffer into the ring buffer (FIXME: split cycles?)
                MidiBuffer& buf = _source_port->get_midi_buffer(nframes);
                for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
@@ -576,6 +567,12 @@ MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool can
 
                playback_distance = nframes;
 
+       } else {
+
+               /* XXX: should be doing varispeed stuff here, similar to the code in AudioDiskstream::process */
+
+               playback_distance = nframes;
+
        }
 
        ret = 0;
@@ -622,7 +619,6 @@ 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;
-
        overwrite_frame = playback_sample;
 }
 
@@ -636,6 +632,7 @@ MidiDiskstream::overwrite_existing_buffers ()
        g_atomic_int_set (&_frames_written_to_ringbuffer, 0);
 
        read (overwrite_frame, disk_io_chunk_frames, false);
+       file_frame = overwrite_frame; // it was adjusted by ::read()
        overwrite_queued = false;
        _pending_overwrite = false;
 
@@ -814,7 +811,6 @@ MidiDiskstream::do_refill ()
        uint32_t frames_read = g_atomic_int_get(&_frames_read_from_ringbuffer);
        uint32_t frames_written = g_atomic_int_get(&_frames_written_to_ringbuffer);
        if ((frames_written - frames_read) >= midi_readahead) {
-               //cout << "MDS Nothing to do. all fine" << endl;
                return 0;
        }
 
@@ -824,7 +820,7 @@ MidiDiskstream::do_refill ()
        //      << frames_written - frames_read << endl;
 
        to_read = (framecnt_t) min ((framecnt_t) to_read, (framecnt_t) (max_framepos - file_frame));
-
        if (read (file_frame, to_read, reversed)) {
                ret = -1;
        }
@@ -882,8 +878,8 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush)
        assert(!destructive());
 
        if (record_enabled() &&
-            ((_session.transport_frame() - _last_flush_frame > disk_io_chunk_frames) ||
-             force_flush)) {
+           ((_session.transport_frame() - _last_flush_frame > disk_io_chunk_frames) ||
+            force_flush)) {
                if ((!_write_source) || _write_source->midi_write (*_capture_buf, get_capture_start_frame (0), to_write) != to_write) {
                        error << string_compose(_("MidiDiskstream %1: cannot write to disk"), _id) << endmsg;
                        return -1;
@@ -937,6 +933,7 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
 
                if (_write_source) {
                        _write_source->mark_for_remove ();
+                       _write_source->drop_references ();
                        _write_source.reset();
                }
 
@@ -974,10 +971,6 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
                        const double total_capture_beats = converter.from(total_capture);
                        _write_source->set_length_beats(total_capture_beats);
 
-                       /* make it not a stub anymore */
-
-                       _write_source->unstubify ();
-
                        /* 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
@@ -1042,6 +1035,7 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
                                        /* start of this region is the offset between the start of its capture and the start of the whole pass */
                                        plist.add (Properties::start, (*ci)->start - initial_capture);
                                        plist.add (Properties::length, (*ci)->frames);
+                                       plist.add (Properties::length_beats, converter.from((*ci)->frames));
                                        plist.add (Properties::name, region_name);
 
                                        boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist));
@@ -1062,7 +1056,21 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
 
                        _playlist->thaw ();
                        _session.add_command (new StatefulDiffCommand(_playlist));
-               }
+
+               } else {
+
+                       /* No data was recorded, so this capture will
+                          effectively be aborted; do the same as we
+                          do for an explicit abort.
+                       */
+
+                       if (_write_source) {
+                               _write_source->mark_for_remove ();
+                               _write_source->drop_references ();
+                               _write_source.reset();
+                       }
+               }
+               
 
                mark_write_completed = true;
        }
@@ -1182,38 +1190,19 @@ void
 MidiDiskstream::disengage_record_enable ()
 {
        g_atomic_int_set (&_record_enabled, 0);
-       if (_source_port && Config->get_monitoring_model() == HardwareMonitoring) {
-               if (_source_port) {
-                       _source_port->request_monitor_input (false);
-               }
-       }
-
        RecordEnableChanged (); /* EMIT SIGNAL */
 }
 
 XMLNode&
 MidiDiskstream::get_state ()
 {
-       XMLNode* node = new XMLNode ("Diskstream");
+       XMLNode& node (Diskstream::get_state());
        char buf[64];
        LocaleGuard lg (X_("POSIX"));
 
-       snprintf (buf, sizeof(buf), "0x%x", _flags);
-       node->add_property ("flags", buf);
-
-       node->add_property("channel-mode", enum_2_string(get_channel_mode()));
-
+       node.add_property("channel-mode", enum_2_string(get_channel_mode()));
        snprintf (buf, sizeof(buf), "0x%x", get_channel_mask());
-       node->add_property("channel-mask", buf);
-
-       node->add_property ("playlist", _playlist->name());
-
-       snprintf (buf, sizeof(buf), "%f", _visible_speed);
-       node->add_property ("speed", buf);
-
-       node->add_property("name", _name);
-       id().print(buf, sizeof(buf));
-       node->add_property("id", buf);
+       node.add_property("channel-mask", buf);
 
        if (_write_source && _session.get_record_enabled()) {
 
@@ -1235,18 +1224,14 @@ MidiDiskstream::get_state ()
                }
 
                cs_child->add_property (X_("at"), buf);
-               node->add_child_nocopy (*cs_child);
-       }
-
-       if (_extra_xml) {
-               node->add_child_copy (*_extra_xml);
+               node.add_child_nocopy (*cs_child);
        }
 
-       return* node;
+       return node;
 }
 
 int
-MidiDiskstream::set_state (const XMLNode& node, int /*version*/)
+MidiDiskstream::set_state (const XMLNode& node, int version)
 {
        const XMLProperty* prop;
        XMLNodeList nlist = node.children();
@@ -1254,12 +1239,11 @@ MidiDiskstream::set_state (const XMLNode& node, int /*version*/)
        XMLNode* capture_pending_node = 0;
        LocaleGuard lg (X_("POSIX"));
 
+       /* prevent write sources from being created */
+
        in_set_state = true;
 
        for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
-               /*if ((*niter)->name() == IO::state_node_name) {
-                       deprecated_io_node = new XMLNode (**niter);
-               }*/
                assert ((*niter)->name() != IO::state_node_name);
 
                if ((*niter)->name() == X_("CapturingSources")) {
@@ -1267,20 +1251,8 @@ MidiDiskstream::set_state (const XMLNode& node, int /*version*/)
                }
        }
 
-       /* prevent write sources from being created */
-
-       in_set_state = true;
-
-       if ((prop = node.property ("name")) != 0) {
-               _name = prop->value();
-       }
-
-       if ((prop = node.property ("id")) != 0) {
-               _id = prop->value ();
-       }
-
-       if ((prop = node.property ("flags")) != 0) {
-               _flags = Flag (string_2_enum (prop->value(), _flags));
+       if (Diskstream::set_state (node, version)) {
+               return -1;
        }
 
        ChannelMode channel_mode = AllChannels;
@@ -1296,36 +1268,12 @@ MidiDiskstream::set_state (const XMLNode& node, int /*version*/)
                }
        }
 
-       set_channel_mode(channel_mode, channel_mask);
 
-       if ((prop = node.property ("playlist")) == 0) {
-               return -1;
+       if (capture_pending_node) {
+               use_pending_capture_data (*capture_pending_node);
        }
 
-       {
-               bool had_playlist = (_playlist != 0);
-
-               if (find_and_use_playlist (prop->value())) {
-                       return -1;
-               }
-
-               if (!had_playlist) {
-                       _playlist->set_orig_diskstream_id (id());
-               }
-
-               if (capture_pending_node) {
-                       use_pending_capture_data (*capture_pending_node);
-               }
-
-       }
-
-       if ((prop = node.property ("speed")) != 0) {
-               double sp = atof (prop->value().c_str());
-
-               if (realtime_set_speed (sp, false)) {
-                       non_realtime_set_speed ();
-               }
-       }
+       set_channel_mode (channel_mode, channel_mask);
 
        in_set_state = false;
 
@@ -1338,19 +1286,14 @@ MidiDiskstream::use_new_write_source (uint32_t n)
        if (!_session.writable() || !recordable()) {
                return 1;
        }
-
+       
        assert(n == 0);
 
        _write_source.reset();
 
        try {
-               /* file starts off as a stub file, it will be converted
-                  when we're done with a capture pass, or when "stolen"
-                  by the GUI.
-               */
-
                _write_source = boost::dynamic_pointer_cast<SMFSource>(
-                       _session.create_midi_source_for_session (0, name (), true));
+                       _session.create_midi_source_for_session (0, name ()));
 
                if (!_write_source) {
                        throw failed_constructor();
@@ -1363,8 +1306,6 @@ MidiDiskstream::use_new_write_source (uint32_t n)
                return -1;
        }
 
-       _write_source->mark_streaming_midi_write_started (_note_mode, _session.transport_frame());
-
        return 0;
 }
 
@@ -1373,16 +1314,9 @@ MidiDiskstream::steal_write_sources()
 {
        list<boost::shared_ptr<Source> > ret;
 
-       /* put some data on the disk, even if its just a header for an empty file.
-          XXX should we not have a more direct method for doing this? Maybe not
-          since we don't want to mess around with the model/disk relationship
-          that the Source has to pay attention to.
-       */
-
-       boost::dynamic_pointer_cast<MidiSource>(_write_source)->session_saved ();
+       /* put some data on the disk, even if its just a header for an empty file */
+       boost::dynamic_pointer_cast<SMFSource> (_write_source)->ensure_disk_file ();
 
-       /* make it visible/present */
-       _write_source->unstubify ();
        /* never let it go away */
        _write_source->mark_nonremovable ();
 
@@ -1408,16 +1342,6 @@ MidiDiskstream::reset_write_sources (bool mark_write_complete, bool /*force*/)
        use_new_write_source (0);
 }
 
-int
-MidiDiskstream::rename_write_sources ()
-{
-       if (_write_source != 0) {
-               _write_source->set_source_name (_name.val(), destructive());
-               /* XXX what to do if this fails ? */
-       }
-       return 0;
-}
-
 void
 MidiDiskstream::set_block_size (pframes_t /*nframes*/)
 {
@@ -1438,23 +1362,15 @@ MidiDiskstream::monitor_input (bool yn)
 void
 MidiDiskstream::set_align_style_from_io ()
 {
-       bool have_physical = false;
-
-       if (_io == 0) {
+       if (_alignment_choice != Automatic) {
                return;
        }
 
-       get_input_sources ();
-
-       if (_source_port && _source_port->flags() & JackPortIsPhysical) {
-               have_physical = true;
-       }
+       /* XXX Not sure what, if anything we can do with MIDI 
+          as far as capture alignment etc.
+       */
 
-       if (have_physical) {
-               set_align_style (ExistingMaterial);
-       } else {
-               set_align_style (CaptureTime);
-       }
+       set_align_style (ExistingMaterial);
 }
 
 
@@ -1492,13 +1408,23 @@ MidiDiskstream::get_playback (MidiBuffer& dst, framepos_t start, framepos_t end)
                return;
        }
 
-       // Translates stamps to be relative to start
+       // Translate stamps to be relative to start
 
 
 #ifndef NDEBUG
+       DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose (
+                            "%1 MDS pre-read read from %2 write to %3\n", _name, 
+                            _playback_buf->get_read_ptr(), _playback_buf->get_write_ptr()));
+//        cerr << "================\n";
+//        _playback_buf->dump (cerr);
+//        cerr << "----------------\n";
+
        const size_t events_read = _playback_buf->read(dst, start, end);
-       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()));
+       DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose (
+                            "%1 MDS events read %2 range %3 .. %4 rspace %5 wspace %6 r@%7 w@%8\n",
+                            _name, events_read, start, end,
+                            _playback_buf->read_space(), _playback_buf->write_space(),
+                        _playback_buf->get_read_ptr(), _playback_buf->get_write_ptr()));
 #else
        _playback_buf->read(dst, start, end);
 #endif
@@ -1507,3 +1433,14 @@ MidiDiskstream::get_playback (MidiBuffer& dst, framepos_t start, framepos_t end)
        g_atomic_int_add(&_frames_read_from_ringbuffer, frames_read);
 }
 
+bool
+MidiDiskstream::set_name (string const & name)
+{
+       Diskstream::set_name (name);
+
+       /* get a new write source so that its name reflects the new diskstream name */
+       use_new_write_source (0);
+
+       return true;
+}
+