fully remove diskstream code

This commit is contained in:
Paul Davis 2017-04-10 11:44:48 +01:00
parent 361cab503b
commit 68e57101ad
18 changed files with 25 additions and 5975 deletions

View File

@ -86,7 +86,8 @@
#include "ardour/audioengine.h"
#include "ardour/audiofilesource.h"
#include "ardour/automation_watch.h"
#include "ardour/diskstream.h"
#include "ardour/disk_reader.h"
#include "ardour/disk_writer.h"
#include "ardour/filename_extensions.h"
#include "ardour/filesystem_paths.h"
#include "ardour/ltc_file_reader.h"
@ -396,8 +397,8 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
rec_button.set_name ("transport recenable button");
midi_panic_button.set_name ("transport button");
ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
ARDOUR::DiskWriter::Overrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
ARDOUR::DiskReader::Underrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());

View File

@ -23,7 +23,8 @@
#include "gtkmm2ext/gui_thread.h"
#include "ardour/audioengine.h"
#include "ardour/diskstream.h"
#include "ardour/disk_reader.h"
#include "ardour/disk_writer.h"
#include "ardour/plugin_manager.h"
#include "ardour/route.h"
#include "ardour/session.h"

View File

@ -77,8 +77,8 @@ STATIC(PluginListChanged, &(PluginManager::instance().PluginListChanged), 0)
STATIC(PluginStatusesChanged, &(PluginManager::instance().PluginStatusesChanged), 0)
// Diskstream static global
STATIC(DiskOverrun, &ARDOUR::Diskstream::DiskOverrun, 0)
STATIC(DiskUnderrun, &ARDOUR::Diskstream::DiskUnderrun, 0)
STATIC(DiskOverrun, &ARDOUR::DiskWriter::Overrun, 0)
STATIC(DiskUnderrun, &ARDOUR::DiskReader::Underrun, 0)
// Region static
STATIC(RegionPropertyChanged, &ARDOUR::Region::RegionPropertyChanged, 2)

View File

@ -1,270 +0,0 @@
/*
Copyright (C) 2000-2006 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __ardour_audio_diskstream_h__
#define __ardour_audio_diskstream_h__
#include <cmath>
#include <string>
#include <queue>
#include <map>
#include <vector>
#include <time.h>
#include <boost/utility.hpp>
#include "pbd/fastlog.h"
#include "pbd/ringbufferNPT.h"
#include "pbd/stateful.h"
#include "pbd/rcu.h"
#include "ardour/ardour.h"
#include "ardour/utils.h"
#include "ardour/diskstream.h"
#include "ardour/audioplaylist.h"
#include "ardour/port.h"
#include "ardour/interpolation.h"
struct tm;
namespace ARDOUR {
class AudioEngine;
class Send;
class Session;
class AudioPlaylist;
class AudioFileSource;
class IO;
class LIBARDOUR_API AudioDiskstream : public Diskstream
{
public:
AudioDiskstream (Session &, const std::string& name, Diskstream::Flag f = Recordable);
AudioDiskstream (Session &, const XMLNode&);
~AudioDiskstream();
float playback_buffer_load() const;
float capture_buffer_load() const;
std::string input_source (uint32_t n=0) const {
boost::shared_ptr<ChannelList> c = channels.reader();
if (n < c->size()) {
return (*c)[n]->source.name;
} else {
return "";
}
}
void set_record_enabled (bool yn);
void set_record_safe (bool yn);
boost::shared_ptr<AudioPlaylist> audio_playlist () { return boost::dynamic_pointer_cast<AudioPlaylist>(_playlist); }
int use_playlist (boost::shared_ptr<Playlist>);
int use_new_playlist ();
int use_copy_playlist ();
Sample *playback_buffer (uint32_t n = 0) {
boost::shared_ptr<ChannelList> c = channels.reader();
if (n < c->size())
return (*c)[n]->current_playback_buffer;
return 0;
}
Sample *capture_buffer (uint32_t n = 0) {
boost::shared_ptr<ChannelList> c = channels.reader();
if (n < c->size())
return (*c)[n]->current_capture_buffer;
return 0;
}
boost::shared_ptr<AudioFileSource> write_source (uint32_t n=0) {
boost::shared_ptr<ChannelList> c = channels.reader();
if (n < c->size())
return (*c)[n]->write_source;
return boost::shared_ptr<AudioFileSource>();
}
int add_channel (uint32_t how_many);
int remove_channel (uint32_t how_many);
bool set_name (std::string const &);
bool set_write_source_name (const std::string& str);
/* stateful */
XMLNode& get_state(void);
int set_state(const XMLNode& node, int version);
void request_input_monitoring (bool);
static void swap_by_ptr (Sample *first, Sample *last) {
while (first < last) {
Sample tmp = *first;
*first++ = *last;
*last-- = tmp;
}
}
protected:
friend class Session;
/* the Session is the only point of access for these
because they require that the Session is "inactive"
while they are called.
*/
void set_pending_overwrite(bool);
int overwrite_existing_buffers ();
void set_block_size (pframes_t);
int internal_playback_seek (framecnt_t distance);
int can_internal_playback_seek (framecnt_t distance);
void reset_write_sources (bool, bool force = false);
void non_realtime_input_change ();
void non_realtime_locate (framepos_t location);
protected:
friend class Auditioner;
friend class AudioTrack;
int seek (framepos_t which_sample, bool complete_refill = false);
int process (BufferSet&, framepos_t transport_frame, pframes_t nframes, framecnt_t &, bool need_disk_signal);
frameoffset_t calculate_playback_distance (pframes_t nframes);
bool commit (framecnt_t);
private:
struct ChannelSource {
std::string name;
bool is_physical () const;
void request_input_monitoring (bool) const;
};
/** Information about one of our channels */
struct ChannelInfo : public boost::noncopyable {
ChannelInfo (framecnt_t playback_buffer_size,
framecnt_t capture_buffer_size,
framecnt_t speed_buffer_size,
framecnt_t wrap_buffer_size);
~ChannelInfo ();
Sample *playback_wrap_buffer;
Sample *capture_wrap_buffer;
Sample *speed_buffer;
boost::shared_ptr<AudioFileSource> write_source;
/** Information about the Port that our audio data comes from */
ChannelSource source;
Sample *current_capture_buffer;
Sample *current_playback_buffer;
/** A ringbuffer for data to be played back, written to in the
butler thread, read from in the process thread.
*/
PBD::RingBufferNPT<Sample> *playback_buf;
PBD::RingBufferNPT<Sample> *capture_buf;
Sample* scrub_buffer;
Sample* scrub_forward_buffer;
Sample* scrub_reverse_buffer;
PBD::RingBufferNPT<Sample>::rw_vector playback_vector;
PBD::RingBufferNPT<Sample>::rw_vector capture_vector;
PBD::RingBufferNPT<CaptureTransition> * capture_transition_buf;
// the following are used in the butler thread only
framecnt_t curr_capture_cnt;
void resize_playback (framecnt_t);
void resize_capture (framecnt_t);
};
typedef std::vector<ChannelInfo*> ChannelList;
CubicInterpolation interpolation;
/* The two central butler operations */
int do_flush (RunContext context, bool force = false);
int do_refill () { return _do_refill(_mixdown_buffer, _gain_buffer, 0); }
int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
framepos_t& start, framecnt_t cnt,
int channel, bool reversed);
void finish_capture (boost::shared_ptr<ChannelList>);
void transport_stopped_wallclock (struct tm&, time_t, bool abort);
void transport_looped (framepos_t transport_frame);
void init ();
void init_channel (ChannelInfo &chan);
void destroy_channel (ChannelInfo &chan);
int use_new_write_source (uint32_t n=0);
int find_and_use_playlist (const std::string &);
void allocate_temporary_buffers ();
int use_pending_capture_data (XMLNode& node);
void get_input_sources ();
void prepare_record_status(framepos_t capture_start_frame);
void set_align_style_from_io();
void setup_destructive_playlist ();
void use_destructive_playlist ();
void adjust_playback_buffering ();
void adjust_capture_buffering ();
bool prep_record_enable ();
bool prep_record_disable ();
// Working buffers for do_refill (butler thread)
static void allocate_working_buffers();
static void free_working_buffers();
static Sample* _mixdown_buffer;
static gain_t* _gain_buffer;
std::vector<boost::shared_ptr<AudioFileSource> > capturing_sources;
SerializedRCUManager<ChannelList> channels;
protected:
int _do_refill_with_alloc (bool one_chunk_only);
/* really */
private:
int _do_refill (Sample *mixdown_buffer, float *gain_buffer, framecnt_t fill_level);
int add_channel_to (boost::shared_ptr<ChannelList>, uint32_t how_many);
int remove_channel_from (boost::shared_ptr<ChannelList>, uint32_t how_many);
};
} // namespace ARDOUR
#endif /* __ardour_audio_diskstream_h__ */

