Use PBD::copy_file in Session::create() to copy the template file.
[ardour.git] / libs / ardour / midi_diskstream.cc
index b399089a27aceb59ed3d1c43b6c925d7641afc1e..50fc1cc8a77906afb02338ab9b27ee3b37fbdb4a 100644 (file)
@@ -14,8 +14,6 @@
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id: diskstream.cc 567 2006-06-07 14:54:12Z trutkin $
 */
 
 #include <fstream>
@@ -36,6 +34,7 @@
 #include <glibmm/thread.h>
 #include <pbd/xml++.h>
 #include <pbd/memento_command.h>
+#include <pbd/enumwriter.h>
 
 #include <ardour/ardour.h>
 #include <ardour/audioengine.h>
 #include <ardour/utils.h>
 #include <ardour/configuration.h>
 #include <ardour/smf_source.h>
-#include <ardour/destructive_filesource.h>
 #include <ardour/send.h>
+#include <ardour/region_factory.h>
 #include <ardour/midi_playlist.h>
+#include <ardour/playlist_factory.h>
 #include <ardour/cycle_timer.h>
 #include <ardour/midi_region.h>
 #include <ardour/midi_port.h>
@@ -66,8 +66,8 @@ MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::F
        //, _playback_wrap_buffer(0)
        //, _capture_wrap_buffer(0)
        , _source_port(0)
-       , _write_source(0)
        , _capture_transition_buf(0)
+       , _last_flush_frame(0)
 {
        /* prevent any write sources from being created */
 
@@ -79,7 +79,6 @@ MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::F
        in_set_state = false;
 
        assert(!destructive());
-       DiskstreamCreated (this); /* EMIT SIGNAL */
 }
        
 MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node)
@@ -91,8 +90,8 @@ MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node)
        //, _playback_wrap_buffer(0)
        //, _capture_wrap_buffer(0)
        , _source_port(0)
-       , _write_source(0)
        , _capture_transition_buf(0)
+       , _last_flush_frame(0)
 {
        in_set_state = true;
        init (Recordable);
@@ -107,8 +106,6 @@ MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node)
        if (destructive()) {
                use_destructive_playlist ();
        }
-
-       DiskstreamCreated (this); /* EMIT SIGNAL */
 }
 
 void
@@ -175,17 +172,19 @@ MidiDiskstream::non_realtime_input_change ()
        /* now refill channel buffers */
 
        if (speed() != 1.0f || speed() != -1.0f) {
-               seek ((jack_nframes_t) (_session.transport_frame() * (double) speed()));
+               seek ((nframes_t) (_session.transport_frame() * (double) speed()));
        }
        else {
                seek (_session.transport_frame());
        }
