fully remove diskstream code
This commit is contained in:
parent
361cab503b
commit
68e57101ad
|
@ -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());
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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
|
|
@ -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
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Reference in New Issue
Block a user