View File

@ -1,369 +0,0 @@
/*
Copyright (C) 2000-2006 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __ardour_diskstream_h__
#define __ardour_diskstream_h__
#include <string>
#include <queue>
#include <map>
#include <vector>
#include <cmath>
#include <time.h>
#include <boost/utility.hpp>
#include "evoral/Range.hpp"
#include "ardour/ardour.h"
#include "ardour/chan_count.h"
#include "ardour/session_object.h"
#include "ardour/libardour_visibility.h"
#include "ardour/types.h"
#include "ardour/utils.h"
#include "ardour/public_diskstream.h"
struct tm;
namespace ARDOUR {
class IO;
class Playlist;
class Processor;
class Source;
class Session;
class Track;
class Location;
class BufferSet;
/** Parent class for classes which can stream data to and from disk.
* These are used by Tracks to get playback and put recorded data.
*/
class LIBARDOUR_API Diskstream : public SessionObject, public PublicDiskstream
{
public:
enum Flag {
Recordable = 0x1,
Hidden = 0x2,
Destructive = 0x4,
NonLayered = 0x8
};
Diskstream (Session &, const std::string& name, Flag f = Recordable);
Diskstream (Session &, const XMLNode&);
virtual ~Diskstream();
virtual bool set_name (const std::string& str);
virtual bool set_write_source_name (const std::string& str);
std::string write_source_name () const {
if (_write_source_name.empty()) {
return name();
} else {
return _write_source_name;
}
}
virtual std::string steal_write_source_name () { return std::string(); }
boost::shared_ptr<ARDOUR::IO> io() const { return _io; }
void set_track (ARDOUR::Track *);
/** @return A number between 0 and 1, where 0 indicates that the playback 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;
void set_flag (Flag f) { _flags = Flag (_flags | f); }
void unset_flag (Flag f) { _flags = Flag (_flags & ~f); }
AlignStyle alignment_style() const { return _alignment_style; }
AlignChoice alignment_choice() const { return _alignment_choice; }
void set_align_style (AlignStyle, bool force=false);
void set_align_choice (AlignChoice a, bool force=false);
framecnt_t roll_delay() const { return _roll_delay; }
void set_roll_delay (framecnt_t);
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;
bool destructive() const { return _flags & Destructive; }
bool hidden() const { return _flags & Hidden; }
bool recordable() const { return _flags & Recordable; }
bool non_layered() const; // { return _flags & NonLayered; }
bool reversed() const { return _actual_speed < 0.0f; }
double speed() const { return _visible_speed; }
virtual void punch_in() {}
virtual void punch_out() {}
void non_realtime_set_speed ();
virtual void non_realtime_locate (framepos_t /*location*/) {};
virtual void playlist_modified ();
boost::shared_ptr<Playlist> playlist () { return _playlist; }
virtual int use_playlist (boost::shared_ptr<Playlist>);
virtual int use_new_playlist () = 0;
virtual int use_copy_playlist () = 0;
/** @return Start position of currently-running capture (in session frames) */
framepos_t current_capture_start() const { return capture_start_frame; }
framepos_t current_capture_end() const { return capture_start_frame + capture_captured; }
framepos_t get_capture_start_frame (uint32_t n = 0) const;
framecnt_t get_captured_frames (uint32_t n = 0) const;
ChanCount n_channels() { return _n_channels; }
static framecnt_t disk_read_frames() { return disk_read_chunk_frames; }
static framecnt_t disk_write_frames() { return disk_write_chunk_frames; }
static void set_disk_read_chunk_frames (framecnt_t n) { disk_read_chunk_frames = n; }
static void set_disk_write_chunk_frames (framecnt_t n) { disk_write_chunk_frames = n; }
static framecnt_t default_disk_read_chunk_frames ();
static framecnt_t default_disk_write_chunk_frames ();
static void set_buffering_parameters (BufferingPreset bp);
/* Stateful */
virtual XMLNode& get_state(void);
virtual int set_state(const XMLNode&, int version);
virtual void request_input_monitoring (bool) {}
virtual void ensure_input_monitoring (bool) {}
framecnt_t capture_offset() const { return _capture_offset; }
virtual void set_capture_offset ();
bool slaved() const { return _slaved; }
void set_slaved(bool yn) { _slaved = yn; }
int set_loop (Location *loc);
std::list<boost::shared_ptr<Source> >& last_capture_sources () { return _last_capture_sources; }
void handle_input_change (IOChange, void *src);
void move_processor_automation (boost::weak_ptr<Processor>,
std::list<Evoral::RangeMove<framepos_t> > const &);
/** For non-butler contexts (allocates temporary working buffers)
*
* This accessible method has a default argument; derived classes
* must inherit the virtual method that we call which does NOT
* have a default argument, to avoid complications with inheritance
*/
int do_refill_with_alloc(bool partial_fill = true) {
return _do_refill_with_alloc (partial_fill);
}
virtual void set_block_size (pframes_t) = 0;
bool pending_overwrite () const {
return _pending_overwrite;
}
PBD::Signal0<void> RecordEnableChanged;
PBD::Signal0<void> RecordSafeChanged;
PBD::Signal0<void> SpeedChanged;
PBD::Signal0<void> ReverseChanged;
/* Emitted when this diskstream is set to use a different playlist */
PBD::Signal0<void> PlaylistChanged;
PBD::Signal0<void> AlignmentStyleChanged;
PBD::Signal1<void,Location *> LoopSet;
static PBD::Signal0<void> DiskOverrun;
static PBD::Signal0<void> DiskUnderrun;
protected:
friend class Session;
friend class Butler;
/* the Session is the only point of access for these because they require
* that the Session is "inactive" while they are called.
*/
virtual void set_pending_overwrite (bool) = 0;
virtual int overwrite_existing_buffers () = 0;
virtual int internal_playback_seek (framecnt_t distance) = 0;
virtual int can_internal_playback_seek (framecnt_t distance) = 0;
virtual void reset_write_sources (bool, bool force = false) = 0;
virtual void non_realtime_input_change () = 0;
/* accessible method has default argument, so use standard C++ "trick"
to avoid complications with inheritance, by adding this virtual
method which does NOT have a default argument.
*/
virtual int _do_refill_with_alloc (bool partial_fill) = 0;
protected:
friend class Auditioner;
virtual int seek (framepos_t which_sample, bool complete_refill = false) = 0;
protected:
friend class Track;
virtual int process (BufferSet&, framepos_t transport_frame, pframes_t nframes, framecnt_t &, bool need_disk_signal) = 0;
virtual frameoffset_t calculate_playback_distance (pframes_t nframes) = 0;
virtual bool commit (framecnt_t) = 0;
//private:
enum TransitionType {
CaptureStart = 0,
CaptureEnd
};
struct CaptureTransition {
TransitionType type;
framepos_t capture_val; ///< The start or end file frame position
};
/* The two central butler operations */
virtual int do_flush (RunContext context, bool force = false) = 0;
virtual int do_refill () = 0;
/* XXX fix this redundancy ... */
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);
virtual void transport_stopped_wallclock (struct tm&, time_t, bool abort) = 0;
virtual void transport_looped (framepos_t transport_frame) = 0;
struct CaptureInfo {
framepos_t start;
framecnt_t frames;
};
virtual int use_new_write_source (uint32_t n=0) = 0;
virtual int find_and_use_playlist (const std::string&) = 0;
virtual void allocate_temporary_buffers () = 0;
virtual bool realtime_set_speed (double, bool global_change);
std::list<boost::shared_ptr<Source> > _last_capture_sources;
virtual int use_pending_capture_data (XMLNode& node) = 0;
virtual void check_record_status (framepos_t transport_frame, bool can_record);
virtual void prepare_record_status (framepos_t /*capture_start_frame*/) {}
virtual void set_align_style_from_io() {}
virtual void setup_destructive_playlist () {}
virtual void use_destructive_playlist () {}
virtual void prepare_to_stop (framepos_t transport_pos, framepos_t audible_frame);
void engage_record_enable ();
void disengage_record_enable ();
void engage_record_safe ();
void disengage_record_safe ();
virtual bool prep_record_enable () = 0;
virtual bool prep_record_disable () = 0;
void calculate_record_range (
Evoral::OverlapType ot, framepos_t transport_frame, framecnt_t nframes,
framecnt_t& rec_nframes, framecnt_t& rec_offset
);
static framecnt_t disk_read_chunk_frames;
static framecnt_t disk_write_chunk_frames;
std::vector<CaptureInfo*> capture_info;
mutable Glib::Threads::Mutex capture_info_lock;
uint32_t i_am_the_modifier;
boost::shared_ptr<ARDOUR::IO> _io;
Track* _track;
ChanCount _n_channels;
boost::shared_ptr<Playlist> _playlist;
gint _record_enabled;
gint _record_safe;
double _visible_speed;
double _actual_speed;
/* items needed for speed change logic */
bool _buffer_reallocation_required;
bool _seek_required;
/** Start of currently running capture in session frames */
framepos_t capture_start_frame;
framecnt_t capture_captured;
bool was_recording;
framecnt_t adjust_capture_position;
framecnt_t _capture_offset;
/** The number of frames by which this diskstream's output should be delayed
with respect to the transport frame. This is used for latency compensation.
*/
framecnt_t _roll_delay;
framepos_t first_recordable_frame;
framepos_t last_recordable_frame;
int last_possibly_recording;
AlignStyle _alignment_style;
AlignChoice _alignment_choice;
bool _slaved;
Location* loop_location;
framepos_t overwrite_frame;
off_t overwrite_offset;
bool _pending_overwrite;
bool overwrite_queued;
IOChange input_change_pending;
framecnt_t wrap_buffer_size;
framecnt_t speed_buffer_size;
double _speed;
double _target_speed;
/** The next frame position that we should be reading from in our playlist */
framepos_t file_frame;
framepos_t playback_sample;
bool in_set_state;
std::string _write_source_name;
Glib::Threads::Mutex state_lock;
PBD::ScopedConnectionList playlist_connections;
PBD::ScopedConnection ic_connection;
Flag _flags;
XMLNode* deprecated_io_node;
void route_going_away ();
static bool get_buffering_presets (BufferingPreset bp,
framecnt_t& read_chunk_size,
framecnt_t& read_buffer_size,
framecnt_t& write_chunk_size,
framecnt_t& write_buffer_size);
};
}; /* namespace ARDOUR */
#endif /* __ardour_diskstream_h__ */