+
+       _last_flush_frame = _session.transport_frame();
 }
 
 void
 MidiDiskstream::get_input_sources ()
 {
-       uint32_t ni = _io->n_inputs().get(DataType::MIDI);
+       uint32_t ni = _io->n_inputs().n_midi();
 
        if (ni == 0) {
                return;
@@ -220,16 +219,14 @@ MidiDiskstream::get_input_sources ()
 int
 MidiDiskstream::find_and_use_playlist (const string& name)
 {
-       Playlist* pl;
-       MidiPlaylist* playlist;
+       boost::shared_ptr<MidiPlaylist> playlist;
                
-       if ((pl = _session.playlist_by_name (name)) == 0) {
-               playlist = new MidiPlaylist(_session, name);
-               pl = playlist;
+       if ((playlist = boost::dynamic_pointer_cast<MidiPlaylist> (_session.playlist_by_name (name))) == 0) {
+               playlist = boost::dynamic_pointer_cast<MidiPlaylist> (PlaylistFactory::create (DataType::MIDI, _session, name));
        }
 
-       if ((playlist = dynamic_cast<MidiPlaylist*> (pl)) == 0) {
-               error << string_compose(_("MidiDiskstream: Playlist \"%1\" isn't a midi playlist"), name) << endmsg;
+       if (!playlist) {
+               error << string_compose(_("MidiDiskstream: Playlist \"%1\" isn't an midi playlist"), name) << endmsg;
                return -1;
        }
 
@@ -237,18 +234,20 @@ MidiDiskstream::find_and_use_playlist (const string& name)
 }
 
 int
-MidiDiskstream::use_playlist (Playlist* playlist)
-{
-       assert(dynamic_cast<MidiPlaylist*>(playlist));
+MidiDiskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
+{      
+       assert(boost::dynamic_pointer_cast<MidiPlaylist>(playlist));
+
+       Diskstream::use_playlist(playlist);
 
-       return Diskstream::use_playlist(playlist);
+       return 0;
 }
 
 int
 MidiDiskstream::use_new_playlist ()
-{
+{      
        string newname;
-       MidiPlaylist* playlist;
+       boost::shared_ptr<MidiPlaylist> playlist;
 
        if (!in_set_state && destructive()) {
                return 0;
@@ -260,9 +259,12 @@ MidiDiskstream::use_new_playlist ()
                newname = Playlist::bump_name (_name, _session);
        }
 
-       if ((playlist = new MidiPlaylist (_session, newname, hidden())) != 0) {
+       if ((playlist = boost::dynamic_pointer_cast<MidiPlaylist> (PlaylistFactory::create (
+                       DataType::MIDI, _session, newname, hidden()))) != 0) {
+               
                playlist->set_orig_diskstream_id (id());
                return use_playlist (playlist);
+
        } else { 
                return -1;
        }
@@ -271,6 +273,8 @@ MidiDiskstream::use_new_playlist ()
 int
 MidiDiskstream::use_copy_playlist ()
 {
+       assert(midi_playlist());
+
        if (destructive()) {
                return 0;
        }
@@ -281,11 +285,11 @@ MidiDiskstream::use_copy_playlist ()
        }
 
        string newname;
-       MidiPlaylist* playlist;
+       boost::shared_ptr<MidiPlaylist> playlist;
 
        newname = Playlist::bump_name (_playlist->name(), _session);
        
-       if ((playlist  = new MidiPlaylist (*midi_playlist(), newname)) != 0) {
+       if ((playlist  = boost::dynamic_pointer_cast<MidiPlaylist>(PlaylistFactory::create (midi_playlist(), newname))) != 0) {
                playlist->set_orig_diskstream_id (id());
                return use_playlist (playlist);
        } else { 
@@ -295,15 +299,16 @@ MidiDiskstream::use_copy_playlist ()
 
 /** Overloaded from parent to die horribly
  */
-void
+int
 MidiDiskstream::set_destructive (bool yn)
 {
        assert( ! destructive());
        assert( ! yn);
+       return -1;
 }
 
 void
-MidiDiskstream::check_record_status (jack_nframes_t transport_frame, jack_nframes_t nframes, bool can_record)
+MidiDiskstream::check_record_status (nframes_t transport_frame, nframes_t nframes, bool can_record)
 {
        // FIXME: waaay too much code to duplicate (AudioDiskstream)
        
@@ -356,7 +361,7 @@ MidiDiskstream::check_record_status (jack_nframes_t transport_frame, jack_nframe
                        if (_alignment_style == ExistingMaterial) {
 
 
-                               if (!_session.get_punch_in()) {
+                               if (!Config->get_punch_in()) {
 
                                        /* manual punch in happens at the correct transport frame
                                           because the user hit a button. but to get alignment correct 
@@ -385,7 +390,7 @@ MidiDiskstream::check_record_status (jack_nframes_t transport_frame, jack_nframe
 
                        } else {
 
-                               if (_session.get_punch_in()) {
+                               if (Config->get_punch_in()) {
                                        first_recordable_frame += _roll_delay;
                                } else {
                                        capture_start_frame -= _roll_delay;
@@ -426,12 +431,12 @@ MidiDiskstream::check_record_status (jack_nframes_t transport_frame, jack_nframe
 }
 
 int
-MidiDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes, jack_nframes_t offset, bool can_record, bool rec_monitors_input)
+MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_t offset, bool can_record, bool rec_monitors_input)
 {
        // FIXME: waay too much code to duplicate (AudioDiskstream::process)
        int            ret = -1;
-       jack_nframes_t rec_offset = 0;
-       jack_nframes_t rec_nframes = 0;
+       nframes_t rec_offset = 0;
+       nframes_t rec_nframes = 0;
        bool           nominally_recording;
        bool           re = record_enabled ();
        bool           collect_playback = false;
@@ -472,7 +477,7 @@ MidiDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes,
 
        adjust_capture_position = 0;
 
-       if (nominally_recording || (_session.get_record_enabled() && _session.get_punch_in())) {
+       if (nominally_recording || (_session.get_record_enabled() && Config->get_punch_in())) {
                OverlapType ot;
 
                ot = coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
@@ -577,12 +582,12 @@ MidiDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes,
 
                /* we're doing playback */
 
-               jack_nframes_t necessary_samples;
+               nframes_t necessary_samples;
 
                /* no varispeed playback if we're recording, because the output .... TBD */
 
                if (rec_nframes == 0 && _actual_speed != 1.0f) {
-                       necessary_samples = (jack_nframes_t) floor ((nframes * fabs (_actual_speed))) + 1;
+                       necessary_samples = (nframes_t) floor ((nframes * fabs (_actual_speed))) + 1;
                } else {
                        necessary_samples = nframes;
                }
@@ -613,7 +618,7 @@ MidiDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes,
 }
 
 bool
-MidiDiskstream::commit (jack_nframes_t nframes)
+MidiDiskstream::commit (nframes_t nframes)
 {
        bool need_butler = false;
 
@@ -669,7 +674,7 @@ MidiDiskstream::overwrite_existing_buffers ()
 }
 
 int
-MidiDiskstream::seek (jack_nframes_t frame, bool complete_refill)
+MidiDiskstream::seek (nframes_t frame, bool complete_refill)
 {
        Glib::Mutex::Lock lm (state_lock);
        int ret = -1;
@@ -679,6 +684,7 @@ MidiDiskstream::seek (jack_nframes_t frame, bool complete_refill)
 
        playback_sample = frame;
        file_frame = frame;
+       _last_flush_frame = frame;
 
        if (complete_refill) {
                while ((ret = do_refill_with_alloc ()) > 0) ;
@@ -690,7 +696,7 @@ MidiDiskstream::seek (jack_nframes_t frame, bool complete_refill)
 }
 
 int
-MidiDiskstream::can_internal_playback_seek (jack_nframes_t distance)
+MidiDiskstream::can_internal_playback_seek (nframes_t distance)
 {
        if (_playback_buf->read_space() < distance) {
                return false;
@@ -700,7 +706,7 @@ MidiDiskstream::can_internal_playback_seek (jack_nframes_t distance)
 }
 
 int
-MidiDiskstream::internal_playback_seek (jack_nframes_t distance)
+MidiDiskstream::internal_playback_seek (nframes_t distance)
 {
        first_recordable_frame += distance;
        playback_sample += distance;
@@ -710,13 +716,13 @@ MidiDiskstream::internal_playback_seek (jack_nframes_t distance)
 
 /** @a start is set to the new frame position (TIME) read up to */
 int
-MidiDiskstream::read (jack_nframes_t& start, jack_nframes_t dur, bool reversed)
+MidiDiskstream::read (nframes_t& start, nframes_t dur, bool reversed)
 {      
-       jack_nframes_t this_read = 0;
+       nframes_t this_read = 0;
        bool reloop = false;
-       jack_nframes_t loop_end = 0;
-       jack_nframes_t loop_start = 0;
-       jack_nframes_t loop_length = 0;
+       nframes_t loop_end = 0;
+       nframes_t loop_start = 0;
+       nframes_t loop_length = 0;
        Location *loc = 0;
 
        if (!reversed) {
@@ -878,8 +884,8 @@ MidiDiskstream::do_refill ()
 
        // So (read it, then) write it:
        
-       jack_nframes_t file_frame_tmp = file_frame;
-       jack_nframes_t to_read = min(disk_io_chunk_frames, (max_frames - file_frame));
+       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)) {
@@ -911,15 +917,19 @@ MidiDiskstream::do_flush (Session::RunContext context, bool force_flush)
        int32_t ret = 0;
        // FIXME: I'd be lying if I said I knew what this thing was
        //RingBufferNPT<CaptureTransition>::rw_vector transvec;
-       jack_nframes_t total;
+       nframes_t total;
 
        _write_data_count = 0;
 
-       total = _capture_buf->read_space();
+       if (_last_flush_frame > _session.transport_frame()) {
+               _last_flush_frame = _session.transport_frame();
+       }
+
+       total = _session.transport_frame() - _last_flush_frame;
 
 
        // FIXME: put this condition back in! (removed for testing)
-       if (total == 0) { // || (total < disk_io_chunk_frames && !force_flush && was_recording)) {
+       if (total == 0 || (total < disk_io_chunk_frames && !force_flush && was_recording)) {
                //cerr << "MDS - no flush 1\n";
                goto out;
        }
@@ -939,16 +949,17 @@ MidiDiskstream::do_flush (Session::RunContext context, bool force_flush)
                ret = 1;
        } 
 
-       //to_write = min (disk_io_chunk_frames, (jack_nframes_t) vector.len[0]);
+       //to_write = min (disk_io_chunk_frames, (nframes_t) vector.len[0]);
        to_write = disk_io_chunk_frames;
 
        assert(!destructive());
 
        if ((!_write_source) || _write_source->write (*_capture_buf, to_write) != to_write) {
                //cerr << "MDS - no flush 2\n";
-               error << string_compose(_("AudioDiskstream %1: cannot write to disk"), _id) << endmsg;
+               error << string_compose(_("MidiDiskstream %1: cannot write to disk"), _id) << endmsg;
                return -1;
        } else {
+               _last_flush_frame = _session.transport_frame();
                //cerr << "MDS - flushed\n";
        }
 
@@ -965,8 +976,8 @@ MidiDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_cap
        uint32_t buffer_position;
        bool more_work = true;
        int err = 0;
-       MidiRegion* region = 0;
-       jack_nframes_t total_capture;
+       boost::shared_ptr<MidiRegion> region;
+       nframes_t total_capture;
        MidiRegion::SourceList srcs;
        MidiRegion::SourceList::iterator src;
        vector<CaptureInfo*>::iterator ci;
@@ -1000,25 +1011,15 @@ MidiDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_cap
 
        if (abort_capture) {
 
-               list<Source*>* deletion_list = new list<Source*>;
-
                if (_write_source) {
-                       _write_source->mark_for_remove ();
-                       _write_source->release ();
 
-                       deletion_list->push_back (_write_source);
-
-                       _write_source = 0;
+                       _write_source->mark_for_remove ();
+                       _write_source->drop_references ();
+                       _write_source.reset();
                }
 
                /* new source set up in "out" below */
 
-               if (!deletion_list->empty()) {
-                       DeleteSources (deletion_list);
-               } else {
-                       delete deletion_list;
-               }
-
        } else {
 
                assert(_write_source);
@@ -1029,7 +1030,7 @@ MidiDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_cap
 
                /* figure out the name for this take */
 
-               SMFSource* s = _write_source;
+               boost::shared_ptr<SMFSource> s = _write_source;
 
                if (s) {
 
@@ -1042,6 +1043,8 @@ MidiDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_cap
 
                }
 
+               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
@@ -1049,10 +1052,12 @@ MidiDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_cap
                   */
                try {
                        assert(_write_source);
-                       region = new MidiRegion (srcs, _write_source->last_capture_start_frame(), total_capture, 
-                                       region_name_from_path (_write_source->name()), 
-                                       0, Region::Flag (Region::DefaultFlags|Region::Automatic|Region::WholeFile));
+                       
+                       boost::shared_ptr<Region> rx (RegionFactory::create (srcs, _write_source->last_capture_start_frame(), total_capture, 
+                                                                            whole_file_region_name, 
+                                                                            0, Region::Flag (Region::DefaultFlags|Region::Automatic|Region::WholeFile)));
 
+                       region = boost::dynamic_pointer_cast<MidiRegion> (rx);
                        region->special_set_position (capture_info.front()->start);
                }
 
@@ -1077,11 +1082,12 @@ MidiDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_cap
                        // cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add a region\n";
 
                        try {
-                               region = new MidiRegion (srcs, buffer_position, (*ci)->frames, region_name);
+                               boost::shared_ptr<Region> rx (RegionFactory::create (srcs, buffer_position, (*ci)->frames, region_name));
+                               region = boost::dynamic_pointer_cast<MidiRegion> (rx);
                        }
 
                        catch (failed_constructor& err) {
-                               error << _("MidiDiskstream: could not create region for captured audio!") << endmsg;
+                               error << _("MidiDiskstream: could not create region for captured midi!") << endmsg;
                                continue; /* XXX is this OK? */
                        }
 
@@ -1090,7 +1096,7 @@ MidiDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_cap
                        // cerr << "add new region, buffer position = " << buffer_position << " @ " << (*ci)->start << endl;
 
                        i_am_the_modifier++;
-                       _playlist->add_region (*region, (*ci)->start);
+                       _playlist->add_region (region, (*ci)->start);
                        i_am_the_modifier--;
 
                        buffer_position += (*ci)->frames;
@@ -1098,7 +1104,7 @@ MidiDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_cap
 
                _playlist->thaw ();
                XMLNode &after = _playlist->get_state();
-               _session.add_command (new MementoCommand<Playlist>(*_playlist, before, after));
+               _session.add_command (new MementoCommand<Playlist>(*_playlist, &before, &after));
 
                mark_write_completed = true;
 
@@ -1184,8 +1190,8 @@ MidiDiskstream::engage_record_enable ()
 
        g_atomic_int_set (&_record_enabled, 1);
        
-       if (Config->get_use_hardware_monitoring() && _source_port) {
-               _source_port->request_monitor_input (!(_session.get_auto_input() && rolling));
+       if (_source_port && Config->get_monitoring_model() == HardwareMonitoring) {
+               _source_port->request_monitor_input (!(Config->get_auto_input() && rolling));
        }
 
        RecordEnableChanged (); /* EMIT SIGNAL */
@@ -1195,7 +1201,7 @@ void
 MidiDiskstream::disengage_record_enable ()
 {
        g_atomic_int_set (&_record_enabled, 0);
-       if (Config->get_use_hardware_monitoring()) {
+       if (_source_port && Config->get_monitoring_model() == HardwareMonitoring) {
                if (_source_port) {
                        _source_port->request_monitor_input (false);
                }
@@ -1220,7 +1226,7 @@ MidiDiskstream::get_state ()
        node->add_property ("speed", buf);
 
        node->add_property("name", _name);
-       id().print(buf);
+       id().print(buf, sizeof(buf));
        node->add_property("id", buf);
 
        if (_write_source && _session.get_record_enabled()) {
@@ -1236,7 +1242,7 @@ MidiDiskstream::get_state ()
 
                Location* pi;
 
-               if (_session.get_punch_in() && ((pi = _session.locations()->auto_punch_location()) != 0)) {
+               if (Config->get_punch_in() && ((pi = _session.locations()->auto_punch_location()) != 0)) {
                        snprintf (buf, sizeof (buf), "%" PRIu32, pi->start());
                } else {
                        snprintf (buf, sizeof (buf), "%" PRIu32, _session.transport_frame());
@@ -1289,7 +1295,7 @@ MidiDiskstream::set_state (const XMLNode& node)
        }
 
        if ((prop = node.property ("flags")) != 0) {
-               _flags = strtol (prop->value().c_str(), 0, 0);
+               _flags = Flag (string_2_enum (prop->value(), _flags));
        }
 
        if ((prop = node.property ("channels")) != 0) {
@@ -1354,16 +1360,14 @@ MidiDiskstream::use_new_write_source (uint32_t n)
 
                if (SMFSource::is_empty (_write_source->path())) {
                        _write_source->mark_for_remove ();
-                       _write_source->release();
-                       delete _write_source;
+                       _write_source.reset();
                } else {
-                       _write_source->release();
-                       _write_source = 0;
+                       _write_source.reset();
                }
        }
 
        try {
-               _write_source = dynamic_cast<SMFSource*>(_session.create_midi_source_for_session (*this));
+               _write_source = boost::dynamic_pointer_cast<SMFSource>(_session.create_midi_source_for_session (*this));
                if (!_write_source) {
                        throw failed_constructor();
                }
@@ -1371,11 +1375,10 @@ MidiDiskstream::use_new_write_source (uint32_t n)
 
        catch (failed_constructor &err) {
                error << string_compose (_("%1:%2 new capture file not initialized correctly"), _name, n) << endmsg;
-               _write_source = 0;
+               _write_source.reset();
                return -1;
        }
 
-       _write_source->use ();
        _write_source->set_allow_remove_if_empty (true);
 
        return 0;
@@ -1408,7 +1411,7 @@ MidiDiskstream::rename_write_sources ()
 }
 
 void
-MidiDiskstream::set_block_size (jack_nframes_t nframes)
+MidiDiskstream::set_block_size (nframes_t nframes)
 {
 }
 
@@ -1474,11 +1477,16 @@ MidiDiskstream::use_pending_capture_data (XMLNode& node)
  * so that an event at start has time = 0
  */
 void
-MidiDiskstream::get_playback(MidiBuffer& dst, jack_nframes_t start, jack_nframes_t end)
+MidiDiskstream::get_playback(MidiBuffer& dst, nframes_t start, nframes_t end)
 {
-       assert(end > start);
        dst.clear();
        assert(dst.size() == 0);
+       
+       // I think this happens with reverse varispeed?  maybe?
+       if (end <= start) {
+               return;
+       }
+
 /*
        cerr << "MIDI Diskstream pretending to read" << endl;
 
@@ -1511,9 +1519,9 @@ MidiDiskstream::get_playback(MidiBuffer& dst, jack_nframes_t start, jack_nframes
        for (size_t i=0; i < dst.size(); ++i) {
                assert(dst[i].time >= start);
                assert(dst[i].time <= end);
-               cerr << "Translating event stamp " << dst[i].time << " to ";
+               //cerr << "Translating event stamp " << dst[i].time << " to ";
                dst[i].time -= start;
-               cerr << dst[i].time << endl;
+               //cerr << dst[i].time << endl;
 
        }
 }