Fix MIDI selection/tool issues (issue #0002415 and other bugs).
[ardour.git] / libs / ardour / midi_diskstream.cc
index 2e1647f507255e430eadcc3de328452157610c4a..84fe21ce353e4176331552a7ac4040c825cada48 100644 (file)
@@ -61,12 +61,7 @@ MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::F
        : Diskstream(sess, name, flag)
        , _playback_buf(0)
        , _capture_buf(0)
-       //, _current_playback_buffer(0)
-       //, _current_capture_buffer(0)
-       //, _playback_wrap_buffer(0)
-       //, _capture_wrap_buffer(0)
        , _source_port(0)
-       , _capture_transition_buf(0)
        , _last_flush_frame(0)
        , _note_mode(Sustained)
 {
@@ -86,12 +81,7 @@ MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node)
        : Diskstream(sess, node)
        , _playback_buf(0)
        , _capture_buf(0)
-       //, _current_playback_buffer(0)
-       //, _current_capture_buffer(0)
-       //, _playback_wrap_buffer(0)
-       //, _capture_wrap_buffer(0)
        , _source_port(0)
-       , _capture_transition_buf(0)
        , _last_flush_frame(0)
        , _note_mode(Sustained)
 {
@@ -123,9 +113,8 @@ MidiDiskstream::init (Diskstream::Flag f)
        set_block_size (_session.get_block_size());
        allocate_temporary_buffers ();
 
-       _playback_buf = new MidiRingBuffer (_session.diskstream_buffer_size());
-       _capture_buf = new MidiRingBuffer (_session.diskstream_buffer_size());
-       _capture_transition_buf = new RingBufferNPT<CaptureTransition> (128);
+       _playback_buf = new MidiRingBuffer (_session.midi_diskstream_buffer_size());
+       _capture_buf = new MidiRingBuffer (_session.midi_diskstream_buffer_size());
        
        _n_channels = ChanCount(DataType::MIDI, 1);
 
@@ -141,10 +130,9 @@ MidiDiskstream::~MidiDiskstream ()
 void
 MidiDiskstream::non_realtime_locate (nframes_t position)
 {
-       //cerr << "MDS: non_realtime_locate: " << position << endl;
        assert(_write_source);
        _write_source->set_timeline_position (position);
-       seek(position, true); // correct?
+       seek(position, false);
 }
 
 
@@ -304,7 +292,6 @@ MidiDiskstream::set_destructive (bool yn)
 void
 MidiDiskstream::set_note_mode (NoteMode m)
 {
-       cout << "MDS: SET NOTE MODE: " << m << endl;
        _note_mode = m;
        midi_playlist()->set_note_mode(m);
        if (_write_source && _write_source->model())
@@ -403,21 +390,6 @@ MidiDiskstream::check_record_status (nframes_t transport_frame, nframes_t nframe
                        
                }
 
-               if (_flags & Recordable) {
-                       RingBufferNPT<CaptureTransition>::rw_vector transvec;
-                       _capture_transition_buf->get_write_vector(&transvec);
-
-                       if (transvec.len[0] > 0) {
-                               transvec.buf[0]->type = CaptureStart;
-                               transvec.buf[0]->capture_val = capture_start_frame;
-                               _capture_transition_buf->increment_write_ptr(1);
-                       } else {
-                               // bad!
-                               fatal << X_("programming error: capture_transition_buf is full on rec start!  inconceivable!") 
-                                       << endmsg;
-                       }
-               }
-
        } else if (!record_enabled() || !can_record) {
                
                /* stop recording */
@@ -468,7 +440,7 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_t
                return 0;
        }
 
-       /* This lock is held until the end of AudioDiskstream::commit, so these two functions
+       /* This lock is held until the end of ::commit, so these two functions
           must always be called as a pair. The only exception is if this function
           returns a non-zero value, in which case, ::commit should not be called.
           */
@@ -549,6 +521,7 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_t
 
                for (size_t i=0; i < to_write; ++i) {
                        const MIDI::Event& ev = *port_iter;
+                       assert(ev.buffer());
                        _capture_buf->write(ev.time() + transport_frame, ev.size(), ev.buffer());
                        ++port_iter;
                }
@@ -641,12 +614,18 @@ MidiDiskstream::commit (nframes_t nframes)
                adjust_capture_position = 0;
        }
 
+       /* what audio does:
+        * can't do this with midi: write space is in bytes, chunk_frames is in frames
        if (_slaved) {
                need_butler = _playback_buf->write_space() >= _playback_buf->capacity() / 2;
        } else {
                need_butler = _playback_buf->write_space() >= disk_io_chunk_frames
                        || _capture_buf->read_space() >= disk_io_chunk_frames;
-       }
+       }*/
+       
+       /* we'll just keep the playback buffer full for now.
+        * this should be decreased to reduce edit latency */
+       need_butler = _playback_buf->write_space() >= _playback_buf->capacity() / 2;
        
        if (commit_should_unlock) {
                state_lock.unlock();
@@ -663,9 +642,8 @@ 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;
-       //overwrite_offset = channels.front().playback_buf->get_read_ptr();
 }
 
 int
@@ -681,8 +659,6 @@ MidiDiskstream::seek (nframes_t frame, bool complete_refill)
        Glib::Mutex::Lock lm (state_lock);
        int ret = -1;
        
-       //cerr << "MDS: seek: " << frame << endl;
-
        _playback_buf->reset();
        _capture_buf->reset();
 
@@ -817,47 +793,20 @@ MidiDiskstream::do_refill_with_alloc ()
 int
 MidiDiskstream::do_refill ()
 {
-       int32_t        ret = 0;
-       size_t         write_space = _playback_buf->write_space();
-
-       bool reversed = (_visible_speed * _session.transport_speed()) < 0.0f;
+       int     ret         = 0;
+       size_t  write_space = _playback_buf->write_space();
+       bool    reversed    = (_visible_speed * _session.transport_speed()) < 0.0f;
 
        if (write_space == 0) {
                return 0;
        }
-
-       /* if we're running close to normal speed and there isn't enough 
-          space to do disk_io_chunk_frames of I/O, then don't bother.  
-
-          at higher speeds, just do it because the sync between butler
-          and audio thread may not be good enough.
-          */
-
-       if ((write_space < disk_io_chunk_frames) && fabs (_actual_speed) < 2.0f) {
-               //cerr << "No refill 1\n";
-               return 0;
-       }
-
-       /* when slaved, don't try to get too close to the read pointer. this
-          leaves space for the buffer reversal to have something useful to
-          work with.
-          */
-
-       if (_slaved && write_space < (_playback_buf->capacity() / 2)) {
-               //cerr << "No refill 2\n";
-               return 0;
-       }
-
+       
        if (reversed) {
-               //cerr << "No refill 3 (reverse)\n";
                return 0;
        }
 
+       /* at end: nothing to do */
        if (file_frame == max_frames) {
-               //cerr << "No refill 4 (EOF)\n";
-
-               /* at end: nothing to do */
-
                return 0;
        }
 
@@ -865,19 +814,12 @@ MidiDiskstream::do_refill ()
        assert(_playback_buf->write_space() > 0); // ... have something to write to, and
        assert(file_frame <= max_frames); // ... something to write
 
-       nframes_t file_frame_tmp = file_frame;
        nframes_t to_read = min(disk_io_chunk_frames, (max_frames - file_frame));
        
-       // FIXME: read count?
-       if (read (file_frame_tmp, to_read, reversed)) {
+       if (read (file_frame, to_read, reversed)) {
                ret = -1;
-               goto out;
        }
-
-       file_frame = file_frame_tmp;
-
-out:
-
+               
        return ret;
 }
 
@@ -896,8 +838,6 @@ MidiDiskstream::do_flush (Session::RunContext context, bool force_flush)
 {
        uint32_t to_write;
        int32_t ret = 0;
-       // FIXME: I'd be lying if I said I knew what this thing was
-       //RingBufferNPT<CaptureTransition>::rw_vector transvec;
        nframes_t total;
 
        _write_data_count = 0;
@@ -928,7 +868,6 @@ MidiDiskstream::do_flush (Session::RunContext context, bool force_flush)
                ret = 1;
        } 
 
-       //to_write = min (disk_io_chunk_frames, (nframes_t) vector.len[0]);
        to_write = disk_io_chunk_frames;
 
        assert(!destructive());
@@ -943,8 +882,7 @@ MidiDiskstream::do_flush (Session::RunContext context, bool force_flush)
        }
 
 out:
-       //return ret;
-       return 0; // FIXME: everything's fine!  always!  honest!
+       return ret;
 }
 
 void