View File

@ -1,194 +0,0 @@
/*
Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: diskstream.h 579 2006-06-12 19:56:37Z essej $
*/
#ifndef __ardour_midi_diskstream_h__
#define __ardour_midi_diskstream_h__
#include <cmath>
#include <cassert>
#include <string>
#include <queue>
#include <map>
#include <vector>
#include <time.h>
#include "pbd/fastlog.h"
#include "pbd/ringbufferNPT.h"
#include "ardour/ardour.h"
#include "ardour/diskstream.h"
#include "ardour/midi_buffer.h"
#include "ardour/utils.h"
#include "ardour/interpolation.h"
struct tm;
namespace ARDOUR {
class IO;
class MidiEngine;
class MidiPlaylist;
class MidiPort;
class MidiRingbuffer;
class MidiSource;
class SMFSource;
class Send;
class Session;
template<typename T> class MidiRingBuffer;
class LIBARDOUR_API MidiDiskstream : public Diskstream
{
public:
MidiDiskstream (Session &, const std::string& name, Diskstream::Flag f = Recordable);
MidiDiskstream (Session &, const XMLNode&);
~MidiDiskstream();
float playback_buffer_load() const;
float capture_buffer_load() const;
void flush_playback (framepos_t, framepos_t);
void set_record_enabled (bool yn);
void set_record_safe (bool yn);
void reset_tracker ();
void resolve_tracker (Evoral::EventSink<framepos_t>& buffer, framepos_t time);
boost::shared_ptr<MidiPlaylist> midi_playlist ();
int use_playlist (boost::shared_ptr<Playlist>);
int use_new_playlist ();
int use_copy_playlist ();
bool set_name (std::string const &);
bool set_write_source_name (const std::string& str);
/* stateful */
XMLNode& get_state(void);
int set_state(const XMLNode&, int version);
void ensure_input_monitoring (bool);
boost::shared_ptr<SMFSource> write_source () { return _write_source; }
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;
boost::shared_ptr<MidiBuffer> get_gui_feed_buffer () const;
protected:
friend class Session;
friend class Butler;
/* the Session is the only point of access for these
because they require that the Session is "inactive"
while they are called.
*/
void set_pending_overwrite(bool);
int overwrite_existing_buffers ();
void set_block_size (pframes_t);
int internal_playback_seek (framecnt_t distance);
int can_internal_playback_seek (framecnt_t distance);
std::string steal_write_source_name();
void reset_write_sources (bool, bool force = false);
void non_realtime_input_change ();
void non_realtime_locate (framepos_t location);
static void set_readahead_frames (framecnt_t frames_ahead) { midi_readahead = frames_ahead; }
protected:
friend class MidiTrack;
friend class Auditioner;
int seek (framepos_t which_sample, bool complete_refill = false);
int _do_refill_with_alloc (bool one_chunk_only);
int process (BufferSet&, framepos_t transport_frame, pframes_t nframes, framecnt_t &, bool need_diskstream);
frameoffset_t calculate_playback_distance (pframes_t nframes);
bool commit (framecnt_t nframes);
static framecnt_t midi_readahead;
private:
void get_playback (MidiBuffer& dst, framecnt_t);
/* The two central butler operations */
int do_flush (RunContext context, bool force = false);
int do_refill ();
int read (framepos_t& start, framecnt_t cnt, bool reversed);
void finish_capture ();
void transport_stopped_wallclock (struct tm&, time_t, bool abort);
void transport_looped (framepos_t transport_frame);
void init ();
int use_new_write_source (uint32_t n=0);
int find_and_use_playlist (const std::string&);
void allocate_temporary_buffers ();
int use_pending_capture_data (XMLNode& node);
void get_input_sources ();
void set_align_style_from_io();
/* fixed size buffers per instance of ardour for now (non-dynamic)
*/
void adjust_playback_buffering () {}
void adjust_capture_buffering () {}
bool prep_record_enable ();
bool prep_record_disable ();
MidiRingBuffer<framepos_t>* _playback_buf;
MidiRingBuffer<framepos_t>* _capture_buf;
boost::weak_ptr<MidiPort> _source_port;
boost::shared_ptr<SMFSource> _write_source;
NoteMode _note_mode;
gint _frames_written_to_ringbuffer;
gint _frames_read_from_ringbuffer;
volatile gint _frames_pending_write;
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;
CubicMidiInterpolation interpolation;
};
}; /* namespace ARDOUR */
#endif /* __ardour_midi_diskstream_h__ */

