Oops, fix build.
[ardour.git] / libs / ardour / midi_diskstream.cc
index 9c0abe53ef220e8537e1e44646a3ab89467d710a..1e28186fb01cb070a3889e8b77c1ffe2a854c67c 100644 (file)
@@ -67,7 +67,7 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-nframes_t MidiDiskstream::midi_readahead = 4096;
+framecnt_t MidiDiskstream::midi_readahead = 4096;
 
 MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::Flag flag)
        : Diskstream(sess, name, flag)
@@ -128,8 +128,8 @@ MidiDiskstream::init ()
        allocate_temporary_buffers ();
 
        const size_t size = _session.butler()->midi_diskstream_buffer_size();
-       _playback_buf = new MidiRingBuffer<nframes_t>(size);
-       _capture_buf = new MidiRingBuffer<nframes_t>(size);
+       _playback_buf = new MidiRingBuffer<framepos_t>(size);
+       _capture_buf = new MidiRingBuffer<framepos_t>(size);
 
        _n_channels = ChanCount(DataType::MIDI, 1);
 
@@ -143,7 +143,7 @@ MidiDiskstream::~MidiDiskstream ()
 
 
 void
-MidiDiskstream::non_realtime_locate (nframes_t position)
+MidiDiskstream::non_realtime_locate (framepos_t position)
 {
        if (_write_source) {
                _write_source->set_timeline_position (position);
@@ -158,11 +158,11 @@ MidiDiskstream::non_realtime_input_change ()
        {
                Glib::Mutex::Lock lm (state_lock);
 
-               if (input_change_pending == NoChange) {
+               if (input_change_pending.type == IOChange::NoChange) {
                        return;
                }
 
-               if (input_change_pending & ConfigurationChanged) {
+               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;
@@ -179,7 +179,7 @@ MidiDiskstream::non_realtime_input_change ()
                        set_align_style_from_io ();
                }
 
-               input_change_pending = NoChange;
+               input_change_pending.type = IOChange::NoChange;
 
                /* implicit unlock */
        }
@@ -192,7 +192,7 @@ MidiDiskstream::non_realtime_input_change ()
        /* now refill channel buffers */
 
        if (speed() != 1.0f || speed() != -1.0f) {
-               seek ((nframes_t) (_session.transport_frame() * (double) speed()));
+               seek ((framepos_t) (_session.transport_frame() * (double) speed()));
        }
        else {
                seek (_session.transport_frame());
@@ -488,17 +488,17 @@ trace_midi (ostream& o, MIDI::byte *msg, size_t len)
 #endif
 
 int
-MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input, bool& need_butler)
+MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool can_record, bool rec_monitors_input, bool& need_butler)
 {
        int       ret = -1;
-       nframes_t rec_offset = 0;
-       nframes_t rec_nframes = 0;
+       framecnt_t rec_offset = 0;
+       framecnt_t rec_nframes = 0;
        bool      nominally_recording;
        bool      re = record_enabled ();
 
         playback_distance = 0;
 
-       check_record_status (transport_frame, nframes, can_record);
+       check_record_status (transport_frame, can_record);
 
        nominally_recording = (can_record && re);
 
@@ -514,7 +514,7 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_
 
        adjust_capture_position = 0;
 
-       if (nominally_recording || (_session.get_record_enabled() && _session.config.get_punch_in())) {
+       if (nominally_recording || (re && was_recording && _session.get_record_enabled() && _session.config.get_punch_in())) {
                OverlapType ot = coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
 
                calculate_record_range(ot, transport_frame, nframes, rec_nframes, rec_offset);
@@ -540,6 +540,16 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_
                        _capture_buf->write(ev.time() + transport_frame, ev.type(), ev.size(), ev.buffer());
                }
 
+               if (buf.size() != 0) {
+                       /* Make a copy of this data and emit it for the GUI to see */
+                       boost::shared_ptr<MidiBuffer> copy (new MidiBuffer (buf.capacity ()));
+                       for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
+                               copy->push_back ((*i).time() + transport_frame, (*i).size(), (*i).buffer());
+                       }
+                               
+                       DataRecorded (copy, _write_source); /* EMIT SIGNAL */
+               }
+
        } else {
 
                if (was_recording) {
@@ -578,7 +588,7 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_
 }
 
 bool
-MidiDiskstream::commit (nframes_t nframes)
+MidiDiskstream::commit (framecnt_t nframes)
 {
        bool need_butler = false;
 
@@ -619,7 +629,13 @@ MidiDiskstream::set_pending_overwrite (bool yn)
 int
 MidiDiskstream::overwrite_existing_buffers ()
 {
-       //read(overwrite_frame, disk_io_chunk_frames, false);
+       /* This is safe as long as the butler thread is suspended, which it should be */
+       _playback_buf->reset ();
+
+       g_atomic_int_set (&_frames_read_from_ringbuffer, 0);
+       g_atomic_int_set (&_frames_written_to_ringbuffer, 0);
+       
+       read (overwrite_frame, disk_io_chunk_frames, false);
        overwrite_queued = false;
        _pending_overwrite = false;
 
@@ -627,7 +643,7 @@ MidiDiskstream::overwrite_existing_buffers ()
 }
 
 int
-MidiDiskstream::seek (nframes_t frame, bool complete_refill)
+MidiDiskstream::seek (framepos_t frame, bool complete_refill)
 {
        Glib::Mutex::Lock lm (state_lock);
        int ret = -1;
@@ -650,7 +666,7 @@ MidiDiskstream::seek (nframes_t frame, bool complete_refill)
 }
 
 int
-MidiDiskstream::can_internal_playback_seek (nframes_t distance)
+MidiDiskstream::can_internal_playback_seek (framecnt_t distance)
 {
        uint32_t frames_read    = g_atomic_int_get(&_frames_read_from_ringbuffer);
        uint32_t frames_written = g_atomic_int_get(&_frames_written_to_ringbuffer);
@@ -658,7 +674,7 @@ MidiDiskstream::can_internal_playback_seek (nframes_t distance)
 }
 
 int
-MidiDiskstream::internal_playback_seek (nframes_t distance)
+MidiDiskstream::internal_playback_seek (framecnt_t distance)
 {
        first_recordable_frame += distance;
        playback_sample += distance;
@@ -668,17 +684,17 @@ MidiDiskstream::internal_playback_seek (nframes_t distance)
 
 /** @a start is set to the new frame position (TIME) read up to */
 int
-MidiDiskstream::read (nframes_t& start, nframes_t dur, bool reversed)
+MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed)
 {
-       nframes_t this_read = 0;
+       framecnt_t this_read = 0;
        bool reloop = false;
-       nframes_t loop_end = 0;
-       nframes_t loop_start = 0;
+       framepos_t loop_end = 0;
+       framepos_t loop_start = 0;
        Location *loc = 0;
 
        if (!reversed) {
 
-               nframes_t loop_length = 0;
+               framecnt_t loop_length = 0;
 
                /* Make the use of a Location atomic for this read operation.
 
@@ -749,10 +765,7 @@ MidiDiskstream::read (nframes_t& start, nframes_t dur, bool reversed)
                        if (reloop) {
                                // Synthesize LoopEvent here, because the next events
                                // written will have non-monotonic timestamps.
-                               _playback_buf->write(loop_end - 1, LoopEventType, 0, 0);
-                               cout << "Pushing LoopEvent ts=" << loop_end-1
-                                    << " start+this_read " << start+this_read << endl;
-
+                               _playback_buf->write(loop_end - 1, LoopEventType, sizeof (framepos_t), (uint8_t *) &loop_start);
                                start = loop_start;
                        } else {
                                start += this_read;
@@ -788,13 +801,13 @@ MidiDiskstream::do_refill ()
        }
 
        /* at end: nothing to do */
-       if (file_frame == max_frames) {
+       if (file_frame == max_framepos) {
                return 0;
        }
 
        // At this point we...
        assert(_playback_buf->write_space() > 0); // ... have something to write to, and
-       assert(file_frame <= max_frames); // ... something to write
+       assert(file_frame <= max_framepos); // ... something to write
 
        // now calculate how much time is in the ringbuffer.
        // and lets write as much as we need to get this to be midi_readahead;
@@ -805,12 +818,12 @@ MidiDiskstream::do_refill ()
                return 0;
        }
 
-       nframes_t to_read = midi_readahead - (frames_written - frames_read);
+       framecnt_t to_read = midi_readahead - (frames_written - frames_read);
 
        //cout << "MDS read for midi_readahead " << to_read << "  rb_contains: "
        //      << frames_written - frames_read << endl;
 
-       to_read = min(to_read, (max_frames - file_frame));
+       to_read = (framecnt_t) min ((framecnt_t) to_read, (framecnt_t) (max_framepos - file_frame));
 
        if (read (file_frame, to_read, reversed)) {
                ret = -1;
@@ -834,14 +847,13 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush)
 {
        uint32_t to_write;
        int32_t ret = 0;
-       nframes_t total;
+       framecnt_t total;
 
        _write_data_count = 0;
 
        total = _session.transport_frame() - _last_flush_frame;
 
-       if (_last_flush_frame > _session.transport_frame()
-                       || _last_flush_frame < capture_start_frame) {
+       if (_last_flush_frame > _session.transport_frame() || _last_flush_frame < capture_start_frame) {
                _last_flush_frame = _session.transport_frame();
        }
 
@@ -872,7 +884,7 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush)
        if (record_enabled() && 
             ((_session.transport_frame() - _last_flush_frame > disk_io_chunk_frames) || 
              force_flush)) {
-               if ((!_write_source) || _write_source->midi_write (*_capture_buf, capture_start_frame, to_write) != to_write) {
+               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;
                } else {
@@ -935,7 +947,7 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
 
                assert(_write_source);
 
-               nframes_t total_capture = 0;
+               framecnt_t total_capture = 0;
                for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
                        total_capture += (*ci)->frames;
                }
@@ -957,14 +969,18 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
 
                         _write_source->mark_streaming_write_completed ();
                         
+                        /* 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
-                           must be considered immutable
+                           must be considered immutable. luckily, we can rely on
+                           MidiSource::mark_streaming_write_completed() to have 
+                           already done the necessary work for that.
                         */
 
-                       _write_source->mark_nonremovable (); 
-                        
                         string whole_file_region_name;
                         whole_file_region_name = region_name_from_path (_write_source->name(), true);
                         
@@ -998,11 +1014,16 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
 
                         _last_capture_sources.insert (_last_capture_sources.end(), srcs.begin(), srcs.end());
 
-                        _playlist->clear_history ();
+                        _playlist->clear_changes ();
                         _playlist->freeze ();
 
-                        uint32_t buffer_position = 0;
-                        for (buffer_position = 0, ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
+                       /* Session frame time of the initial capture in this pass, which is where the source starts */
+                       framepos_t initial_capture = 0;
+                       if (!capture_info.empty()) {
+                               initial_capture = capture_info.front()->start;
+                       }
+                       
+                        for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
 
                                 string region_name;
 
@@ -1012,8 +1033,9 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
 
                                 try {
                                         PropertyList plist;
-                               
-                                        plist.add (Properties::start, buffer_position);
+
+                                       /* 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::name, region_name);
                                
@@ -1031,8 +1053,6 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
                                 i_am_the_modifier++;
                                 _playlist->add_region (region, (*ci)->start);
                                 i_am_the_modifier--;
-
-                                buffer_position += (*ci)->frames;
                         }
 
                         _playlist->thaw ();
@@ -1057,7 +1077,7 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
 }
 
 void
-MidiDiskstream::transport_looped (nframes_t transport_frame)
+MidiDiskstream::transport_looped (framepos_t transport_frame)
 {
        if (was_recording) {
 
@@ -1080,7 +1100,7 @@ MidiDiskstream::transport_looped (nframes_t transport_frame)
                // no latency adjustment or capture offset needs to be made, as that already happened the first time
                capture_start_frame = transport_frame;
                first_recordable_frame = transport_frame; // mild lie
-               last_recordable_frame = max_frames;
+               last_recordable_frame = max_framepos;
                was_recording = true;
        }
 }
@@ -1142,7 +1162,7 @@ MidiDiskstream::set_record_enabled (bool yn)
 void
 MidiDiskstream::engage_record_enable ()
 {
-    bool rolling = _session.transport_speed() != 0.0f;
+       bool const rolling = _session.transport_speed() != 0.0f;
 
        g_atomic_int_set (&_record_enabled, 1);
 
@@ -1150,8 +1170,6 @@ MidiDiskstream::engage_record_enable ()
                _source_port->request_monitor_input (!(_session.config.get_auto_input() && rolling));
        }
 
-       _write_source->mark_streaming_midi_write_started (_note_mode, _session.transport_frame());
-
        RecordEnableChanged (); /* EMIT SIGNAL */
 }
 
@@ -1321,7 +1339,14 @@ MidiDiskstream::use_new_write_source (uint32_t n)
         _write_source.reset();
 
        try {
-               _write_source = boost::dynamic_pointer_cast<SMFSource>(_session.create_midi_source_for_session (0, name ()));
+                /* 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));
+
                if (!_write_source) {
                        throw failed_constructor();
                }
@@ -1342,8 +1367,26 @@ list<boost::shared_ptr<Source> >
 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 ();
+
+        /* make it visible/present */
+        _write_source->unstubify ();
+        /* never let it go away */
+        _write_source->mark_nonremovable ();
+
         ret.push_back (_write_source);
+
+        /* get a new one */
+
         use_new_write_source (0);
+
         return ret;
 }
 
@@ -1371,7 +1414,7 @@ MidiDiskstream::rename_write_sources ()
 }
 
 void
-MidiDiskstream::set_block_size (nframes_t /*nframes*/)
+MidiDiskstream::set_block_size (pframes_t /*nframes*/)
 {
 }
 
@@ -1434,7 +1477,7 @@ MidiDiskstream::use_pending_capture_data (XMLNode& /*node*/)
  * so that an event at \a start has time = 0
  */
 void
-MidiDiskstream::get_playback (MidiBuffer& dst, nframes_t start, nframes_t end)
+MidiDiskstream::get_playback (MidiBuffer& dst, framepos_t start, framepos_t end)
 {
        dst.clear();
        assert(dst.size() == 0);