diff options
author | David Robillard <d@drobilla.net> | 2006-06-26 20:29:45 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2006-06-26 20:29:45 +0000 |
commit | b7f3a6350783ffda019c22f74dd67e7d619b387b (patch) | |
tree | e9af93f232feb417a07815c2516d18bb562f0b58 /libs/ardour/midi_diskstream.cc | |
parent | 2336aa1a5014964050165e1e6c81b05fd1670126 (diff) |
Actually added the code mentioned in my last commit. Whoops.
git-svn-id: svn://localhost/ardour2/branches/midi@643 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour/midi_diskstream.cc')
-rw-r--r-- | libs/ardour/midi_diskstream.cc | 624 |
1 files changed, 624 insertions, 0 deletions
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc new file mode 100644 index 0000000000..0af4af4f7c --- /dev/null +++ b/libs/ardour/midi_diskstream.cc @@ -0,0 +1,624 @@ +/* + Copyright (C) 2000-2003 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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> +#include <cstdio> +#include <unistd.h> +#include <cmath> +#include <cerrno> +#include <string> +#include <climits> +#include <fcntl.h> +#include <cstdlib> +#include <ctime> +#include <sys/stat.h> +#include <sys/mman.h> + +#include <pbd/error.h> +#include <pbd/basename.h> +#include <glibmm/thread.h> +#include <pbd/xml++.h> + +#include <ardour/ardour.h> +#include <ardour/audioengine.h> +#include <ardour/midi_diskstream.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/midi_playlist.h> +#include <ardour/cycle_timer.h> +#include <ardour/midi_region.h> + +#include "i18n.h" +#include <locale.h> + +using namespace std; +using namespace ARDOUR; +using namespace PBD; + +//sigc::signal<void,MidiDiskstream*> MidiDiskstream::MidiDiskstreamCreated; +sigc::signal<void,list<SMFSource*>*> MidiDiskstream::DeleteSources; +//sigc::signal<void> MidiDiskstream::DiskOverrun; +//sigc::signal<void> MidiDiskstream::DiskUnderrun; + +MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::Flag flag) + : Diskstream(sess, name, flag) + , _playlist(NULL) +{ + /* prevent any write sources from being created */ + + in_set_state = true; + + init (flag); + use_new_playlist (); + + in_set_state = false; + + DiskstreamCreated (this); /* EMIT SIGNAL */ +} + +MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node) + : Diskstream(sess, node) + , _playlist(NULL) +{ + in_set_state = true; + init (Recordable); + + if (set_state (node)) { + in_set_state = false; + throw failed_constructor(); + } + + in_set_state = false; + + if (destructive()) { + use_destructive_playlist (); + } + + DiskstreamCreated (this); /* EMIT SIGNAL */ +} + +void +MidiDiskstream::init (Diskstream::Flag f) +{ + Diskstream::init(f); + + /* there are no channels at this point, so these + two calls just get speed_buffer_size and wrap_buffer + size setup without duplicating their code. + */ + + set_block_size (_session.get_block_size()); + allocate_temporary_buffers (); + + /* FIXME: this is now done before the above. OK? */ + /*pending_overwrite = false; + overwrite_frame = 0; + overwrite_queued = false; + input_change_pending = NoChange;*/ + + _n_channels = 1; +} + +MidiDiskstream::~MidiDiskstream () +{ + Glib::Mutex::Lock lm (state_lock); + + if (_playlist) + _playlist->unref (); +} +/* +void +MidiDiskstream::handle_input_change (IOChange change, void *src) +{ + Glib::Mutex::Lock lm (state_lock); + + if (!(input_change_pending & change)) { + input_change_pending = IOChange (input_change_pending|change); + _session.request_input_change_handling (); + } +} +*/ +void +MidiDiskstream::non_realtime_input_change () +{ +} + +void +MidiDiskstream::get_input_sources () +{ +} + +int +MidiDiskstream::find_and_use_playlist (const string& name) +{ + Playlist* pl; + MidiPlaylist* playlist; + + if ((pl = _session.get_playlist (name)) == 0) { + error << string_compose(_("MidiDiskstream: Session doesn't know about a Playlist called \"%1\""), name) << endmsg; + return -1; + } + + if ((playlist = dynamic_cast<MidiPlaylist*> (pl)) == 0) { + error << string_compose(_("MidiDiskstream: Playlist \"%1\" isn't an midi playlist"), name) << endmsg; + return -1; + } + + return use_playlist (playlist); +} + +int +MidiDiskstream::use_playlist (Playlist* playlist) +{ + assert(dynamic_cast<MidiPlaylist*>(playlist)); + + { + Glib::Mutex::Lock lm (state_lock); + + if (playlist == _playlist) { + return 0; + } + + plstate_connection.disconnect(); + plmod_connection.disconnect (); + plgone_connection.disconnect (); + + if (_playlist) { + _playlist->unref(); + } + + _playlist = dynamic_cast<MidiPlaylist*>(playlist); + _playlist->ref(); + + if (!in_set_state && recordable()) { + reset_write_sources (false); + } + + plstate_connection = _playlist->StateChanged.connect (mem_fun (*this, &MidiDiskstream::playlist_changed)); + plmod_connection = _playlist->Modified.connect (mem_fun (*this, &MidiDiskstream::playlist_modified)); + plgone_connection = _playlist->GoingAway.connect (mem_fun (*this, &MidiDiskstream::playlist_deleted)); + } + + if (!overwrite_queued) { + _session.request_overwrite_buffer (this); + overwrite_queued = true; + } + + PlaylistChanged (); /* EMIT SIGNAL */ + _session.set_dirty (); + + return 0; +} + +int +MidiDiskstream::use_new_playlist () +{ + string newname; + MidiPlaylist* playlist; + + if (!in_set_state && destructive()) { + return 0; + } + + if (_playlist) { + newname = Playlist::bump_name (_playlist->name(), _session); + } else { + newname = Playlist::bump_name (_name, _session); + } + + if ((playlist = new MidiPlaylist (_session, newname, hidden())) != 0) { + playlist->set_orig_diskstream_id (id()); + return use_playlist (playlist); + } else { + return -1; + } +} + +int +MidiDiskstream::use_copy_playlist () +{ + if (destructive()) { + return 0; + } + + if (_playlist == 0) { + error << string_compose(_("MidiDiskstream %1: there is no existing playlist to make a copy of!"), _name) << endmsg; + return -1; + } + + string newname; + MidiPlaylist* playlist; + + newname = Playlist::bump_name (_playlist->name(), _session); + + if ((playlist = new MidiPlaylist (*_playlist, newname)) != 0) { + playlist->set_orig_diskstream_id (id()); + return use_playlist (playlist); + } else { + return -1; + } +} + + +void +MidiDiskstream::playlist_deleted (Playlist* pl) +{ + /* this catches an ordering issue with session destruction. playlists + are destroyed before diskstreams. we have to invalidate any handles + we have to the playlist. + */ + + _playlist = 0; +} + + +void +MidiDiskstream::setup_destructive_playlist () +{ + /* a single full-sized region */ + + //MidiRegion* region = new MidiRegion (srcs, 0, max_frames, _name); + //_playlist->add_region (*region, 0); +} + +void +MidiDiskstream::use_destructive_playlist () +{ + /* use the sources associated with the single full-extent region */ + + Playlist::RegionList* rl = _playlist->regions_at (0); + + if (rl->empty()) { + reset_write_sources (false, true); + return; + } + + MidiRegion* region = dynamic_cast<MidiRegion*> (rl->front()); + + if (region == 0) { + throw failed_constructor(); + } + + delete rl; + + /* the source list will never be reset for a destructive track */ +} + +void +MidiDiskstream::set_io (IO& io) +{ + _io = &io; + set_align_style_from_io (); +} + +void +MidiDiskstream::non_realtime_set_speed () +{ + if (_buffer_reallocation_required) + { + Glib::Mutex::Lock lm (state_lock); + allocate_temporary_buffers (); + + _buffer_reallocation_required = false; + } + + if (_seek_required) { + if (speed() != 1.0f || speed() != -1.0f) { + seek ((jack_nframes_t) (_session.transport_frame() * (double) speed()), true); + } + else { + seek (_session.transport_frame(), true); + } + + _seek_required = false; + } +} + +void +MidiDiskstream::check_record_status (jack_nframes_t transport_frame, jack_nframes_t nframes, bool can_record) +{ +} + +int +MidiDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes, jack_nframes_t offset, bool can_record, bool rec_monitors_input) +{ + return 0; +} + +bool +MidiDiskstream::commit (jack_nframes_t nframes) +{ + return 0; +} + +void +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 +MidiDiskstream::overwrite_existing_buffers () +{ + return 0; +} + +int +MidiDiskstream::seek (jack_nframes_t frame, bool complete_refill) +{ + return 0; +} + +int +MidiDiskstream::can_internal_playback_seek (jack_nframes_t distance) +{ + return 0; +} + +int +MidiDiskstream::internal_playback_seek (jack_nframes_t distance) +{ + return 0; +} + +int +MidiDiskstream::read (RawMidi* buf, RawMidi* mixdown_buffer, char * workbuf, jack_nframes_t& start, jack_nframes_t cnt, bool reversed) +{ + return 0; +} + +int +MidiDiskstream::do_refill (RawMidi* mixdown_buffer, float* gain_buffer, char * workbuf) +{ + return 0; +} + +int +MidiDiskstream::do_flush (char * workbuf, bool force_flush) +{ + return 0; +} + +void +MidiDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_capture) +{ +} + +void +MidiDiskstream::finish_capture (bool rec_monitors_input) +{ +} + +void +MidiDiskstream::set_record_enabled (bool yn, void* src) +{ +} + +XMLNode& +MidiDiskstream::get_state () +{ + XMLNode* node = new XMLNode ("MidiDiskstream"); + char buf[64]; + LocaleGuard lg (X_("POSIX")); + + snprintf (buf, sizeof(buf), "0x%x", _flags); + node->add_property ("flags", buf); + + node->add_property ("playlist", _playlist->name()); + + snprintf (buf, sizeof(buf), "%f", _visible_speed); + node->add_property ("speed", buf); + + node->add_property("name", _name); + snprintf (buf, sizeof(buf), "%" PRIu64, id()); + node->add_property("id", buf); + + if (!_capturing_sources.empty() && _session.get_record_enabled()) { + + XMLNode* cs_child = new XMLNode (X_("CapturingSources")); + XMLNode* cs_grandchild; + + for (vector<SMFSource*>::iterator i = _capturing_sources.begin(); i != _capturing_sources.end(); ++i) { + cs_grandchild = new XMLNode (X_("file")); + cs_grandchild->add_property (X_("path"), (*i)->path()); + cs_child->add_child_nocopy (*cs_grandchild); + } + + /* store the location where capture will start */ + + Location* pi; + + if (_session.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()); + } + + cs_child->add_property (X_("at"), buf); + node->add_child_nocopy (*cs_child); + } + + if (_extra_xml) { + node->add_child_copy (*_extra_xml); + } + + return* node; +} + +int +MidiDiskstream::set_state (const XMLNode& node) +{ + const XMLProperty* prop; + XMLNodeList nlist = node.children(); + XMLNodeIterator niter; + uint32_t nchans = 1; + XMLNode* capture_pending_node = 0; + LocaleGuard lg (X_("POSIX")); + + 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); + } + + if ((*niter)->name() == X_("CapturingSources")) { + capture_pending_node = *niter; + } + } + + /* prevent write sources from being created */ + + in_set_state = true; + + if ((prop = node.property ("name")) != 0) { + _name = prop->value(); + } + + if (deprecated_io_node) { + if ((prop = deprecated_io_node->property ("id")) != 0) { + sscanf (prop->value().c_str(), "%" PRIu64, &_id); + } + } else { + if ((prop = node.property ("id")) != 0) { + sscanf (prop->value().c_str(), "%" PRIu64, &_id); + } + } + + if ((prop = node.property ("flags")) != 0) { + _flags = strtol (prop->value().c_str(), 0, 0); + } + + if ((prop = node.property ("channels")) != 0) { + nchans = atoi (prop->value().c_str()); + } + + if ((prop = node.property ("playlist")) == 0) { + return -1; + } + + { + bool had_playlist = (_playlist != 0); + + if (find_and_use_playlist (prop->value())) { + return -1; + } + + if (!had_playlist) { + _playlist->set_orig_diskstream_id (_id); + } + + if (!destructive() && capture_pending_node) { + /* destructive streams have one and only one source per channel, + and so they never end up in pending capture in any useful + sense. + */ + 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 (); + } + } + + in_set_state = false; + + /* make sure this is clear before we do anything else */ + + _capturing_sources.clear (); + + /* 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; +} + +int +MidiDiskstream::use_new_write_source (uint32_t n) +{ + return 0; +} + +void +MidiDiskstream::reset_write_sources (bool mark_write_complete, bool force) +{ +} + +int +MidiDiskstream::rename_write_sources () +{ + return 0; +} + +void +MidiDiskstream::set_block_size (jack_nframes_t nframes) +{ +} + +void +MidiDiskstream::allocate_temporary_buffers () +{ +} + +void +MidiDiskstream::monitor_input (bool yn) +{ +} + +void +MidiDiskstream::set_align_style_from_io () +{ +} + + +float +MidiDiskstream::playback_buffer_load () const +{ + return 0; +} + +float +MidiDiskstream::capture_buffer_load () const +{ + return 0; +} + + +int +MidiDiskstream::use_pending_capture_data (XMLNode& node) +{ + return 0; +} |