View File

@ -1,82 +0,0 @@
/*
Copyright (C) 2010 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __ardour_public_diskstream_h__
#define __ardour_public_diskstream_h__
namespace ARDOUR {
class Playlist;
class Source;
class Location;
/** Public interface to a Diskstream */
class LIBARDOUR_API PublicDiskstream
{
public:
virtual ~PublicDiskstream() {}
virtual boost::shared_ptr<Playlist> playlist () = 0;
virtual void request_input_monitoring (bool) = 0;
virtual void ensure_input_monitoring (bool) = 0;
virtual bool destructive () const = 0;
virtual std::list<boost::shared_ptr<Source> > & last_capture_sources () = 0;
virtual void set_capture_offset () = 0;
virtual std::string steal_write_source_name () = 0;
virtual void reset_write_sources (bool, bool force = false) = 0;
virtual float playback_buffer_load () const = 0;
virtual float capture_buffer_load () const = 0;
virtual int do_refill () = 0;
virtual int do_flush (RunContext, bool force = false) = 0;
virtual void set_pending_overwrite (bool) = 0;
virtual int seek (framepos_t, bool complete_refill = false) = 0;
virtual bool hidden () const = 0;
virtual int can_internal_playback_seek (framecnt_t) = 0;
virtual int internal_playback_seek (framecnt_t) = 0;
virtual void non_realtime_input_change () = 0;
virtual void non_realtime_locate (framepos_t) = 0;
virtual void non_realtime_set_speed () = 0;
virtual int overwrite_existing_buffers () = 0;
virtual framecnt_t get_captured_frames (uint32_t n = 0) const = 0;
virtual int set_loop (Location *) = 0;
virtual void transport_looped (framepos_t) = 0;
virtual bool realtime_set_speed (double, bool) = 0;
virtual void transport_stopped_wallclock (struct tm &, time_t, bool) = 0;
virtual bool pending_overwrite () const = 0;
virtual double speed () const = 0;
virtual void prepare_to_stop (framepos_t,framepos_t) = 0;
virtual void set_slaved (bool) = 0;
virtual ChanCount n_channels () = 0;
virtual framepos_t get_capture_start_frame (uint32_t n = 0) const = 0;
virtual AlignStyle alignment_style () const = 0;
virtual framepos_t current_capture_start () const = 0;
virtual framepos_t current_capture_end () const = 0;
virtual void playlist_modified () = 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;
virtual int use_new_playlist () = 0;
virtual void adjust_playback_buffering () = 0;
virtual void adjust_capture_buffering () = 0;
};
}
#endif

View File

@ -89,8 +89,8 @@ CONFIG_VARIABLE (bool, use_tranzport, "use-tranzport", false)
/* disk operations */
CONFIG_VARIABLE (uint32_t, minimum_disk_read_bytes, "minimum-disk-read-bytes", ARDOUR::Diskstream::default_disk_read_chunk_frames() * sizeof (ARDOUR::Sample))
CONFIG_VARIABLE (uint32_t, minimum_disk_write_bytes, "minimum-disk-write-bytes", ARDOUR::Diskstream::default_disk_write_chunk_frames() * sizeof (ARDOUR::Sample))
CONFIG_VARIABLE (uint32_t, minimum_disk_read_bytes, "minimum-disk-read-bytes", ARDOUR::DiskReader::default_chunk_frames() * sizeof (ARDOUR::Sample))
CONFIG_VARIABLE (uint32_t, minimum_disk_write_bytes, "minimum-disk-write-bytes", ARDOUR::DiskWriter::default_chunk_frames() * sizeof (ARDOUR::Sample))
CONFIG_VARIABLE (float, midi_readahead, "midi-readahead", 1.0)
CONFIG_VARIABLE (BufferingPreset, buffering_preset, "buffering-preset", Medium)
CONFIG_VARIABLE (float, audio_capture_buffer_seconds, "capture-buffer-seconds", 5.0)

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,6 @@
#include "ardour/amp.h"
#include "ardour/audio_buffer.h"
#include "ardour/audio_diskstream.h"
#include "ardour/audio_track.h"
#include "ardour/audioplaylist.h"
#include "ardour/boost_debug.h"