@@ -1226,11 +1164,10 @@ MidiDiskstream::get_state ()
        snprintf (buf, sizeof(buf), "0x%x", _flags);
        node->add_property ("flags", buf);
 
+       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);
-
-       snprintf (buf, sizeof(buf), "%d", get_force_channel());
-       node->add_property("force_channel", buf);
+       node->add_property("channel-mask", buf);
        
        node->add_property ("playlist", _playlist->name());
        
@@ -1309,19 +1246,22 @@ MidiDiskstream::set_state (const XMLNode& node)
        if ((prop = node.property ("flags")) != 0) {
                _flags = Flag (string_2_enum (prop->value(), _flags));
        }
-       
-       if ((prop = node.property ("channel_mask")) != 0) {
-               unsigned int channel_mask;
-               sscanf (prop->value().c_str(), "0x%x", &channel_mask);
-               set_channel_mask(channel_mask);
+
+       ChannelMode channel_mode = AllChannels;
+       if ((prop = node.property ("channel-mode")) != 0) {
+               channel_mode = ChannelMode (string_2_enum(prop->value(), channel_mode));
        }
        
-       if ((prop = node.property ("force_channel")) != 0) {
-               int force_channel;
-               sscanf (prop->value().c_str(), "%d", &force_channel);
-               set_force_channel(force_channel);
+       unsigned int channel_mask = 0xFFFF;
+       if ((prop = node.property ("channel-mask")) != 0) {
+               sscanf (prop->value().c_str(), "0x%x", &channel_mask);
+               if (channel_mask & (~0xFFFF)) {
+                       warning << _("MidiDiskstream: XML property channel-mask out of range") << endmsg;
+               }
        }
 
+       set_channel_mode(channel_mode, channel_mask);
+       
        if ((prop = node.property ("channels")) != 0) {
                nchans = atoi (prop->value().c_str());
        }