/*
- Copyright (C) 2000-2006 Paul Davis
+ Copyright (C) 2000-2006 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
#include <sigc++/bind.h>
-#include <pbd/error.h>
-#include <pbd/basename.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/diskstream.h>
-#include <ardour/utils.h>
-#include <ardour/configuration.h>
-#include <ardour/audiofilesource.h>
-#include <ardour/send.h>
-#include <ardour/playlist.h>
-#include <ardour/cycle_timer.h>
-#include <ardour/region.h>
-#include <ardour/panner.h>
+#include "pbd/xml++.h"
+#include "pbd/memento_command.h"
+
+#include "ardour/ardour.h"
+#include "ardour/audioengine.h"
+#include "ardour/diskstream.h"
+#include "ardour/utils.h"
+#include "ardour/configuration.h"
+#include "ardour/audiofilesource.h"
+#include "ardour/send.h"
+#include "ardour/playlist.h"
+#include "ardour/cycle_timer.h"
+#include "ardour/region.h"
+#include "ardour/panner.h"
+#include "ardour/session.h"
+#include "ardour/io.h"
+#include "ardour/route.h"
#include "i18n.h"
#include <locale.h>
{
init (flag);
}
-
-Diskstream::Diskstream (Session& sess, const XMLNode& node)
+
+Diskstream::Diskstream (Session& sess, const XMLNode& /*node*/)
: SessionObject(sess, "unnamed diskstream")
{
init (Recordable);
Diskstream::init (Flag f)
{
_flags = f;
- _io = 0;
+ _route = 0;
_alignment_style = ExistingMaterial;
_persistent_alignment_style = ExistingMaterial;
first_input_change = true;
loop_location = 0;
wrap_buffer_size = 0;
speed_buffer_size = 0;
- last_phase = 0;
- // speed = 1 in 40.24 fixed point math
- phi = (uint64_t) (0x1000000);
- target_phi = phi;
+ _speed = 1.0;
+ _target_speed = _speed;
file_frame = 0;
playback_sample = 0;
playback_distance = 0;
}
void
-Diskstream::set_io (IO& io)
+Diskstream::set_route (Route& r)
{
- _io = &io;
+ _route = &r;
+ _io = _route->input();
+ input_change_pending = ConfigurationChanged;
+ non_realtime_input_change ();
set_align_style_from_io ();
+
+ _route->GoingAway.connect (mem_fun (*this, &Diskstream::route_going_away));
}
void
-Diskstream::handle_input_change (IOChange change, void *src)
+Diskstream::handle_input_change (IOChange change, void * /*src*/)
{
Glib::Mutex::Lock lm (state_lock);
{
bool changed = false;
double new_speed = sp * _session.transport_speed();
-
+
if (_visible_speed != sp) {
_visible_speed = sp;
changed = true;
}
-
+
if (new_speed != _actual_speed) {
-
- nframes_t required_wrap_size = (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) {
_buffer_reallocation_required = true;
}
-
+
_actual_speed = new_speed;
- target_phi = (uint64_t) (0x1000000 * fabs(_actual_speed));
+ _target_speed = fabs(_actual_speed);
}
if (changed) {
return;
}
- _capture_offset = _io->input_latency();
+ _capture_offset = _io->latency();
}
void
if (_playlist) {
_playlist->release();
}
-
+
_playlist = playlist;
_playlist->use();
if (!in_set_state && recordable()) {
reset_write_sources (false);
}
-
+
plmod_connection = _playlist->Modified.connect (mem_fun (*this, &Diskstream::playlist_modified));
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));
_session.request_overwrite_buffer (this);
overwrite_queued = true;
}
-
+
PlaylistChanged (); /* EMIT SIGNAL */
_session.set_dirty ();
}
void
-Diskstream::playlist_changed (Change ignored)
+Diskstream::playlist_changed (Change)
{
playlist_modified ();
}
if (!i_am_the_modifier && !overwrite_queued) {
_session.request_overwrite_buffer (this);
overwrite_queued = true;
- }
+ }
}
void
if (pl == _playlist) {
- /* this catches an ordering issue with session destruction. playlists
+ /* 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 ();
- }
+ }
}
}
if (str != _name) {
assert(playlist());
playlist()->set_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 ();
if (!region) {
return;
}
-
+
_last_capture_regions.remove (region);
}
void
-Diskstream::playlist_ranges_moved (Evoral::RangeMoveList const & movements)
+Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<nframes_t> > const & movements_frames)
{
- if (Config->get_automation_follows_regions () == false) {
+ if (!_route || 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 ()
- )
- );
+ list< Evoral::RangeMove<double> > movements;
+
+ for (list< Evoral::RangeMove<nframes_t> >::const_iterator i = movements_frames.begin();
+ i != movements_frames.end();
+ ++i) {
+
+ movements.push_back(Evoral::RangeMove<double>(i->from, i->length, i->to));
}
- /* 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));
+ /* move panner automation */
+ boost::shared_ptr<Panner> p = _route->main_outs()->panner ();
+ if (p) {
+ 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 */
+ _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &Diskstream::move_processor_automation), movements_frames));
}
void
-Diskstream::move_processor_automation (boost::weak_ptr<Processor> p, Evoral::RangeMoveList const & movements)
+Diskstream::move_processor_automation (boost::weak_ptr<Processor> p,
+ list< Evoral::RangeMove<nframes_t> > const & movements_frames)
{
boost::shared_ptr<Processor> processor (p.lock ());
if (!processor) {
return;
}
-
+
+ list< Evoral::RangeMove<double> > movements;
+ for (list< Evoral::RangeMove<nframes_t> >::const_iterator i = movements_frames.begin();
+ i != movements_frames.end(); ++i) {
+ movements.push_back(Evoral::RangeMove<double>(i->from, i->length, i->to));
+ }
+
set<Evoral::Parameter> const a = processor->what_can_be_automated ();
for (set<Evoral::Parameter>::iterator i = a.begin (); i != a.end (); ++i) {
}
}
+void
+Diskstream::route_going_away ()
+{
+ _io.reset ();
+}