View File

@ -21,7 +21,7 @@
#include "ardour/audio_track_importer.h"
#include "ardour/audio_playlist_importer.h"
#include "ardour/audio_diskstream.h"
#include "ardour/disk_reader.h"
#include "ardour/session.h"
#include "pbd/controllable.h"
@ -277,6 +277,8 @@ AudioTrackImporter::_cancel_move ()
void
AudioTrackImporter::_move ()
{
/* XXX DISK */
#if 0
/* Add diskstream */
boost::shared_ptr<XMLSharedNodeList> ds_node_list;
@ -293,7 +295,7 @@ AudioTrackImporter::_move ()
assert (p);
p->set_value (new_ds_id.to_s());
boost::shared_ptr<Diskstream> new_ds (new AudioDiskstream (session, *ds_node));
boost::shared_ptr<DiskReader> new_ds (new DiskReader (session, *ds_node));
new_ds->set_name (name);
new_ds->do_refill_with_alloc ();
new_ds->set_block_size (session.get_block_size ());
@ -309,6 +311,7 @@ AudioTrackImporter::_move ()
XMLNode routes ("Routes");
routes.add_child_copy (xml_track);
session.load_routes (routes, 3000);
#endif
}
bool

View File

@ -1,902 +0,0 @@
/*
Copyright (C) 2000-2006 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <cassert>
#include <cstdio>
#include <unistd.h>
#include <cmath>
#include <cerrno>
#include <string>
#include <climits>
#include <fcntl.h>
#include <cstdlib>
#include <ctime>
#include <sys/stat.h>
#include <glibmm/threads.h>
#include "pbd/error.h"
#include "pbd/basename.h"
#include "pbd/memento_command.h"
#include "pbd/xml++.h"
#include "pbd/stacktrace.h"
#include "pbd/enum_convert.h"
#include "pbd/types_convert.h"
#include "ardour/debug.h"
#include "ardour/diskstream.h"
#include "ardour/io.h"
#include "ardour/pannable.h"
#include "ardour/profile.h"
#include "ardour/playlist.h"
#include "ardour/session.h"
#include "ardour/session_playlists.h"
#include "ardour/track.h"
#include "ardour/types_convert.h"
#include "pbd/i18n.h"
#include <locale.h>
using namespace std;
using namespace ARDOUR;
using namespace PBD;
namespace PBD {
DEFINE_ENUM_CONVERT(Diskstream::Flag);
}
ARDOUR::framecnt_t Diskstream::disk_read_chunk_frames = default_disk_read_chunk_frames ();
ARDOUR::framecnt_t Diskstream::disk_write_chunk_frames = default_disk_write_chunk_frames ();
PBD::Signal0<void> Diskstream::DiskOverrun;
PBD::Signal0<void> Diskstream::DiskUnderrun;
Diskstream::Diskstream (Session &sess, const string &name, Flag flag)
: SessionObject(sess, name)
, i_am_the_modifier (0)
, _track (0)
, _record_enabled (0)
, _record_safe (0)
, _visible_speed (1.0f)
, _actual_speed (1.0f)
, _buffer_reallocation_required (false)
, _seek_required (false)
, capture_start_frame (0)
, capture_captured (0)
, was_recording (false)
, adjust_capture_position (0)
, _capture_offset (0)
, _roll_delay (0)
, first_recordable_frame (max_framepos)
, last_recordable_frame (max_framepos)
, last_possibly_recording (0)
, _alignment_style (ExistingMaterial)
, _alignment_choice (Automatic)
, _slaved (false)
, loop_location (0)
, overwrite_frame (0)
, overwrite_offset (0)
, _pending_overwrite (false)
, overwrite_queued (false)
, wrap_buffer_size (0)
, speed_buffer_size (0)
, _speed (1.0)
, _target_speed (_speed)
, file_frame (0)
, playback_sample (0)
, in_set_state (false)
, _flags (flag)
, deprecated_io_node (0)
{
}
Diskstream::Diskstream (Session& sess, const XMLNode& /*node*/)
: SessionObject(sess, "unnamed diskstream")
, i_am_the_modifier (0)
, _track (0)
, _record_enabled (0)
, _record_safe (0)
, _visible_speed (1.0f)
, _actual_speed (1.0f)
, _buffer_reallocation_required (false)
, _seek_required (false)
, capture_start_frame (0)
, capture_captured (0)
, was_recording (false)
, adjust_capture_position (0)
, _capture_offset (0)
, _roll_delay (0)
, first_recordable_frame (max_framepos)
, last_recordable_frame (max_framepos)
, last_possibly_recording (0)
, _alignment_style (ExistingMaterial)
, _alignment_choice (Automatic)
, _slaved (false)
, loop_location (0)
, overwrite_frame (0)
, overwrite_offset (0)
, _pending_overwrite (false)
, overwrite_queued (false)
, wrap_buffer_size (0)
, speed_buffer_size (0)
, _speed (1.0)
, _target_speed (_speed)
, file_frame (0)
, playback_sample (0)
, in_set_state (false)
, _flags (Recordable)
, deprecated_io_node (0)
{
}
Diskstream::~Diskstream ()
{
DEBUG_TRACE (DEBUG::Destruction, string_compose ("Diskstream %1 deleted\n", _name));
if (_playlist) {
_playlist->release ();
}
delete deprecated_io_node;
}
bool
Diskstream::non_layered () const
{
return _session.config.get_layered_record_mode();
}
void
Diskstream::set_track (Track* t)
{
_track = t;
_io = _track->input();
ic_connection.disconnect();
_io->changed.connect_same_thread (ic_connection, boost::bind (&Diskstream::handle_input_change, this, _1, _2));
if (_io->n_ports() != ChanCount::ZERO) {
input_change_pending.type = IOChange::Type (IOChange::ConfigurationChanged|IOChange::ConnectionsChanged);
non_realtime_input_change ();
}
_track->Destroyed.connect_same_thread (*this, boost::bind (&Diskstream::route_going_away, this));
}
void
Diskstream::handle_input_change (IOChange change, void * /*src*/)
{
Glib::Threads::Mutex::Lock lm (state_lock);
if (change.type & (IOChange::ConfigurationChanged|IOChange::ConnectionsChanged)) {
/* rather than handle this here on a DS-by-DS basis we defer to the
session transport/butler thread, and let it tackle
as many diskstreams as need it in one shot. this avoids many repeated
takings of the audioengine process lock.
*/
if (!(input_change_pending.type & change.type)) {
input_change_pending.type = IOChange::Type (input_change_pending.type | change.type);
_session.request_input_change_handling ();
}
}
}
void
Diskstream::non_realtime_set_speed ()
{
if (_buffer_reallocation_required)
{
Glib::Threads::Mutex::Lock lm (state_lock);
allocate_temporary_buffers ();
_buffer_reallocation_required = false;
}
if (_seek_required) {
if (speed() != 1.0f || speed() != -1.0f) {
seek ((framepos_t) (_session.transport_frame() * (double) speed()), true);
}
else {
seek (_session.transport_frame(), true);
}
_seek_required = false;
}
}
bool
Diskstream::realtime_set_speed (double sp, bool global)
{
bool changed = false;
double new_speed = sp * _session.transport_speed();
if (_visible_speed != sp) {
_visible_speed = sp;
changed = true;
}
if (new_speed != _actual_speed) {
framecnt_t required_wrap_size = (framecnt_t) ceil (_session.get_block_size() *
fabs (new_speed)) + 2;
if (required_wrap_size > wrap_buffer_size) {
_buffer_reallocation_required = true;
}
_actual_speed = new_speed;
_target_speed = fabs(_actual_speed);
}
if (changed) {
if (!global) {
_seek_required = true;
}
SpeedChanged (); /* EMIT SIGNAL */
}
return _buffer_reallocation_required || _seek_required;
}
void
Diskstream::set_capture_offset ()
{
if (_io == 0) {
/* can't capture, so forget it */
return;
}
switch (_alignment_style) {
case ExistingMaterial:
_capture_offset = _io->latency();
#ifdef MIXBUS
/* add additional latency, delayline inside the channelstrip + master-bus
* in MB the master-bus has no input-ports, so its latency does not propagate
*/
if (_session.master_out()) {
_capture_offset += _session.master_out()->signal_latency();
}
#endif
break;
case CaptureTime:
default:
_capture_offset = 0;
break;
}
#ifdef MIXBUS
framecnt_t port_offset;
if (_track->mixbus_internal_bounce (port_offset)) {
/* _capture_offset may become negative, but the sum
* _capture_offset + existing_material_offset
* will be postive.
*/
_capture_offset -= port_offset;
}
#endif
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: using IO latency, capture offset set to %2 with style = %3\n", name(), _capture_offset, enum_2_string (_alignment_style)));
}
void
Diskstream::set_align_style (AlignStyle a, bool force)
{
if (record_enabled() && _session.actively_recording()) {
return;
}
if ((a != _alignment_style) || force) {
_alignment_style = a;
set_capture_offset ();
AlignmentStyleChanged ();
}
}
void
Diskstream::set_align_choice (AlignChoice a, bool force)
{
if (record_enabled() && _session.actively_recording()) {
return;
}
if ((a != _alignment_choice) || force) {
_alignment_choice = a;
switch (_alignment_choice) {
case Automatic:
set_align_style_from_io ();
break;
case UseExistingMaterial:
set_align_style (ExistingMaterial);
break;
case UseCaptureTime:
set_align_style (CaptureTime);
break;
}
}
}
int
Diskstream::set_loop (Location *location)
{
if (location) {
if (location->start() >= location->end()) {
error << string_compose(_("Location \"%1\" not valid for track loop (start >= end)"), location->name()) << endl;
return -1;
}
}
loop_location = location;
LoopSet (location); /* EMIT SIGNAL */
return 0;
}
/** Get the start position (in session frames) of the nth capture in the current pass */
ARDOUR::framepos_t
Diskstream::get_capture_start_frame (uint32_t n) const
{
Glib::Threads::Mutex::Lock lm (capture_info_lock);
if (capture_info.size() > n) {
/* this is a completed capture */
return capture_info[n]->start;
} else {
/* this is the currently in-progress capture */
return capture_start_frame;
}
}
ARDOUR::framecnt_t
Diskstream::get_captured_frames (uint32_t n) const
{
Glib::Threads::Mutex::Lock lm (capture_info_lock);
if (capture_info.size() > n) {
/* this is a completed capture */
return capture_info[n]->frames;
} else {
/* this is the currently in-progress capture */
return capture_captured;
}
}
void
Diskstream::set_roll_delay (ARDOUR::framecnt_t nframes)
{
_roll_delay = nframes;
}
int
Diskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
{
if (!playlist) {
return 0;
}
bool prior_playlist = false;
{
Glib::Threads::Mutex::Lock lm (state_lock);
if (playlist == _playlist) {
return 0;
}
playlist_connections.drop_connections ();
if (_playlist) {
_playlist->release();
prior_playlist = true;
}
_playlist = playlist;
_playlist->use();
if (!in_set_state && destructive() && recordable()) {
reset_write_sources (false);
}
_playlist->ContentsChanged.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_modified, this));
_playlist->LayeringChanged.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_modified, this));
_playlist->DropReferences.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_deleted, this, boost::weak_ptr<Playlist>(_playlist)));
_playlist->RangesMoved.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_ranges_moved, this, _1, _2));
}
/* don't do this if we've already asked for it *or* if we are setting up
the diskstream for the very first time - the input changed handling will
take care of the buffer refill.
*/
if (!overwrite_queued && prior_playlist) {
_session.request_overwrite_buffer (_track);
overwrite_queued = true;
}
PlaylistChanged (); /* EMIT SIGNAL */
_session.set_dirty ();
return 0;
}
void
Diskstream::playlist_changed (const PropertyChange&)
{
playlist_modified ();
}
void
Diskstream::playlist_modified ()
{
if (!i_am_the_modifier && !overwrite_queued) {
_session.request_overwrite_buffer (_track);
overwrite_queued = true;
}
}
void
Diskstream::playlist_deleted (boost::weak_ptr<Playlist> wpl)
{
boost::shared_ptr<Playlist> pl (wpl.lock());
if (pl == _playlist) {
/* this catches an ordering issue with session destruction. playlists
are destroyed before diskstreams. we have to invalidate any handles
we have to the playlist.
*/
if (_playlist) {
_playlist.reset ();
}
}
}
bool
Diskstream::set_name (const string& str)
{
if (_name != str) {
assert(playlist());
std::string name (str);
while (_session.playlists->by_name (name)) {
name = Playlist::bump_name (name, _session);
}
playlist()->set_name (name);
SessionObject::set_name(name);
}
return true;
}
bool
Diskstream::set_write_source_name (const std::string& str) {
_write_source_name = str;
return true;
}
XMLNode&
Diskstream::get_state ()
{
XMLNode* node = new XMLNode ("Diskstream");
node->set_property ("flags", _flags);
node->set_property ("playlist", _playlist->name());
node->set_property ("name", name());
node->set_property ("id", id ());
node->set_property ("speed", _visible_speed);
node->set_property ("capture-alignment", _alignment_choice);
node->set_property ("record-safe", _record_safe);
if (_extra_xml) {
node->add_child_copy (*_extra_xml);
}
return *node;
}
int
Diskstream::set_state (const XMLNode& node, int /*version*/)
{
std::string name;
if (node.get_property ("name", name)) {
_name = name;
}
if (deprecated_io_node) {
set_id (*deprecated_io_node);
} else {
set_id (node);
}
node.get_property ("flags", _flags);
if (Profile->get_trx() && (_flags & Destructive)) {
error << string_compose (_("%1: this session uses destructive tracks, which are not supported"), PROGRAM_NAME) << endmsg;
return -1;
}
AlignChoice achoice = Automatic;
node.get_property (X_("capture-alignment"), achoice);
set_align_choice (achoice, true);
XMLProperty const * prop;
if ((prop = node.property ("playlist")) == 0) {
return -1;
}
if (find_and_use_playlist (prop->value())) {
return -1;
}
double sp;
if (node.get_property ("speed", sp)) {
if (realtime_set_speed (sp, false)) {
non_realtime_set_speed ();
}
}
bool record_safe;
if (node.get_property ("record-safe", record_safe)) {
_record_safe = record_safe ? 1 : 0;
}
return 0;
}
void
Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<framepos_t> > const & movements_frames, bool from_undo)
{
/* If we're coming from an undo, it will have handled
automation undo (it must, since automation-follows-regions
can lose automation data). Hence we can do nothing here.
*/
if (from_undo) {
return;
}
if (!_track || Config->get_automation_follows_regions () == false) {
return;
}
list< Evoral::RangeMove<double> > movements;
for (list< Evoral::RangeMove<framepos_t> >::const_iterator i = movements_frames.begin();
i != movements_frames.end();
++i) {
movements.push_back(Evoral::RangeMove<double>(i->from, i->length, i->to));
}
/* move panner automation */
boost::shared_ptr<Pannable> pannable = _track->pannable();
Evoral::ControlSet::Controls& c (pannable->controls());
for (Evoral::ControlSet::Controls::iterator ci = c.begin(); ci != c.end(); ++ci) {
boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl>(ci->second);
if (!ac) {
continue;
}
boost::shared_ptr<AutomationList> alist = ac->alist();
if (!alist->size()) {
continue;
}
XMLNode & before = alist->get_state ();
bool const things_moved = alist->move_ranges (movements);
if (things_moved) {
_session.add_command (new MementoCommand<AutomationList> (
*alist.get(), &before, &alist->get_state ()));
}
}
/* move processor automation */
_track->foreach_processor (boost::bind (&Diskstream::move_processor_automation, this, _1, movements_frames));
}
void
Diskstream::move_processor_automation (boost::weak_ptr<Processor> p, list< Evoral::RangeMove<framepos_t> > const & movements_frames)
{
boost::shared_ptr<Processor> processor (p.lock ());
if (!processor) {
return;
}
list< Evoral::RangeMove<double> > movements;
for (list< Evoral::RangeMove<framepos_t> >::const_iterator i = movements_frames.begin(); i != movements_frames.end(); ++i) {
movements.push_back(Evoral::RangeMove<double>(i->from, i->length, i->to));
}
set<Evoral::Parameter> const a = processor->what_can_be_automated ();
for (set<Evoral::Parameter>::const_iterator i = a.begin (); i != a.end (); ++i) {
boost::shared_ptr<AutomationList> al = processor->automation_control(*i)->alist();
if (!al->size()) {
continue;
}
XMLNode & before = al->get_state ();
bool const things_moved = al->move_ranges (movements);
if (things_moved) {
_session.add_command (
new MementoCommand<AutomationList> (
*al.get(), &before, &al->get_state ()
)
);
}
}
}
void
Diskstream::check_record_status (framepos_t transport_frame, bool can_record)
{
int possibly_recording;
int rolling;
int change;
const int transport_rolling = 0x4;
const int track_rec_enabled = 0x2;
const int global_rec_enabled = 0x1;
const int fully_rec_enabled = (transport_rolling|track_rec_enabled|global_rec_enabled);
/* merge together the 3 factors that affect record status, and compute
* what has changed.
*/
rolling = _session.transport_speed() != 0.0f;
possibly_recording = (rolling << 2) | ((int)record_enabled() << 1) | (int)can_record;
change = possibly_recording ^ last_possibly_recording;
if (possibly_recording == last_possibly_recording) {
return;
}
const framecnt_t existing_material_offset = _session.worst_playback_latency();
if (possibly_recording == fully_rec_enabled) {
if (last_possibly_recording == fully_rec_enabled) {
return;
}
capture_start_frame = _session.transport_frame();
first_recordable_frame = capture_start_frame + _capture_offset;
last_recordable_frame = max_framepos;
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: @ %7 (%9) FRF = %2 CSF = %4 CO = %5, EMO = %6 RD = %8 WOL %10 WTL %11\n",
name(), first_recordable_frame, last_recordable_frame, capture_start_frame,
_capture_offset,
existing_material_offset,
transport_frame,
_roll_delay,
_session.transport_frame(),
_session.worst_output_latency(),
_session.worst_track_latency()));
if (_alignment_style == ExistingMaterial) {
first_recordable_frame += existing_material_offset;
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tshift FRF by EMO %1\n",
first_recordable_frame));
}
prepare_record_status (capture_start_frame);
} else {
if (last_possibly_recording == fully_rec_enabled) {
/* we were recording last time */
if (change & transport_rolling) {
/* transport-change (stopped rolling): last_recordable_frame was set in ::prepare_to_stop(). We
* had to set it there because we likely rolled past the stopping point to declick out,
* and then backed up.
*/
} else {
/* punch out */
last_recordable_frame = _session.transport_frame() + _capture_offset;
if (_alignment_style == ExistingMaterial) {
last_recordable_frame += existing_material_offset;
}
}
}
}
last_possibly_recording = possibly_recording;
}
void
Diskstream::route_going_away ()
{
_io.reset ();
}
void
Diskstream::calculate_record_range (Evoral::OverlapType ot, framepos_t transport_frame, framecnt_t nframes,
framecnt_t & rec_nframes, framecnt_t & rec_offset)
{
switch (ot) {
case Evoral::OverlapNone:
rec_nframes = 0;
break;
case Evoral::OverlapInternal:
/* ---------- recrange
* |---| transrange
*/
rec_nframes = nframes;
rec_offset = 0;
break;
case Evoral::OverlapStart:
/* |--------| recrange
* -----| transrange
*/
rec_nframes = transport_frame + nframes - first_recordable_frame;
if (rec_nframes) {
rec_offset = first_recordable_frame - transport_frame;
}
break;
case Evoral::OverlapEnd:
/* |--------| recrange
* |-------- transrange
*/
rec_nframes = last_recordable_frame - transport_frame;
rec_offset = 0;
break;
case Evoral::OverlapExternal:
/* |--------| recrange
* -------------- transrange
*/
rec_nframes = last_recordable_frame - first_recordable_frame;
rec_offset = first_recordable_frame - transport_frame;
break;
}
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 rec? %2 @ %3 (for %4) FRF %5 LRF %6 : rf %7 @ %8\n",
_name, enum_2_string (ot), transport_frame, nframes,
first_recordable_frame, last_recordable_frame, rec_nframes, rec_offset));
}
void
Diskstream::prepare_to_stop (framepos_t transport_frame, framepos_t audible_frame)
{
switch (_alignment_style) {
case ExistingMaterial:
last_recordable_frame = transport_frame + _capture_offset;
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose("%1: prepare to stop sets last recordable frame to %2 + %3 = %4\n", _name, transport_frame, _capture_offset, last_recordable_frame));
break;
case CaptureTime:
last_recordable_frame = audible_frame; // note that capture_offset is zero
/* we may already have captured audio before the last_recordable_frame (audible frame),
so deal with this.
*/
if (last_recordable_frame > capture_start_frame) {
capture_captured = min (capture_captured, last_recordable_frame - capture_start_frame);
}
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose("%1: prepare to stop sets last recordable frame to audible frame @ %2\n", _name, audible_frame));
break;
}
}
void
Diskstream::engage_record_enable ()
{
g_atomic_int_set (&_record_enabled, 1);
}
void
Diskstream::disengage_record_enable ()
{
g_atomic_int_set (&_record_enabled, 0);
}
void
Diskstream::engage_record_safe ()
{
g_atomic_int_set (&_record_safe, 1);
}
void
Diskstream::disengage_record_safe ()
{
g_atomic_int_set (&_record_safe, 0);
}
framecnt_t
Diskstream::default_disk_read_chunk_frames()
{
return 65536;
}
framecnt_t
Diskstream::default_disk_write_chunk_frames ()
{
return 65536;
}
void
Diskstream::set_buffering_parameters (BufferingPreset bp)
{
framecnt_t read_chunk_size;
framecnt_t read_buffer_size;
framecnt_t write_chunk_size;
framecnt_t write_buffer_size;
if (!get_buffering_presets (bp, read_chunk_size, read_buffer_size, write_chunk_size, write_buffer_size)) {
return;
}
disk_read_chunk_frames = read_chunk_size;
disk_write_chunk_frames = write_chunk_size;
Config->set_audio_capture_buffer_seconds (write_buffer_size);
Config->set_audio_playback_buffer_seconds (read_buffer_size);
#ifndef NDEBUG
cerr << "Set buffering params to " << disk_read_chunk_frames << '|' << disk_write_chunk_frames << '|'
<< Config->get_audio_playback_buffer_seconds() << '|'
<< Config->get_audio_capture_buffer_seconds ()
<< endl;
#endif
}
bool
Diskstream::get_buffering_presets (BufferingPreset bp,
framecnt_t& read_chunk_size,
framecnt_t& read_buffer_size,
framecnt_t& write_chunk_size,
framecnt_t& write_buffer_size)
{
switch (bp) {
case Small:
read_chunk_size = 65536; /* samples */
write_chunk_size = 65536; /* samples */
read_buffer_size = 5; /* seconds */
write_buffer_size = 5; /* seconds */
break;
case Medium:
read_chunk_size = 262144; /* samples */
write_chunk_size = 131072; /* samples */
read_buffer_size = 10; /* seconds */
write_buffer_size = 10; /* seconds */
break;
case Large:
read_chunk_size = 524288; /* samples */
write_chunk_size = 131072; /* samples */
read_buffer_size = 20; /* seconds */
write_buffer_size = 20; /* seconds */
break;
default:
return false;
}
return true;
}

