summaryrefslogtreecommitdiff
path: root/libs/ardour
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2017-03-31 17:28:14 +0200
committerPaul Davis <paul@linuxaudiosystems.com>2017-09-18 11:40:52 -0400
commita4a87f56e9dc8e2351101439aeea7a87064fa146 (patch)
tree940715c29eb1fcdd478b1998a9e0caad5032c9df /libs/ardour
parent94604c6979be790a072c9d76566250a3aadf6e79 (diff)
mega-commit to save state of first "it compilesand links" state for separated disk i/o changes.
THIS WILL NOT RUN. THIS REQUIRES MANY CHANGES
Diffstat (limited to 'libs/ardour')
-rw-r--r--libs/ardour/ardour/audio_track.h11
-rw-r--r--libs/ardour/ardour/auditioner.h6
-rw-r--r--libs/ardour/ardour/disk_io.h14
-rw-r--r--libs/ardour/ardour/disk_reader.h9
-rw-r--r--libs/ardour/ardour/disk_writer.h40
-rw-r--r--libs/ardour/ardour/midi_track.h6
-rw-r--r--libs/ardour/ardour/public_diskstream.h2
-rw-r--r--libs/ardour/ardour/route.h7
-rw-r--r--libs/ardour/ardour/track.h32
-rw-r--r--libs/ardour/audio_track.cc170
-rw-r--r--libs/ardour/auditioner.cc162
-rw-r--r--libs/ardour/disk_io.cc85
-rw-r--r--libs/ardour/disk_reader.cc40
-rw-r--r--libs/ardour/disk_writer.cc1000
-rw-r--r--libs/ardour/midi_track.cc129
-rw-r--r--libs/ardour/session.cc9
-rw-r--r--libs/ardour/session_state.cc2
-rw-r--r--libs/ardour/track.cc257
18 files changed, 1292 insertions, 689 deletions
diff --git a/libs/ardour/ardour/audio_track.h b/libs/ardour/ardour/audio_track.h
index 7103825daf..2779e6a4f8 100644
--- a/libs/ardour/ardour/audio_track.h
+++ b/libs/ardour/ardour/audio_track.h
@@ -40,13 +40,6 @@ class LIBARDOUR_API AudioTrack : public Track
int roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
int declick, bool& need_butler);
- boost::shared_ptr<Diskstream> create_diskstream ();
- void set_diskstream (boost::shared_ptr<Diskstream>);
-
- DataType data_type () const {
- return DataType::AUDIO;
- }
-
void freeze_me (InterThreadInfo&);
void unfreeze ();
@@ -62,13 +55,9 @@ class LIBARDOUR_API AudioTrack : public Track
boost::shared_ptr<AudioFileSource> write_source (uint32_t n = 0);
protected:
- boost::shared_ptr<AudioDiskstream> audio_diskstream () const;
XMLNode& state (bool full);
private:
-
- boost::shared_ptr<Diskstream> diskstream_factory (XMLNode const &);
-
int deprecated_use_diskstream_connections ();
void set_state_part_two ();
void set_state_part_three ();
diff --git a/libs/ardour/ardour/auditioner.h b/libs/ardour/ardour/auditioner.h
index 48d889344a..1dbe0cd81e 100644
--- a/libs/ardour/ardour/auditioner.h
+++ b/libs/ardour/ardour/auditioner.h
@@ -80,9 +80,6 @@ class LIBARDOUR_API Auditioner : public Track
int roll_audio (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& need_butler);
int roll_midi (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& need_butler);
- boost::shared_ptr<Diskstream> create_diskstream ();
- void set_diskstream (boost::shared_ptr<Diskstream> ds);
-
/* fake track */
void set_state_part_two () {}
int set_state (const XMLNode&, int) { return 0; }
@@ -102,9 +99,6 @@ class LIBARDOUR_API Auditioner : public Track
boost::shared_ptr<Diskstream> diskstream_factory (XMLNode const &)
{ return boost::shared_ptr<Diskstream> (); }
- boost::shared_ptr<AudioDiskstream> audio_diskstream() const;
- boost::shared_ptr<MidiDiskstream> midi_diskstream() const;
-
private:
boost::shared_ptr<AudioRegion> the_region;
boost::shared_ptr<MidiRegion> midi_region;
diff --git a/libs/ardour/ardour/disk_io.h b/libs/ardour/ardour/disk_io.h
index dd775cbe84..c10dad54a1 100644
--- a/libs/ardour/ardour/disk_io.h
+++ b/libs/ardour/ardour/disk_io.h
@@ -65,12 +65,11 @@ class LIBARDOUR_API DiskIOProcessor : public Processor
bool configure_io (ChanCount in, ChanCount out);
bool can_support_io_configuration (const ChanCount& in, ChanCount& out);
- /** @return A number between 0 and 1, where 0 indicates that the playback buffer
+ /** @return A number between 0 and 1, where 0 indicates that the playback/capture buffer
* is dry (ie the disk subsystem could not keep up) and 1 indicates that the
* buffer is full.
*/
- virtual float playback_buffer_load() const = 0;
- virtual float capture_buffer_load() const = 0;
+ virtual float buffer_load() const = 0;
void set_flag (Flag f) { _flags = Flag (_flags | f); }
void unset_flag (Flag f) { _flags = Flag (_flags & ~f); }
@@ -89,8 +88,6 @@ class LIBARDOUR_API DiskIOProcessor : public Processor
virtual void punch_in() {}
virtual void punch_out() {}
- virtual float buffer_load() const = 0;
-
bool slaved() const { return _slaved; }
void set_slaved(bool yn) { _slaved = yn; }
@@ -113,8 +110,6 @@ class LIBARDOUR_API DiskIOProcessor : public Processor
virtual void playlist_modified () {}
virtual int use_playlist (DataType, boost::shared_ptr<Playlist>);
- virtual int use_new_playlist (DataType);
- virtual int use_copy_playlist (DataType);
PBD::Signal1<void,DataType> PlaylistChanged;
@@ -135,6 +130,8 @@ class LIBARDOUR_API DiskIOProcessor : public Processor
bool _slaved;
Location* loop_location;
bool in_set_state;
+ framepos_t file_frame;
+ framepos_t playback_sample;
framecnt_t wrap_buffer_size;
framecnt_t speed_buffer_size;
bool _need_butler;
@@ -202,7 +199,6 @@ class LIBARDOUR_API DiskIOProcessor : public Processor
virtual void playlist_changed (const PBD::PropertyChange&) {}
virtual void playlist_deleted (boost::weak_ptr<Playlist>);
virtual void playlist_ranges_moved (std::list< Evoral::RangeMove<framepos_t> > const &, bool) {}
- int find_and_use_playlist (DataType, std::string const &);
/* The MIDI stuff */
@@ -210,6 +206,8 @@ class LIBARDOUR_API DiskIOProcessor : public Processor
gint _frames_written_to_ringbuffer;
gint _frames_read_from_ringbuffer;
CubicMidiInterpolation midi_interpolation;
+
+ static void get_location_times (const Location* location, framepos_t* start, framepos_t* end, framepos_t* length);
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/disk_reader.h b/libs/ardour/ardour/disk_reader.h
index 7b076ab23f..e09904ad34 100644
--- a/libs/ardour/ardour/disk_reader.h
+++ b/libs/ardour/ardour/disk_reader.h
@@ -86,14 +86,18 @@ class LIBARDOUR_API DiskReader : public DiskIOProcessor
void adjust_buffering ();
int can_internal_playback_seek (framecnt_t distance);
+ int internal_playback_seek (framecnt_t distance);
int seek (framepos_t frame, bool complete_refill = false);
static PBD::Signal0<void> Underrun;
void playlist_modified ();
+ void reset_tracker ();
protected:
- void reset_tracker ();
+ friend class Track;
+ friend class MidiTrack;
+
void resolve_tracker (Evoral::EventSink<framepos_t>& buffer, framepos_t time);
boost::shared_ptr<MidiBuffer> get_gui_feed_buffer () const;
@@ -113,8 +117,6 @@ class LIBARDOUR_API DiskReader : public DiskIOProcessor
IOChange input_change_pending;
framecnt_t wrap_buffer_size;
framecnt_t speed_buffer_size;
- framepos_t file_frame;
- framepos_t playback_sample;
MonitorChoice _monitoring_choice;
int _do_refill_with_alloc (bool partial_fill);
@@ -142,7 +144,6 @@ class LIBARDOUR_API DiskReader : public DiskIOProcessor
int refill_audio (Sample *mixdown_buffer, float *gain_buffer, framecnt_t fill_level);
int refill_midi ();
- int internal_playback_seek (framecnt_t distance);
frameoffset_t calculate_playback_distance (pframes_t);
void get_playback (MidiBuffer& dst, framecnt_t nframes);
diff --git a/libs/ardour/ardour/disk_writer.h b/libs/ardour/ardour/disk_writer.h
index 3eed3c6d99..d0f3672cbd 100644
--- a/libs/ardour/ardour/disk_writer.h
+++ b/libs/ardour/ardour/disk_writer.h
@@ -24,12 +24,14 @@
#include <vector>
#include "ardour/disk_io.h"
+#include "ardour/midi_buffer.h"
namespace ARDOUR
{
class AudioFileSource;
class SMFSource;
+class MidiSource;
class LIBARDOUR_API DiskWriter : public DiskIOProcessor
{
@@ -50,8 +52,6 @@ class LIBARDOUR_API DiskWriter : public DiskIOProcessor
virtual XMLNode& state (bool full);
int set_state (const XMLNode&, int version);
- virtual int use_new_write_source (uint32_t n=0) = 0;
-
std::string write_source_name () const {
if (_write_source_name.empty()) {
return name();
@@ -72,6 +72,8 @@ class LIBARDOUR_API DiskWriter : public DiskIOProcessor
boost::shared_ptr<SMFSource> midi_write_source () { return _midi_write_source; }
virtual std::string steal_write_source_name () { return std::string(); }
+ int use_new_write_source (DataType, uint32_t n = 0);
+ void reset_write_sources (bool, bool force = false);
AlignStyle alignment_style() const { return _alignment_style; }
AlignChoice alignment_choice() const { return _alignment_choice; }
@@ -87,8 +89,8 @@ class LIBARDOUR_API DiskWriter : public DiskIOProcessor
bool record_enabled() const { return g_atomic_int_get (const_cast<gint*>(&_record_enabled)); }
bool record_safe () const { return g_atomic_int_get (const_cast<gint*>(&_record_safe)); }
- virtual void set_record_enabled (bool yn) = 0;
- virtual void set_record_safe (bool yn) = 0;
+ virtual void set_record_enabled (bool yn);
+ virtual void set_record_safe (bool yn);
bool destructive() const { return _flags & Destructive; }
int set_destructive (bool yn);
@@ -109,16 +111,31 @@ class LIBARDOUR_API DiskWriter : public DiskIOProcessor
framecnt_t capture_offset() const { return _capture_offset; }
virtual void set_capture_offset ();
+ int seek (framepos_t frame, bool complete_refill);
+
static PBD::Signal0<void> Overrun;
+ void set_note_mode (NoteMode m);
+
+ /** Emitted when some MIDI data has been received for recording.
+ * Parameter is the source that it is destined for.
+ * A caller can get a copy of the data with get_gui_feed_buffer ()
+ */
+ PBD::Signal1<void, boost::weak_ptr<MidiSource> > DataRecorded;
+
PBD::Signal0<void> RecordEnableChanged;
PBD::Signal0<void> RecordSafeChanged;
+ void check_record_status (framepos_t transport_frame, bool can_record);
+
+ void transport_looped (framepos_t transport_frame);
+ void transport_stopped_wallclock (struct tm&, time_t, bool abort);
+
protected:
- virtual int do_flush (RunContext context, bool force = false) = 0;
+ friend class Track;
+ int do_flush (RunContext context, bool force = false);
void get_input_sources ();
- void check_record_status (framepos_t transport_frame, bool can_record);
void prepare_record_status (framepos_t /*capture_start_frame*/);
void set_align_style_from_io();
void setup_destructive_playlist ();
@@ -138,9 +155,6 @@ class LIBARDOUR_API DiskWriter : public DiskIOProcessor
framecnt_t& rec_nframes, framecnt_t& rec_offset
);
- static framecnt_t disk_read_chunk_frames;
- static framecnt_t disk_write_chunk_frames;
-
struct CaptureInfo {
framepos_t start;
framecnt_t frames;
@@ -168,7 +182,7 @@ class LIBARDOUR_API DiskWriter : public DiskIOProcessor
std::list<boost::shared_ptr<Source> > _last_capture_sources;
std::vector<boost::shared_ptr<AudioFileSource> > capturing_sources;
-
+
static framecnt_t _chunk_frames;
NoteMode _note_mode;
@@ -176,6 +190,12 @@ class LIBARDOUR_API DiskWriter : public DiskIOProcessor
volatile gint _num_captured_loops;
framepos_t _accumulated_capture_offset;
+ /** A buffer that we use to put newly-arrived MIDI data in for
+ the GUI to read (so that it can update itself).
+ */
+ MidiBuffer _gui_feed_buffer;
+ mutable Glib::Threads::Mutex _gui_feed_buffer_mutex;
+
void finish_capture (boost::shared_ptr<ChannelList> c);
};
diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h
index dc2d4ec2cf..ea6e4e3636 100644
--- a/libs/ardour/ardour/midi_track.h
+++ b/libs/ardour/ardour/midi_track.h
@@ -54,10 +54,6 @@ public:
bool can_be_record_enabled ();
bool can_be_record_safe ();
- DataType data_type () const {
- return DataType::MIDI;
- }
-
void freeze_me (InterThreadInfo&);
void unfreeze ();
@@ -156,8 +152,6 @@ private:
virtual boost::shared_ptr<Diskstream> diskstream_factory (XMLNode const &);
- boost::shared_ptr<MidiDiskstream> midi_diskstream () const;
-
void write_out_of_band_data (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, framecnt_t nframes);
void set_state_part_two ();
diff --git a/libs/ardour/ardour/public_diskstream.h b/libs/ardour/ardour/public_diskstream.h
index 1fc93a6674..a80219ff80 100644
--- a/libs/ardour/ardour/public_diskstream.h
+++ b/libs/ardour/ardour/public_diskstream.h
@@ -68,7 +68,7 @@ public:
virtual framepos_t current_capture_start () const = 0;
virtual framepos_t current_capture_end () const = 0;
virtual void playlist_modified () = 0;
- virtual int use_playlist (boost::shared_ptr<Playlist>) = 0;
+ // XXX DISK removed virtual int use_playlist (boost::shared_ptr<Playlist>) = 0;
virtual void set_align_style (AlignStyle, bool force=false) = 0;
virtual void set_align_choice (AlignChoice, bool force=false) = 0;
virtual int use_copy_playlist () = 0;
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 2c668f6ed7..619e79fafc 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -100,6 +100,13 @@ public:
virtual int init ();
+ DataType data_type () const {
+ /* XXX ultimately nice to do away with this concept, but it is
+ quite useful for coders and for users too.
+ */
+ return _default_type;
+ }
+
boost::shared_ptr<IO> input() const { return _input; }
boost::shared_ptr<IO> output() const { return _output; }
IOVector all_inputs () const;
diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h
index b67e9d970a..33c967f088 100644
--- a/libs/ardour/ardour/track.h
+++ b/libs/ardour/ardour/track.h
@@ -36,15 +36,19 @@ class RouteGroup;
class Source;
class Region;
class Diskstream;
+class DiskReader;
+class DiskWriter;
class IO;
class MonitorControl;
class RecordEnableControl;
class RecordSafeControl;
/** A track is an route (bus) with a recordable diskstream and
- * related objects relevant to tracking, playback and editing.
+ * related objects relevant to recording, playback and editing.
*
- * Specifically a track has regions and playlist objects.
+ * Specifically a track has a playlist object that describes material
+ * to be played from disk, and modifies that object during recording and
+ * editing.
*/
class LIBARDOUR_API Track : public Route, public Recordable, public PublicDiskstream
{
@@ -75,14 +79,8 @@ class LIBARDOUR_API Track : public Route, public Recordable, public PublicDiskst
bool needs_butler() const { return _needs_butler; }
- virtual DataType data_type () const = 0;
-
bool can_record();
- void use_new_diskstream ();
- virtual boost::shared_ptr<Diskstream> create_diskstream() = 0;
- virtual void set_diskstream (boost::shared_ptr<Diskstream>);
-
void set_latency_compensation (framecnt_t);
enum FreezeState {
@@ -179,18 +177,17 @@ class LIBARDOUR_API Track : public Route, public Recordable, public PublicDiskst
AlignChoice alignment_choice () const;
framepos_t current_capture_start () const;
framepos_t current_capture_end () const;
- void playlist_modified ();
- int use_playlist (boost::shared_ptr<Playlist>);
void set_align_style (AlignStyle, bool force=false);
void set_align_choice (AlignChoice, bool force=false);
+ void playlist_modified ();
+ int use_playlist (DataType, boost::shared_ptr<Playlist>);
+ int find_and_use_playlist (DataType, std::string const & name);
int use_copy_playlist ();
int use_new_playlist ();
void adjust_playback_buffering ();
void adjust_capture_buffering ();
- PBD::Signal0<void> DiskstreamChanged;
PBD::Signal0<void> FreezeChange;
- /* Emitted when our diskstream is set to use a different playlist */
PBD::Signal0<void> PlaylistChanged;
PBD::Signal0<void> SpeedChanged;
PBD::Signal0<void> AlignmentStyleChanged;
@@ -199,6 +196,11 @@ class LIBARDOUR_API Track : public Route, public Recordable, public PublicDiskst
XMLNode& state (bool full);
boost::shared_ptr<Diskstream> _diskstream;
+
+ boost::shared_ptr<DiskReader> _disk_reader;
+ boost::shared_ptr<DiskWriter> _disk_writer;
+ boost::shared_ptr<Playlist> _playlists[DataType::num_types];
+
MeterPoint _saved_meter_point;
TrackMode _mode;
bool _needs_butler;
@@ -245,12 +247,6 @@ class LIBARDOUR_API Track : public Route, public Recordable, public PublicDiskst
virtual void monitoring_changed (bool, PBD::Controllable::GroupControlDisposition);
private:
-
- virtual boost::shared_ptr<Diskstream> diskstream_factory (XMLNode const &) = 0;
-
- void diskstream_playlist_changed ();
- void diskstream_speed_changed ();
- void diskstream_alignment_style_changed ();
void parameter_changed (std::string const & p);
std::string _diskstream_name;
diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc
index ef0f3f0dab..4076ed5056 100644
--- a/libs/ardour/audio_track.cc
+++ b/libs/ardour/audio_track.cc
@@ -32,6 +32,8 @@
#include "ardour/boost_debug.h"
#include "ardour/buffer_set.h"
#include "ardour/delivery.h"
+#include "ardour/disk_reader.h"
+#include "ardour/disk_writer.h"
#include "ardour/meter.h"
#include "ardour/monitor_control.h"
#include "ardour/playlist_factory.h"
@@ -63,96 +65,47 @@ AudioTrack::~AudioTrack ()
}
}
-boost::shared_ptr<Diskstream>
-AudioTrack::create_diskstream ()
-{
- AudioDiskstream::Flag dflags = AudioDiskstream::Flag (AudioDiskstream::Recordable);
-
- if (_mode == Destructive && !Profile->get_trx()) {
- dflags = AudioDiskstream::Flag (dflags | AudioDiskstream::Destructive);
- } else if (_mode == NonLayered){
- dflags = AudioDiskstream::Flag(dflags | AudioDiskstream::NonLayered);
- }
-
- return boost::shared_ptr<AudioDiskstream> (new AudioDiskstream (_session, name(), dflags));
-}
-
-void
-AudioTrack::set_diskstream (boost::shared_ptr<Diskstream> ds)
+#ifdef XXX_OLD_DESTRUCTIVE_API_XXX
+int
+AudioTrack::set_mode (TrackMode m)
{
- Track::set_diskstream (ds);
+ if (m != _mode) {
- _diskstream->set_track (this);
-
- if (audio_diskstream()->deprecated_io_node) {
-
- if (!IO::connecting_legal) {
- IO::ConnectingLegal.connect_same_thread (*this, boost::bind (&AudioTrack::deprecated_use_diskstream_connections, this));
- } else {
- deprecated_use_diskstream_connections ();
+ if (!Profile->get_trx() && _diskstream->set_destructive (m == Destructive)) {
+ return -1;
}
- }
- _diskstream->set_record_enabled (false);
- _diskstream->request_input_monitoring (false);
+ _diskstream->set_non_layered (m == NonLayered);
+ _mode = m;
- DiskstreamChanged (); /* EMIT SIGNAL */
-}
+ TrackModeChanged (); /* EMIT SIGNAL */
+ }
-boost::shared_ptr<AudioDiskstream>
-AudioTrack::audio_diskstream() const
-{
- return boost::dynamic_pointer_cast<AudioDiskstream>(_diskstream);
+ return 0;
}
-int
-AudioTrack::deprecated_use_diskstream_connections ()
+bool
+AudioTrack::can_use_mode (TrackMode m, bool& bounce_required)
{
- boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
-
- if (diskstream->deprecated_io_node == 0) {
- return 0;
- }
-
- XMLNode& node (*diskstream->deprecated_io_node);
-
- /* don't do this more than once. */
-
- diskstream->deprecated_io_node = 0;
-
- float val;
- if (node.get_property ("gain", val)) {
- _amp->gain_control()->set_value (val, PBD::Controllable::NoGroup);
- }
-
- std::string str;
- if (node.get_property ("input-connection", str)) {
- boost::shared_ptr<Bundle> c = _session.bundle_by_name (str);
-
- if (c == 0) {
- error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), str, _name) << endmsg;
+ switch (m) {
+ case NonLayered:
+ case Normal:
+ bounce_required = false;
+ return true;
- if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
- error << _("No input bundles available as a replacement")
- << endmsg;
- return -1;
- } else {
- info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), str)
- << endmsg;
- }
+ case Destructive:
+ if (Profile->get_trx()) {
+ return false;
+ } else {
+ return _diskstream->can_become_destructive (bounce_required);
}
+ break;
- _input->connect_ports_to_bundle (c, true, this);
-
- } else if (node.get_property ("inputs", str)) {
- if (_input->set_ports (str)) {
- error << string_compose(_("improper input channel list in XML node (%1)"), str) << endmsg;
- return -1;
- }
+ default:
+ return false;
}
-
- return 0;
}
+#endif
int
AudioTrack::set_state (const XMLNode& node, int version)
@@ -279,49 +232,21 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
if (!lm.locked()) {
- boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
- framecnt_t playback_distance = diskstream->calculate_playback_distance(nframes);
- if (can_internal_playback_seek(::llabs(playback_distance))) {
- /* TODO should declick */
- internal_playback_seek(playback_distance);
- }
return 0;
}
- framepos_t transport_frame;
- boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
-
if (n_outputs().n_total() == 0 && _processors.empty()) {
return 0;
}
if (!_active) {
silence (nframes);
- if (_meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _diskstream->record_enabled())) {
+ if (_meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _disk_writer->record_enabled())) {
_meter->reset();
}
return 0;
}
- transport_frame = _session.transport_frame();
-
- int dret;
- framecnt_t playback_distance;
-
- if ((nframes = check_initial_delay (nframes, transport_frame)) == 0) {
-
- /* need to do this so that the diskstream sets its
- playback distance to zero, thus causing diskstream::commit
- to do nothing.
- */
-
- BufferSet bufs; /* empty set, no matter - nothing will happen */
-
- dret = diskstream->process (bufs, transport_frame, 0, playback_distance, false);
- need_butler = diskstream->commit (playback_distance);
- return dret;
- }
-
_silent = false;
_amp->apply_gain_automation(false);
@@ -333,18 +258,10 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
_meter->run (bufs, start_frame, end_frame, 1.0 /*speed()*/, nframes, true);
}
- if ((dret = diskstream->process (bufs, transport_frame, nframes, playback_distance, (monitoring_state() == MonitoringDisk))) != 0) {
- need_butler = diskstream->commit (playback_distance);
- silence (nframes);
- return dret;
- }
-
- process_output_buffers (bufs, start_frame, end_frame, nframes, declick, (!diskstream->record_enabled() && _session.transport_rolling()));
+ process_output_buffers (bufs, start_frame, end_frame, nframes, declick, (!_disk_writer->record_enabled() && _session.transport_rolling()));
flush_processor_buffers_locked (nframes);
- need_butler = diskstream->commit (playback_distance);
-
return 0;
}
@@ -354,11 +271,10 @@ AudioTrack::export_stuff (BufferSet& buffers, framepos_t start, framecnt_t nfram
{
boost::scoped_array<gain_t> gain_buffer (new gain_t[nframes]);
boost::scoped_array<Sample> mix_buffer (new Sample[nframes]);
- boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
Glib::Threads::RWLock::ReaderLock rlock (_processor_lock);
- boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist>(diskstream->playlist());
+ boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist>(playlist());
assert(apl);
assert(buffers.count().n_audio() >= 1);
@@ -373,7 +289,7 @@ AudioTrack::export_stuff (BufferSet& buffers, framepos_t start, framecnt_t nfram
BufferSet::audio_iterator bi = buffers.audio_begin();
++bi;
for ( ; bi != buffers.audio_end(); ++bi, ++n) {
- if (n < diskstream->n_channels().n_audio()) {
+ if (n < _disk_reader->output_streams().n_audio()) {
if (apl->read (bi->data(), mix_buffer.get(), gain_buffer.get(), start, nframes, n) != nframes) {
return -1;
}
@@ -468,9 +384,8 @@ AudioTrack::freeze_me (InterThreadInfo& itt)
boost::shared_ptr<Playlist> new_playlist;
string dir;
string region_name;
- boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
- if ((_freeze_record.playlist = boost::dynamic_pointer_cast<AudioPlaylist>(diskstream->playlist())) == 0) {
+ if ((_freeze_record.playlist = boost::dynamic_pointer_cast<AudioPlaylist>(playlist())) == 0) {
return;
}
@@ -555,8 +470,8 @@ AudioTrack::freeze_me (InterThreadInfo& itt)
new_playlist->set_frozen (true);
region->set_locked (true);
- diskstream->use_playlist (boost::dynamic_pointer_cast<AudioPlaylist>(new_playlist));
- diskstream->set_record_enabled (false);
+ use_playlist (DataType::AUDIO, boost::dynamic_pointer_cast<AudioPlaylist>(new_playlist));
+ _disk_writer->set_record_enabled (false);
_freeze_record.playlist->use(); // prevent deletion
@@ -576,7 +491,7 @@ AudioTrack::unfreeze ()
{
if (_freeze_record.playlist) {
_freeze_record.playlist->release();
- audio_diskstream()->use_playlist (_freeze_record.playlist);
+ use_playlist (DataType::AUDIO, _freeze_record.playlist);
{
Glib::Threads::RWLock::ReaderLock lm (_processor_lock); // should this be a write lock? jlc
@@ -601,13 +516,6 @@ AudioTrack::unfreeze ()
boost::shared_ptr<AudioFileSource>
AudioTrack::write_source (uint32_t n)
{
- boost::shared_ptr<AudioDiskstream> ds = boost::dynamic_pointer_cast<AudioDiskstream> (_diskstream);
- assert (ds);
- return ds->write_source (n);
-}
-
-boost::shared_ptr<Diskstream>
-AudioTrack::diskstream_factory (XMLNode const & node)
-{
- return boost::shared_ptr<Diskstream> (new AudioDiskstream (_session, node));
+ assert (_disk_writer);
+ return _disk_writer->audio_write_source (n);
}
diff --git a/libs/ardour/auditioner.cc b/libs/ardour/auditioner.cc
index 85fa4cce31..4426464adc 100644
--- a/libs/ardour/auditioner.cc
+++ b/libs/ardour/auditioner.cc
@@ -22,7 +22,6 @@
#include "pbd/error.h"
#include "ardour/amp.h"
-#include "ardour/audio_diskstream.h"
#include "ardour/audio_port.h"
#include "ardour/audioengine.h"
#include "ardour/audioplaylist.h"
@@ -30,7 +29,8 @@
#include "ardour/auditioner.h"
#include "ardour/data_type.h"
#include "ardour/delivery.h"
-#include "ardour/midi_diskstream.h"
+#include "ardour/disk_reader.h"
+#include "ardour/midi_playlist.h"
#include "ardour/midi_region.h"
#include "ardour/plugin.h"
#include "ardour/plugin_insert.h"
@@ -215,37 +215,8 @@ Auditioner::data_type () const {
}
}
-boost::shared_ptr<Diskstream>
-Auditioner::create_diskstream () {
-
- {
- AudioDiskstream::Flag dflags = AudioDiskstream::Flag (0);
- dflags = AudioDiskstream::Flag (dflags | AudioDiskstream::Hidden);
- _diskstream_audio = boost::shared_ptr<AudioDiskstream> (new AudioDiskstream (_session, name(), dflags));
- }
-
- {
- MidiDiskstream::Flag dflags = MidiDiskstream::Flag (0);
- dflags = MidiDiskstream::Flag (dflags | MidiDiskstream::Hidden);
- _diskstream_midi = boost::shared_ptr<Diskstream> (new MidiDiskstream (_session, name(), dflags));
- _diskstream_midi->do_refill_with_alloc ();
- _diskstream_midi->playlist()->set_orig_track_id (id());
- }
-
- return _diskstream_audio;
-}
-
int
-Auditioner::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& need_butler) {
- if (_midi_audition) {
- return roll_midi(nframes, start_frame, end_frame, declick, need_butler);
- } else {
- return roll_audio(nframes, start_frame, end_frame, declick, need_butler);
- }
-}
-
-int
-Auditioner::roll_midi (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& need_butler)
+Auditioner::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& need_butler)
{
Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
if (!lm.locked()) {
@@ -254,17 +225,13 @@ Auditioner::roll_midi (pframes_t nframes, framepos_t start_frame, framepos_t end
assert(_active);
- framecnt_t playback_distance = nframes;
- boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream();
BufferSet& bufs = _session.get_route_buffers (n_process_buffers());
- MidiBuffer& mbuf (bufs.get_midi (0));
- _silent = false;
- ChanCount cnt (DataType::MIDI, 1);
- cnt.set (DataType::AUDIO, bufs.count().n_audio());
- bufs.set_count (cnt);
+ _silent = false;
+ _amp->apply_gain_automation(false);
if (_queue_panic) {
+ MidiBuffer& mbuf (bufs.get_midi (0));
_queue_panic = false;
for (uint8_t chn = 0; chn < 0xf; ++chn) {
uint8_t buf[3] = { ((uint8_t) (MIDI_CMD_CONTROL | chn)), ((uint8_t) MIDI_CTL_SUSTAIN), 0 };
@@ -274,20 +241,9 @@ Auditioner::roll_midi (pframes_t nframes, framepos_t start_frame, framepos_t end
buf[1] = MIDI_CTL_RESET_CONTROLLERS;
mbuf.push_back(0, 3, buf);
}
- process_output_buffers (bufs, start_frame, start_frame+1, 1, false, false);
-
- for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
- boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery> (*i);
- if (d) {
- d->flush_buffers (nframes);
- }
- }
}
- diskstream->get_playback (mbuf, nframes);
-
- process_output_buffers (bufs, start_frame, end_frame, nframes,
- declick, (!diskstream->record_enabled() && !_session.transport_stopped()));
+ process_output_buffers (bufs, start_frame, end_frame, nframes, declick, !_session.transport_stopped());
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery> (*i);
@@ -296,67 +252,23 @@ Auditioner::roll_midi (pframes_t nframes, framepos_t start_frame, framepos_t end
}
}
- need_butler = diskstream->commit (playback_distance);
- return 0;
-}
-
-
-int
-Auditioner::roll_audio (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& need_butler) {
- Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
- if (!lm.locked()) {
- return 0;
- }
-
- assert(n_outputs().n_total() > 0);
- assert(_active);
-
- int dret;
- framecnt_t playback_distance;
- framepos_t transport_frame = _session.transport_frame();
- boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
- BufferSet& bufs = _session.get_route_buffers (n_process_buffers ());
-
- _silent = false;
- _amp->apply_gain_automation(false);
-
- if ((dret = diskstream->process (bufs, transport_frame, nframes, playback_distance, (monitoring_state() == MonitoringDisk))) != 0) {
- need_butler = diskstream->commit (playback_distance);
- silence (nframes);
- return dret;
- }
-
- process_output_buffers (bufs, start_frame, end_frame, nframes, declick, (!diskstream->record_enabled() && _session.transport_rolling()));
- need_butler = diskstream->commit (playback_distance);
return 0;
}
-void
-Auditioner::set_diskstream (boost::shared_ptr<Diskstream> ds)
-{
- Track::set_diskstream (ds);
-
- _diskstream->set_track (this);
- _diskstream->set_record_enabled (false);
- _diskstream->request_input_monitoring (false);
-
- DiskstreamChanged (); /* EMIT SIGNAL */
-}
-
AudioPlaylist&
Auditioner::prepare_playlist ()
{
// used by CrossfadeEditor::audition()
_midi_audition = false;
- set_diskstream(_diskstream_audio);
+
if (_synth_added) {
remove_processor(asynth);
_synth_added = false;
}
// FIXME auditioner is still audio-only
- boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist>(_diskstream->playlist());
+ boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist>(playlist());
assert(apl);
apl->clear ();
@@ -378,7 +290,7 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
if (boost::dynamic_pointer_cast<AudioRegion>(region) != 0) {
_midi_audition = false;
- set_diskstream(_diskstream_audio);
+
if (_synth_added) {
remove_processor(asynth);
_synth_added = false;
@@ -390,14 +302,8 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
the_region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (region));
the_region->set_position (0);
- _diskstream->playlist()->drop_regions ();
- _diskstream->playlist()->add_region (the_region, 0, 1);
-
- if (_diskstream->n_channels().n_audio() < the_region->n_channels()) {
- audio_diskstream()->add_channel (the_region->n_channels() - _diskstream->n_channels().n_audio());
- } else if (_diskstream->n_channels().n_audio() > the_region->n_channels()) {
- audio_diskstream()->remove_channel (_diskstream->n_channels().n_audio() - the_region->n_channels());
- }
+ _disk_reader->audio_playlist()->drop_regions ();
+ _disk_reader->audio_playlist()->add_region (the_region, 0, 1);
ProcessorStreams ps;
{
@@ -405,14 +311,14 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
if (configure_processors (&ps)) {
error << string_compose (_("Cannot setup auditioner processing flow for %1 channels"),
- _diskstream->n_channels()) << endmsg;
+ region->n_channels()) << endmsg;
return;
}
}
} else if (boost::dynamic_pointer_cast<MidiRegion>(region)) {
_midi_audition = true;
- set_diskstream(_diskstream_midi);
+
the_region.reset();
_import_position = region->position();
@@ -420,9 +326,9 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
midi_region = (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (region)));
midi_region->set_position (_import_position);
- _diskstream->playlist()->drop_regions ();
- _diskstream->playlist()->add_region (midi_region, _import_position, 1);
- midi_diskstream()->reset_tracker();
+ _disk_reader->midi_playlist()->drop_regions ();
+ _disk_reader->midi_playlist()->add_region (midi_region, _import_position, 1);
+ _disk_reader->reset_tracker();
ProcessorStreams ps;
@@ -435,7 +341,6 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
lookup_synth();
}
-
if (!_synth_added && asynth) {
int rv = add_processor (asynth, PreFader, &ps, true);
if (rv) {
@@ -452,7 +357,7 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
if (configure_processors (&ps)) {
error << string_compose (_("Cannot setup auditioner processing flow for %1 channels"),
- _diskstream->n_channels()) << endmsg;
+ region->n_channels()) << endmsg;
return;
}
}
@@ -485,7 +390,7 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
offset = 0;
}
- _diskstream->seek (offset, true);
+ _disk_reader->seek (offset, true);
current_frame = offset;
g_atomic_int_set (&_auditioning, 1);
@@ -515,9 +420,7 @@ Auditioner::play_audition (framecnt_t nframes)
_seek_complete = false;
_seeking = false;
_seek_frame = -1;
- if (_midi_audition && midi_diskstream()) {
- midi_diskstream()->reset_tracker();
- }
+ _disk_reader->reset_tracker();
}
if(!_seeking) {
@@ -604,18 +507,10 @@ ChanCount
Auditioner::input_streams () const
{
/* auditioner never has any inputs - its channel configuration
- depends solely on the region we are auditioning.
- */
+ depends solely on the region we are auditioning.
+ */
- if (!_midi_audition && audio_diskstream()) {
- return audio_diskstream()->n_channels();
- }
- if (_midi_audition && midi_diskstream()) {
- ChanCount cnt (DataType::MIDI, 1);
- return cnt;
- }
-
- return ChanCount ();
+ return _disk_reader->input_streams ();
}
MonitorState
@@ -624,14 +519,3 @@ Auditioner::monitoring_state () const
return MonitoringDisk;
}
-boost::shared_ptr<AudioDiskstream>
-Auditioner::audio_diskstream() const
-{
- return boost::dynamic_pointer_cast<AudioDiskstream> (_diskstream);
-}
-
-boost::shared_ptr<MidiDiskstream>
-Auditioner::midi_diskstream() const
-{
- return boost::dynamic_pointer_cast<MidiDiskstream> (_diskstream);
-}
diff --git a/libs/ardour/disk_io.cc b/libs/ardour/disk_io.cc
index 1516933e32..89aba80322 100644
--- a/libs/ardour/disk_io.cc
+++ b/libs/ardour/disk_io.cc
@@ -56,6 +56,8 @@ DiskIOProcessor::DiskIOProcessor (Session& s, string const & str, Flag f)
, _slaved (false)
, loop_location (0)
, in_set_state (false)
+ , file_frame (0)
+ , playback_sample (0)
, wrap_buffer_size (0)
, speed_buffer_size (0)
, _need_butler (false)
@@ -394,68 +396,6 @@ DiskIOProcessor::use_playlist (DataType dt, boost::shared_ptr<Playlist> playlist
return 0;
}
-int
-DiskIOProcessor::find_and_use_playlist (DataType dt, const string& name)
-{
- boost::shared_ptr<Playlist> playlist;
-
- if ((playlist = _session.playlists->by_name (name)) == 0) {
- playlist = PlaylistFactory::create (dt, _session, name);
- }
-
- if (!playlist) {
- error << string_compose(_("DiskIOProcessor: \"%1\" isn't an playlist"), name) << endmsg;
- return -1;
- }
-
- return use_playlist (dt, playlist);
-}
-
-int
-DiskIOProcessor::use_new_playlist (DataType dt)
-{
- string newname;
- boost::shared_ptr<Playlist> playlist = _playlists[dt];
-
- if (playlist) {
- newname = Playlist::bump_name (playlist->name(), _session);
- } else {
- newname = Playlist::bump_name (_name, _session);
- }
-
- playlist = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (dt, _session, newname, hidden()));
-
- if (!playlist) {
- return -1;
- }
-
- return use_playlist (dt, playlist);
-}
-
-int
-DiskIOProcessor::use_copy_playlist (DataType dt)
-{
- assert (_playlists[dt]);
-
- if (_playlists[dt] == 0) {
- error << string_compose(_("DiskIOProcessor %1: there is no existing playlist to make a copy of!"), _name) << endmsg;
- return -1;
- }
-
- string newname;
- boost::shared_ptr<Playlist> playlist;
-
- newname = Playlist::bump_name (_playlists[dt]->name(), _session);
-
- if ((playlist = PlaylistFactory::create (_playlists[dt], newname)) == 0) {
- return -1;
- }
-
- playlist->reset_shares();
-
- return use_playlist (dt, playlist);
-}
-
DiskIOProcessor::ChannelInfo::ChannelInfo (framecnt_t bufsize)
{
buf = new RingBufferNPT<Sample> (bufsize);
@@ -492,3 +432,24 @@ DiskIOProcessor::set_route (boost::shared_ptr<Route> r)
{
_route = r;
}
+
+/** Get the start, end, and length of a location "atomically".
+ *
+ * Note: Locations don't get deleted, so all we care about when I say "atomic"
+ * is that we are always pointing to the same one and using start/length values
+ * obtained just once. Use this function to achieve this since location being
+ * a parameter achieves this.
+ */
+void
+DiskIOProcessor::get_location_times(const Location* location,
+ framepos_t* start,
+ framepos_t* end,
+ framepos_t* length)
+{
+ if (location) {
+ *start = location->start();
+ *end = location->end();
+ *length = *end - *start;
+ }
+}
+
diff --git a/libs/ardour/disk_reader.cc b/libs/ardour/disk_reader.cc
index aa26f2644f..7cdbaf1a0f 100644
--- a/libs/ardour/disk_reader.cc
+++ b/libs/ardour/disk_reader.cc
@@ -51,8 +51,6 @@ DiskReader::DiskReader (Session& s, string const & str, DiskIOProcessor::Flag f)
, overwrite_offset (0)
, _pending_overwrite (false)
, overwrite_queued (false)
- , file_frame (0)
- , playback_sample (0)
, _monitoring_choice (MonitorDisk)
, _gui_feed_buffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI))
{
@@ -143,28 +141,10 @@ DiskReader::state (bool full)
int
DiskReader::set_state (const XMLNode& node, int version)
{
- XMLProperty const * prop;
-
if (DiskIOProcessor::set_state (node, version)) {
return -1;
}
- if ((prop = node.property ("audio-playlist")) == 0) {
- return -1;
- }
-
- if (find_and_use_playlist (DataType::AUDIO, prop->value())) {
- return -1;
- }
-
- if ((prop = node.property ("midi-playlist")) == 0) {
- return -1;
- }
-
- if (find_and_use_playlist (DataType::MIDI, prop->value())) {
- return -1;
- }
-
return 0;
}
@@ -1310,26 +1290,6 @@ DiskReader::get_playback (MidiBuffer& dst, framecnt_t nframes)
//cerr << "----------------\n";
}
-/** Get the start, end, and length of a location "atomically".
- *
- * Note: Locations don't get deleted, so all we care about when I say "atomic"
- * is that we are always pointing to the same one and using start/length values
- * obtained just once. Use this function to achieve this since location being
- * a parameter achieves this.
- */
-static void
-get_location_times(const Location* location,
- framepos_t* start,
- framepos_t* end,
- framepos_t* length)
-{
- if (location) {
- *start = location->start();
- *end = location->end();
- *length = *end - *start;
- }
-}
-
/** @a start is set to the new frame position (TIME) read up to */
int
DiskReader::midi_read (framepos_t& start, framecnt_t dur, bool reversed)
diff --git a/libs/ardour/disk_writer.cc b/libs/ardour/disk_writer.cc
index c6f5c92c76..32d22fb1ae 100644
--- a/libs/ardour/disk_writer.cc
+++ b/libs/ardour/disk_writer.cc
@@ -19,12 +19,19 @@
#include "pbd/i18n.h"
+#include "ardour/analyser.h"
#include "ardour/audioengine.h"
-#include "ardour/audio_buffer.h"
#include "ardour/audiofilesource.h"
+#include "ardour/audio_buffer.h"
+#include "ardour/audioplaylist.h"
+#include "ardour/audioregion.h"
#include "ardour/debug.h"
#include "ardour/disk_writer.h"
+#include "ardour/midi_playlist.h"
+#include "ardour/midi_source.h"
+#include "ardour/midi_track.h"
#include "ardour/port.h"
+#include "ardour/region_factory.h"
#include "ardour/session.h"
#include "ardour/smf_source.h"
@@ -47,6 +54,9 @@ DiskWriter::DiskWriter (Session& s, string const & str, DiskIOProcessor::Flag f)
, last_possibly_recording (0)
, _alignment_style (ExistingMaterial)
, _alignment_choice (Automatic)
+ , _num_captured_loops (0)
+ , _accumulated_capture_offset (0)
+ , _gui_feed_buffer(AudioEngine::instance()->raw_buffer_size (DataType::MIDI))
{
DiskIOProcessor::init ();
}
@@ -475,6 +485,8 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
ChannelList::iterator chan;
framecnt_t rec_offset = 0;
framecnt_t rec_nframes = 0;
+ bool nominally_recording;
+ bool re = record_enabled ();
bool can_record = _session.actively_recording ();
check_record_status (start_frame, can_record);
@@ -483,6 +495,8 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
return;
}
+ nominally_recording = (can_record && re);
+
Glib::Threads::Mutex::Lock sm (state_lock, Glib::Threads::TRY_LOCK);
if (!sm.locked()) {
@@ -496,7 +510,18 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
last_recordable_frame = max_framepos;
}
- if (record_enabled()) {
+ const Location* const loop_loc = loop_location;
+ framepos_t loop_start = 0;
+ framepos_t loop_end = 0;
+ framepos_t loop_length = 0;
+
+ if (loop_loc) {
+ get_location_times (loop_loc, &loop_start, &loop_end, &loop_length);
+ }
+
+ adjust_capture_position = 0;
+
+ if (nominally_recording || (re && was_recording && _session.get_record_enabled() && (_session.config.get_punch_in() || _session.preroll_record_punch_enabled()))) {
Evoral::OverlapType ot = Evoral::coverage (first_recordable_frame, last_recordable_frame, start_frame, end_frame);
// XXX should this be transport_frame + nframes - 1 ? coverage() expects its parameter ranges to include their end points
@@ -507,8 +532,36 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
if (rec_nframes && !was_recording) {
capture_captured = 0;
+
+ if (loop_loc) {
+ /* Loop recording, so pretend the capture started at the loop
+ start rgardless of what time it is now, so the source starts
+ at the loop start and can handle time wrapping around.
+ Otherwise, start the source right now as usual.
+ */
+ capture_captured = start_frame - loop_start;
+ capture_start_frame = loop_start;
+ }
+
+ _midi_write_source->mark_write_starting_now (capture_start_frame, capture_captured, loop_length);
+
+ g_atomic_int_set(const_cast<gint*> (&_frames_pending_write), 0);
+ g_atomic_int_set(const_cast<gint*> (&_num_captured_loops), 0);
+
was_recording = true;
+
}
+
+ /* For audio: not writing frames to the capture ringbuffer offsets
+ * the recording. For midi: we need to keep track of the record range
+ * and subtract the accumulated difference from the event time.
+ */
+ if (rec_nframes) {
+ _accumulated_capture_offset += rec_offset;
+ } else {
+ _accumulated_capture_offset += nframes;
+ }
+
}
if (can_record && !_last_capture_sources.empty()) {
@@ -517,6 +570,8 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
if (rec_nframes) {
+ /* AUDIO */
+
const size_t n_buffers = bufs.count().n_audio();
for (n = 0; chan != c->end(); ++chan, ++n) {
@@ -548,38 +603,106 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
memcpy (chaninfo->rw_vector.buf[0], incoming, sizeof (Sample) * first);
memcpy (chaninfo->rw_vector.buf[1], incoming + first, sizeof (Sample) * (rec_nframes - first));
}
- }
- } else {
+ chaninfo->buf->increment_write_ptr (rec_nframes);
- if (was_recording) {
- finish_capture (c);
}
- }
+ /* MIDI */
- for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
- if (rec_nframes) {
- (*chan)->buf->increment_write_ptr (rec_nframes);
+ // Pump entire port buffer into the ring buffer (TODO: split cycles?)
+ MidiBuffer& buf = bufs.get_midi (0);
+ boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack>(_route);
+ MidiChannelFilter* filter = mt ? &mt->capture_filter() : 0;
+
+ for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
+ Evoral::Event<MidiBuffer::TimeType> ev(*i, false);
+ if (ev.time() + rec_offset > rec_nframes) {
+ break;
+ }
+#ifndef NDEBUG
+ if (DEBUG_ENABLED(DEBUG::MidiIO)) {
+ const uint8_t* __data = ev.buffer();
+ DEBUG_STR_DECL(a);
+ DEBUG_STR_APPEND(a, string_compose ("mididiskstream %1 capture event @ %2 + %3 sz %4 ", this, ev.time(), start_frame, ev.size()));
+ for (size_t i=0; i < ev.size(); ++i) {
+ DEBUG_STR_APPEND(a,hex);
+ DEBUG_STR_APPEND(a,"0x");
+ DEBUG_STR_APPEND(a,(int)__data[i]);
+ DEBUG_STR_APPEND(a,' ');
+ }
+ DEBUG_STR_APPEND(a,'\n');
+ DEBUG_TRACE (DEBUG::MidiIO, DEBUG_STR(a).str());
+ }
+#endif
+ /* Write events to the capture buffer in frames from session start,
+ but ignoring looping so event time progresses monotonically.
+ The source knows the loop length so it knows exactly where the
+ event occurs in the series of recorded loops and can implement
+ any desirable behaviour. We don't want to send event with
+ transport time here since that way the source can not
+ reconstruct their actual time; future clever MIDI looping should
+ probably be implemented in the source instead of here.
+ */
+ const framecnt_t loop_offset = _num_captured_loops * loop_length;
+ const framepos_t event_time = start_frame + loop_offset - _accumulated_capture_offset + ev.time();
+ if (event_time < 0 || event_time < first_recordable_frame) {
+ /* Event out of range, skip */
+ continue;
+ }
+
+ if (!filter || !filter->filter(ev.buffer(), ev.size())) {
+ _midi_buf->write (event_time, ev.event_type(), ev.size(), ev.buffer());
+ }
+ }
+ g_atomic_int_add(const_cast<gint*>(&_frames_pending_write), nframes);
+
+ if (buf.size() != 0) {
+ Glib::Threads::Mutex::Lock lm (_gui_feed_buffer_mutex, Glib::Threads::TRY_LOCK);
+
+ if (lm.locked ()) {
+ /* Copy this data into our GUI feed buffer and tell the GUI
+ that it can read it if it likes.
+ */
+ _gui_feed_buffer.clear ();
+
+ for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
+ /* This may fail if buf is larger than _gui_feed_buffer, but it's not really
+ the end of the world if it does.
+ */
+ _gui_feed_buffer.push_back ((*i).time() + start_frame, (*i).size(), (*i).buffer());
+ }
+ }
+
+ DataRecorded (_midi_write_source); /* EMIT SIGNAL */
}
- }
- if (rec_nframes != 0) {
capture_captured += rec_nframes;
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 now captured %2 (by %3)\n", name(), capture_captured, rec_nframes));
+
+ } else {
+
+ /* not recording this time, but perhaps we were before .. */
+
+ if (was_recording) {
+ finish_capture (c);
+ _accumulated_capture_offset = 0;
+ }
}
+ /* AUDIO BUTLER REQUIRED CODE */
+
if (!c->empty()) {
- if (_slaved) {
- if (c->front()->buf->write_space() >= c->front()->buf->bufsize() / 2) {
- _need_butler = true;
- }
- } else {
- if (((framecnt_t) c->front()->buf->read_space() >= _chunk_frames)) {
- _need_butler = true;
- }
+ if (((framecnt_t) c->front()->buf->read_space() >= _chunk_frames)) {
+ _need_butler = true;
}
}
+
+ /* MIDI BUTLER REQUIRED CODE */
+
+ if (_midi_buf->read_space() < _midi_buf->bufsize() / 2) {
+ _need_butler = true;
+ }
}
void
@@ -737,3 +860,840 @@ DiskWriter::buffer_load () const
return (float) ((double) c->front()->buf->write_space()/
(double) c->front()->buf->bufsize());
}
+
+void
+DiskWriter::set_note_mode (NoteMode m)
+{
+ _note_mode = m;
+
+ boost::shared_ptr<MidiPlaylist> mp = boost::dynamic_pointer_cast<MidiPlaylist> (_playlists[DataType::MIDI]);
+
+ if (mp) {
+ mp->set_note_mode (m);
+ }
+
+ if (_midi_write_source && _midi_write_source->model())
+ _midi_write_source->model()->set_note_mode(m);
+}
+
+int
+DiskWriter::seek (framepos_t frame, bool complete_refill)
+{
+ uint32_t n;
+ ChannelList::iterator chan;
+ boost::shared_ptr<ChannelList> c = channels.reader();
+
+ Glib::Threads::Mutex::Lock lm (state_lock);
+
+ for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
+ (*chan)->buf->reset ();
+ }
+
+ _midi_buf->reset ();
+ g_atomic_int_set(&_frames_read_from_ringbuffer, 0);
+ g_atomic_int_set(&_frames_written_to_ringbuffer, 0);
+
+ /* can't rec-enable in destructive mode if transport is before start */
+
+ if (destructive() && record_enabled() && frame < _session.current_start_frame()) {
+ disengage_record_enable ();
+ }
+
+ playback_sample = frame;
+ file_frame = frame;
+
+ return 0;
+}
+
+int
+DiskWriter::do_flush (RunContext ctxt, bool force_flush)
+{
+ uint32_t to_write;
+ int32_t ret = 0;
+ RingBufferNPT<Sample>::rw_vector vector;
+ RingBufferNPT<CaptureTransition>::rw_vector transvec;
+ framecnt_t total;
+
+ transvec.buf[0] = 0;
+ transvec.buf[1] = 0;
+ vector.buf[0] = 0;
+ vector.buf[1] = 0;
+
+ boost::shared_ptr<ChannelList> c = channels.reader();
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
+
+ (*chan)->buf->get_read_vector (&vector);
+
+ total = vector.len[0] + vector.len[1];
+
+ if (total == 0 || (total < _chunk_frames && !force_flush && was_recording)) {
+ goto out;
+ }
+
+ /* if there are 2+ chunks of disk i/o possible for
+ this track, let the caller know so that it can arrange
+ for us to be called again, ASAP.
+
+ if we are forcing a flush, then if there is* any* extra
+ work, let the caller know.
+
+ if we are no longer recording and there is any extra work,
+ let the caller know too.
+ */
+
+ if (total >= 2 * _chunk_frames || ((force_flush || !was_recording) && total > _chunk_frames)) {
+ ret = 1;
+ }
+
+ to_write = min (_chunk_frames, (framecnt_t) vector.len[0]);
+
+ // check the transition buffer when recording destructive
+ // important that we get this after the capture buf
+
+ if (destructive()) {
+ (*chan)->capture_transition_buf->get_read_vector(&transvec);
+ size_t transcount = transvec.len[0] + transvec.len[1];
+ size_t ti;
+
+ for (ti=0; ti < transcount; ++ti) {
+ CaptureTransition & captrans = (ti < transvec.len[0]) ? transvec.buf[0][ti] : transvec.buf[1][ti-transvec.len[0]];
+
+ if (captrans.type == CaptureStart) {
+ // by definition, the first data we got above represents the given capture pos
+
+ (*chan)->write_source->mark_capture_start (captrans.capture_val);
+ (*chan)->curr_capture_cnt = 0;
+
+ } else if (captrans.type == CaptureEnd) {
+
+ // capture end, the capture_val represents total frames in capture
+
+ if (captrans.capture_val <= (*chan)->curr_capture_cnt + to_write) {
+
+ // shorten to make the write a perfect fit
+ uint32_t nto_write = (captrans.capture_val - (*chan)->curr_capture_cnt);
+
+ if (nto_write < to_write) {
+ ret = 1; // should we?
+ }
+ to_write = nto_write;
+
+ (*chan)->write_source->mark_capture_end ();
+
+ // increment past this transition, but go no further
+ ++ti;
+ break;
+ }
+ else {
+ // actually ends just beyond this chunk, so force more work
+ ret = 1;
+ break;
+ }
+ }
+ }
+
+ if (ti > 0) {
+ (*chan)->capture_transition_buf->increment_read_ptr(ti);
+ }
+ }
+
+ if ((!(*chan)->write_source) || (*chan)->write_source->write (vector.buf[0], to_write) != to_write) {
+ error << string_compose(_("AudioDiskstream %1: cannot write to disk"), id()) << endmsg;
+ return -1;
+ }
+
+ (*chan)->buf->increment_read_ptr (to_write);
+ (*chan)->curr_capture_cnt += to_write;
+
+ if ((to_write == vector.len[0]) && (total > to_write) && (to_write < _chunk_frames) && !destructive()) {
+
+ /* we wrote all of vector.len[0] but it wasn't an entire
+ disk_write_chunk_frames of data, so arrange for some part
+ of vector.len[1] to be flushed to disk as well.
+ */
+
+ to_write = min ((framecnt_t)(_chunk_frames - to_write), (framecnt_t) vector.len[1]);
+
+ DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 additional write of %2\n", name(), to_write));
+
+ if ((*chan)->write_source->write (vector.buf[1], to_write) != to_write) {
+ error << string_compose(_("AudioDiskstream %1: cannot write to disk"), id()) << endmsg;
+ return -1;
+ }
+
+ (*chan)->buf->increment_read_ptr (to_write);
+ (*chan)->curr_capture_cnt += to_write;
+ }
+ }
+
+ /* MIDI*/
+
+ out:
+ return ret;
+
+}
+
+void
+DiskWriter::reset_write_sources (bool mark_write_complete, bool /*force*/)
+{
+ ChannelList::iterator chan;
+ boost::shared_ptr<ChannelList> c = channels.reader();
+ uint32_t n;
+
+ if (!_session.writable() || !recordable()) {
+ return;
+ }
+
+ capturing_sources.clear ();
+
+ for (chan = c->begin(), n = 0; chan != c->end(); ++chan, ++n) {
+
+ if (!destructive()) {
+
+ if ((*chan)->write_source) {
+
+ if (mark_write_complete) {
+ Source::Lock lock((*chan)->write_source->mutex());
+ (*chan)->write_source->mark_streaming_write_completed (lock);
+ (*chan)->write_source->done_with_peakfile_writes ();
+ }
+
+ if ((*chan)->write_source->removable()) {
+ (*chan)->write_source->mark_for_remove ();
+ (*chan)->write_source->drop_references ();
+ }
+
+ (*chan)->write_source.reset ();
+ }
+
+ use_new_write_source (DataType::AUDIO, n);
+
+ if (record_enabled()) {
+ capturing_sources.push_back ((*chan)->write_source);
+ }
+
+ } else {
+
+ if ((*chan)->write_source == 0) {
+ use_new_write_source (DataType::AUDIO, n);
+ }
+ }
+ }
+
+ if (_midi_write_source) {
+ if (mark_write_complete) {
+ Source::Lock lm(_midi_write_source->mutex());
+ _midi_write_source->mark_streaming_write_completed (lm);
+ }
+
+ use_new_write_source (DataType::MIDI);
+
+ if (destructive() && !c->empty ()) {
+
+ /* we now have all our write sources set up, so create the
+ playlist's single region.
+ */
+
+ if (_playlists[DataType::MIDI]->empty()) {
+ setup_destructive_playlist ();
+ }
+ }
+ }
+}
+
+int
+DiskWriter::use_new_write_source (DataType dt, uint32_t n)
+{
+ if (dt == DataType::MIDI) {
+
+ _accumulated_capture_offset = 0;
+ _midi_write_source.reset();
+
+ try {
+ _midi_write_source = boost::dynamic_pointer_cast<SMFSource>(
+ _session.create_midi_source_for_session (write_source_name ()));
+
+ if (!_midi_write_source) {
+ throw failed_constructor();
+ }
+ }
+
+ catch (failed_constructor &err) {
+ error << string_compose (_("%1:%2 new capture file not initialized correctly"), _name, n) << endmsg;
+ _midi_write_source.reset();
+ return -1;
+ }
+ } else {
+ boost::shared_ptr<ChannelList> c = channels.reader();
+
+ if (!recordable()) {
+ return 1;
+ }
+
+ if (n >= c->size()) {
+ error << string_compose (_("AudioDiskstream: channel %1 out of range"), n) << endmsg;
+ return -1;
+ }
+
+ ChannelInfo* chan = (*c)[n];
+
+ try {
+ if ((chan->write_source = _session.create_audio_source_for_session (
+ c->size(), write_source_name(), n, destructive())) == 0) {
+ throw failed_constructor();
+ }
+ }
+
+ catch (failed_constructor &err) {
+ error << string_compose (_("%1:%2 new capture file not initialized correctly"), _name, n) << endmsg;
+ chan->write_source.reset ();
+ return -1;
+ }
+
+ /* do not remove destructive files even if they are empty */
+
+ chan->write_source->set_allow_remove_if_empty (!destructive());
+ }
+
+ return 0;
+}
+
+void
+DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abort_capture)
+{
+ uint32_t buffer_position;
+ bool more_work = true;
+ int err = 0;
+ boost::shared_ptr<AudioRegion> region;
+ framecnt_t total_capture;
+ SourceList srcs;
+ SourceList::iterator src;
+ ChannelList::iterator chan;
+ vector<CaptureInfo*>::iterator ci;
+ boost::shared_ptr<ChannelList> c = channels.reader();
+ uint32_t n = 0;
+ bool mark_write_completed = false;
+
+ finish_capture (c);
+
+ boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> (_playlists[DataType::AUDIO]);
+
+ /* butler is already stopped, but there may be work to do
+ to flush remaining data to disk.
+ */
+
+ while (more_work && !err) {
+ switch (do_flush (TransportContext, true)) {
+ case 0:
+ more_work = false;
+ break;
+ case 1:
+ break;
+ case -1:
+ error << string_compose(_("AudioDiskstream \"%1\": cannot flush captured data to disk!"), _name) << endmsg;
+ err++;
+ }
+ }
+
+ /* XXX is there anything we can do if err != 0 ? */
+ Glib::Threads::Mutex::Lock lm (capture_info_lock);
+
+ if (capture_info.empty()) {
+ return;
+ }
+
+ if (abort_capture) {
+
+ if (destructive()) {
+ goto outout;
+ }
+
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
+
+ if ((*chan)->write_source) {
+
+ (*chan)->write_source->mark_for_remove ();
+ (*chan)->write_source->drop_references ();
+ (*chan)->write_source.reset ();
+ }
+
+ /* new source set up in "out" below */
+ }
+
+ goto out;
+ }
+
+ for (total_capture = 0, ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
+ total_capture += (*ci)->frames;
+ }
+
+ /* figure out the name for this take */
+
+ for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
+
+ boost::shared_ptr<AudioFileSource> s = (*chan)->write_source;
+
+ if (s) {
+ srcs.push_back (s);
+ s->update_header (capture_info.front()->start, when, twhen);
+ s->set_captured_for (_name.val());
+ s->mark_immutable ();
+
+ if (Config->get_auto_analyse_audio()) {
+ Analyser::queue_source_for_analysis (s, true);
+ }
+
+ DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("newly captured source %1 length %2\n", s->path(), s->length (0)));
+ }
+ }
+
+ if (!pl) {
+ goto midi;
+ }
+
+ /* destructive tracks have a single, never changing region */
+
+ if (destructive()) {
+
+ /* send a signal that any UI can pick up to do the right thing. there is
+ a small problem here in that a UI may need the peak data to be ready
+ for the data that was recorded and this isn't interlocked with that
+ process. this problem is deferred to the UI.
+ */
+
+ pl->LayeringChanged(); // XXX this may not get the UI to do the right thing
+
+ } else {
+
+ string whole_file_region_name;
+ whole_file_region_name = region_name_from_path (c->front()->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
+ children of this one (later!)
+ */
+
+ try {
+ PropertyList plist;
+
+ plist.add (Properties::start, c->front()->write_source->last_capture_start_frame());
+ plist.add (Properties::length, total_capture);
+ plist.add (Properties::name, whole_file_region_name);
+ boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist));
+ rx->set_automatic (true);
+ rx->set_whole_file (true);
+
+ region = boost::dynamic_pointer_cast<AudioRegion> (rx);
+ region->special_set_position (capture_info.front()->start);
+ }
+
+
+ catch (failed_constructor& err) {
+ error << string_compose(_("%1: could not create region for complete audio file"), _name) << endmsg;
+ /* XXX what now? */
+ }
+
+ _last_capture_sources.insert (_last_capture_sources.end(), srcs.begin(), srcs.end());
+
+ pl->clear_changes ();
+ pl->set_capture_insertion_in_progress (true);
+ pl->freeze ();
+
+ const framepos_t preroll_off = _session.preroll_record_trim_len ();
+ for (buffer_position = c->front()->write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
+
+ string region_name;
+
+ RegionFactory::region_name (region_name, whole_file_region_name, false);
+
+ DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 capture bufpos %5 start @ %2 length %3 add new region %4\n",
+ _name, (*ci)->start, (*ci)->frames, region_name, buffer_position));
+
+ try {
+
+ PropertyList plist;
+
+ plist.add (Properties::start, buffer_position);
+ plist.add (Properties::length, (*ci)->frames);
+ plist.add (Properties::name, region_name);
+
+ boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist));
+ region = boost::dynamic_pointer_cast<AudioRegion> (rx);
+ if (preroll_off > 0) {
+ region->trim_front (buffer_position + preroll_off);
+ }
+ }
+
+ catch (failed_constructor& err) {
+ error << _("AudioDiskstream: could not create region for captured audio!") << endmsg;
+ continue; /* XXX is this OK? */
+ }
+
+ i_am_the_modifier++;
+
+ pl->add_region (region, (*ci)->start + preroll_off, 1, non_layered());
+ pl->set_layer (region, DBL_MAX);
+ i_am_the_modifier--;
+
+ buffer_position += (*ci)->frames;
+ }
+
+ pl->thaw ();
+ pl->set_capture_insertion_in_progress (false);
+ _session.add_command (new StatefulDiffCommand (pl));
+ }
+
+ mark_write_completed = true;
+
+ out:
+ reset_write_sources (mark_write_completed);
+
+ outout:
+
+ for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
+ delete *ci;
+ }
+
+ capture_info.clear ();
+ capture_start_frame = 0;
+
+ midi:
+ return;
+}
+
+#if 0 // MIDI PART
+void
+DiskWriter::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen*/, bool abort_capture)
+{
+ bool more_work = true;
+ int err = 0;
+ boost::shared_ptr<MidiRegion> region;
+ MidiRegion::SourceList srcs;
+ MidiRegion::SourceList::iterator src;
+ vector<CaptureInfo*>::iterator ci;
+
+ finish_capture ();
+
+ /* butler is already stopped, but there may be work to do
+ to flush remaining data to disk.
+ */
+
+ while (more_work && !err) {
+ switch (do_flush (TransportContext, true)) {
+ case 0:
+ more_work = false;
+ break;
+ case 1:
+ break;
+ case -1:
+ error << string_compose(_("MidiDiskstream \"%1\": cannot flush captured data to disk!"), _name) << endmsg;
+ err++;
+ }
+ }
+
+ /* XXX is there anything we can do if err != 0 ? */
+ Glib::Threads::Mutex::Lock lm (capture_info_lock);
+
+ if (capture_info.empty()) {
+ goto no_capture_stuff_to_do;
+ }
+
+ if (abort_capture) {
+
+ if (_write_source) {
+ _write_source->mark_for_remove ();
+ _write_source->drop_references ();
+ _write_source.reset();
+ }
+
+ /* new source set up in "out" below */
+
+ } else {
+
+ framecnt_t total_capture = 0;
+ for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
+ total_capture += (*ci)->frames;
+ }
+
+ if (_write_source->length (capture_info.front()->start) != 0) {
+
+ /* phew, we have data */
+
+ Source::Lock source_lock(_write_source->mutex());
+
+ /* figure out the name for this take */
+
+ srcs.push_back (_write_source);
+
+ _write_source->set_timeline_position (capture_info.front()->start);
+ _write_source->set_captured_for (_name);
+
+ /* set length in beats to entire capture length */
+
+ BeatsFramesConverter converter (_session.tempo_map(), capture_info.front()->start);
+ const Evoral::Beats total_capture_beats = converter.from (total_capture);
+ _write_source->set_length_beats (total_capture_beats);
+
+ /* flush to disk: this step differs from the audio path,
+ where all the data is already on disk.
+ */
+
+ _write_source->mark_midi_streaming_write_completed (source_lock, Evoral::Sequence<Evoral::Beats>::ResolveStuckNotes, total_capture_beats);
+
+ /* 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. luckily, we can rely on
+ MidiSource::mark_streaming_write_completed() to have
+ already done the necessary work for that.
+ */
+
+ 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
+ children of this one (later!)
+ */
+
+ try {
+ PropertyList plist;
+
+ plist.add (Properties::name, whole_file_region_name);
+ plist.add (Properties::whole_file, true);
+ plist.add (Properties::automatic, true);
+ plist.add (Properties::start, 0);
+ plist.add (Properties::length, total_capture);
+ plist.add (Properties::layer, 0);
+
+ boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist));
+
+ region = boost::dynamic_pointer_cast<MidiRegion> (rx);
+ region->special_set_position (capture_info.front()->start);
+ }
+
+
+ catch (failed_constructor& err) {
+ error << string_compose(_("%1: could not create region for complete midi file"), _name) << endmsg;
+ /* XXX what now? */
+ }
+
+ _last_capture_sources.insert (_last_capture_sources.end(), srcs.begin(), srcs.end());
+
+ _playlist->clear_changes ();
+ _playlist->freeze ();
+
+ /* 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;
+ }
+
+ const framepos_t preroll_off = _session.preroll_record_trim_len ();
+ for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
+
+ string region_name;
+
+ RegionFactory::region_name (region_name, _write_source->name(), false);
+
+ DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 capture start @ %2 length %3 add new region %4\n",
+ _name, (*ci)->start, (*ci)->frames, region_name));
+
+
+ // cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add a region\n";
+
+ try {
+ PropertyList plist;
+
+ /* 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::length_beats, converter.from((*ci)->frames).to_double());
+ plist.add (Properties::name, region_name);
+
+ boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist));
+ region = boost::dynamic_pointer_cast<MidiRegion> (rx);
+ if (preroll_off > 0) {
+ region->trim_front ((*ci)->start - initial_capture + preroll_off);
+ }
+ }
+
+ catch (failed_constructor& err) {
+ error << _("MidiDiskstream: could not create region for captured midi!") << endmsg;
+ continue; /* XXX is this OK? */
+ }
+
+ // cerr << "add new region, buffer position = " << buffer_position << " @ " << (*ci)->start << endl;
+
+ i_am_the_modifier++;
+ _playlist->add_region (region, (*ci)->start + preroll_off);
+ i_am_the_modifier--;
+ }
+
+ _playlist->thaw ();
+ _session.add_command (new StatefulDiffCommand(_playlist));
+
+ } else {
+
+ /* No data was recorded, so this capture will
+ effectively be aborted; do the same as we
+ do for an explicit abort.
+ */
+
+ if (_write_source) {
+ _write_source->mark_for_remove ();
+ _write_source->drop_references ();
+ _write_source.reset();
+ }
+ }
+
+ }
+
+ use_new_write_source (0);
+
+ for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
+ delete *ci;
+ }
+
+ capture_info.clear ();
+ capture_start_frame = 0;
+
+ no_capture_stuff_to_do:
+
+ reset_tracker ();
+}
+#endif
+
+void
+DiskWriter::transport_looped (framepos_t transport_frame)
+{
+ if (was_recording) {
+ // all we need to do is finish this capture, with modified capture length
+ boost::shared_ptr<ChannelList> c = channels.reader();
+
+ finish_capture (c);
+
+ // the next region will start recording via the normal mechanism
+ // we'll set the start position to the current transport pos
+ // 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_framepos;
+ was_recording = true;
+
+ if (recordable() && destructive()) {
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
+
+ RingBufferNPT<CaptureTransition>::rw_vector transvec;
+ (*chan)->capture_transition_buf->get_write_vector(&transvec);
+
+ if (transvec.len[0] > 0) {
+ transvec.buf[0]->type = CaptureStart;
+ transvec.buf[0]->capture_val = capture_start_frame;
+ (*chan)->capture_transition_buf->increment_write_ptr(1);
+ }
+ else {
+ // bad!
+ fatal << X_("programming error: capture_transition_buf is full on rec loop! inconceivable!")
+ << endmsg;
+ }
+ }
+ }
+
+ }
+
+ /* Here we only keep track of the number of captured loops so monotonic
+ event times can be delivered to the write source in process(). Trying
+ to be clever here is a world of trouble, it is better to simply record
+ the input in a straightforward non-destructive way. In the future when
+ we want to implement more clever MIDI looping modes it should be done in
+ the Source and/or entirely after the capture is finished.
+ */
+ if (was_recording) {
+ g_atomic_int_add(const_cast<gint*> (&_num_captured_loops), 1);
+ }
+}
+
+void
+DiskWriter::setup_destructive_playlist ()
+{
+ SourceList srcs;
+ boost::shared_ptr<ChannelList> c = channels.reader();
+
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
+ srcs.push_back ((*chan)->write_source);
+ }
+
+ /* a single full-sized region */
+
+ assert (!srcs.empty ());
+
+ PropertyList plist;
+ plist.add (Properties::name, _name.val());
+ plist.add (Properties::start, 0);
+ plist.add (Properties::length, max_framepos - srcs.front()->natural_position());
+
+ boost::shared_ptr<Region> region (RegionFactory::create (srcs, plist));
+ _playlists[DataType::AUDIO]->add_region (region, srcs.front()->natural_position());
+
+ /* apply region properties and update write sources */
+ use_destructive_playlist();
+}
+
+void
+DiskWriter::use_destructive_playlist ()
+{
+ /* this is called from the XML-based constructor or ::set_destructive. when called,
+ we already have a playlist and a region, but we need to
+ set up our sources for write. we use the sources associated
+ with the (presumed single, full-extent) region.
+ */
+
+ boost::shared_ptr<Region> rp;
+ {
+ const RegionList& rl (_playlists[DataType::AUDIO]->region_list_property().rlist());
+ if (rl.size() > 0) {
+ /* this can happen when dragging a region onto a tape track */
+ assert((rl.size() == 1));
+ rp = rl.front();
+ }
+ }
+
+ if (!rp) {
+ reset_write_sources (false, true);
+ return;
+ }
+
+ boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (rp);
+
+ if (region == 0) {
+ throw failed_constructor();
+ }
+
+ /* be sure to stretch the region out to the maximum length (non-musical)*/
+
+ region->set_length (max_framepos - region->position(), 0);
+
+ uint32_t n;
+ ChannelList::iterator chan;
+ boost::shared_ptr<ChannelList> c = channels.reader();
+
+ for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
+ (*chan)->write_source = boost::dynamic_pointer_cast<AudioFileSource>(region->source (n));
+ assert((*chan)->write_source);
+ (*chan)->write_source->set_allow_remove_if_empty (false);
+
+ /* this might be false if we switched modes, so force it */
+
+#ifdef XXX_OLD_DESTRUCTIVE_API_XXX
+ (*chan)->write_source->set_destructive (true);
+#else
+ // should be set when creating the source or loading the state
+ assert ((*chan)->write_source->destructive());
+#endif
+ }
+
+ /* the source list will never be reset for a destructive track */
+}
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index 5d315c52a7..6cbf700f03 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -33,10 +33,13 @@
#include "pbd/types_convert.h"
#include "evoral/midi_util.h"
+#include "ardour/amp.h"
#include "ardour/beats_frames_converter.h"
#include "ardour/buffer_set.h"
#include "ardour/debug.h"
#include "ardour/delivery.h"
+#include "ardour/disk_reader.h"
+#include "ardour/disk_writer.h"
#include "ardour/event_type_map.h"
#include "ardour/meter.h"
#include "ardour/midi_diskstream.h"
@@ -72,11 +75,15 @@ MidiTrack::MidiTrack (Session& sess, string name, TrackMode mode)
: Track (sess, name, PresentationInfo::MidiTrack, mode, DataType::MIDI)
, _immediate_events(6096) // FIXME: size?
, _step_edit_ring_buffer(64) // FIXME: size?
- , _note_mode(Sustained)
+ , _note_mode (Sustained)
, _step_editing (false)
, _input_active (true)
{
_session.SessionLoaded.connect_same_thread (*this, boost::bind (&MidiTrack::restore_controls, this));
+
+ _disk_writer->set_note_mode (_note_mode);
+ _disk_reader->reset_tracker ();
+
}
MidiTrack::~MidiTrack ()
@@ -126,36 +133,6 @@ MidiTrack::can_be_record_enabled ()
return Track::can_be_record_enabled ();
}
-void
-MidiTrack::set_diskstream (boost::shared_ptr<Diskstream> ds)
-{
- /* We have to do this here, as Track::set_diskstream will cause a buffer refill,
- and the diskstream must be set up to fill its buffers using the correct _note_mode.
- */
- boost::shared_ptr<MidiDiskstream> mds = boost::dynamic_pointer_cast<MidiDiskstream> (ds);
- mds->set_note_mode (_note_mode);
-
- Track::set_diskstream (ds);
-
- mds->reset_tracker ();
-
- _diskstream->set_track (this);
- _diskstream->set_record_enabled (false);
-
- _diskstream_data_recorded_connection.disconnect ();
- mds->DataRecorded.connect_same_thread (
- _diskstream_data_recorded_connection,
- boost::bind (&MidiTrack::diskstream_data_recorded, this, _1));
-
- DiskstreamChanged (); /* EMIT SIGNAL */
-}
-
-boost::shared_ptr<MidiDiskstream>
-MidiTrack::midi_diskstream() const
-{
- return boost::dynamic_pointer_cast<MidiDiskstream>(_diskstream);
-}
-
int
MidiTrack::set_state (const XMLNode& node, int version)
{
@@ -323,10 +300,6 @@ MidiTrack::set_state_part_two ()
}
}
- if (midi_diskstream ()) {
- midi_diskstream()->set_block_size (_session.get_block_size ());
- }
-
return;
}
@@ -364,18 +337,11 @@ int
MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& need_butler)
{
Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
+
if (!lm.locked()) {
- boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream();
- framecnt_t playback_distance = diskstream->calculate_playback_distance(nframes);
- if (can_internal_playback_seek(::llabs(playback_distance))) {
- /* TODO should declick, and/or note-off */
- internal_playback_seek(playback_distance);
- }
return 0;
}
- boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream();
-
if (n_outputs().n_total() == 0 && _processors.empty()) {
return 0;
}
@@ -388,22 +354,8 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
return 0;
}
- framepos_t transport_frame = _session.transport_frame();
-
- int dret;
- framecnt_t playback_distance;
-
- if ((nframes = check_initial_delay (nframes, transport_frame)) == 0) {
- /* need to do this so that the diskstream sets its
- playback distance to zero, thus causing diskstream::commit
- to do nothing.
- */
- BufferSet bufs; /* empty set - is OK, since nothing will happen */
-
- dret = diskstream->process (bufs, transport_frame, 0, playback_distance, false);
- need_butler = diskstream->commit (playback_distance);
- return dret;
- }
+ _silent = false;
+ _amp->apply_gain_automation (false);
BufferSet& bufs = _session.get_route_buffers (n_process_buffers());
@@ -416,47 +368,16 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
_meter->run (bufs, start_frame, end_frame, 1.0 /*speed()*/, nframes, true);
}
-
- _silent = false;
-
- if ((dret = diskstream->process (bufs, transport_frame, nframes, playback_distance, (monitoring_state() == MonitoringDisk))) != 0) {
- need_butler = diskstream->commit (playback_distance);
- silence (nframes);
- return dret;
- }
-
- /* note diskstream uses our filter to filter/map playback channels appropriately. */
-
- if (monitoring_state() == MonitoringInput) {
-
- /* not actually recording, but we want to hear the input material anyway,
- at least potentially (depending on monitoring options)
- */
-
- /* because the playback buffer is event based and not a
- * continuous stream, we need to make sure that we empty
- * it of events every cycle to avoid it filling up with events
- * read from disk, while we are actually monitoring input
- */
-
- diskstream->flush_playback (start_frame, end_frame);
-
- }
-
-
/* append immediate messages to the first MIDI buffer (thus sending it to the first output port) */
write_out_of_band_data (bufs, start_frame, end_frame, nframes);
/* final argument: don't waste time with automation if we're not recording or rolling */
- process_output_buffers (bufs, start_frame, end_frame, nframes,
- declick, (!diskstream->record_enabled() && !_session.transport_stopped()));
+ process_output_buffers (bufs, start_frame, end_frame, nframes, declick, (!_disk_writer->record_enabled() && !_session.transport_stopped()));
flush_processor_buffers_locked (nframes);
- need_butler = diskstream->commit (playback_distance);
-
return 0;
}
@@ -485,7 +406,7 @@ MidiTrack::realtime_locate ()
(*i)->realtime_locate ();
}
- midi_diskstream()->reset_tracker ();
+ _disk_reader->reset_tracker ();
}
void
@@ -507,7 +428,7 @@ MidiTrack::non_realtime_locate (framepos_t pos)
{
Track::non_realtime_locate(pos);
- boost::shared_ptr<MidiPlaylist> playlist = midi_diskstream()->midi_playlist();
+ boost::shared_ptr<MidiPlaylist> playlist = _disk_writer->midi_playlist();
if (!playlist) {
return;
}
@@ -612,11 +533,9 @@ MidiTrack::export_stuff (BufferSet& buffers,
return -1;
}
- boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream();
-
Glib::Threads::RWLock::ReaderLock rlock (_processor_lock);
- boost::shared_ptr<MidiPlaylist> mpl = boost::dynamic_pointer_cast<MidiPlaylist>(diskstream->playlist());
+ boost::shared_ptr<MidiPlaylist> mpl = _disk_writer->midi_playlist();
if (!mpl) {
return -2;
}
@@ -665,7 +584,7 @@ void
MidiTrack::set_note_mode (NoteMode m)
{
_note_mode = m;
- midi_diskstream()->set_note_mode(m);
+ _disk_writer->set_note_mode(m);
}
std::string
@@ -809,7 +728,7 @@ MidiTrack::set_step_editing (bool yn)
boost::shared_ptr<SMFSource>
MidiTrack::write_source (uint32_t)
{
- return midi_diskstream()->write_source ();
+ return _disk_writer->midi_write_source ();
}
void
@@ -847,7 +766,7 @@ MidiTrack::set_capture_channel_mask (uint16_t mask)
boost::shared_ptr<MidiPlaylist>
MidiTrack::midi_playlist ()
{
- return midi_diskstream()->midi_playlist ();
+ return boost::dynamic_pointer_cast<MidiPlaylist> (_playlists[DataType::MIDI]);
}
void
@@ -906,7 +825,7 @@ MidiTrack::diskstream_factory (XMLNode const & node)
boost::shared_ptr<MidiBuffer>
MidiTrack::get_gui_feed_buffer () const
{
- return midi_diskstream()->get_gui_feed_buffer ();
+ return _disk_reader->get_gui_feed_buffer ();
}
void
@@ -922,7 +841,7 @@ MidiTrack::act_on_mute ()
/* If we haven't got a diskstream yet, there's nothing to worry about,
and we can't call get_channel_mask() anyway.
*/
- if (!midi_diskstream()) {
+ if (!_disk_writer) {
return;
}
@@ -945,7 +864,7 @@ MidiTrack::act_on_mute ()
}
/* Resolve active notes. */
- midi_diskstream()->resolve_tracker(_immediate_events, Port::port_offset());
+ _disk_reader->resolve_tracker(_immediate_events, Port::port_offset());
}
}
@@ -967,11 +886,7 @@ MidiTrack::monitoring_changed (bool self, Controllable::GroupControlDisposition
}
}
- boost::shared_ptr<MidiDiskstream> md (midi_diskstream());
-
- if (md) {
- md->reset_tracker ();
- }
+ _disk_reader->reset_tracker ();
}
MonitorState
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 8814d01978..28b99fd427 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -1546,7 +1546,6 @@ Session::hookup_io ()
if (a->init()) {
throw failed_constructor ();
}
- a->use_new_diskstream ();
auditioner = a;
}
@@ -2625,8 +2624,6 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, bool s
track->set_strict_io (true);
}
- track->use_new_diskstream();
-
BOOST_MARK_TRACK (track);
{
@@ -2648,8 +2645,6 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, bool s
route_group->add (track);
}
- track->DiskstreamChanged.connect_same_thread (*this, boost::bind (&Session::resort_routes, this));
-
new_routes.push_back (track);
ret.push_back (track);
}
@@ -3223,8 +3218,6 @@ Session::new_audio_track (int input_channels, int output_channels, RouteGroup* r
}
}
- track->use_new_diskstream();
-
BOOST_MARK_TRACK (track);
{
@@ -3253,8 +3246,6 @@ Session::new_audio_track (int input_channels, int output_channels, RouteGroup* r
track->non_realtime_input_change();
- track->DiskstreamChanged.connect_same_thread (*this, boost::bind (&Session::resort_routes, this));
-
new_routes.push_back (track);
ret.push_back (track);
}
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index b454c33367..c818943e1d 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -1845,7 +1845,7 @@ Session::XMLRouteFactory_2X (const XMLNode& node, int version)
return ret;
}
- track->set_diskstream (*i);
+ // XXX DISK NEED TO SET UP DISKSTREAM ???
BOOST_MARK_TRACK (track);
ret = track;
diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc
index d7d9a0a9d1..5cc87f8ecd 100644
--- a/libs/ardour/track.cc
+++ b/libs/ardour/track.cc
@@ -21,11 +21,14 @@
#include "ardour/debug.h"
#include "ardour/delivery.h"
#include "ardour/diskstream.h"
+#include "ardour/disk_reader.h"
+#include "ardour/disk_writer.h"
#include "ardour/event_type_map.h"
#include "ardour/io_processor.h"
#include "ardour/meter.h"
#include "ardour/monitor_control.h"
#include "ardour/playlist.h"
+#include "ardour/playlist_factory.h"
#include "ardour/port.h"
#include "ardour/processor.h"
#include "ardour/profile.h"
@@ -51,6 +54,25 @@ Track::Track (Session& sess, string name, PresentationInfo::Flag flag, TrackMode
{
_freeze_record.state = NoFreeze;
_declickable = true;
+
+ DiskIOProcessor::Flag dflags = DiskIOProcessor::Recordable;
+
+ if (_mode == Destructive && !Profile->get_trx()) {
+ dflags = DiskIOProcessor::Flag (dflags | DiskIOProcessor::Destructive);
+ } else if (_mode == NonLayered){
+ dflags = DiskIOProcessor::Flag(dflags | DiskIOProcessor::NonLayered);
+ }
+
+ _disk_reader.reset (new DiskReader (sess, name, dflags));
+
+ _disk_reader->set_block_size (_session.get_block_size ());
+ _disk_reader->set_route (shared_from_this());
+ _disk_reader->do_refill_with_alloc ();
+
+ _disk_writer.reset (new DiskWriter (sess, name, dflags));
+ _disk_writer->set_block_size (_session.get_block_size ());
+ _disk_writer->set_route (shared_from_this());
+
}
Track::~Track ()
@@ -86,18 +108,6 @@ Track::init ()
return 0;
}
-void
-Track::use_new_diskstream ()
-{
- boost::shared_ptr<Diskstream> ds = create_diskstream ();
-
- ds->do_refill_with_alloc ();
- ds->set_block_size (_session.get_block_size ());
- ds->playlist()->set_orig_track_id (id());
-
- set_diskstream (ds);
-}
-
XMLNode&
Track::get_state ()
{
@@ -128,18 +138,12 @@ Track::set_state (const XMLNode& node, int version)
XMLNode* child;
- if (version >= 3000) {
+ if (version >= 3000 && version < 4000) {
if ((child = find_named_node (node, X_("Diskstream"))) != 0) {
- boost::shared_ptr<Diskstream> ds = diskstream_factory (*child);
- ds->do_refill_with_alloc ();
- set_diskstream (ds);
+ /* XXX DISK ... setup reader/writer from XML */
}
}
- if (_diskstream) {
- _diskstream->playlist()->set_orig_track_id (id());
- }
-
/* set rec-enable control *AFTER* setting up diskstream, because it may
want to operate on the diskstream as it sets its own state
*/
@@ -406,7 +410,7 @@ Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
*/
}
- _diskstream->check_record_status (start_frame, can_record);
+ _disk_writer->check_record_status (start_frame, can_record);
bool be_silent;
@@ -443,7 +447,7 @@ Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
if (_meter_point == MeterInput) {
/* still need input monitoring and metering */
- bool const track_rec = _diskstream->record_enabled ();
+ bool const track_rec = _disk_writer->record_enabled ();
bool const auto_input = _session.config.get_auto_input ();
bool const software_monitor = Config->get_monitoring_model() == SoftwareMonitoring;
bool const tape_machine_mode = Config->get_tape_machine_mode ();
@@ -502,10 +506,11 @@ Track::silent_roll (pframes_t nframes, framepos_t /*start_frame*/, framepos_t /*
{
Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
if (!lm.locked()) {
- framecnt_t playback_distance = _diskstream->calculate_playback_distance(nframes);
- if (can_internal_playback_seek(playback_distance)) {
- internal_playback_seek(playback_distance);
- }
+ // XXX DISK reader needs to seek ahead the correct distance ?? OR DOES IT ?
+ //framecnt_t playback_distance = _disk_reader->calculate_playback_distance(nframes);
+ //if (can_internal_playback_seek(playback_distance)) {
+ // internal_playback_seek(playback_distance);
+ //}
return 0;
}
@@ -524,42 +529,9 @@ Track::silent_roll (pframes_t nframes, framepos_t /*start_frame*/, framepos_t /*
silence (nframes);
flush_processor_buffers_locked (nframes);
- framecnt_t playback_distance;
-
- BufferSet& bufs (_session.get_route_buffers (n_process_buffers(), true));
-
- int const dret = _diskstream->process (bufs, _session.transport_frame(), nframes, playback_distance, false);
- need_butler = _diskstream->commit (playback_distance);
- return dret;
-}
-
-void
-Track::set_diskstream (boost::shared_ptr<Diskstream> ds)
-{
- _diskstream = ds;
-
- ds->PlaylistChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_playlist_changed, this));
- diskstream_playlist_changed ();
- ds->SpeedChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_speed_changed, this));
- ds->AlignmentStyleChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_alignment_style_changed, this));
-}
-
-void
-Track::diskstream_playlist_changed ()
-{
- PlaylistChanged (); /* EMIT SIGNAL */
-}
-
-void
-Track::diskstream_speed_changed ()
-{
- SpeedChanged (); /* EMIT SIGNAL */
-}
-
-void
-Track::diskstream_alignment_style_changed ()
-{
- AlignmentStyleChanged (); /* EMIT SIGNAL */
+ //BufferSet& bufs (_session.get_route_buffers (n_process_buffers(), true));
+ // XXXX DISKWRITER/READER ADVANCE, SET need_butler
+ return 0;
}
boost::shared_ptr<Playlist>
@@ -571,103 +543,100 @@ Track::playlist ()
void
Track::request_input_monitoring (bool m)
{
- _diskstream->request_input_monitoring (m);
+ // XXX DISK
}
void
Track::ensure_input_monitoring (bool m)
{
- _diskstream->ensure_input_monitoring (m);
+ // XXX DISK
}
bool
Track::destructive () const
{
- return _diskstream->destructive ();
+ return _disk_writer->destructive ();
}
list<boost::shared_ptr<Source> > &
Track::last_capture_sources ()
{
- return _diskstream->last_capture_sources ();
+ return _disk_writer->last_capture_sources ();
}
void
Track::set_capture_offset ()
{
- _diskstream->set_capture_offset ();
+ _disk_writer->set_capture_offset ();
}
std::string
Track::steal_write_source_name()
{
- return _diskstream->steal_write_source_name ();
+ return _disk_writer->steal_write_source_name ();
}
void
Track::reset_write_sources (bool r, bool force)
{
- _diskstream->reset_write_sources (r, force);
+ _disk_writer->reset_write_sources (r, force);
}
float
Track::playback_buffer_load () const
{
- return _diskstream->playback_buffer_load ();
+ return _disk_reader->buffer_load ();
}
float
Track::capture_buffer_load () const
{
- return _diskstream->capture_buffer_load ();
+ return _disk_writer->buffer_load ();
}
int
Track::do_refill ()
{
- return _diskstream->do_refill ();
+ return _disk_reader->do_refill ();
}
int
Track::do_flush (RunContext c, bool force)
{
- return _diskstream->do_flush (c, force);
+ return _disk_writer->do_flush (c, force);
}
void
Track::set_pending_overwrite (bool o)
{
- _diskstream->set_pending_overwrite (o);
+ _disk_reader->set_pending_overwrite (o);
}
int
Track::seek (framepos_t p, bool complete_refill)
{
- return _diskstream->seek (p, complete_refill);
+ if (_disk_reader->seek (p, complete_refill)) {
+ return -1;
+ }
+ return _disk_writer->seek (p, complete_refill);
}
bool
Track::hidden () const
{
- return _diskstream->hidden ();
+ return _disk_writer->hidden () || _disk_reader->hidden();
}
int
Track::can_internal_playback_seek (framecnt_t p)
{
- return _diskstream->can_internal_playback_seek (p);
+ return _disk_reader->can_internal_playback_seek (p);
}
int
Track::internal_playback_seek (framecnt_t p)
{
- return _diskstream->internal_playback_seek (p);
-}
-
-void
-Track::non_realtime_input_change ()
-{
- _diskstream->non_realtime_input_change ();
+ return _disk_reader->internal_playback_seek (p);
}
void
@@ -679,74 +648,82 @@ Track::non_realtime_locate (framepos_t p)
/* don't waste i/o cycles and butler calls
for hidden (secret) tracks
*/
- _diskstream->non_realtime_locate (p);
+ _disk_reader->non_realtime_locate (p);
+ _disk_writer->non_realtime_locate (p);
}
}
void
Track::non_realtime_set_speed ()
{
- _diskstream->non_realtime_set_speed ();
+ _disk_reader->non_realtime_set_speed ();
}
int
Track::overwrite_existing_buffers ()
{
- return _diskstream->overwrite_existing_buffers ();
+ return _disk_reader->overwrite_existing_buffers ();
}
framecnt_t
Track::get_captured_frames (uint32_t n) const
{
- return _diskstream->get_captured_frames (n);
+ return _disk_writer->get_captured_frames (n);
}
int
Track::set_loop (Location* l)
{
- return _diskstream->set_loop (l);
+ if (_disk_reader->set_loop (l)) {
+ return -1;
+ }
+ return _disk_writer->set_loop (l);
}
void
Track::transport_looped (framepos_t p)
{
- _diskstream->transport_looped (p);
+ return _disk_writer->transport_looped (p);
}
bool
Track::realtime_set_speed (double s, bool g)
{
- return _diskstream->realtime_set_speed (s, g);
+ if (_disk_reader->realtime_set_speed (s, g)) {
+ return -1;
+ }
+ return _disk_writer->realtime_set_speed (s, g);
}
void
Track::transport_stopped_wallclock (struct tm & n, time_t t, bool g)
{
- _diskstream->transport_stopped_wallclock (n, t, g);
+ _disk_writer->transport_stopped_wallclock (n, t, g);
}
bool
Track::pending_overwrite () const
{
- return _diskstream->pending_overwrite ();
+ return _disk_reader->pending_overwrite ();
}
double
Track::speed () const
{
- return _diskstream->speed ();
+ return _disk_reader->speed ();
}
void
Track::prepare_to_stop (framepos_t t, framepos_t a)
{
- _diskstream->prepare_to_stop (t, a);
+ _disk_writer->prepare_to_stop (t, a);
}
void
Track::set_slaved (bool s)
{
- _diskstream->set_slaved (s);
+ _disk_reader->set_slaved (s);
+ _disk_writer->set_slaved (s);
}
ChanCount
@@ -758,71 +735,113 @@ Track::n_channels ()
framepos_t
Track::get_capture_start_frame (uint32_t n) const
{
- return _diskstream->get_capture_start_frame (n);
+ return _disk_writer->get_capture_start_frame (n);
}
AlignStyle
Track::alignment_style () const
{
- return _diskstream->alignment_style ();
+ return _disk_writer->alignment_style ();
}
AlignChoice
Track::alignment_choice () const
{
- return _diskstream->alignment_choice ();
+ return _disk_writer->alignment_choice ();
}
framepos_t
Track::current_capture_start () const
{
- return _diskstream->current_capture_start ();
+ return _disk_writer->current_capture_start ();
}
framepos_t
Track::current_capture_end () const
{
- return _diskstream->current_capture_end ();
+ return _disk_writer->current_capture_end ();
}
void
Track::playlist_modified ()
{
- _diskstream->playlist_modified ();
+ _disk_reader->playlist_modified ();
+}
+
+int
+Track::find_and_use_playlist (DataType dt, const string& name)
+{
+ boost::shared_ptr<Playlist> playlist;
+
+ if ((playlist = _session.playlists->by_name (name)) == 0) {
+ playlist = PlaylistFactory::create (dt, _session, name);
+ }
+
+ if (!playlist) {
+ error << string_compose(_("DiskIOProcessor: \"%1\" isn't an playlist"), name) << endmsg;
+ return -1;
+ }
+
+ return use_playlist (dt, playlist);
}
int
-Track::use_playlist (boost::shared_ptr<Playlist> p)
+Track::use_playlist (DataType dt, boost::shared_ptr<Playlist> p)
{
- int ret = _diskstream->use_playlist (p);
- if (ret == 0) {
- p->set_orig_track_id (id());
+ int ret;
+
+ if ((ret = _disk_reader->use_playlist (dt, p)) == 0) {
+ if ((ret = _disk_writer->use_playlist (dt, p)) == 0) {
+ p->set_orig_track_id (id());
+ }
}
+
return ret;
}
int
Track::use_copy_playlist ()
{
- int ret = _diskstream->use_copy_playlist ();
+ assert (_playlists[data_type()]);
- if (ret == 0) {
- _diskstream->playlist()->set_orig_track_id (id());
+ if (_playlists[data_type()] == 0) {
+ error << string_compose(_("DiskIOProcessor %1: there is no existing playlist to make a copy of!"), _name) << endmsg;
+ return -1;
}
- return ret;
+ string newname;
+ boost::shared_ptr<Playlist> playlist;
+
+ newname = Playlist::bump_name (_playlists[data_type()]->name(), _session);
+
+ if ((playlist = PlaylistFactory::create (_playlists[data_type()], newname)) == 0) {
+ return -1;
+ }
+
+ playlist->reset_shares();
+
+ return use_playlist (data_type(), playlist);
}
int
Track::use_new_playlist ()
{
- int ret = _diskstream->use_new_playlist ();
+ string newname;
+ boost::shared_ptr<Playlist> playlist = _playlists[data_type()];
- if (ret == 0) {
- _diskstream->playlist()->set_orig_track_id (id());
+ if (playlist) {
+ newname = Playlist::bump_name (playlist->name(), _session);
+ } else {
+ newname = Playlist::bump_name (_name, _session);
}
- return ret;
+ playlist = PlaylistFactory::create (data_type(), _session, newname, hidden());
+
+ if (!playlist) {
+ return -1;
+ }
+
+ return use_playlist (data_type(), playlist);
}
void
@@ -955,7 +974,7 @@ Track::monitoring_state () const
*/
bool const roll = _session.transport_rolling ();
- bool const track_rec = _diskstream->record_enabled ();
+ bool const track_rec = _disk_writer->record_enabled ();
bool const auto_input = _session.config.get_auto_input ();
bool const software_monitor = Config->get_monitoring_model() == SoftwareMonitoring;
bool const tape_machine_mode = Config->get_tape_machine_mode ();
@@ -1078,10 +1097,16 @@ Track::metering_state () const
bool rv;
if (_session.transport_rolling ()) {
// audio_track.cc || midi_track.cc roll() runs meter IFF:
- rv = _meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _diskstream->record_enabled());
+ rv = _meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _disk_writer->record_enabled());
} else {
// track no_roll() always metering if
rv = _meter_point == MeterInput;
}
return rv ? MeteringInput : MeteringRoute;
}
+
+void
+Track::non_realtime_input_change ()
+{
+ // XXX DISK do we need to do anything here anymore ?
+}