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 <cassert>
#include <cstdio>
#include <unistd.h>
#include <cmath>
#include <sys/stat.h>
#include <sys/mman.h>
+#include <sigc++/bind.h>
+
#include <pbd/error.h>
#include <pbd/basename.h>
#include <glibmm/thread.h>
#include <pbd/xml++.h>
+#include <pbd/memento_command.h>
#include <ardour/ardour.h>
#include <ardour/audioengine.h>
#include <ardour/utils.h>
#include <ardour/configuration.h>
#include <ardour/audiofilesource.h>
-#include <ardour/destructive_filesource.h>
#include <ardour/send.h>
#include <ardour/playlist.h>
#include <ardour/cycle_timer.h>
#include <ardour/region.h>
+#include <ardour/panner.h>
#include "i18n.h"
#include <locale.h>
using namespace ARDOUR;
using namespace PBD;
-jack_nframes_t Diskstream::disk_io_chunk_frames = 0;
+/* XXX This goes uninitialized when there is no ~/.ardour3 directory.
+ * I can't figure out why, so this will do for now (just stole the
+ * default from configuration_vars.h). 0 is not a good value for
+ * allocating buffer sizes..
+ */
+ARDOUR::nframes_t Diskstream::disk_io_chunk_frames = 1024 * 256;
-sigc::signal<void,Diskstream*> Diskstream::DiskstreamCreated;
-sigc::signal<void,list<Source*>*> Diskstream::DeleteSources;
sigc::signal<void> Diskstream::DiskOverrun;
sigc::signal<void> Diskstream::DiskUnderrun;
Diskstream::Diskstream (Session &sess, const string &name, Flag flag)
- : _name (name)
- , _session (sess)
- , _playlist(NULL)
+ : SessionObject(sess, name)
{
init (flag);
}
Diskstream::Diskstream (Session& sess, const XMLNode& node)
- : _session (sess)
- , _playlist(NULL)
+ : SessionObject(sess, "unnamed diskstream")
{
init (Recordable);
}
void
Diskstream::init (Flag f)
{
- _refcnt = 0;
_flags = f;
_io = 0;
_alignment_style = ExistingMaterial;
speed_buffer_size = 0;
last_phase = 0;
phi = (uint64_t) (0x1000000);
+ target_phi = phi;
file_frame = 0;
playback_sample = 0;
playback_distance = 0;
_read_data_count = 0;
_write_data_count = 0;
+ commit_should_unlock = false;
pending_overwrite = false;
overwrite_frame = 0;
overwrite_queued = false;
input_change_pending = NoChange;
-
- _n_channels = 0;
}
Diskstream::~Diskstream ()
{
- // Taken by derived class destrctors.. should assure locked here somehow?
- //Glib::Mutex::Lock lm (state_lock);
-
if (_playlist)
- _playlist->unref ();
+ _playlist->release ();
}
void
if (_seek_required) {
if (speed() != 1.0f || speed() != -1.0f) {
- seek ((jack_nframes_t) (_session.transport_frame() * (double) speed()), true);
+ seek ((nframes_t) (_session.transport_frame() * (double) speed()), true);
}
else {
seek (_session.transport_frame(), true);
if (new_speed != _actual_speed) {
- jack_nframes_t required_wrap_size = (jack_nframes_t) floor (_session.get_block_size() *
+ nframes_t required_wrap_size = (nframes_t) floor (_session.get_block_size() *
fabs (new_speed)) + 1;
if (required_wrap_size > wrap_buffer_size) {
}
_actual_speed = new_speed;
- phi = (uint64_t) (0x1000000 * fabs(_actual_speed));
+ target_phi = (uint64_t) (0x1000000 * fabs(_actual_speed));
}
if (changed) {
void
Diskstream::recover ()
{
- state_lock.unlock();
+ if (commit_should_unlock) {
+ state_lock.unlock();
+ }
_processed = false;
}
return 0;
}
-jack_nframes_t
+ARDOUR::nframes_t
Diskstream::get_capture_start_frame (uint32_t n)
{
Glib::Mutex::Lock lm (capture_info_lock);
}
}
-jack_nframes_t
+ARDOUR::nframes_t
Diskstream::get_captured_frames (uint32_t n)
{
Glib::Mutex::Lock lm (capture_info_lock);
}
void
-Diskstream::set_roll_delay (jack_nframes_t nframes)
+Diskstream::set_roll_delay (ARDOUR::nframes_t nframes)
{
_roll_delay = nframes;
}
}
int
-Diskstream::use_playlist (Playlist* playlist)
+Diskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
{
{
Glib::Mutex::Lock lm (state_lock);
return 0;
}
- plstate_connection.disconnect();
plmod_connection.disconnect ();
plgone_connection.disconnect ();
+ plregion_connection.disconnect ();
if (_playlist) {
- _playlist->unref();
+ _playlist->release();
}
_playlist = playlist;
- _playlist->ref();
+ _playlist->use();
if (!in_set_state && recordable()) {
reset_write_sources (false);
}
- plstate_connection = _playlist->StateChanged.connect (mem_fun (*this, &Diskstream::playlist_changed));
plmod_connection = _playlist->Modified.connect (mem_fun (*this, &Diskstream::playlist_modified));
- plgone_connection = _playlist->GoingAway.connect (mem_fun (*this, &Diskstream::playlist_deleted));
+ plgone_connection = _playlist->GoingAway.connect (bind (mem_fun (*this, &Diskstream::playlist_deleted), boost::weak_ptr<Playlist>(_playlist)));
+ plregion_connection = _playlist->RangesMoved.connect (mem_fun (*this, &Diskstream::playlist_ranges_moved));
}
- if (!overwrite_queued) {
+ /* don't do this if we've already asked for it *or* if we are setting up
+ the diskstream for the very first time - the input changed handling will
+ take care of the buffer refill.
+ */
+
+ if (!overwrite_queued && !(_session.state_of_the_state() & Session::CannotSave)) {
_session.request_overwrite_buffer (this);
overwrite_queued = true;
}
}
void
-Diskstream::playlist_deleted (Playlist* pl)
+Diskstream::playlist_deleted (boost::weak_ptr<Playlist> wpl)
{
- /* this catches an ordering issue with session destruction. playlists
- are destroyed before diskstreams. we have to invalidate any handles
- we have to the playlist.
- */
+ boost::shared_ptr<Playlist> pl (wpl.lock());
+
+ if (pl == _playlist) {
- _playlist = 0;
+ /* this catches an ordering issue with session destruction. playlists
+ are destroyed before diskstreams. we have to invalidate any handles
+ we have to the playlist.
+ */
+
+ if (_playlist) {
+ _playlist.reset ();
+ }
+ }
}
-int
-Diskstream::set_name (string str)
+bool
+Diskstream::set_name (const string& str)
{
if (str != _name) {
assert(playlist());
playlist()->set_name (str);
- _name = str;
+
+ SessionObject::set_name(str);
if (!in_set_state && recordable()) {
/* rename existing capture files so that they have the correct name */
return rename_write_sources ();
} else {
- return -1;
+ return false;
}
}
- return 0;
+ return true;
}
void
-Diskstream::set_destructive (bool yn)
+Diskstream::remove_region_from_last_capture (boost::weak_ptr<Region> wregion)
{
- if (yn != destructive()) {
- reset_write_sources (true, true);
- if (yn) {
- _flags |= Destructive;
- } else {
- _flags &= ~Destructive;
- }
+ boost::shared_ptr<Region> region (wregion.lock());
+
+ if (!region) {
+ return;
}
+
+ _last_capture_regions.remove (region);
}
+
+void
+Diskstream::playlist_ranges_moved (Evoral::RangeMoveList const & movements)
+{
+ if (Config->get_automation_follows_regions () == false) {
+ return;
+ }
+
+ /* move gain automation */
+ boost::shared_ptr<AutomationList> gain_alist = _io->gain_control()->alist();
+ XMLNode & before = gain_alist->get_state ();
+ gain_alist->move_ranges (movements);
+ _session.add_command (
+ new MementoCommand<AutomationList> (
+ *gain_alist.get(), &before, &gain_alist->get_state ()
+ )
+ );
+
+ /* move panner automation */
+ Panner & p = _io->panner ();
+ for (uint32_t i = 0; i < p.npanners (); ++i) {
+
+ boost::shared_ptr<AutomationList> pan_alist = p.streampanner(i).pan_control()->alist();
+ XMLNode & before = pan_alist->get_state ();
+ pan_alist->move_ranges (movements);
+ _session.add_command (
+ new MementoCommand<AutomationList> (
+ *pan_alist.get(), &before, &pan_alist->get_state ()
+ )
+ );
+ }
+
+ /* move processor automation */
+ /* XXX: ewww */
+ Route * route = dynamic_cast<Route*> (_io);
+ if (route) {
+ route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &Diskstream::move_processor_automation), movements));
+ }
+}
+
+void
+Diskstream::move_processor_automation (boost::weak_ptr<Processor> p, Evoral::RangeMoveList const & movements)
+{
+ boost::shared_ptr<Processor> processor (p.lock ());
+ if (!processor) {
+ return;
+ }
+
+ set<Evoral::Parameter> const a = processor->what_can_be_automated ();
+
+ for (set<Evoral::Parameter>::iterator i = a.begin (); i != a.end (); ++i) {
+ boost::shared_ptr<AutomationList> al = processor->automation_control(*i)->alist();
+ XMLNode & before = al->get_state ();
+ al->move_ranges (movements);
+ _session.add_command (
+ new MementoCommand<AutomationList> (
+ *al.get(), &before, &al->get_state ()
+ )
+ );
+ }
+}
+