View File

@ -23,7 +23,7 @@
#include "evoral/Range.hpp" // shouldn't Evoral have its own enum registration?
#include "ardour/delivery.h"
#include "ardour/diskstream.h"
#include "ardour/disk_io.h"
#include "ardour/export_channel.h"
#include "ardour/export_filename.h"
#include "ardour/export_format_base.h"
@ -100,7 +100,7 @@ setup_enum_writer ()
TracksAutoNamingRule _TracksAutoNamingRule;
Session::StateOfTheState _Session_StateOfTheState;
Source::Flag _Source_Flag;
Diskstream::Flag _Diskstream_Flag;
DiskIOProcessor::Flag _DiskIOProcessor_Flag;
Location::Flags _Location_Flags;
PositionLockStyle _PositionLockStyle;
TempoSection::Type _TempoSection_Type;
@ -507,10 +507,10 @@ setup_enum_writer ()
REGISTER_ENUM(ExistingNewlyCreatedBoth);
REGISTER (_RegionSelectionAfterSplit);
REGISTER_CLASS_ENUM (Diskstream, Recordable);
REGISTER_CLASS_ENUM (Diskstream, Hidden);
REGISTER_CLASS_ENUM (Diskstream, Destructive);
REGISTER_BITS (_Diskstream_Flag);
REGISTER_CLASS_ENUM (DiskIOProcessor, Recordable);
REGISTER_CLASS_ENUM (DiskIOProcessor, Hidden);
REGISTER_CLASS_ENUM (DiskIOProcessor, Destructive);
REGISTER_BITS (_DiskIOProcessor_Flag);
REGISTER_CLASS_ENUM (Location, IsMark);
REGISTER_CLASS_ENUM (Location, IsAutoPunch);

View File

@ -47,7 +47,6 @@
#include "ardour/analyser.h"
#include "ardour/ardour.h"
#include "ardour/audio_diskstream.h"
#include "ardour/audioengine.h"
#include "ardour/audioregion.h"
#include "ardour/import_status.h"

File diff suppressed because it is too large Load Diff

View File

@ -29,8 +29,9 @@
#include "pbd/replace_all.h"
#include "ardour/audioengine.h"
#include "ardour/disk_reader.h"
#include "ardour/disk_writer.h"
#include "ardour/control_protocol_manager.h"
#include "ardour/diskstream.h"
#include "ardour/filesystem_paths.h"
#include "ardour/port.h"
#include "ardour/rc_configuration.h"
@ -235,8 +236,8 @@ RCConfiguration::set_state (const XMLNode& root, int version)
}
}
Diskstream::set_disk_read_chunk_frames (minimum_disk_read_bytes.get() / sizeof (Sample));
Diskstream::set_disk_write_chunk_frames (minimum_disk_write_bytes.get() / sizeof (Sample));
DiskReader::set_chunk_frames (minimum_disk_read_bytes.get() / sizeof (Sample));
DiskWriter::set_chunk_frames (minimum_disk_write_bytes.get() / sizeof (Sample));
return 0;
}

View File

@ -20,7 +20,6 @@
#include "ardour/amp.h"
#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"

View File

@ -25,7 +25,6 @@ libardour_sources = [
'async_midi_port.cc',
'audio_backend.cc',
'audio_buffer.cc',
'audio_diskstream.cc',
'audio_library.cc',
'audio_playlist.cc',
'audio_playlist_importer.cc',
@ -70,7 +69,6 @@ libardour_sources = [
'disk_io.cc',
'disk_reader.cc',
'disk_writer.cc',
'diskstream.cc',
'dsp_filter.cc',
'ebur128_analysis.cc',
'element_import_handler.cc',
@ -128,7 +126,6 @@ libardour_sources = [
'midi_buffer.cc',
'midi_channel_filter.cc',
'midi_clock_slave.cc',
'midi_diskstream.cc',
'midi_model.cc',
'midi_patch_manager.cc',
'midi_playlist.cc',