mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-06 21:55:43 +01:00
Merge libs/ardour and gtk2_ardour with 2.0-ongoing R2837.
git-svn-id: svn://localhost/ardour2/trunk@2883 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
73dd9d37e7
commit
bb457bb960
168 changed files with 11821 additions and 5338 deletions
|
|
@ -129,7 +129,6 @@ sndfile_helpers.cc
|
|||
sndfilesource.cc
|
||||
source.cc
|
||||
source_factory.cc
|
||||
stretch.cc
|
||||
tape_file_matcher.cc
|
||||
template_utils.cc
|
||||
tempo.cc
|
||||
|
|
@ -145,6 +144,7 @@ vst_files = [ 'vst_plugin.cc', 'session_vst.cc' ]
|
|||
audiounit_files = [ 'audio_unit.cc' ]
|
||||
coreaudio_files = [ 'coreaudiosource.cc' ]
|
||||
extra_sources = [ ]
|
||||
timefx_sources = [ ]
|
||||
|
||||
if ardour['VST']:
|
||||
extra_sources += vst_files
|
||||
|
|
@ -296,22 +296,28 @@ ardour.Merge ([
|
|||
libraries['samplerate'],
|
||||
libraries['sigc2'],
|
||||
libraries['pbd'],
|
||||
libraries['soundtouch'],
|
||||
libraries['midi++2'],
|
||||
libraries['glib2'],
|
||||
libraries['glibmm2']
|
||||
])
|
||||
|
||||
#if ardour['RUBBERBAND']:
|
||||
# ardour.Merge ([ libraries['rubberband'], libraries['vamp'], libraries['fftw3f'] ])
|
||||
# timefx_sources += [ 'rb_effect.cc' ]
|
||||
#else:
|
||||
ardour.Merge ([ libraries['soundtouch'] ])
|
||||
timefx_sources += [ 'st_stretch.cc', 'st_pitch.cc' ]
|
||||
|
||||
if ardour['LIBLO']:
|
||||
ardour.Merge ([ libraries['lo'] ])
|
||||
ardour.Merge ([ libraries['lo'] ])
|
||||
|
||||
if ardour['COREAUDIO'] or ardour['AUDIOUNITS']:
|
||||
ardour.Merge ([ libraries['appleutility'] ])
|
||||
ardour.Merge ([ libraries['appleutility'] ])
|
||||
|
||||
def SharedAsmObjectEmitter(target, source, env):
|
||||
for tgt in target:
|
||||
tgt.attributes.shared = 1
|
||||
return (target, source)
|
||||
for tgt in target:
|
||||
tgt.attributes.shared = 1
|
||||
return (target, source)
|
||||
|
||||
|
||||
env['BUILDERS']['SharedAsmObject'] = Builder (action = '$CXX -c -fPIC $SOURCE -o $TARGET',
|
||||
|
|
@ -341,12 +347,12 @@ if env['FPU_OPTIMIZATION']:
|
|||
arch_specific_objects = env.SharedAsmObject('sse_functions_64bit.os', 'sse_functions_64bit.s')
|
||||
always_sse_objects += [ sse_env.SharedObject (source = 'sse_functions_xmm.cc') ]
|
||||
|
||||
libardour = ardour.SharedLibrary('ardour', ardour_files + always_sse_objects + extra_sources + arch_specific_objects)
|
||||
libardour = ardour.SharedLibrary('ardour', ardour_files + always_sse_objects + timefx_sources + extra_sources + arch_specific_objects)
|
||||
|
||||
Default(libardour)
|
||||
|
||||
if env['NLS']:
|
||||
i18n (ardour, ardour_files + vst_files + coreaudio_files + audiounit_files, env)
|
||||
i18n (ardour, ardour_files + vst_files + coreaudio_files + timefx_sources + audiounit_files, env)
|
||||
|
||||
|
||||
env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libardour))
|
||||
|
|
@ -354,6 +360,8 @@ env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ar
|
|||
env.Alias('version', ardour.VersionBuild(['version.cc', 'ardour/version.h'], []))
|
||||
|
||||
env.Alias('tarball', env.Distribute (env['DISTTREE'],
|
||||
[ 'SConscript', 'i18n.h', 'gettext.h', 'sse_functions_xmm.cc', 'sse_functions.s', 'sse_functions_64bit.s' ] +
|
||||
[ 'SConscript', 'i18n.h', 'gettext.h' ] +
|
||||
[ 'sse_functions_xmm.cc', 'sse_functions.s', 'sse_functions_64bit.s' ] +
|
||||
[ 'rb_effect.cc', 'st_stretch.cc', 'st_pitch.cc' ] +
|
||||
ardour_files + osc_files + vst_files + coreaudio_files + audiounit_files +
|
||||
glob.glob('po/*.po') + glob.glob('ardour/*.h')))
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ namespace ARDOUR {
|
|||
int cleanup ();
|
||||
|
||||
std::string get_ardour_revision ();
|
||||
|
||||
const layer_t max_layer = UCHAR_MAX;
|
||||
|
||||
microseconds_t get_microseconds ();
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ public:
|
|||
|
||||
/** Read @a len frames FROM THE START OF @a src into self at @a offset */
|
||||
void read_from(const Buffer& src, nframes_t len, nframes_t offset) {
|
||||
assert(&src != this);
|
||||
assert(_capacity > 0);
|
||||
assert(src.type() == DataType::AUDIO);
|
||||
assert(offset + len <= _capacity);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#define __ardour_audio_unit_h__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
|
@ -30,6 +31,8 @@
|
|||
|
||||
#include <ardour/plugin.h>
|
||||
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
class CAComponent;
|
||||
|
|
@ -45,13 +48,13 @@ class Session;
|
|||
class AUPlugin : public ARDOUR::Plugin
|
||||
{
|
||||
public:
|
||||
AUPlugin (AudioEngine& engine, Session& session, CAComponent* comp);
|
||||
AUPlugin (AudioEngine& engine, Session& session, boost::shared_ptr<CAComponent> comp);
|
||||
virtual ~AUPlugin ();
|
||||
|
||||
uint32_t unique_id () const;
|
||||
std::string unique_id () const;
|
||||
const char * label () const;
|
||||
const char * name () const { return _info->name.c_str(); }
|
||||
const char * maker () const;
|
||||
const char * maker () const { return _info->creator.c_str(); }
|
||||
uint32_t parameter_count () const;
|
||||
float default_value (uint32_t port);
|
||||
nframes_t signal_latency () const;
|
||||
|
|
@ -87,34 +90,65 @@ class AUPlugin : public ARDOUR::Plugin
|
|||
|
||||
bool has_editor () const;
|
||||
|
||||
CAAudioUnit* get_au () { return unit; }
|
||||
CAComponent* get_comp () { return comp; }
|
||||
|
||||
private:
|
||||
CAComponent* comp;
|
||||
CAAudioUnit* unit;
|
||||
bool fixed_io() const { return false; }
|
||||
int32_t can_support_input_configuration (int32_t in);
|
||||
int32_t compute_output_streams (int32_t nplugins);
|
||||
uint32_t output_streams() const;
|
||||
uint32_t input_streams() const;
|
||||
|
||||
AudioBufferList* in_list;
|
||||
AudioBufferList* out_list;
|
||||
boost::shared_ptr<CAAudioUnit> get_au () { return unit; }
|
||||
boost::shared_ptr<CAComponent> get_comp () { return comp; }
|
||||
|
||||
OSStatus render_callback(AudioUnitRenderActionFlags *ioActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
UInt32 inNumberFrames,
|
||||
AudioBufferList* ioData);
|
||||
private:
|
||||
boost::shared_ptr<CAComponent> comp;
|
||||
boost::shared_ptr<CAAudioUnit> unit;
|
||||
|
||||
AudioStreamBasicDescription streamFormat;
|
||||
bool initialized;
|
||||
int format_set;
|
||||
AudioBufferList* buffers;
|
||||
|
||||
UInt32 global_elements;
|
||||
UInt32 output_elements;
|
||||
UInt32 input_elements;
|
||||
|
||||
int set_output_format ();
|
||||
int set_input_format ();
|
||||
int set_stream_format (int scope, uint32_t cnt);
|
||||
int _set_block_size (nframes_t nframes);
|
||||
|
||||
std::vector<std::pair<uint32_t, uint32_t> > parameter_map;
|
||||
uint32_t current_maxbuf;
|
||||
nframes_t current_offset;
|
||||
nframes_t cb_offset;
|
||||
vector<Sample*>* current_buffers;
|
||||
nframes_t frames_processed;
|
||||
};
|
||||
|
||||
|
||||
typedef boost::shared_ptr<AUPlugin> AUPluginPtr;
|
||||
|
||||
class AUPluginInfo : public PluginInfo {
|
||||
public:
|
||||
AUPluginInfo () { };
|
||||
AUPluginInfo (boost::shared_ptr<CAComponentDescription>);
|
||||
~AUPluginInfo ();
|
||||
|
||||
CAComponentDescription* desc;
|
||||
|
||||
static PluginInfoList discover ();
|
||||
PluginPtr load (Session& session);
|
||||
|
||||
static PluginInfoList discover ();
|
||||
static void get_names (CAComponentDescription&, std::string& name, Glib::ustring& maker);
|
||||
static std::string stringify_descriptor (const CAComponentDescription&);
|
||||
|
||||
private:
|
||||
static std::string get_name (CAComponentDescription&);
|
||||
void setup_nchannels (CAComponentDescription&);
|
||||
boost::shared_ptr<CAComponentDescription> descriptor;
|
||||
|
||||
static void discover_music (PluginInfoList&);
|
||||
static void discover_fx (PluginInfoList&);
|
||||
static void discover_by_description (PluginInfoList&, CAComponentDescription&);
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<AUPluginInfo> AUPluginInfoPtr;
|
||||
|
|
|
|||
|
|
@ -106,7 +106,13 @@ class AudioEngine : public sigc::trackable
|
|||
|
||||
class PortRegistrationFailure : public std::exception {
|
||||
public:
|
||||
virtual const char *what() const throw() { return "failed port registration"; }
|
||||
PortRegistrationFailure (const char* why = "") {
|
||||
reason = why;
|
||||
}
|
||||
virtual const char *what() const throw() { return reason; }
|
||||
|
||||
private:
|
||||
const char* reason;
|
||||
};
|
||||
|
||||
class NoBackendAvailable : public std::exception {
|
||||
|
|
@ -235,6 +241,8 @@ class AudioEngine : public sigc::trackable
|
|||
|
||||
std::string get_nth_physical (DataType type, uint32_t n, int flags);
|
||||
|
||||
void port_registration_failure (const std::string& portname);
|
||||
|
||||
static int _xrun_callback (void *arg);
|
||||
static int _graph_order_callback (void *arg);
|
||||
static int _process_callback (nframes_t nframes, void *arg);
|
||||
|
|
|
|||
|
|
@ -76,8 +76,10 @@ class AudioRegion : public Region
|
|||
uint32_t chan_n=0, double samples_per_unit= 1.0) const;
|
||||
|
||||
virtual nframes_t read_at (Sample *buf, Sample *mixdown_buf,
|
||||
float *gain_buf, nframes_t position, nframes_t cnt,
|
||||
uint32_t chan_n = 0) const;
|
||||
float *gain_buf, nframes_t position, nframes_t cnt,
|
||||
uint32_t chan_n = 0,
|
||||
nframes_t read_frames = 0,
|
||||
nframes_t skip_frames = 0) const;
|
||||
|
||||
virtual nframes_t master_read_at (Sample *buf, Sample *mixdown_buf,
|
||||
float *gain_buf,
|
||||
|
|
@ -146,8 +148,10 @@ class AudioRegion : public Region
|
|||
void recompute_gain_at_start ();
|
||||
|
||||
nframes_t _read_at (const SourceList&, Sample *buf, Sample *mixdown_buffer,
|
||||
float *gain_buffer, nframes_t position, nframes_t cnt,
|
||||
uint32_t chan_n = 0) const;
|
||||
float *gain_buffer, nframes_t position, nframes_t cnt,
|
||||
uint32_t chan_n = 0,
|
||||
nframes_t read_frames = 0,
|
||||
nframes_t skip_frames = 0) const;
|
||||
|
||||
void recompute_at_start ();
|
||||
void recompute_at_end ();
|
||||
|
|
@ -174,13 +178,6 @@ class AudioRegion : public Region
|
|||
AudioRegion (boost::shared_ptr<const AudioRegion>);
|
||||
|
||||
int set_live_state (const XMLNode&, Change&, bool send);
|
||||
|
||||
virtual bool verify_start (nframes_t);
|
||||
virtual bool verify_start_and_length (nframes_t, nframes_t);
|
||||
virtual bool verify_start_mutable (nframes_t&_start);
|
||||
virtual bool verify_length (nframes_t);
|
||||
/*virtual void recompute_at_start () = 0;
|
||||
virtual void recompute_at_end () = 0;*/
|
||||
};
|
||||
|
||||
} /* namespace ARDOUR */
|
||||
|
|
|
|||
|
|
@ -43,9 +43,7 @@ using std::vector;
|
|||
|
||||
namespace ARDOUR {
|
||||
|
||||
const nframes_t frames_per_peak = 256;
|
||||
|
||||
class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR::AudioSource>
|
||||
class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR::AudioSource>
|
||||
{
|
||||
public:
|
||||
AudioSource (Session&, Glib::ustring name);
|
||||
|
|
@ -72,7 +70,8 @@ const nframes_t frames_per_peak = 256;
|
|||
uint32_t read_data_count() const { return _read_data_count; }
|
||||
uint32_t write_data_count() const { return _write_data_count; }
|
||||
|
||||
virtual int read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_unit) const;
|
||||
int read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_visual_peak) const;
|
||||
|
||||
int build_peaks ();
|
||||
bool peaks_ready (sigc::slot<void>, sigc::connection&) const;
|
||||
|
||||
|
|
@ -129,6 +128,12 @@ const nframes_t frames_per_peak = 256;
|
|||
|
||||
void update_length (nframes_t pos, nframes_t cnt);
|
||||
|
||||
virtual int read_peaks_with_fpp (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt,
|
||||
double samples_per_visual_peak, nframes_t fpp) const;
|
||||
|
||||
int compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force,
|
||||
bool intermediate_peaks_ready_signal, nframes_t frames_per_peak);
|
||||
|
||||
private:
|
||||
int peakfile;
|
||||
nframes_t peak_leftover_cnt;
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ CONFIG_VARIABLE (uint32_t, destructive_xfade_msecs, "destructive-xfade-msecs",
|
|||
|
||||
CONFIG_VARIABLE (EditMode, edit_mode, "edit-mode", Slide)
|
||||
CONFIG_VARIABLE (LayerModel, layer_model, "layer-model", MoveAddHigher)
|
||||
CONFIG_VARIABLE (bool, link_region_and_track_selection, "link-region-and-track-selection", false)
|
||||
CONFIG_VARIABLE (std::string, keyboard_layout_name, "keyboard-layout-name", "ansi")
|
||||
|
||||
/* monitoring, mute, solo etc */
|
||||
|
||||
|
|
@ -148,6 +150,8 @@ CONFIG_VARIABLE (uint32_t, periodic_safety_backup_interval, "periodic-safety-bac
|
|||
CONFIG_VARIABLE (float, automation_interval, "automation-interval", 50)
|
||||
CONFIG_VARIABLE (bool, sync_all_route_ordering, "sync-all-route-ordering", true)
|
||||
CONFIG_VARIABLE (bool, only_copy_imported_files, "only-copy-imported-files", true)
|
||||
CONFIG_VARIABLE (std::string, keyboard_layout, "keyboard-layout", "ansi")
|
||||
CONFIG_VARIABLE (std::string, default_bindings, "default-bindings", "ardour")
|
||||
|
||||
/* denormal management */
|
||||
|
||||
|
|
|
|||
|
|
@ -81,8 +81,10 @@ class Crossfade : public ARDOUR::AudioRegion
|
|||
boost::shared_ptr<ARDOUR::AudioRegion> out() const { return _out; }
|
||||
|
||||
nframes_t read_at (Sample *buf, Sample *mixdown_buffer,
|
||||
float *gain_buffer, nframes_t position, nframes_t cnt,
|
||||
uint32_t chan_n) const;
|
||||
float *gain_buffer, nframes_t position, nframes_t cnt,
|
||||
uint32_t chan_n,
|
||||
nframes_t read_frames = 0,
|
||||
nframes_t skip_frames = 0) const;
|
||||
|
||||
bool refresh ();
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ class LadspaPlugin : public ARDOUR::Plugin
|
|||
|
||||
/* Plugin interface */
|
||||
|
||||
uint32_t unique_id() const { return descriptor->UniqueID; }
|
||||
std::string unique_id() const;
|
||||
const char * label() const { return descriptor->Label; }
|
||||
const char * name() const { return descriptor->Name; }
|
||||
const char * maker() const { return descriptor->Maker; }
|
||||
|
|
|
|||
|
|
@ -146,6 +146,8 @@ class Locations : public PBD::StatefulDestructible
|
|||
Locations ();
|
||||
~Locations ();
|
||||
|
||||
const LocationList& list() { return locations; }
|
||||
|
||||
void add (Location *, bool make_current = false);
|
||||
void remove (Location *);
|
||||
void clear ();
|
||||
|
|
|
|||
62
libs/ardour/ardour/pitch.h
Normal file
62
libs/ardour/ardour/pitch.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
Copyright (C) 2007 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_pitch_h__
|
||||
#define __ardour_pitch_h__
|
||||
|
||||
#include <ardour/filter.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
class AudioRegion;
|
||||
}
|
||||
|
||||
#ifdef USE_RUBBERBAND
|
||||
|
||||
#include <ardour/rb_effect.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class Pitch : public RBEffect {
|
||||
public:
|
||||
Pitch (ARDOUR::Session&, TimeFXRequest&);
|
||||
~Pitch () {}
|
||||
};
|
||||
|
||||
} /* namespace */
|
||||
|
||||
# else
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class Pitch : public Filter {
|
||||
public:
|
||||
Pitch (ARDOUR::Session&, TimeFXRequest&);
|
||||
~Pitch () {}
|
||||
|
||||
int run (boost::shared_ptr<ARDOUR::Region>);
|
||||
|
||||
private:
|
||||
TimeFXRequest& tsr;
|
||||
};
|
||||
|
||||
} /* namespace */
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __ardour_pitch_h__ */
|
||||
|
|
@ -95,6 +95,7 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
|
|||
void partition (nframes_t start, nframes_t end, bool just_top_level);
|
||||
void duplicate (boost::shared_ptr<Region>, nframes_t position, float times);
|
||||
void nudge_after (nframes_t start, nframes_t distance, bool forwards);
|
||||
void shuffle (boost::shared_ptr<Region>, int dir);
|
||||
|
||||
boost::shared_ptr<Playlist> cut (list<AudioRange>&, bool result_is_hidden = true);
|
||||
boost::shared_ptr<Playlist> copy (list<AudioRange>&, bool result_is_hidden = true);
|
||||
|
|
@ -102,9 +103,12 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
|
|||
|
||||
RegionList* regions_at (nframes_t frame);
|
||||
RegionList* regions_touched (nframes_t start, nframes_t end);
|
||||
RegionList* regions_to_read (nframes_t start, nframes_t end);
|
||||
boost::shared_ptr<Region> find_region (const PBD::ID&) const;
|
||||
boost::shared_ptr<Region> top_region_at (nframes_t frame);
|
||||
boost::shared_ptr<Region> find_next_region (nframes_t frame, RegionPoint point, int dir);
|
||||
nframes64_t find_next_region_boundary (nframes64_t frame, int dir);
|
||||
bool region_is_shuffle_constrained (boost::shared_ptr<Region>);
|
||||
|
||||
template<class T> void foreach_region (T *t, void (T::*func)(boost::shared_ptr<Region>, void *), void *arg);
|
||||
template<class T> void foreach_region (T *t, void (T::*func)(boost::shared_ptr<Region>));
|
||||
|
|
@ -124,6 +128,8 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
|
|||
void freeze ();
|
||||
void thaw ();
|
||||
|
||||
void raise_region (boost::shared_ptr<Region>);
|
||||
void lower_region (boost::shared_ptr<Region>);
|
||||
void raise_region_to_top (boost::shared_ptr<Region>);
|
||||
void lower_region_to_bottom (boost::shared_ptr<Region>);
|
||||
|
||||
|
|
@ -182,6 +188,7 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
|
|||
bool first_set_state;
|
||||
bool _hidden;
|
||||
bool _splicing;
|
||||
bool _shuffling;
|
||||
bool _nudging;
|
||||
uint32_t _refcnt;
|
||||
EditMode _edit_mode;
|
||||
|
|
@ -227,12 +234,12 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
|
|||
|
||||
void sort_regions ();
|
||||
|
||||
void possibly_splice ();
|
||||
void possibly_splice_unlocked();
|
||||
void core_splice ();
|
||||
void splice_locked ();
|
||||
void splice_unlocked ();
|
||||
void possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude = boost::shared_ptr<Region>());
|
||||
void possibly_splice_unlocked(nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude = boost::shared_ptr<Region>());
|
||||
|
||||
void core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude);
|
||||
void splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude);
|
||||
void splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude);
|
||||
|
||||
virtual void finalize_split_region (boost::shared_ptr<Region> original, boost::shared_ptr<Region> left, boost::shared_ptr<Region> right) {}
|
||||
|
||||
|
|
@ -258,6 +265,7 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
|
|||
boost::shared_ptr<Playlist> cut (nframes_t start, nframes_t cnt, bool result_is_hidden);
|
||||
boost::shared_ptr<Playlist> copy (nframes_t start, nframes_t cnt, bool result_is_hidden);
|
||||
|
||||
int move_region_to_layer (layer_t, boost::shared_ptr<Region> r, int dir);
|
||||
void relayer ();
|
||||
|
||||
void unset_freeze_parent (Playlist*);
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ class PluginInfo {
|
|||
ChanCount n_outputs;
|
||||
ARDOUR::PluginType type;
|
||||
|
||||
long unique_id;
|
||||
std::string unique_id;
|
||||
|
||||
virtual PluginPtr load (Session& session) = 0;
|
||||
|
||||
|
|
@ -114,7 +114,7 @@ class Plugin : public PBD::StatefulDestructible, public Latent
|
|||
bool max_unbound;
|
||||
};
|
||||
|
||||
virtual uint32_t unique_id() const = 0;
|
||||
virtual std::string unique_id() const = 0;
|
||||
virtual const char * label() const = 0;
|
||||
virtual const char * name() const = 0;
|
||||
virtual const char * maker() const = 0;
|
||||
|
|
@ -170,7 +170,7 @@ class Plugin : public PBD::StatefulDestructible, public Latent
|
|||
bool save_preset(string name, string domain /* vst, ladspa etc. */);
|
||||
};
|
||||
|
||||
PluginPtr find_plugin(ARDOUR::Session&, string name, long unique_id, ARDOUR::PluginType);
|
||||
PluginPtr find_plugin(ARDOUR::Session&, string unique_id, ARDOUR::PluginType);
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class PluginManager {
|
|||
|
||||
ARDOUR::PluginInfoList &vst_plugin_info () { return _vst_plugin_info; }
|
||||
ARDOUR::PluginInfoList &ladspa_plugin_info () { return _ladspa_plugin_info; }
|
||||
ARDOUR::PluginInfoList &au_plugin_info () { return _au_plugin_info; }
|
||||
|
||||
void refresh ();
|
||||
|
||||
|
|
@ -51,6 +52,8 @@ class PluginManager {
|
|||
private:
|
||||
ARDOUR::PluginInfoList _vst_plugin_info;
|
||||
ARDOUR::PluginInfoList _ladspa_plugin_info;
|
||||
ARDOUR::PluginInfoList _au_plugin_info;
|
||||
|
||||
std::map<uint32_t, std::string> rdf_type;
|
||||
|
||||
std::string ladspa_path;
|
||||
|
|
@ -64,6 +67,9 @@ class PluginManager {
|
|||
void add_vst_presets ();
|
||||
void add_presets (std::string domain);
|
||||
|
||||
int au_discover ();
|
||||
void au_refresh ();
|
||||
|
||||
int vst_discover_from_path (std::string path);
|
||||
int vst_discover (std::string path);
|
||||
|
||||
|
|
@ -71,6 +77,7 @@ class PluginManager {
|
|||
int ladspa_discover (std::string path);
|
||||
|
||||
std::string get_ladspa_category (uint32_t id);
|
||||
std::vector<uint32_t> ladspa_plugin_whitelist;
|
||||
|
||||
static PluginManager* _manager; // singleton
|
||||
};
|
||||
|
|
|
|||
42
libs/ardour/ardour/rb_effect.h
Normal file
42
libs/ardour/ardour/rb_effect.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
Copyright (C) 2007 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_rbeffect_h__
|
||||
#define __ardour_rbeffect_h__
|
||||
|
||||
#include <ardour/audiofilter.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class AudioRegion;
|
||||
|
||||
class RBEffect : public Filter {
|
||||
public:
|
||||
RBEffect (ARDOUR::Session&, TimeFXRequest&);
|
||||
~RBEffect ();
|
||||
|
||||
int run (boost::shared_ptr<ARDOUR::Region>);
|
||||
|
||||
private:
|
||||
TimeFXRequest& tsr;
|
||||
};
|
||||
|
||||
} /* namespace */
|
||||
|
||||
#endif /* __ardour_rbeffect_h__ */
|
||||
|
|
@ -96,11 +96,17 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
|
|||
nframes_t length() const { return _length; }
|
||||
layer_t layer () const { return _layer; }
|
||||
|
||||
/* these two are valid ONLY during a StateChanged signal handler */
|
||||
|
||||
nframes_t last_position() const { return _last_position; }
|
||||
nframes_t last_length() const { return _last_length; }
|
||||
|
||||
nframes64_t ancestral_start () const { return _ancestral_start; }
|
||||
nframes64_t ancestral_length () const { return _ancestral_length; }
|
||||
float stretch() const { return _stretch; }
|
||||
float shift() const { return _shift; }
|
||||
|
||||
void set_ancestral_data (nframes64_t start, nframes64_t length, float stretch);
|
||||
void set_ancestral_data (nframes64_t start, nframes64_t length, float stretch, float shift);
|
||||
|
||||
nframes_t sync_offset(int& dir) const;
|
||||
nframes_t sync_position() const;
|
||||
|
|
@ -129,7 +135,7 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
|
|||
void thaw (const string& why);
|
||||
|
||||
bool covers (nframes_t frame) const {
|
||||
return first_frame() <= frame && frame < last_frame();
|
||||
return first_frame() <= frame && frame <= last_frame();
|
||||
}
|
||||
|
||||
OverlapType coverage (nframes_t start, nframes_t end) const {
|
||||
|
|
@ -149,7 +155,7 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
|
|||
void set_position (nframes_t, void *src);
|
||||
void set_position_on_top (nframes_t, void *src);
|
||||
void special_set_position (nframes_t);
|
||||
void nudge_position (long, void *src);
|
||||
void nudge_position (nframes64_t, void *src);
|
||||
|
||||
bool at_natural_position () const;
|
||||
void move_to_natural_position (void *src);
|
||||
|
|
@ -160,6 +166,8 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
|
|||
void trim_to (nframes_t position, nframes_t length, void *src);
|
||||
|
||||
void set_layer (layer_t l); /* ONLY Playlist can call this */
|
||||
void raise ();
|
||||
void lower ();
|
||||
void raise_to_top ();
|
||||
void lower_to_bottom ();
|
||||
|
||||
|
|
@ -232,10 +240,11 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
|
|||
void maybe_uncopy ();
|
||||
void first_edit ();
|
||||
|
||||
virtual bool verify_start (nframes_t);
|
||||
virtual bool verify_start_and_length (nframes_t, nframes_t);
|
||||
virtual bool verify_start_mutable (nframes_t&_start);
|
||||
virtual bool verify_length (nframes_t);
|
||||
bool verify_start (nframes_t);
|
||||
bool verify_start_and_length (nframes_t, nframes_t&);
|
||||
bool verify_start_mutable (nframes_t&_start);
|
||||
bool verify_length (nframes_t);
|
||||
|
||||
virtual void recompute_at_start () = 0;
|
||||
virtual void recompute_at_end () = 0;
|
||||
|
||||
|
|
@ -243,7 +252,9 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
|
|||
Flag _flags;
|
||||
nframes_t _start;
|
||||
nframes_t _length;
|
||||
nframes_t _last_length;
|
||||
nframes_t _position;
|
||||
nframes_t _last_position;
|
||||
nframes_t _sync_position;
|
||||
layer_t _layer;
|
||||
mutable RegionEditState _first_edit;
|
||||
|
|
@ -251,6 +262,7 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
|
|||
nframes64_t _ancestral_start;
|
||||
nframes64_t _ancestral_length;
|
||||
float _stretch;
|
||||
float _shift;
|
||||
mutable uint32_t _read_data_count; ///< modified in read()
|
||||
Change _pending_changed;
|
||||
uint64_t _last_layer_op; ///< timestamp
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ class Route : public IO
|
|||
|
||||
void set_gain (gain_t val, void *src);
|
||||
void inc_gain (gain_t delta, void *src);
|
||||
|
||||
|
||||
bool active() const { return _active; }
|
||||
void set_active (bool yn);
|
||||
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ class Session : public PBD::StatefulDestructible
|
|||
SetDiskstreamSpeed,
|
||||
Locate,
|
||||
LocateRoll,
|
||||
LocateRollLocate,
|
||||
SetLoop,
|
||||
PunchIn,
|
||||
PunchOut,
|
||||
|
|
@ -224,9 +225,9 @@ class Session : public PBD::StatefulDestructible
|
|||
/* creating from an XML file */
|
||||
|
||||
Session (AudioEngine&,
|
||||
string fullpath,
|
||||
string snapshot_name,
|
||||
string* mix_template = 0);
|
||||
const string& fullpath,
|
||||
const string& snapshot_name,
|
||||
string mix_template = "");
|
||||
|
||||
/* creating a new Session */
|
||||
|
||||
|
|
@ -354,7 +355,7 @@ class Session : public PBD::StatefulDestructible
|
|||
|
||||
sigc::signal<void,RouteList&> RouteAdded;
|
||||
|
||||
void request_roll ();
|
||||
void request_roll_at_and_return (nframes_t start, nframes_t return_to);
|
||||
void request_bounded_roll (nframes_t start, nframes_t end);
|
||||
void request_stop (bool abort = false);
|
||||
void request_locate (nframes_t frame, bool with_roll = false);
|
||||
|
|
@ -499,6 +500,7 @@ class Session : public PBD::StatefulDestructible
|
|||
|
||||
nframes_t transport_frame () const {return _transport_frame; }
|
||||
nframes_t audible_frame () const;
|
||||
nframes64_t requested_return_frame() const { return _requested_return_frame; }
|
||||
|
||||
enum PullupFormat {
|
||||
pullup_Plus4Plus1,
|
||||
|
|
@ -542,6 +544,9 @@ class Session : public PBD::StatefulDestructible
|
|||
float transport_speed() const { return _transport_speed; }
|
||||
bool transport_stopped() const { return _transport_speed == 0.0f; }
|
||||
bool transport_rolling() const { return _transport_speed != 0.0f; }
|
||||
|
||||
void set_silent (bool yn);
|
||||
bool silent () { return _silent; }
|
||||
|
||||
int jack_slave_sync (nframes_t);
|
||||
|
||||
|
|
@ -701,6 +706,13 @@ class Session : public PBD::StatefulDestructible
|
|||
uint32_t n_port_inserts() const { return _port_inserts.size(); }
|
||||
uint32_t n_plugin_inserts() const { return _plugin_inserts.size(); }
|
||||
uint32_t n_sends() const { return _sends.size(); }
|
||||
|
||||
static void set_disable_all_loaded_plugins (bool yn) {
|
||||
_disable_all_loaded_plugins = yn;
|
||||
}
|
||||
static bool get_disable_all_loaded_plugins() {
|
||||
return _disable_all_loaded_plugins;
|
||||
}
|
||||
|
||||
uint32_t next_send_id();
|
||||
uint32_t next_insert_id();
|
||||
|
|
@ -901,6 +913,18 @@ class Session : public PBD::StatefulDestructible
|
|||
long value,
|
||||
void* ptr,
|
||||
float opt);
|
||||
|
||||
typedef float (*compute_peak_t) (Sample *, nframes_t, float);
|
||||
typedef void (*find_peaks_t) (Sample *, nframes_t, float *, float*);
|
||||
typedef void (*apply_gain_to_buffer_t) (Sample *, nframes_t, float);
|
||||
typedef void (*mix_buffers_with_gain_t) (Sample *, Sample *, nframes_t, float);
|
||||
typedef void (*mix_buffers_no_gain_t) (Sample *, Sample *, nframes_t);
|
||||
|
||||
static compute_peak_t compute_peak;
|
||||
static find_peaks_t find_peaks;
|
||||
static apply_gain_to_buffer_t apply_gain_to_buffer;
|
||||
static mix_buffers_with_gain_t mix_buffers_with_gain;
|
||||
static mix_buffers_no_gain_t mix_buffers_no_gain;
|
||||
|
||||
static sigc::signal<void> SendFeedback;
|
||||
|
||||
|
|
@ -927,12 +951,9 @@ class Session : public PBD::StatefulDestructible
|
|||
void update_latency_compensation (bool, bool);
|
||||
|
||||
private:
|
||||
int create (bool& new_session, const string& mix_template, nframes_t initial_length);
|
||||
void destroy ();
|
||||
|
||||
void initialize_start_and_end_locations(nframes_t start, nframes_t end);
|
||||
bool create_session_file();
|
||||
bool create_session_file_from_template (const string& template_path);
|
||||
|
||||
|
||||
nframes_t compute_initial_length ();
|
||||
|
||||
enum SubState {
|
||||
|
|
@ -949,35 +970,36 @@ class Session : public PBD::StatefulDestructible
|
|||
*/
|
||||
|
||||
typedef void (Session::*process_function_type)(nframes_t);
|
||||
|
||||
AudioEngine &_engine;
|
||||
mutable gint processing_prohibited;
|
||||
/// the function called when the main JACK process callback happens
|
||||
|
||||
AudioEngine& _engine;
|
||||
mutable gint processing_prohibited;
|
||||
process_function_type process_function;
|
||||
process_function_type last_process_function;
|
||||
bool waiting_for_sync_offset;
|
||||
nframes_t _base_frame_rate;
|
||||
nframes_t _current_frame_rate; //this includes video pullup offset
|
||||
nframes_t _base_frame_rate;
|
||||
nframes_t _current_frame_rate; //this includes video pullup offset
|
||||
int transport_sub_state;
|
||||
mutable gint _record_status;
|
||||
nframes_t _transport_frame;
|
||||
mutable gint _record_status;
|
||||
volatile nframes_t _transport_frame;
|
||||
Location* end_location;
|
||||
Location* start_location;
|
||||
Slave *_slave;
|
||||
Slave* _slave;
|
||||
bool _silent;
|
||||
volatile float _transport_speed;
|
||||
volatile float _desired_transport_speed;
|
||||
float _last_transport_speed;
|
||||
bool auto_play_legal;
|
||||
nframes_t _last_slave_transport_frame;
|
||||
nframes_t maximum_output_latency;
|
||||
nframes_t last_stop_frame;
|
||||
nframes_t _last_slave_transport_frame;
|
||||
nframes_t maximum_output_latency;
|
||||
nframes_t last_stop_frame;
|
||||
volatile nframes64_t _requested_return_frame;
|
||||
BufferSet* _scratch_buffers;
|
||||
BufferSet* _silent_buffers;
|
||||
BufferSet* _mix_buffers;
|
||||
nframes_t current_block_size;
|
||||
nframes_t _worst_output_latency;
|
||||
nframes_t _worst_input_latency;
|
||||
nframes_t _worst_track_latency;
|
||||
nframes_t current_block_size;
|
||||
nframes_t _worst_output_latency;
|
||||
nframes_t _worst_input_latency;
|
||||
nframes_t _worst_track_latency;
|
||||
bool _have_captured;
|
||||
float _meter_hold;
|
||||
float _meter_falloff;
|
||||
|
|
@ -1675,6 +1697,8 @@ class Session : public PBD::StatefulDestructible
|
|||
|
||||
void set_history_depth (uint32_t depth);
|
||||
void sync_order_keys ();
|
||||
|
||||
static bool _disable_all_loaded_plugins;
|
||||
};
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
|
|
|||
|
|
@ -34,11 +34,6 @@ class SilentFileSource : public AudioFileSource {
|
|||
|
||||
void set_length (nframes_t len);
|
||||
|
||||
int read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_unit) const {
|
||||
memset (peaks, 0, sizeof (PeakData) * npeaks);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool destructive() const { return false; }
|
||||
|
||||
protected:
|
||||
|
|
@ -58,6 +53,11 @@ class SilentFileSource : public AudioFileSource {
|
|||
|
||||
void set_header_timeline_position () {}
|
||||
|
||||
int read_peaks_with_fpp (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_unit, nframes_t fpp) const {
|
||||
memset (peaks, 0, sizeof (PeakData) * npeaks);
|
||||
return 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ class Slave {
|
|||
virtual bool starting() const { return false; }
|
||||
virtual nframes_t resolution() const = 0;
|
||||
virtual bool requires_seekahead () const = 0;
|
||||
virtual bool is_always_synced() const { return false; }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -139,6 +140,7 @@ class JACK_Slave : public Slave
|
|||
nframes_t resolution() const { return 1; }
|
||||
bool requires_seekahead () const { return false; }
|
||||
void reset_client (jack_client_t* jack);
|
||||
bool is_always_synced() const { return true; }
|
||||
|
||||
private:
|
||||
jack_client_t* jack;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ using std::string;
|
|||
// Use this define when initializing arrarys for use in sndfile_*_format()
|
||||
#define SNDFILE_STR_LENGTH 32
|
||||
|
||||
#define SNDFILE_HEADER_FORMATS 7
|
||||
#define SNDFILE_HEADER_FORMATS 5
|
||||
extern const char * const sndfile_header_formats_strings[SNDFILE_HEADER_FORMATS+1];
|
||||
extern const char * const sndfile_file_endings_strings[SNDFILE_HEADER_FORMATS+1];
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ class Source : public SessionObject
|
|||
XMLNode& get_state ();
|
||||
int set_state (const XMLNode&);
|
||||
|
||||
virtual bool destructive() const { return false; }
|
||||
|
||||
void use () { _in_use++; }
|
||||
void disuse () { if (_in_use) { _in_use--; } }
|
||||
|
||||
|
|
|
|||
|
|
@ -21,31 +21,46 @@
|
|||
#define __ardour_stretch_h__
|
||||
|
||||
#include <ardour/filter.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
class AudioRegion;
|
||||
}
|
||||
|
||||
#ifdef USE_RUBBERBAND
|
||||
|
||||
#include <ardour/rb_effect.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class Stretch : public RBEffect {
|
||||
public:
|
||||
Stretch (ARDOUR::Session&, TimeFXRequest&);
|
||||
~Stretch() {}
|
||||
};
|
||||
|
||||
} /* namespace */
|
||||
|
||||
#else
|
||||
|
||||
#include <soundtouch/SoundTouch.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class AudioRegion;
|
||||
|
||||
struct TimeStretchRequest : public InterThreadInfo {
|
||||
float fraction;
|
||||
bool quick_seek;
|
||||
bool antialias;
|
||||
};
|
||||
|
||||
class Stretch : public Filter {
|
||||
public:
|
||||
Stretch (ARDOUR::Session&, TimeStretchRequest&);
|
||||
Stretch (ARDOUR::Session&, TimeFXRequest&);
|
||||
~Stretch ();
|
||||
|
||||
int run (boost::shared_ptr<ARDOUR::Region>);
|
||||
|
||||
private:
|
||||
TimeStretchRequest& tsr;
|
||||
soundtouch::SoundTouch st;
|
||||
TimeFXRequest& tsr;
|
||||
|
||||
soundtouch::SoundTouch st;
|
||||
};
|
||||
|
||||
} /* namespace */
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __ardour_stretch_h__ */
|
||||
|
|
|
|||
|
|
@ -40,27 +40,29 @@ using std::list;
|
|||
using std::vector;
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class Meter;
|
||||
class Tempo {
|
||||
public:
|
||||
Tempo (double bpm)
|
||||
: _beats_per_minute (bpm) {}
|
||||
Tempo (double bpm, double type=4.0) // defaulting to quarter note
|
||||
: _beats_per_minute (bpm), _note_type(type) {}
|
||||
Tempo (const Tempo& other) {
|
||||
_beats_per_minute = other._beats_per_minute;
|
||||
_note_type = other._note_type;
|
||||
}
|
||||
void operator= (const Tempo& other) {
|
||||
if (&other != this) {
|
||||
_beats_per_minute = other._beats_per_minute;
|
||||
_note_type = other._note_type;
|
||||
}
|
||||
}
|
||||
|
||||
double beats_per_minute () const { return _beats_per_minute; }
|
||||
double frames_per_beat (nframes_t sr) const {
|
||||
return ((60.0 * sr) / _beats_per_minute);
|
||||
}
|
||||
double beats_per_minute () const { return _beats_per_minute;}
|
||||
double note_type () const { return _note_type;}
|
||||
double frames_per_beat (nframes_t sr, const Meter& meter) const;
|
||||
|
||||
protected:
|
||||
double _beats_per_minute;
|
||||
double _note_type;
|
||||
};
|
||||
|
||||
class Meter {
|
||||
|
|
@ -149,8 +151,8 @@ class MeterSection : public MetricSection, public Meter {
|
|||
|
||||
class TempoSection : public MetricSection, public Tempo {
|
||||
public:
|
||||
TempoSection (const BBT_Time& start, double qpm)
|
||||
: MetricSection (start), Tempo (qpm) {}
|
||||
TempoSection (const BBT_Time& start, double qpm, double note_type)
|
||||
: MetricSection (start), Tempo (qpm, note_type) {}
|
||||
TempoSection (const XMLNode&);
|
||||
|
||||
static const string xml_state_node_name;
|
||||
|
|
|
|||
|
|
@ -379,6 +379,13 @@ namespace ARDOUR {
|
|||
SrcFastest
|
||||
};
|
||||
|
||||
struct TimeFXRequest : public InterThreadInfo {
|
||||
float time_fraction;
|
||||
float pitch_fraction;
|
||||
bool quick_seek;
|
||||
bool antialias;
|
||||
};
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf);
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ class VSTPlugin : public ARDOUR::Plugin
|
|||
|
||||
/* Plugin interface */
|
||||
|
||||
uint32_t unique_id() const;
|
||||
std::string unique_id() const;
|
||||
const char * label() const;
|
||||
const char * name() const;
|
||||
const char * maker() const;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ AudioBuffer::AudioBuffer(size_t capacity)
|
|||
, _owns_data (false)
|
||||
, _data (0)
|
||||
{
|
||||
if (_capacity) {
|
||||
if (_capacity > 0) {
|
||||
_owns_data = true; // prevent resize() from gagging
|
||||
resize (_capacity);
|
||||
silence (_capacity);
|
||||
|
|
|
|||
|
|
@ -850,10 +850,18 @@ AudioDiskstream::commit (nframes_t nframes)
|
|||
}
|
||||
|
||||
if (_slaved) {
|
||||
need_butler = c->front()->playback_buf->write_space() >= c->front()->playback_buf->bufsize() / 2;
|
||||
/*if (_io && _io->active()) {*/
|
||||
need_butler = c->front()->playback_buf->write_space() >= c->front()->playback_buf->bufsize() / 2;
|
||||
/*} else {
|
||||
need_butler = false;
|
||||
}*/
|
||||
} else {
|
||||
need_butler = c->front()->playback_buf->write_space() >= disk_io_chunk_frames
|
||||
|| c->front()->capture_buf->read_space() >= disk_io_chunk_frames;
|
||||
/*if (_io && _io->active()) {*/
|
||||
need_butler = c->front()->playback_buf->write_space() >= disk_io_chunk_frames
|
||||
|| c->front()->capture_buf->read_space() >= disk_io_chunk_frames;
|
||||
/*} else {
|
||||
need_butler = c->front()->capture_buf->read_space() >= disk_io_chunk_frames;
|
||||
}*/
|
||||
}
|
||||
|
||||
if (commit_should_unlock) {
|
||||
|
|
@ -1940,6 +1948,7 @@ AudioDiskstream::set_state (const XMLNode& node)
|
|||
if (nchans > _n_channels.n_audio()) {
|
||||
|
||||
add_channel (nchans - _n_channels.n_audio());
|
||||
IO::PortCountChanged(_n_channels);
|
||||
|
||||
} else if (nchans < _n_channels.n_audio()) {
|
||||
|
||||
|
|
|
|||
|
|
@ -123,7 +123,10 @@ ARDOUR::nframes_t
|
|||
AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
|
||||
nframes_t cnt, unsigned chan_n)
|
||||
{
|
||||
nframes_t ret = cnt;
|
||||
nframes_t end;
|
||||
nframes_t read_frames;
|
||||
nframes_t skip_frames;
|
||||
|
||||
/* optimizing this memset() away involves a lot of conditionals
|
||||
that may well cause more of a hit due to cache misses
|
||||
|
|
@ -147,14 +150,24 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nf
|
|||
Glib::Mutex::Lock rm (region_lock);
|
||||
|
||||
end = start + cnt - 1;
|
||||
read_frames = 0;
|
||||
skip_frames = 0;
|
||||
_read_data_count = 0;
|
||||
|
||||
_read_data_count = 0;
|
||||
|
||||
RegionList* rlist = regions_to_read (start, start+cnt);
|
||||
|
||||
if (rlist->empty()) {
|
||||
delete rlist;
|
||||
return cnt;
|
||||
}
|
||||
|
||||
map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
|
||||
map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
|
||||
vector<uint32_t> relevant_layers;
|
||||
|
||||
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
|
||||
for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ++i) {
|
||||
if ((*i)->coverage (start, end) != OverlapNone) {
|
||||
relevant_regions[(*i)->layer()].push_back (*i);
|
||||
relevant_layers.push_back ((*i)->layer());
|
||||
|
|
@ -186,7 +199,7 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nf
|
|||
for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
|
||||
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
|
||||
assert(ar);
|
||||
ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
|
||||
ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
|
||||
_read_data_count += ar->read_data_count();
|
||||
}
|
||||
|
||||
|
|
@ -199,7 +212,8 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nf
|
|||
}
|
||||
}
|
||||
|
||||
return cnt;
|
||||
delete rlist;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -25,10 +25,10 @@
|
|||
using namespace ARDOUR;
|
||||
using namespace std;
|
||||
|
||||
AudioPort::AudioPort (const std::string& name, Flags flgs, bool external, nframes_t capacity)
|
||||
: Port (name, flgs)
|
||||
, BaseAudioPort (name, flgs)
|
||||
, PortFacade (name, flgs)
|
||||
AudioPort::AudioPort (const std::string& name, Flags flags, bool external, nframes_t capacity)
|
||||
: Port (name, flags)
|
||||
, BaseAudioPort (name, flags)
|
||||
, PortFacade (name, flags)
|
||||
{
|
||||
if (!external || receives_input()) {
|
||||
|
||||
|
|
@ -43,6 +43,7 @@ AudioPort::AudioPort (const std::string& name, Flags flgs, bool external, nframe
|
|||
if (!external) {
|
||||
|
||||
_ext_port = 0;
|
||||
set_name (name);
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -52,7 +53,7 @@ AudioPort::AudioPort (const std::string& name, Flags flgs, bool external, nframe
|
|||
will in turn be using the JACK port buffer for data.
|
||||
*/
|
||||
|
||||
_ext_port = new JackAudioPort (name, flgs, 0);
|
||||
_ext_port = new JackAudioPort (name, flags, 0);
|
||||
|
||||
if (sends_output()) {
|
||||
_buffer = &dynamic_cast<JackAudioPort*>(_ext_port)->get_audio_buffer();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2006 Paul Davis
|
||||
Written by Taybin Rutkin
|
||||
|
||||
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
|
||||
|
|
@ -18,10 +17,16 @@
|
|||
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <pbd/transmitter.h>
|
||||
#include <pbd/xml++.h>
|
||||
#include <pbd/whitespace.h>
|
||||
|
||||
#include <glibmm/thread.h>
|
||||
|
||||
#include <ardour/audioengine.h>
|
||||
#include <ardour/io.h>
|
||||
#include <ardour/audio_unit.h>
|
||||
#include <ardour/session.h>
|
||||
#include <ardour/utils.h>
|
||||
|
|
@ -37,66 +42,93 @@ using namespace std;
|
|||
using namespace PBD;
|
||||
using namespace ARDOUR;
|
||||
|
||||
AUPlugin::AUPlugin (AudioEngine& engine, Session& session, CAComponent* _comp)
|
||||
static OSStatus
|
||||
_render_callback(void *userData,
|
||||
AudioUnitRenderActionFlags *ioActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
UInt32 inNumberFrames,
|
||||
AudioBufferList* ioData)
|
||||
{
|
||||
return ((AUPlugin*)userData)->render_callback (ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
|
||||
}
|
||||
|
||||
AUPlugin::AUPlugin (AudioEngine& engine, Session& session, boost::shared_ptr<CAComponent> _comp)
|
||||
:
|
||||
Plugin (engine, session),
|
||||
comp (_comp),
|
||||
unit (new CAAudioUnit)
|
||||
unit (new CAAudioUnit),
|
||||
initialized (false),
|
||||
buffers (0),
|
||||
current_maxbuf (0),
|
||||
current_offset (0),
|
||||
current_buffers (0),
|
||||
frames_processed (0)
|
||||
{
|
||||
OSErr err = CAAudioUnit::Open (*comp, *unit);
|
||||
OSErr err = CAAudioUnit::Open (*(comp.get()), *unit);
|
||||
|
||||
if (err != noErr) {
|
||||
error << _("AudioUnit: Could not convert CAComponent to CAAudioUnit") << endmsg;
|
||||
delete unit;
|
||||
delete comp;
|
||||
throw failed_constructor ();
|
||||
}
|
||||
|
||||
unit->Initialize ();
|
||||
AURenderCallbackStruct renderCallbackInfo;
|
||||
|
||||
renderCallbackInfo.inputProc = _render_callback;
|
||||
renderCallbackInfo.inputProcRefCon = this;
|
||||
|
||||
if ((err = unit->SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input,
|
||||
0, (void*) &renderCallbackInfo, sizeof(renderCallbackInfo))) != 0) {
|
||||
cerr << "cannot install render callback (err = " << err << ')' << endl;
|
||||
throw failed_constructor();
|
||||
}
|
||||
|
||||
unit->GetElementCount (kAudioUnitScope_Input, input_elements);
|
||||
unit->GetElementCount (kAudioUnitScope_Output, output_elements);
|
||||
|
||||
// set up the basic stream format. these fields do not change
|
||||
|
||||
streamFormat.mSampleRate = session.frame_rate();
|
||||
streamFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
streamFormat.mFormatFlags = kAudioFormatFlagIsFloat|kAudioFormatFlagIsPacked|kAudioFormatFlagIsNonInterleaved;
|
||||
streamFormat.mBitsPerChannel = 32;
|
||||
streamFormat.mFramesPerPacket = 1;
|
||||
|
||||
// subject to later modification as we discover channel counts
|
||||
|
||||
streamFormat.mBytesPerPacket = 4;
|
||||
streamFormat.mBytesPerFrame = 4;
|
||||
streamFormat.mChannelsPerFrame = 1;
|
||||
|
||||
format_set = 0;
|
||||
|
||||
if (_set_block_size (_session.get_block_size())) {
|
||||
error << _("AUPlugin: cannot set processing block size") << endmsg;
|
||||
throw failed_constructor();
|
||||
}
|
||||
}
|
||||
|
||||
AUPlugin::~AUPlugin ()
|
||||
{
|
||||
if (unit) {
|
||||
unit->Uninitialize ();
|
||||
delete unit;
|
||||
}
|
||||
|
||||
if (comp) {
|
||||
delete comp;
|
||||
}
|
||||
|
||||
if (in_list) {
|
||||
delete in_list;
|
||||
}
|
||||
|
||||
if (out_list) {
|
||||
delete out_list;
|
||||
|
||||
if (buffers) {
|
||||
free (buffers);
|
||||
}
|
||||
}
|
||||
|
||||
AUPluginInfo::~AUPluginInfo ()
|
||||
{
|
||||
if (desc) {
|
||||
delete desc;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
string
|
||||
AUPlugin::unique_id () const
|
||||
{
|
||||
return 0;
|
||||
return AUPluginInfo::stringify_descriptor (comp->Desc());
|
||||
}
|
||||
|
||||
const char *
|
||||
AUPlugin::label () const
|
||||
{
|
||||
return "AUPlugin label";
|
||||
}
|
||||
|
||||
const char *
|
||||
AUPlugin::maker () const
|
||||
{
|
||||
return "AUplugin maker";
|
||||
return _info->name.c_str();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
|
@ -125,7 +157,7 @@ AUPlugin::signal_latency () const
|
|||
void
|
||||
AUPlugin::set_parameter (uint32_t which, float val)
|
||||
{
|
||||
unit->SetParameter (parameter_map[which].first, parameter_map[which].second, 0, val);
|
||||
// unit->SetParameter (parameter_map[which].first, parameter_map[which].second, 0, val);
|
||||
}
|
||||
|
||||
float
|
||||
|
|
@ -133,7 +165,7 @@ AUPlugin::get_parameter (uint32_t which) const
|
|||
{
|
||||
float outValue = 0.0;
|
||||
|
||||
unit->GetParameter(parameter_map[which].first, parameter_map[which].second, 0, outValue);
|
||||
// unit->GetParameter(parameter_map[which].first, parameter_map[which].second, 0, outValue);
|
||||
|
||||
return outValue;
|
||||
}
|
||||
|
|
@ -153,19 +185,174 @@ AUPlugin::nth_parameter (uint32_t which, bool& ok) const
|
|||
void
|
||||
AUPlugin::activate ()
|
||||
{
|
||||
unit->GlobalReset ();
|
||||
if (!initialized) {
|
||||
OSErr err;
|
||||
if ((err = unit->Initialize()) != noErr) {
|
||||
error << string_compose (_("AUPlugin: cannot initialize plugin (err = %1)"), err) << endmsg;
|
||||
} else {
|
||||
frames_processed = 0;
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AUPlugin::deactivate ()
|
||||
{
|
||||
// not needed. GlobalReset () takes care of it.
|
||||
unit->GlobalReset ();
|
||||
}
|
||||
|
||||
void
|
||||
AUPlugin::set_block_size (nframes_t nframes)
|
||||
{
|
||||
_set_block_size (nframes);
|
||||
}
|
||||
|
||||
int
|
||||
AUPlugin::_set_block_size (nframes_t nframes)
|
||||
{
|
||||
bool was_initialized = initialized;
|
||||
UInt32 numFrames = nframes;
|
||||
OSErr err;
|
||||
|
||||
if (initialized) {
|
||||
unit->Uninitialize ();
|
||||
}
|
||||
|
||||
if ((err = unit->SetProperty (kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global,
|
||||
0, &numFrames, sizeof (numFrames))) != noErr) {
|
||||
cerr << "cannot set max frames (err = " << err << ')' << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (was_initialized) {
|
||||
activate ();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
AUPlugin::can_support_input_configuration (int32_t in)
|
||||
{
|
||||
streamFormat.mChannelsPerFrame = in;
|
||||
/* apple says that for non-interleaved data, these
|
||||
values always refer to a single channel.
|
||||
*/
|
||||
streamFormat.mBytesPerPacket = 4;
|
||||
streamFormat.mBytesPerFrame = 4;
|
||||
|
||||
if (set_input_format () == 0) {
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
AUPlugin::set_input_format ()
|
||||
{
|
||||
return set_stream_format (kAudioUnitScope_Input, input_elements);
|
||||
}
|
||||
|
||||
int
|
||||
AUPlugin::set_output_format ()
|
||||
{
|
||||
return set_stream_format (kAudioUnitScope_Output, output_elements);
|
||||
}
|
||||
|
||||
int
|
||||
AUPlugin::set_stream_format (int scope, uint32_t cnt)
|
||||
{
|
||||
OSErr result;
|
||||
|
||||
for (uint32_t i = 0; i < cnt; ++i) {
|
||||
if ((result = unit->SetFormat (scope, i, streamFormat)) != 0) {
|
||||
error << string_compose (_("AUPlugin: could not set stream format for %1/%2 (err = %3)"),
|
||||
(scope == kAudioUnitScope_Input ? "input" : "output"), i, result) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (scope == kAudioUnitScope_Input) {
|
||||
format_set |= 0x1;
|
||||
} else {
|
||||
format_set |= 0x2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
AUPlugin::compute_output_streams (int32_t nplugins)
|
||||
{
|
||||
/* we will never replicate AU plugins - either they can do the I/O we need
|
||||
or not. thus, we can ignore nplugins entirely.
|
||||
*/
|
||||
|
||||
if (set_output_format() == 0) {
|
||||
|
||||
if (buffers) {
|
||||
free (buffers);
|
||||
buffers = 0;
|
||||
}
|
||||
|
||||
buffers = (AudioBufferList *) malloc (offsetof(AudioBufferList, mBuffers) +
|
||||
streamFormat.mChannelsPerFrame * sizeof(AudioBuffer));
|
||||
|
||||
Glib::Mutex::Lock em (_session.engine().process_lock());
|
||||
IO::MoreOutputs (streamFormat.mChannelsPerFrame);
|
||||
|
||||
return streamFormat.mChannelsPerFrame;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
AUPlugin::output_streams() const
|
||||
{
|
||||
if (!(format_set & 0x2)) {
|
||||
warning << _("AUPlugin: output_streams() called without any format set!") << endmsg;
|
||||
return 1;
|
||||
}
|
||||
return streamFormat.mChannelsPerFrame;
|
||||
}
|
||||
|
||||
|
||||
uint32_t
|
||||
AUPlugin::input_streams() const
|
||||
{
|
||||
if (!(format_set & 0x1)) {
|
||||
warning << _("AUPlugin: input_streams() called without any format set!") << endmsg;
|
||||
return 1;
|
||||
}
|
||||
return streamFormat.mChannelsPerFrame;
|
||||
}
|
||||
|
||||
OSStatus
|
||||
AUPlugin::render_callback(AudioUnitRenderActionFlags *ioActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
UInt32 inNumberFrames,
|
||||
AudioBufferList* ioData)
|
||||
{
|
||||
/* not much to do - the data is already in the buffers given to us in connect_and_run() */
|
||||
|
||||
if (current_maxbuf == 0) {
|
||||
error << _("AUPlugin: render callback called illegally!") << endmsg;
|
||||
return kAudioUnitErr_CannotDoInCurrentContext;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < current_maxbuf; ++i) {
|
||||
ioData->mBuffers[i].mNumberChannels = 1;
|
||||
ioData->mBuffers[i].mDataByteSize = sizeof (Sample) * inNumberFrames;
|
||||
ioData->mBuffers[i].mData = (*current_buffers)[i] + cb_offset + current_offset;
|
||||
}
|
||||
|
||||
cb_offset += inNumberFrames;
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -173,17 +360,37 @@ AUPlugin::connect_and_run (vector<Sample*>& bufs, uint32_t maxbuf, int32_t& in,
|
|||
{
|
||||
AudioUnitRenderActionFlags flags = 0;
|
||||
AudioTimeStamp ts;
|
||||
|
||||
AudioBufferList abl;
|
||||
abl.mNumberBuffers = 1;
|
||||
abl.mBuffers[0].mNumberChannels = 1;
|
||||
abl.mBuffers[0].mDataByteSize = nframes * sizeof(Sample);
|
||||
abl.mBuffers[0].mData = &bufs[0];
|
||||
|
||||
|
||||
unit->Render (&flags, &ts, 0, 0, &abl);
|
||||
|
||||
return 0;
|
||||
|
||||
current_buffers = &bufs;
|
||||
current_maxbuf = maxbuf;
|
||||
current_offset = offset;
|
||||
cb_offset = 0;
|
||||
|
||||
buffers->mNumberBuffers = maxbuf;
|
||||
|
||||
for (uint32_t i = 0; i < maxbuf; ++i) {
|
||||
buffers->mBuffers[i].mNumberChannels = 1;
|
||||
buffers->mBuffers[i].mDataByteSize = nframes * sizeof (Sample);
|
||||
buffers->mBuffers[i].mData = 0;
|
||||
}
|
||||
|
||||
ts.mSampleTime = frames_processed;
|
||||
ts.mFlags = kAudioTimeStampSampleTimeValid;
|
||||
|
||||
if (unit->Render (&flags, &ts, 0, nframes, buffers) == noErr) {
|
||||
|
||||
current_maxbuf = 0;
|
||||
frames_processed += nframes;
|
||||
|
||||
for (uint32_t i = 0; i < maxbuf; ++i) {
|
||||
if (bufs[i] + offset != buffers->mBuffers[i].mData) {
|
||||
memcpy (bufs[i]+offset, buffers->mBuffers[i].mData, nframes * sizeof (Sample));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
set<uint32_t>
|
||||
|
|
@ -245,8 +452,8 @@ AUPlugin::parameter_is_output (uint32_t) const
|
|||
XMLNode&
|
||||
AUPlugin::get_state()
|
||||
{
|
||||
XMLNode* root = new XMLNode (state_node_name());
|
||||
|
||||
XMLNode *root = new XMLNode (state_node_name());
|
||||
LocaleGuard lg (X_("POSIX"));
|
||||
return *root;
|
||||
}
|
||||
|
||||
|
|
@ -279,7 +486,19 @@ AUPlugin::get_presets ()
|
|||
bool
|
||||
AUPlugin::has_editor () const
|
||||
{
|
||||
return false;
|
||||
// even if the plugin doesn't have its own editor, the AU API can be used
|
||||
// to create one that looks native.
|
||||
return true;
|
||||
}
|
||||
|
||||
AUPluginInfo::AUPluginInfo (boost::shared_ptr<CAComponentDescription> d)
|
||||
: descriptor (d)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AUPluginInfo::~AUPluginInfo ()
|
||||
{
|
||||
}
|
||||
|
||||
PluginPtr
|
||||
|
|
@ -288,7 +507,7 @@ AUPluginInfo::load (Session& session)
|
|||
try {
|
||||
PluginPtr plugin;
|
||||
|
||||
CAComponent* comp = new CAComponent(*desc);
|
||||
boost::shared_ptr<CAComponent> comp (new CAComponent(*descriptor));
|
||||
|
||||
if (!comp->IsValid()) {
|
||||
error << ("AudioUnit: not a valid Component") << endmsg;
|
||||
|
|
@ -296,7 +515,7 @@ AUPluginInfo::load (Session& session)
|
|||
plugin.reset (new AUPlugin (session.engine(), session, comp));
|
||||
}
|
||||
|
||||
plugin->set_info(PluginInfoPtr(new AUPluginInfo(*this)));
|
||||
plugin->set_info (PluginInfoPtr (new AUPluginInfo (*this)));
|
||||
return plugin;
|
||||
}
|
||||
|
||||
|
|
@ -310,6 +529,28 @@ AUPluginInfo::discover ()
|
|||
{
|
||||
PluginInfoList plugs;
|
||||
|
||||
discover_fx (plugs);
|
||||
discover_music (plugs);
|
||||
|
||||
return plugs;
|
||||
}
|
||||
|
||||
void
|
||||
AUPluginInfo::discover_music (PluginInfoList& plugs)
|
||||
{
|
||||
CAComponentDescription desc;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
desc.componentSubType = 0;
|
||||
desc.componentManufacturer = 0;
|
||||
desc.componentType = kAudioUnitType_MusicEffect;
|
||||
|
||||
discover_by_description (plugs, desc);
|
||||
}
|
||||
|
||||
void
|
||||
AUPluginInfo::discover_fx (PluginInfoList& plugs)
|
||||
{
|
||||
CAComponentDescription desc;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
|
|
@ -317,35 +558,146 @@ AUPluginInfo::discover ()
|
|||
desc.componentManufacturer = 0;
|
||||
desc.componentType = kAudioUnitType_Effect;
|
||||
|
||||
discover_by_description (plugs, desc);
|
||||
}
|
||||
|
||||
void
|
||||
AUPluginInfo::discover_by_description (PluginInfoList& plugs, CAComponentDescription& desc)
|
||||
{
|
||||
Component comp = 0;
|
||||
|
||||
comp = FindNextComponent (NULL, &desc);
|
||||
|
||||
while (comp != NULL) {
|
||||
CAComponentDescription temp;
|
||||
GetComponentInfo (comp, &temp, NULL, NULL, NULL);
|
||||
|
||||
AUPluginInfoPtr plug(new AUPluginInfo);
|
||||
plug->name = AUPluginInfo::get_name (temp);
|
||||
plug->type = ARDOUR::AudioUnit;
|
||||
plug->n_inputs = 0;
|
||||
plug->n_outputs = 0;
|
||||
// plug->setup_nchannels (temp);
|
||||
plug->category = "AudioUnit";
|
||||
plug->desc = new CAComponentDescription(temp);
|
||||
|
||||
plugs.push_back(plug);
|
||||
AUPluginInfoPtr info (new AUPluginInfo
|
||||
(boost::shared_ptr<CAComponentDescription> (new CAComponentDescription(temp))));
|
||||
|
||||
/* no panners, format converters or i/o AU's for our purposes
|
||||
*/
|
||||
|
||||
switch (info->descriptor->Type()) {
|
||||
case kAudioUnitType_Panner:
|
||||
case kAudioUnitType_OfflineEffect:
|
||||
case kAudioUnitType_FormatConverter:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (info->descriptor->SubType()) {
|
||||
case kAudioUnitSubType_DefaultOutput:
|
||||
case kAudioUnitSubType_SystemOutput:
|
||||
case kAudioUnitSubType_GenericOutput:
|
||||
case kAudioUnitSubType_AUConverter:
|
||||
continue;
|
||||
break;
|
||||
|
||||
case kAudioUnitSubType_DLSSynth:
|
||||
info->category = "DLSSynth";
|
||||
break;
|
||||
|
||||
case kAudioUnitType_MusicEffect:
|
||||
info->category = "MusicEffect";
|
||||
break;
|
||||
|
||||
case kAudioUnitSubType_Varispeed:
|
||||
info->category = "Varispeed";
|
||||
break;
|
||||
|
||||
case kAudioUnitSubType_Delay:
|
||||
info->category = "Delay";
|
||||
break;
|
||||
|
||||
case kAudioUnitSubType_LowPassFilter:
|
||||
info->category = "LowPassFilter";
|
||||
break;
|
||||
|
||||
case kAudioUnitSubType_HighPassFilter:
|
||||
info->category = "HighPassFilter";
|
||||
break;
|
||||
|
||||
case kAudioUnitSubType_BandPassFilter:
|
||||
info->category = "BandPassFilter";
|
||||
break;
|
||||
|
||||
case kAudioUnitSubType_HighShelfFilter:
|
||||
info->category = "HighShelfFilter";
|
||||
break;
|
||||
|
||||
case kAudioUnitSubType_LowShelfFilter:
|
||||
info->category = "LowShelfFilter";
|
||||
break;
|
||||
|
||||
case kAudioUnitSubType_ParametricEQ:
|
||||
info->category = "ParametricEQ";
|
||||
break;
|
||||
|
||||
case kAudioUnitSubType_GraphicEQ:
|
||||
info->category = "GraphicEQ";
|
||||
break;
|
||||
|
||||
case kAudioUnitSubType_PeakLimiter:
|
||||
info->category = "PeakLimiter";
|
||||
break;
|
||||
|
||||
case kAudioUnitSubType_DynamicsProcessor:
|
||||
info->category = "DynamicsProcessor";
|
||||
break;
|
||||
|
||||
case kAudioUnitSubType_MultiBandCompressor:
|
||||
info->category = "MultiBandCompressor";
|
||||
break;
|
||||
|
||||
case kAudioUnitSubType_MatrixReverb:
|
||||
info->category = "MatrixReverb";
|
||||
break;
|
||||
|
||||
case kAudioUnitType_Mixer:
|
||||
info->category = "Mixer";
|
||||
break;
|
||||
|
||||
case kAudioUnitSubType_StereoMixer:
|
||||
info->category = "StereoMixer";
|
||||
break;
|
||||
|
||||
case kAudioUnitSubType_3DMixer:
|
||||
info->category = "3DMixer";
|
||||
break;
|
||||
|
||||
case kAudioUnitSubType_MatrixMixer:
|
||||
info->category = "MatrixMixer";
|
||||
break;
|
||||
|
||||
default:
|
||||
info->category = "";
|
||||
}
|
||||
|
||||
AUPluginInfo::get_names (temp, info->name, info->creator);
|
||||
|
||||
info->type = ARDOUR::AudioUnit;
|
||||
info->unique_id = stringify_descriptor (*info->descriptor);
|
||||
|
||||
/* mark the plugin as having flexible i/o */
|
||||
|
||||
info->n_inputs = -1;
|
||||
info->n_outputs = -1;
|
||||
|
||||
|
||||
plugs.push_back (info);
|
||||
|
||||
comp = FindNextComponent (comp, &desc);
|
||||
}
|
||||
|
||||
return plugs;
|
||||
}
|
||||
|
||||
string
|
||||
AUPluginInfo::get_name (CAComponentDescription& comp_desc)
|
||||
void
|
||||
AUPluginInfo::get_names (CAComponentDescription& comp_desc, std::string& name, Glib::ustring& maker)
|
||||
{
|
||||
CFStringRef itemName = NULL;
|
||||
// Marc Poirier -style item name
|
||||
|
||||
// Marc Poirier-style item name
|
||||
CAComponent auComponent (comp_desc);
|
||||
if (auComponent.IsValid()) {
|
||||
CAComponentDescription dummydesc;
|
||||
|
|
@ -379,23 +731,36 @@ AUPluginInfo::get_name (CAComponentDescription& comp_desc)
|
|||
CFRelease(compManufacturerString);
|
||||
}
|
||||
|
||||
return CFStringRefToStdString(itemName);
|
||||
}
|
||||
string str = CFStringRefToStdString(itemName);
|
||||
string::size_type colon = str.find (':');
|
||||
|
||||
void
|
||||
AUPluginInfo::setup_nchannels (CAComponentDescription& comp_desc)
|
||||
{
|
||||
CAAudioUnit unit;
|
||||
|
||||
CAAudioUnit::Open (comp_desc, unit);
|
||||
|
||||
if (unit.SupportsNumChannels()) {
|
||||
n_inputs = n_outputs = 0;
|
||||
if (colon) {
|
||||
name = str.substr (colon+1);
|
||||
maker = str.substr (0, colon);
|
||||
// strip_whitespace_edges (maker);
|
||||
// strip_whitespace_edges (name);
|
||||
} else {
|
||||
AUChannelInfo cinfo;
|
||||
size_t info_size = sizeof(cinfo);
|
||||
OSStatus err = AudioUnitGetProperty (unit.AU(), kAudioUnitProperty_SupportedNumChannels, kAudioUnitScope_Global,
|
||||
0, &cinfo, &info_size);
|
||||
name = str;
|
||||
maker = "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
// from CAComponentDescription.cpp (in libs/appleutility in ardour source)
|
||||
extern char *StringForOSType (OSType t, char *writeLocation);
|
||||
|
||||
std::string
|
||||
AUPluginInfo::stringify_descriptor (const CAComponentDescription& desc)
|
||||
{
|
||||
char str[24];
|
||||
stringstream s;
|
||||
|
||||
s << StringForOSType (desc.Type(), str);
|
||||
s << " - ";
|
||||
|
||||
s << StringForOSType (desc.SubType(), str);
|
||||
s << " - ";
|
||||
|
||||
s << StringForOSType (desc.Manu(), str);
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include <vector>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
|
||||
#include <glibmm/timer.h>
|
||||
#include <pbd/pthread_utils.h>
|
||||
|
|
@ -368,6 +369,20 @@ AudioEngine::process_callback (nframes_t nframes)
|
|||
last_monitor_check = next_processed_frames;
|
||||
}
|
||||
|
||||
if (session->silent()) {
|
||||
|
||||
boost::shared_ptr<Ports> p = ports.reader();
|
||||
|
||||
for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
|
||||
|
||||
Port *port = (*i);
|
||||
|
||||
if (port->sends_output()) {
|
||||
port->get_buffer().silence(nframes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_processed_frames = next_processed_frames;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -510,6 +525,26 @@ AudioEngine::remove_session ()
|
|||
remove_all_ports ();
|
||||
}
|
||||
|
||||
void
|
||||
AudioEngine::port_registration_failure (const std::string& portname)
|
||||
{
|
||||
string full_portname = jack_client_name;
|
||||
full_portname += ':';
|
||||
full_portname += portname;
|
||||
|
||||
|
||||
jack_port_t* p = jack_port_by_name (_jack, full_portname.c_str());
|
||||
string reason;
|
||||
|
||||
if (p) {
|
||||
reason = _("a port with this name already exists: check for duplicated track/bus names");
|
||||
} else {
|
||||
reason = _("unknown error");
|
||||
}
|
||||
|
||||
throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
|
||||
}
|
||||
|
||||
Port *
|
||||
AudioEngine::register_port (DataType dtype, const string& portname, bool input, bool publish)
|
||||
{
|
||||
|
|
@ -533,7 +568,7 @@ AudioEngine::register_port (DataType dtype, const string& portname, bool input,
|
|||
}
|
||||
|
||||
catch (...) {
|
||||
throw PortRegistrationFailure();
|
||||
throw PortRegistrationFailure("unable to create port (unknown type?)");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -563,7 +598,7 @@ AudioEngine::register_output_port (DataType type, const string& portname, bool p
|
|||
return register_port (type, portname, false, publish);
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
AudioEngine::unregister_port (Port& port)
|
||||
{
|
||||
/* caller must hold process lock */
|
||||
|
|
@ -590,6 +625,8 @@ AudioEngine::unregister_port (Port& port)
|
|||
|
||||
/* writer goes out of scope, forces update */
|
||||
}
|
||||
|
||||
remove_connections_for (port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1054,6 +1091,23 @@ AudioEngine::remove_all_ports ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioEngine::remove_connections_for (Port& port)
|
||||
{
|
||||
for (PortConnections::iterator i = port_connections.begin(); i != port_connections.end(); ) {
|
||||
PortConnections::iterator tmp;
|
||||
|
||||
tmp = i;
|
||||
++tmp;
|
||||
|
||||
if ((*i).first == port.name()) {
|
||||
port_connections.erase (i);
|
||||
}
|
||||
|
||||
i = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_JACK_CLIENT_OPEN
|
||||
|
||||
|
|
|
|||
|
|
@ -135,18 +135,15 @@ AudioFileSource::removable () const
|
|||
int
|
||||
AudioFileSource::init (ustring pathstr, bool must_exist)
|
||||
{
|
||||
bool is_new = false;
|
||||
|
||||
_length = 0;
|
||||
timeline_position = 0;
|
||||
_peaks_built = false;
|
||||
file_is_new = false;
|
||||
|
||||
if (!find (pathstr, must_exist, is_new, _channel)) {
|
||||
if (!find (pathstr, must_exist, file_is_new, _channel)) {
|
||||
throw non_existent_source ();
|
||||
}
|
||||
|
||||
if (is_new && must_exist) {
|
||||
if (file_is_new && must_exist) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -237,54 +237,6 @@ AudioRegion::listen_to_my_curves ()
|
|||
_fade_out->StateChanged.connect (mem_fun (*this, &AudioRegion::fade_out_changed));
|
||||
}
|
||||
|
||||
bool
|
||||
AudioRegion::verify_length (nframes_t len)
|
||||
{
|
||||
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source());
|
||||
|
||||
if (afs && afs->destructive()) {
|
||||
return true;
|
||||
} else {
|
||||
return Region::verify_length(len);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AudioRegion::verify_start_and_length (nframes_t new_start, nframes_t new_length)
|
||||
{
|
||||
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source());
|
||||
|
||||
if (afs && afs->destructive()) {
|
||||
return true;
|
||||
} else {
|
||||
return Region::verify_start_and_length(new_start, new_length);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AudioRegion::verify_start (nframes_t pos)
|
||||
{
|
||||
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source());
|
||||
|
||||
if (afs && afs->destructive()) {
|
||||
return true;
|
||||
} else {
|
||||
return Region::verify_start(pos);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AudioRegion::verify_start_mutable (nframes_t& new_start)
|
||||
{
|
||||
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source());
|
||||
|
||||
if (afs && afs->destructive()) {
|
||||
return true;
|
||||
} else {
|
||||
return Region::verify_start_mutable(new_start);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioRegion::set_envelope_active (bool yn)
|
||||
{
|
||||
|
|
@ -321,25 +273,26 @@ AudioRegion::read_peaks (PeakData *buf, nframes_t npeaks, nframes_t offset, nfra
|
|||
}
|
||||
}
|
||||
|
||||
ARDOUR::nframes_t
|
||||
AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t position, nframes_t cnt, uint32_t chan_n) const
|
||||
nframes_t
|
||||
AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t position,
|
||||
nframes_t cnt,
|
||||
uint32_t chan_n, nframes_t read_frames, nframes_t skip_frames) const
|
||||
{
|
||||
return _read_at (_sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n);
|
||||
return _read_at (_sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, read_frames, skip_frames);
|
||||
}
|
||||
|
||||
ARDOUR::nframes_t
|
||||
nframes_t
|
||||
AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t position,
|
||||
nframes_t cnt, uint32_t chan_n) const
|
||||
{
|
||||
return _read_at (_master_sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n);
|
||||
return _read_at (_master_sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, 0, 0);
|
||||
}
|
||||
|
||||
ARDOUR::nframes_t
|
||||
nframes_t
|
||||
AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
|
||||
nframes_t position, nframes_t cnt, uint32_t chan_n) const
|
||||
nframes_t position, nframes_t cnt,
|
||||
uint32_t chan_n, nframes_t read_frames, nframes_t skip_frames) const
|
||||
{
|
||||
// cerr << _name << "._read_at(" << position << ") - " << _position << endl;
|
||||
|
||||
nframes_t internal_offset;
|
||||
nframes_t buf_offset;
|
||||
nframes_t to_read;
|
||||
|
|
@ -377,13 +330,12 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
|
|||
_read_data_count = 0;
|
||||
|
||||
if (chan_n < n_channels()) {
|
||||
|
||||
|
||||
boost::shared_ptr<AudioSource> src = audio_source(chan_n);
|
||||
if (src->read (mixdown_buffer, _start + internal_offset, to_read) != to_read) {
|
||||
|
||||
return 0; /* "read nothing" */
|
||||
}
|
||||
|
||||
|
||||
_read_data_count += src->read_data_count();
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ using Glib::ustring;
|
|||
bool AudioSource::_build_missing_peakfiles = false;
|
||||
bool AudioSource::_build_peakfiles = false;
|
||||
|
||||
#define _FPP 256
|
||||
|
||||
AudioSource::AudioSource (Session& s, ustring name)
|
||||
: Source (s, name, DataType::AUDIO)
|
||||
{
|
||||
|
|
@ -135,7 +137,7 @@ AudioSource::peaks_ready (sigc::slot<void> the_slot, sigc::connection& conn) con
|
|||
/* check to see if the peak data is ready. if not
|
||||
connect the slot while still holding the lock.
|
||||
*/
|
||||
|
||||
|
||||
if (!(ret = _peaks_built)) {
|
||||
conn = PeaksReady.connect (the_slot);
|
||||
}
|
||||
|
|
@ -192,44 +194,36 @@ AudioSource::initialize_peakfile (bool newfile, ustring audio_path)
|
|||
peakpath = find_broken_peakfile (peakpath, audio_path);
|
||||
}
|
||||
|
||||
if (newfile) {
|
||||
|
||||
if (!_build_peakfiles) {
|
||||
return 0;
|
||||
if (stat (peakpath.c_str(), &statbuf)) {
|
||||
if (errno != ENOENT) {
|
||||
/* it exists in the peaks dir, but there is some kind of error */
|
||||
|
||||
error << string_compose(_("AudioSource: cannot stat peakfile \"%1\""), peakpath) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* peakfile does not exist */
|
||||
|
||||
_peaks_built = false;
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
if (stat (peakpath.c_str(), &statbuf)) {
|
||||
if (errno != ENOENT) {
|
||||
/* it exists in the peaks dir, but there is some kind of error */
|
||||
|
||||
error << string_compose(_("AudioSource: cannot stat peakfile \"%1\""), peakpath) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* we found it in the peaks dir, so check it out */
|
||||
|
||||
if (statbuf.st_size == 0) {
|
||||
// empty
|
||||
_peaks_built = false;
|
||||
|
||||
} else {
|
||||
// Check if the audio file has changed since the peakfile was built.
|
||||
struct stat stat_file;
|
||||
int err = stat (audio_path.c_str(), &stat_file);
|
||||
|
||||
/* we found it in the peaks dir, so check it out */
|
||||
|
||||
if (statbuf.st_size == 0) {
|
||||
if (!err && stat_file.st_mtime > statbuf.st_mtime){
|
||||
_peaks_built = false;
|
||||
_peak_byte_max = 0;
|
||||
} else {
|
||||
// Check if the audio file has changed since the peakfile was built.
|
||||
struct stat stat_file;
|
||||
int err = stat (audio_path.c_str(), &stat_file);
|
||||
|
||||
if (!err && stat_file.st_mtime > statbuf.st_mtime){
|
||||
_peaks_built = false;
|
||||
_peak_byte_max = 0;
|
||||
} else {
|
||||
_peaks_built = true;
|
||||
_peak_byte_max = statbuf.st_size;
|
||||
}
|
||||
_peaks_built = true;
|
||||
_peak_byte_max = statbuf.st_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -255,8 +249,15 @@ AudioSource::write (Sample *dst, nframes_t cnt)
|
|||
return write_unlocked (dst, cnt);
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_visual_peak) const
|
||||
{
|
||||
return read_peaks_with_fpp (peaks, npeaks, start, cnt, samples_per_visual_peak, _FPP);
|
||||
}
|
||||
|
||||
int
|
||||
AudioSource::read_peaks_with_fpp (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt,
|
||||
double samples_per_visual_peak, nframes_t samples_per_file_peak) const
|
||||
{
|
||||
Glib::Mutex::Lock lm (_lock);
|
||||
double scale;
|
||||
|
|
@ -271,7 +272,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
|
|||
Sample* raw_staging = 0;
|
||||
int _peakfile = -1;
|
||||
|
||||
expected_peaks = (cnt / (double) frames_per_peak);
|
||||
expected_peaks = (cnt / (double) samples_per_file_peak);
|
||||
scale = npeaks/expected_peaks;
|
||||
|
||||
#undef DEBUG_READ_PEAKS
|
||||
|
|
@ -326,7 +327,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
|
|||
|
||||
if (scale == 1.0) {
|
||||
|
||||
off_t first_peak_byte = (start / frames_per_peak) * sizeof (PeakData);
|
||||
off_t first_peak_byte = (start / samples_per_file_peak) * sizeof (PeakData);
|
||||
|
||||
/* open, read, close */
|
||||
|
||||
|
|
@ -390,10 +391,10 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
|
|||
/* compute the rounded up frame position */
|
||||
|
||||
nframes_t current_frame = start;
|
||||
nframes_t current_stored_peak = (nframes_t) ceil (current_frame / (double) frames_per_peak);
|
||||
nframes_t current_stored_peak = (nframes_t) ceil (current_frame / (double) samples_per_file_peak);
|
||||
uint32_t next_visual_peak = (uint32_t) ceil (current_frame / samples_per_visual_peak);
|
||||
double next_visual_peak_frame = next_visual_peak * samples_per_visual_peak;
|
||||
uint32_t stored_peak_before_next_visual_peak = (nframes_t) next_visual_peak_frame / frames_per_peak;
|
||||
uint32_t stored_peak_before_next_visual_peak = (nframes_t) next_visual_peak_frame / samples_per_file_peak;
|
||||
uint32_t nvisual_peaks = 0;
|
||||
uint32_t stored_peaks_read = 0;
|
||||
uint32_t i = 0;
|
||||
|
|
@ -414,7 +415,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
|
|||
if (i == stored_peaks_read) {
|
||||
|
||||
uint32_t start_byte = current_stored_peak * sizeof(PeakData);
|
||||
tnp = min ((_length/frames_per_peak - current_stored_peak), (nframes_t) expected_peaks);
|
||||
tnp = min ((_length/samples_per_file_peak - current_stored_peak), (nframes_t) expected_peaks);
|
||||
to_read = min (chunksize, tnp);
|
||||
|
||||
#ifdef DEBUG_READ_PEAKS
|
||||
|
|
@ -437,7 +438,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
|
|||
<< ')'
|
||||
<< " at start_byte = " << start_byte
|
||||
<< " _length = " << _length << " versus len = " << fend
|
||||
<< " expected maxpeaks = " << (_length - current_frame)/frames_per_peak
|
||||
<< " expected maxpeaks = " << (_length - current_frame)/samples_per_file_peak
|
||||
<< " npeaks was " << npeaks
|
||||
<< endl;
|
||||
goto out;
|
||||
|
|
@ -466,7 +467,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
|
|||
|
||||
//next_visual_peak_frame = min ((next_visual_peak * samples_per_visual_peak), (next_visual_peak_frame+samples_per_visual_peak) );
|
||||
next_visual_peak_frame = min ((double) start+cnt, (next_visual_peak_frame+samples_per_visual_peak) );
|
||||
stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_frame / frames_per_peak;
|
||||
stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_frame / samples_per_file_peak;
|
||||
}
|
||||
|
||||
if (zero_fill) {
|
||||
|
|
@ -611,7 +612,7 @@ AudioSource::build_peaks_from_scratch ()
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (compute_and_write_peaks (buf, current_frame, frames_read, true, false)) {
|
||||
if (compute_and_write_peaks (buf, current_frame, frames_read, true, false, _FPP)) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -662,7 +663,7 @@ void
|
|||
AudioSource::done_with_peakfile_writes (bool done)
|
||||
{
|
||||
if (peak_leftover_cnt) {
|
||||
compute_and_write_peaks (0, 0, 0, true, false);
|
||||
compute_and_write_peaks (0, 0, 0, true, false, _FPP);
|
||||
}
|
||||
|
||||
if (done) {
|
||||
|
|
@ -677,6 +678,13 @@ AudioSource::done_with_peakfile_writes (bool done)
|
|||
|
||||
int
|
||||
AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force, bool intermediate_peaks_ready)
|
||||
{
|
||||
return compute_and_write_peaks (buf, first_frame, cnt, force, intermediate_peaks_ready, _FPP);
|
||||
}
|
||||
|
||||
int
|
||||
AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force,
|
||||
bool intermediate_peaks_ready, nframes_t fpp)
|
||||
{
|
||||
Sample* buf2 = 0;
|
||||
nframes_t to_do;
|
||||
|
|
@ -707,9 +715,7 @@ AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframe
|
|||
x.min = peak_leftovers[0];
|
||||
x.max = peak_leftovers[0];
|
||||
|
||||
ARDOUR::find_peaks (peak_leftovers + 1, peak_leftover_cnt - 1, &x.min, &x.max);
|
||||
|
||||
off_t byte = (peak_leftover_frame / frames_per_peak) * sizeof (PeakData);
|
||||
off_t byte = (peak_leftover_frame / fpp) * sizeof (PeakData);
|
||||
|
||||
if (::pwrite (peakfile, &x, sizeof (PeakData), byte) != sizeof (PeakData)) {
|
||||
error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
|
||||
|
|
@ -761,7 +767,7 @@ AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframe
|
|||
to_do = cnt;
|
||||
}
|
||||
|
||||
peakbuf = new PeakData[(to_do/frames_per_peak)+1];
|
||||
peakbuf = new PeakData[(to_do/fpp)+1];
|
||||
peaks_computed = 0;
|
||||
current_frame = first_frame;
|
||||
frames_done = 0;
|
||||
|
|
@ -769,11 +775,11 @@ AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframe
|
|||
while (to_do) {
|
||||
|
||||
/* if some frames were passed in (i.e. we're not flushing leftovers)
|
||||
and there are less than frames_per_peak to do, save them till
|
||||
and there are less than fpp to do, save them till
|
||||
next time
|
||||
*/
|
||||
|
||||
if (force && (to_do < frames_per_peak)) {
|
||||
if (force && (to_do < fpp)) {
|
||||
/* keep the left overs around for next time */
|
||||
|
||||
if (peak_leftover_size < to_do) {
|
||||
|
|
@ -790,7 +796,7 @@ AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframe
|
|||
break;
|
||||
}
|
||||
|
||||
nframes_t this_time = min (frames_per_peak, to_do);
|
||||
nframes_t this_time = min (fpp, to_do);
|
||||
|
||||
peakbuf[peaks_computed].max = buf[0];
|
||||
peakbuf[peaks_computed].min = buf[0];
|
||||
|
|
@ -804,7 +810,7 @@ AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframe
|
|||
current_frame += this_time;
|
||||
}
|
||||
|
||||
first_peak_byte = (first_frame / frames_per_peak) * sizeof (PeakData);
|
||||
first_peak_byte = (first_frame / fpp) * sizeof (PeakData);
|
||||
|
||||
if (can_truncate_peaks()) {
|
||||
|
||||
|
|
@ -887,7 +893,7 @@ AudioSource::available_peaks (double zoom_factor) const
|
|||
{
|
||||
off_t end;
|
||||
|
||||
if (zoom_factor < frames_per_peak) {
|
||||
if (zoom_factor < _FPP) {
|
||||
return length(); // peak data will come from the audio file
|
||||
}
|
||||
|
||||
|
|
@ -899,7 +905,7 @@ AudioSource::available_peaks (double zoom_factor) const
|
|||
|
||||
end = _peak_byte_max;
|
||||
|
||||
return (end/sizeof(PeakData)) * frames_per_peak;
|
||||
return (end/sizeof(PeakData)) * _FPP;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -151,8 +151,19 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
|
|||
reset_panner();
|
||||
|
||||
length = the_region->length();
|
||||
_diskstream->seek (0);
|
||||
current_frame = 0;
|
||||
|
||||
int dir;
|
||||
nframes_t offset = the_region->sync_offset (dir);
|
||||
|
||||
/* can't audition from a negative sync point */
|
||||
|
||||
if (dir < 0) {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
_diskstream->seek (offset);
|
||||
current_frame = offset;
|
||||
|
||||
g_atomic_int_set (&_active, 1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -260,7 +260,8 @@ Crossfade::read_raw_internal (Sample* buf, nframes_t start, nframes_t cnt) const
|
|||
|
||||
nframes_t
|
||||
Crossfade::read_at (Sample *buf, Sample *mixdown_buffer,
|
||||
float *gain_buffer, nframes_t start, nframes_t cnt, uint32_t chan_n) const
|
||||
float *gain_buffer, nframes_t start, nframes_t cnt, uint32_t chan_n,
|
||||
nframes_t read_frames, nframes_t skip_frames) const
|
||||
{
|
||||
nframes_t offset;
|
||||
nframes_t to_write;
|
||||
|
|
@ -301,9 +302,9 @@ Crossfade::read_at (Sample *buf, Sample *mixdown_buffer,
|
|||
} else if (!(_in->opaque())) {
|
||||
memset (crossfade_buffer_in, 0, sizeof (Sample) * to_write);
|
||||
}
|
||||
|
||||
_out->read_at (crossfade_buffer_out, mixdown_buffer, gain_buffer, start, to_write, chan_n);
|
||||
_in->read_at (crossfade_buffer_in, mixdown_buffer, gain_buffer, start, to_write, chan_n);
|
||||
|
||||
_out->read_at (crossfade_buffer_out, mixdown_buffer, gain_buffer, start, to_write, chan_n, read_frames, skip_frames);
|
||||
_in->read_at (crossfade_buffer_in, mixdown_buffer, gain_buffer, start, to_write, chan_n, read_frames, skip_frames);
|
||||
|
||||
float* fiv = new float[to_write];
|
||||
float* fov = new float[to_write];
|
||||
|
|
|
|||
|
|
@ -164,7 +164,6 @@ setup_enum_writer ()
|
|||
REGISTER_ENUM (SyncPoint);
|
||||
REGISTER (_RegionPoint);
|
||||
|
||||
|
||||
REGISTER_ENUM (PreFader);
|
||||
REGISTER_ENUM (PostFader);
|
||||
REGISTER (_Placement);
|
||||
|
|
@ -243,6 +242,7 @@ setup_enum_writer ()
|
|||
REGISTER_CLASS_ENUM (Session::Event, SetDiskstreamSpeed);
|
||||
REGISTER_CLASS_ENUM (Session::Event, Locate);
|
||||
REGISTER_CLASS_ENUM (Session::Event, LocateRoll);
|
||||
REGISTER_CLASS_ENUM (Session::Event, LocateRollLocate);
|
||||
REGISTER_CLASS_ENUM (Session::Event, SetLoop);
|
||||
REGISTER_CLASS_ENUM (Session::Event, PunchIn);
|
||||
REGISTER_CLASS_ENUM (Session::Event, PunchOut);
|
||||
|
|
|
|||
|
|
@ -34,11 +34,11 @@
|
|||
#include <boost/scoped_array.hpp>
|
||||
#include <boost/shared_array.hpp>
|
||||
|
||||
#include <pbd/basename.h>
|
||||
#include <pbd/convert.h>
|
||||
|
||||
#include <ardour/ardour.h>
|
||||
#include <ardour/session.h>
|
||||
#include <ardour/session_directory.h>
|
||||
#include <ardour/audio_diskstream.h>
|
||||
#include <ardour/sndfilesource.h>
|
||||
#include <ardour/sndfile_helpers.h>
|
||||
|
|
@ -52,22 +52,19 @@
|
|||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
|
||||
std::auto_ptr<ImportableSource>
|
||||
open_importable_source (const string& path, nframes_t samplerate,
|
||||
ARDOUR::SrcQuality quality)
|
||||
static std::auto_ptr<ImportableSource>
|
||||
open_importable_source (const string& path, nframes_t samplerate, ARDOUR::SrcQuality quality)
|
||||
{
|
||||
std::auto_ptr<ImportableSource> source(new ImportableSource(path));
|
||||
|
||||
if (source->samplerate() == samplerate) {
|
||||
return source;
|
||||
}
|
||||
|
||||
return std::auto_ptr<ImportableSource>(
|
||||
new ResampledImportableSource(path, samplerate, quality)
|
||||
);
|
||||
|
||||
return std::auto_ptr<ImportableSource>(new ResampledImportableSource(path, samplerate, quality));
|
||||
}
|
||||
|
||||
std::string
|
||||
static std::string
|
||||
get_non_existent_filename (const std::string& basename, uint channel, uint channels)
|
||||
{
|
||||
char buf[PATH_MAX+1];
|
||||
|
|
@ -86,8 +83,8 @@ get_non_existent_filename (const std::string& basename, uint channel, uint chann
|
|||
} else {
|
||||
snprintf (buf, sizeof(buf), "%s.wav", base.c_str());
|
||||
}
|
||||
|
||||
if (sys::exists (buf)) {
|
||||
|
||||
if (Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) {
|
||||
|
||||
/* if the file already exists, we must come up with
|
||||
* a new name for it. for now we just keep appending
|
||||
|
|
@ -106,27 +103,27 @@ get_non_existent_filename (const std::string& basename, uint channel, uint chann
|
|||
return buf;
|
||||
}
|
||||
|
||||
vector<string>
|
||||
get_paths_for_new_sources (const string& import_file_path, const string& session_dir,
|
||||
uint channels)
|
||||
static vector<string>
|
||||
get_paths_for_new_sources (const string& import_file_path, const string& session_dir, uint channels)
|
||||
{
|
||||
vector<string> new_paths;
|
||||
const string basename = sys::basename (import_file_path);
|
||||
SessionDirectory sdir(session_dir);
|
||||
const string basename = basename_nosuffix (import_file_path);
|
||||
|
||||
for (uint n = 0; n < channels; ++n) {
|
||||
|
||||
std::string filename = get_non_existent_filename (basename, n, channels);
|
||||
std::string filepath;
|
||||
|
||||
sys::path filepath = sdir.sound_path() / filename;
|
||||
filepath = session_dir;
|
||||
filepath += '/';
|
||||
filepath += get_non_existent_filename (basename, n, channels);
|
||||
|
||||
new_paths.push_back (filepath.to_string());
|
||||
new_paths.push_back (filepath);
|
||||
}
|
||||
|
||||
return new_paths;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
create_mono_sources_for_writing (const vector<string>& new_paths, Session& sess,
|
||||
uint samplerate, vector<boost::shared_ptr<AudioFileSource> >& newfiles)
|
||||
{
|
||||
|
|
@ -138,12 +135,12 @@ create_mono_sources_for_writing (const vector<string>& new_paths, Session& sess,
|
|||
try
|
||||
{
|
||||
source = SourceFactory::createWritable (
|
||||
DataType::AUDIO,
|
||||
sess,
|
||||
i->c_str(),
|
||||
false, // destructive
|
||||
samplerate
|
||||
);
|
||||
DataType::AUDIO,
|
||||
sess,
|
||||
i->c_str(),
|
||||
false, // destructive
|
||||
samplerate
|
||||
);
|
||||
}
|
||||
catch (const failed_constructor& err)
|
||||
{
|
||||
|
|
@ -156,29 +153,29 @@ create_mono_sources_for_writing (const vector<string>& new_paths, Session& sess,
|
|||
return true;
|
||||
}
|
||||
|
||||
Glib::ustring
|
||||
static Glib::ustring
|
||||
compose_status_message (const string& path,
|
||||
uint file_samplerate,
|
||||
uint session_samplerate,
|
||||
uint current_file,
|
||||
uint total_files)
|
||||
uint file_samplerate,
|
||||
uint session_samplerate,
|
||||
uint current_file,
|
||||
uint total_files)
|
||||
{
|
||||
if (file_samplerate != session_samplerate) {
|
||||
return string_compose (_("converting %1\n(resample from %2KHz to %3KHz)\n(%4 of %5)"),
|
||||
sys::path(path).leaf(),
|
||||
file_samplerate/1000.0f,
|
||||
session_samplerate/1000.0f,
|
||||
current_file, total_files);
|
||||
Glib::path_get_basename (path),
|
||||
file_samplerate/1000.0f,
|
||||
session_samplerate/1000.0f,
|
||||
current_file, total_files);
|
||||
}
|
||||
|
||||
return string_compose (_("converting %1\n(%2 of %3)"),
|
||||
sys::path(path).leaf(),
|
||||
current_file, total_files);
|
||||
Glib::path_get_basename (path),
|
||||
current_file, total_files);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
write_audio_data_to_new_files (ImportableSource* source, Session::import_status& status,
|
||||
vector<boost::shared_ptr<AudioFileSource> >& newfiles)
|
||||
vector<boost::shared_ptr<AudioFileSource> >& newfiles)
|
||||
{
|
||||
const nframes_t nframes = ResampledImportableSource::blocksize;
|
||||
uint channels = source->channels();
|
||||
|
|
@ -225,10 +222,10 @@ write_audio_data_to_new_files (ImportableSource* source, Session::import_status&
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
remove_file_source (boost::shared_ptr<AudioFileSource> file_source)
|
||||
{
|
||||
sys::remove (std::string(file_source->path()));
|
||||
::unlink (file_source->path().c_str());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -260,7 +257,7 @@ Session::import_audiofiles (import_status& status)
|
|||
vector<string> new_paths = get_paths_for_new_sources (*p,
|
||||
get_best_session_directory_for_new_source (),
|
||||
source->channels());
|
||||
|
||||
|
||||
AudioSources newfiles;
|
||||
|
||||
status.cancel = !create_mono_sources_for_writing (new_paths, *this, frame_rate(), newfiles);
|
||||
|
|
@ -309,3 +306,4 @@ Session::import_audiofiles (import_status& status)
|
|||
|
||||
status.done = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -307,12 +307,12 @@ void
|
|||
IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset)
|
||||
{
|
||||
assert(outs.available() >= n_inputs());
|
||||
|
||||
if (n_inputs() == ChanCount::ZERO)
|
||||
return;
|
||||
|
||||
outs.set_count(n_inputs());
|
||||
|
||||
if (outs.count() == ChanCount::ZERO)
|
||||
return;
|
||||
|
||||
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
|
||||
|
||||
BufferSet::iterator o = outs.begin(*t);
|
||||
|
|
@ -2567,3 +2567,4 @@ IO::UserBundleInfo::UserBundleInfo (IO* io, boost::shared_ptr<UserBundle> b)
|
|||
sigc::mem_fun (*io, &IO::bundle_ports_have_changed)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,10 +29,14 @@ JackAudioPort::JackAudioPort (const std::string& name, Flags flgs, AudioBuffer*
|
|||
{
|
||||
if (buf) {
|
||||
|
||||
cout << "jack audio port buffer" << endl;
|
||||
|
||||
_buffer = buf;
|
||||
_own_buffer = false;
|
||||
|
||||
} else {
|
||||
|
||||
cout << "jack audio port no buffer" << endl;
|
||||
|
||||
/* data space will be provided by JACK */
|
||||
|
||||
|
|
|
|||
|
|
@ -71,8 +71,8 @@ JackMidiPort::cycle_start (nframes_t nframes, nframes_t offset_ignored_but_proba
|
|||
|
||||
assert(_buffer->size() == event_count);
|
||||
|
||||
if (_buffer->size() > 0)
|
||||
cerr << "MIDIPort got " << event_count << " events." << endl;
|
||||
/*if (_buffer->size() > 0)
|
||||
cerr << "JackMIDIPort got " << event_count << " events (buf " << _buffer << ")" << endl;*/
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -185,6 +185,14 @@ LadspaPlugin::restore_state (PluginState& state)
|
|||
}
|
||||
}
|
||||
|
||||
string
|
||||
LadspaPlugin::unique_id() const
|
||||
{
|
||||
char buf[32];
|
||||
snprintf (buf, sizeof (buf), "%lu", descriptor->UniqueID);
|
||||
return string (buf);
|
||||
}
|
||||
|
||||
float
|
||||
LadspaPlugin::default_value (uint32_t port)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ PeakMeter::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_f
|
|||
|
||||
// Meter what we have (midi)
|
||||
for ( ; n < meterable && n < bufs.count().n_midi(); ++n) {
|
||||
|
||||
|
||||
float val = 0;
|
||||
|
||||
// GUI needs a better MIDI meter, not much information can be
|
||||
|
|
|
|||
|
|
@ -104,21 +104,23 @@ void
|
|||
MidiBuffer::read_from(const Buffer& src, nframes_t nframes, nframes_t offset)
|
||||
{
|
||||
assert(src.type() == DataType::MIDI);
|
||||
const MidiBuffer& msrc = (MidiBuffer&)src;
|
||||
assert(&src != this);
|
||||
|
||||
assert(_capacity >= src.size());
|
||||
const MidiBuffer& msrc = (MidiBuffer&)src;
|
||||
|
||||
assert(_capacity >= msrc.size());
|
||||
|
||||
clear();
|
||||
assert(_size == 0);
|
||||
|
||||
|
||||
// FIXME: slow
|
||||
for (size_t i=0; i < src.size(); ++i) {
|
||||
for (size_t i=0; i < msrc.size(); ++i) {
|
||||
const MidiEvent& ev = msrc[i];
|
||||
if (ev.time() >= offset && ev.time() < offset+nframes) {
|
||||
//cerr << "MidiBuffer::read_from got event, " << ev.time() << endl;
|
||||
//cout << "MidiBuffer::read_from got event, " << ev.time() << endl;
|
||||
push_back(ev);
|
||||
} else {
|
||||
//cerr << "MidiBuffer event out of range, " << ev.time() << endl;
|
||||
cerr << "MidiBuffer event out of range, " << ev.time() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,23 +26,23 @@
|
|||
using namespace ARDOUR;
|
||||
using namespace std;
|
||||
|
||||
MidiPort::MidiPort (const std::string& name, Flags flags, bool external, nframes_t bufsize)
|
||||
MidiPort::MidiPort (const std::string& name, Flags flags, bool external, nframes_t capacity)
|
||||
: Port (name, flags)
|
||||
, BaseMidiPort (name, flags)
|
||||
, PortFacade (name, flags)
|
||||
{
|
||||
set_name (name);
|
||||
_buffer = new MidiBuffer (capacity);
|
||||
|
||||
_buffer = new MidiBuffer (bufsize);
|
||||
|
||||
cout << "MIDI port " << name << " external: " << external << endl;
|
||||
|
||||
if (!external) {
|
||||
_ext_port = 0;
|
||||
} else {
|
||||
if (external) {
|
||||
/* external ports use the same buffer for the jack port (_ext_port)
|
||||
* and internal ports (this) */
|
||||
_ext_port = new JackMidiPort (name, flags, _buffer);
|
||||
} else {
|
||||
/* internal ports just have a single buffer, no jack port */
|
||||
_ext_port = 0;
|
||||
}
|
||||
|
||||
set_name (name);
|
||||
reset ();
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +70,6 @@ MidiPort::cycle_start (nframes_t nframes, nframes_t offset)
|
|||
/* caller must hold process lock */
|
||||
|
||||
if (_ext_port) {
|
||||
// cout << "external\n";
|
||||
_ext_port->cycle_start (nframes, offset);
|
||||
}
|
||||
|
||||
|
|
@ -78,11 +77,9 @@ MidiPort::cycle_start (nframes_t nframes, nframes_t offset)
|
|||
|
||||
if (_ext_port) {
|
||||
|
||||
// cout << "external in\n";
|
||||
|
||||
_buffer->read_from (dynamic_cast<BaseMidiPort*>(_ext_port)->get_midi_buffer(), nframes, offset);
|
||||
|
||||
// cout << "read " << _buffer->size() << " events." << endl;
|
||||
BaseMidiPort* mprt = dynamic_cast<BaseMidiPort*>(_ext_port);
|
||||
assert(mprt);
|
||||
assert(&mprt->get_midi_buffer() == _buffer);
|
||||
|
||||
if (!_connections.empty()) {
|
||||
(*_mixdown) (_connections, _buffer, nframes, offset, false);
|
||||
|
|
@ -90,8 +87,6 @@ MidiPort::cycle_start (nframes_t nframes, nframes_t offset)
|
|||
|
||||
} else {
|
||||
|
||||
// cout << "internal in\n";
|
||||
|
||||
if (_connections.empty()) {
|
||||
_buffer->silence (nframes, offset);
|
||||
} else {
|
||||
|
|
@ -101,10 +96,6 @@ MidiPort::cycle_start (nframes_t nframes, nframes_t offset)
|
|||
|
||||
} else {
|
||||
|
||||
// cout << "out\n";
|
||||
|
||||
_buffer->silence (nframes, offset);
|
||||
}
|
||||
|
||||
// cout << endl;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <pbd/failed_constructor.h>
|
||||
#include <pbd/stl_delete.h>
|
||||
#include <pbd/xml++.h>
|
||||
#include <pbd/stacktrace.h>
|
||||
|
||||
#include <ardour/playlist.h>
|
||||
#include <ardour/session.h>
|
||||
|
|
@ -233,6 +234,7 @@ Playlist::init (bool hide)
|
|||
_refcnt = 0;
|
||||
_hidden = hide;
|
||||
_splicing = false;
|
||||
_shuffling = false;
|
||||
_nudging = false;
|
||||
in_set_state = 0;
|
||||
_edit_mode = Config->get_edit_mode();
|
||||
|
|
@ -351,7 +353,7 @@ Playlist::notify_region_removed (boost::shared_ptr<Region> r)
|
|||
/* this might not be true, but we have to act
|
||||
as though it could be.
|
||||
*/
|
||||
pending_length = false;
|
||||
pending_length = false;
|
||||
LengthChanged (); /* EMIT SIGNAL */
|
||||
pending_modified = false;
|
||||
Modified (); /* EMIT SIGNAL */
|
||||
|
|
@ -439,7 +441,6 @@ Playlist::flush_notifications ()
|
|||
|
||||
if (n || pending_modified) {
|
||||
if (!in_set_state) {
|
||||
possibly_splice ();
|
||||
relayer ();
|
||||
}
|
||||
pending_modified = false;
|
||||
|
|
@ -479,12 +480,7 @@ Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, floa
|
|||
--itimes;
|
||||
}
|
||||
|
||||
/* later regions will all be spliced anyway */
|
||||
|
||||
if (!holding_state ()) {
|
||||
possibly_splice_unlocked ();
|
||||
}
|
||||
|
||||
/* note that itimes can be zero if we being asked to just
|
||||
insert a single fraction of the region.
|
||||
*/
|
||||
|
|
@ -495,14 +491,18 @@ Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, floa
|
|||
pos += region->length();
|
||||
}
|
||||
|
||||
nframes_t length = 0;
|
||||
|
||||
if (floor (times) != times) {
|
||||
nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
|
||||
length = (nframes_t) floor (region->length() * (times - floor (times)));
|
||||
string name;
|
||||
_session.region_name (name, region->name(), false);
|
||||
boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
|
||||
add_region_internal (sub, pos);
|
||||
}
|
||||
|
||||
|
||||
possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
|
||||
release_notifications ();
|
||||
}
|
||||
|
||||
|
|
@ -540,6 +540,8 @@ Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t posit
|
|||
regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
|
||||
all_regions.insert (region);
|
||||
|
||||
possibly_splice_unlocked (position, region->length(), region);
|
||||
|
||||
if (!holding_state () && !in_set_state) {
|
||||
/* layers get assigned from XML state */
|
||||
relayer ();
|
||||
|
|
@ -565,12 +567,15 @@ Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Regio
|
|||
{
|
||||
RegionLock rlock (this);
|
||||
|
||||
bool old_sp = _splicing;
|
||||
_splicing = true;
|
||||
|
||||
remove_region_internal (old);
|
||||
add_region_internal (newr, pos);
|
||||
|
||||
if (!holding_state ()) {
|
||||
possibly_splice_unlocked ();
|
||||
}
|
||||
_splicing = old_sp;
|
||||
|
||||
possibly_splice_unlocked (pos, (nframes64_t) old->length() - (nframes64_t) newr->length());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -578,14 +583,10 @@ Playlist::remove_region (boost::shared_ptr<Region> region)
|
|||
{
|
||||
RegionLock rlock (this);
|
||||
remove_region_internal (region);
|
||||
|
||||
if (!holding_state ()) {
|
||||
possibly_splice_unlocked ();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
Playlist::remove_region_internal (boost::shared_ptr<Region>region)
|
||||
Playlist::remove_region_internal (boost::shared_ptr<Region> region)
|
||||
{
|
||||
RegionList::iterator i;
|
||||
nframes_t old_length = 0;
|
||||
|
|
@ -602,8 +603,13 @@ Playlist::remove_region_internal (boost::shared_ptr<Region>region)
|
|||
for (i = regions.begin(); i != regions.end(); ++i) {
|
||||
if (*i == region) {
|
||||
|
||||
nframes_t pos = (*i)->position();
|
||||
nframes64_t distance = (*i)->length();
|
||||
|
||||
regions.erase (i);
|
||||
|
||||
possibly_splice_unlocked (pos, -distance);
|
||||
|
||||
if (!holding_state ()) {
|
||||
relayer ();
|
||||
remove_dependents (region);
|
||||
|
|
@ -617,6 +623,9 @@ Playlist::remove_region_internal (boost::shared_ptr<Region>region)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -664,6 +673,7 @@ Playlist::partition (nframes_t start, nframes_t end, bool just_top_level)
|
|||
void
|
||||
Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
|
||||
{
|
||||
RegionLock rlock (this);
|
||||
boost::shared_ptr<Region> region;
|
||||
boost::shared_ptr<Region> current;
|
||||
string new_name;
|
||||
|
|
@ -671,19 +681,14 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
|
|||
OverlapType overlap;
|
||||
nframes_t pos1, pos2, pos3, pos4;
|
||||
RegionList new_regions;
|
||||
RegionList copy;
|
||||
|
||||
in_partition = true;
|
||||
|
||||
delay_notifications();
|
||||
|
||||
/* need to work from a copy, because otherwise the regions we add during the process
|
||||
get operated on as well.
|
||||
*/
|
||||
{
|
||||
RegionLock rlock (this);
|
||||
copy = regions;
|
||||
}
|
||||
|
||||
RegionList copy = regions;
|
||||
|
||||
for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
|
||||
|
||||
|
|
@ -691,10 +696,9 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
|
|||
++tmp;
|
||||
|
||||
current = *i;
|
||||
|
||||
|
||||
if (current->first_frame() == start && current->last_frame() == end) {
|
||||
if (cutting) {
|
||||
RegionLock rlock (this);
|
||||
remove_region_internal (current);
|
||||
}
|
||||
continue;
|
||||
|
|
@ -703,14 +707,14 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
|
|||
if ((overlap = current->coverage (start, end)) == OverlapNone) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
pos1 = current->position();
|
||||
pos2 = start;
|
||||
pos3 = end;
|
||||
pos4 = current->last_frame();
|
||||
|
||||
if (overlap == OverlapInternal) {
|
||||
|
||||
|
||||
/* split: we need 3 new regions, the front, middle and end.
|
||||
cut: we need 2 regions, the front and end.
|
||||
*/
|
||||
|
|
@ -730,10 +734,9 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
|
|||
|
||||
/* "middle" ++++++ */
|
||||
|
||||
_session.region_name (new_name, current->name(), false); //takes the session-wide region lock
|
||||
_session.region_name (new_name, current->name(), false);
|
||||
region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
|
||||
regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
|
||||
RegionLock rlock (this);
|
||||
add_region_internal (region, start);
|
||||
new_regions.push_back (region);
|
||||
}
|
||||
|
|
@ -743,11 +746,10 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
|
|||
_session.region_name (new_name, current->name(), false);
|
||||
region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
|
||||
regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
|
||||
{
|
||||
RegionLock rlock (this);
|
||||
add_region_internal (region, end);
|
||||
new_regions.push_back (region);
|
||||
}
|
||||
|
||||
add_region_internal (region, end);
|
||||
new_regions.push_back (region);
|
||||
|
||||
/* "front" ***** */
|
||||
|
||||
current->freeze ();
|
||||
|
|
@ -772,9 +774,8 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
|
|||
/* end +++++ */
|
||||
|
||||
_session.region_name (new_name, current->name(), false);
|
||||
region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, regions.size(),
|
||||
region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
|
||||
Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
|
||||
RegionLock rlock (this);
|
||||
add_region_internal (region, start);
|
||||
new_regions.push_back (region);
|
||||
}
|
||||
|
|
@ -809,7 +810,6 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
|
|||
_session.region_name (new_name, current->name(), false);
|
||||
region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
|
||||
regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
|
||||
RegionLock rlock (this);
|
||||
add_region_internal (region, pos1);
|
||||
new_regions.push_back (region);
|
||||
}
|
||||
|
|
@ -839,7 +839,6 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
|
|||
*/
|
||||
|
||||
if (cutting) {
|
||||
RegionLock rlock (this);
|
||||
remove_region_internal (current);
|
||||
}
|
||||
new_regions.push_back (current);
|
||||
|
|
@ -851,8 +850,6 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
|
|||
for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
|
||||
check_dependents (*i, false);
|
||||
}
|
||||
|
||||
release_notifications ();
|
||||
}
|
||||
|
||||
boost::shared_ptr<Playlist>
|
||||
|
|
@ -919,7 +916,6 @@ Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
|
|||
}
|
||||
|
||||
partition_internal (start, start+cnt-1, true, thawlist);
|
||||
possibly_splice ();
|
||||
|
||||
for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
|
||||
(*i)->thaw ("playlist cut");
|
||||
|
|
@ -973,7 +969,6 @@ Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float ti
|
|||
pos += shift;
|
||||
}
|
||||
|
||||
possibly_splice_unlocked ();
|
||||
|
||||
/* XXX shall we handle fractional cases at some point? */
|
||||
|
||||
|
|
@ -1033,10 +1028,14 @@ Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_pos
|
|||
string before_name;
|
||||
string after_name;
|
||||
|
||||
/* split doesn't change anything about length, so don't try to splice */
|
||||
|
||||
bool old_sp = _splicing;
|
||||
_splicing = true;
|
||||
|
||||
before = playlist_position - region->position();
|
||||
after = region->length() - before;
|
||||
|
||||
|
||||
_session.region_name (before_name, region->name(), false);
|
||||
left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
|
||||
|
||||
|
|
@ -1045,7 +1044,7 @@ Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_pos
|
|||
|
||||
add_region_internal (left, region->position());
|
||||
add_region_internal (right, region->position() + before);
|
||||
|
||||
|
||||
uint64_t orig_layer_op = region->last_layer_op();
|
||||
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
|
||||
if ((*i)->last_layer_op() > orig_layer_op) {
|
||||
|
|
@ -1060,71 +1059,84 @@ Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_pos
|
|||
|
||||
finalize_split_region (region, left, right);
|
||||
|
||||
if (remove_region_internal (region)) {
|
||||
remove_region_internal (region);
|
||||
|
||||
_splicing = old_sp;
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
|
||||
{
|
||||
if (_splicing || in_set_state) {
|
||||
/* don't respond to splicing moves or state setting */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::possibly_splice ()
|
||||
{
|
||||
if (_edit_mode == Splice) {
|
||||
splice_locked ();
|
||||
splice_locked (at, distance, exclude);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::possibly_splice_unlocked ()
|
||||
Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
|
||||
{
|
||||
if (_splicing || in_set_state) {
|
||||
/* don't respond to splicing moves or state setting */
|
||||
return;
|
||||
}
|
||||
|
||||
if (_edit_mode == Splice) {
|
||||
splice_unlocked ();
|
||||
splice_unlocked (at, distance, exclude);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::splice_locked ()
|
||||
Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
|
||||
{
|
||||
{
|
||||
RegionLock rl (this);
|
||||
core_splice ();
|
||||
core_splice (at, distance, exclude);
|
||||
}
|
||||
|
||||
notify_length_changed ();
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::splice_unlocked ()
|
||||
Playlist::splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
|
||||
{
|
||||
core_splice ();
|
||||
notify_length_changed ();
|
||||
core_splice (at, distance, exclude);
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::core_splice ()
|
||||
Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
|
||||
{
|
||||
_splicing = true;
|
||||
|
||||
|
||||
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
|
||||
|
||||
RegionList::iterator next;
|
||||
|
||||
next = i;
|
||||
++next;
|
||||
|
||||
if (next == regions.end()) {
|
||||
break;
|
||||
|
||||
if (exclude && (*i) == exclude) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((*i)->position() >= at) {
|
||||
nframes64_t new_pos = (*i)->position() + distance;
|
||||
if (new_pos < 0) {
|
||||
new_pos = 0;
|
||||
} else if (new_pos >= max_frames - (*i)->length()) {
|
||||
new_pos = max_frames - (*i)->length();
|
||||
}
|
||||
|
||||
(*i)->set_position (new_pos, this);
|
||||
}
|
||||
|
||||
(*next)->set_position ((*i)->last_frame() + 1, this);
|
||||
}
|
||||
|
||||
|
||||
_splicing = false;
|
||||
|
||||
notify_length_changed ();
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
|
||||
{
|
||||
if (in_set_state || _splicing || _nudging) {
|
||||
if (in_set_state || _splicing || _nudging || _shuffling) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1147,10 +1159,24 @@ Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region>
|
|||
|
||||
regions.erase (i);
|
||||
regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
|
||||
|
||||
}
|
||||
|
||||
if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
|
||||
|
||||
nframes64_t delta = 0;
|
||||
|
||||
if (what_changed & ARDOUR::PositionChanged) {
|
||||
delta = (nframes64_t) region->position() - (nframes64_t) region->last_position();
|
||||
}
|
||||
|
||||
if (what_changed & ARDOUR::LengthChanged) {
|
||||
delta += (nframes64_t) region->length() - (nframes64_t) region->last_length();
|
||||
}
|
||||
|
||||
if (delta) {
|
||||
possibly_splice (region->last_position() + region->last_length(), delta, region);
|
||||
}
|
||||
|
||||
if (holding_state ()) {
|
||||
pending_bounds.push_back (region);
|
||||
} else {
|
||||
|
|
@ -1159,7 +1185,6 @@ Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region>
|
|||
timestamp_layer_op (region);
|
||||
}
|
||||
|
||||
possibly_splice ();
|
||||
notify_length_changed ();
|
||||
relayer ();
|
||||
check_dependents (region, false);
|
||||
|
|
@ -1269,9 +1294,114 @@ Playlist::top_region_at (nframes_t frame)
|
|||
return region;
|
||||
}
|
||||
|
||||
Playlist::RegionList*
|
||||
Playlist::regions_to_read (nframes_t start, nframes_t end)
|
||||
{
|
||||
/* Caller must hold lock */
|
||||
|
||||
RegionList covering;
|
||||
set<nframes_t> to_check;
|
||||
set<boost::shared_ptr<Region> > unique;
|
||||
RegionList here;
|
||||
|
||||
to_check.insert (start);
|
||||
to_check.insert (end);
|
||||
|
||||
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
|
||||
|
||||
/* find all/any regions that span start+end */
|
||||
|
||||
switch ((*i)->coverage (start, end)) {
|
||||
case OverlapNone:
|
||||
break;
|
||||
|
||||
case OverlapInternal:
|
||||
covering.push_back (*i);
|
||||
break;
|
||||
|
||||
case OverlapStart:
|
||||
to_check.insert ((*i)->position());
|
||||
covering.push_back (*i);
|
||||
break;
|
||||
|
||||
case OverlapEnd:
|
||||
to_check.insert ((*i)->last_frame());
|
||||
covering.push_back (*i);
|
||||
break;
|
||||
|
||||
case OverlapExternal:
|
||||
covering.push_back (*i);
|
||||
to_check.insert ((*i)->position());
|
||||
to_check.insert ((*i)->last_frame());
|
||||
break;
|
||||
}
|
||||
|
||||
/* don't go too far */
|
||||
|
||||
if ((*i)->position() > end) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RegionList* rlist = new RegionList;
|
||||
|
||||
/* find all the regions that cover each position .... */
|
||||
|
||||
if (covering.size() == 1) {
|
||||
|
||||
rlist->push_back (covering.front());
|
||||
|
||||
} else {
|
||||
|
||||
for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
|
||||
|
||||
here.clear ();
|
||||
|
||||
for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
|
||||
|
||||
if ((*x)->covers (*t)) {
|
||||
here.push_back (*x);
|
||||
}
|
||||
}
|
||||
|
||||
RegionSortByLayer cmp;
|
||||
here.sort (cmp);
|
||||
|
||||
/* ... and get the top/transparent regions at "here" */
|
||||
|
||||
for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
|
||||
|
||||
unique.insert (*c);
|
||||
|
||||
if ((*c)->opaque()) {
|
||||
|
||||
/* the other regions at this position are hidden by this one */
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
|
||||
rlist->push_back (*s);
|
||||
}
|
||||
|
||||
if (rlist->size() > 1) {
|
||||
/* now sort by time order */
|
||||
|
||||
RegionSortByPosition cmp;
|
||||
rlist->sort (cmp);
|
||||
}
|
||||
}
|
||||
|
||||
return rlist;
|
||||
}
|
||||
|
||||
Playlist::RegionList *
|
||||
Playlist::find_regions_at (nframes_t frame)
|
||||
{
|
||||
/* Caller must hold lock */
|
||||
|
||||
RegionList *rlist = new RegionList;
|
||||
|
||||
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
|
||||
|
|
@ -1352,6 +1482,92 @@ Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
|
|||
return ret;
|
||||
}
|
||||
|
||||
nframes64_t
|
||||
Playlist::find_next_region_boundary (nframes64_t frame, int dir)
|
||||
{
|
||||
RegionLock rlock (this);
|
||||
|
||||
nframes64_t closest = max_frames;
|
||||
nframes64_t ret = -1;
|
||||
|
||||
if (dir > 0) {
|
||||
|
||||
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
|
||||
|
||||
boost::shared_ptr<Region> r = (*i);
|
||||
nframes64_t distance;
|
||||
nframes64_t end = r->position() + r->length();
|
||||
bool reset;
|
||||
|
||||
reset = false;
|
||||
|
||||
if (r->first_frame() > frame) {
|
||||
|
||||
distance = r->first_frame() - frame;
|
||||
|
||||
if (distance < closest) {
|
||||
ret = r->first_frame();
|
||||
closest = distance;
|
||||
reset = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (end > frame) {
|
||||
|
||||
distance = end - frame;
|
||||
|
||||
if (distance < closest) {
|
||||
ret = end;
|
||||
closest = distance;
|
||||
reset = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (reset) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
|
||||
|
||||
boost::shared_ptr<Region> r = (*i);
|
||||
nframes64_t distance;
|
||||
bool reset;
|
||||
|
||||
reset = false;
|
||||
|
||||
if (r->last_frame() < frame) {
|
||||
|
||||
distance = frame - r->last_frame();
|
||||
|
||||
if (distance < closest) {
|
||||
ret = r->last_frame();
|
||||
closest = distance;
|
||||
reset = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (r->first_frame() < frame) {
|
||||
distance = frame - r->last_frame();
|
||||
|
||||
if (distance < closest) {
|
||||
ret = r->first_frame();
|
||||
closest = distance;
|
||||
reset = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (reset) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
|
||||
|
|
@ -1685,6 +1901,33 @@ Playlist::relayer ()
|
|||
|
||||
/* XXX these layer functions are all deprecated */
|
||||
|
||||
void
|
||||
Playlist::raise_region (boost::shared_ptr<Region> region)
|
||||
{
|
||||
uint32_t rsz = regions.size();
|
||||
layer_t target = region->layer() + 1U;
|
||||
|
||||
if (target >= rsz) {
|
||||
/* its already at the effective top */
|
||||
return;
|
||||
}
|
||||
|
||||
move_region_to_layer (target, region, 1);
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::lower_region (boost::shared_ptr<Region> region)
|
||||
{
|
||||
if (region->layer() == 0) {
|
||||
/* its already at the bottom */
|
||||
return;
|
||||
}
|
||||
|
||||
layer_t target = region->layer() - 1U;
|
||||
|
||||
move_region_to_layer (target, region, -1);
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
|
||||
{
|
||||
|
|
@ -1707,6 +1950,79 @@ Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
|
||||
{
|
||||
RegionList::iterator i;
|
||||
typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
|
||||
list<LayerInfo> layerinfo;
|
||||
layer_t dest;
|
||||
|
||||
{
|
||||
RegionLock rlock (const_cast<Playlist *> (this));
|
||||
|
||||
for (i = regions.begin(); i != regions.end(); ++i) {
|
||||
|
||||
if (region == *i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dir > 0) {
|
||||
|
||||
/* region is moving up, move all regions on intermediate layers
|
||||
down 1
|
||||
*/
|
||||
|
||||
if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
|
||||
dest = (*i)->layer() - 1;
|
||||
} else {
|
||||
/* not affected */
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
|
||||
/* region is moving down, move all regions on intermediate layers
|
||||
up 1
|
||||
*/
|
||||
|
||||
if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
|
||||
dest = (*i)->layer() + 1;
|
||||
} else {
|
||||
/* not affected */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
LayerInfo newpair;
|
||||
|
||||
newpair.first = *i;
|
||||
newpair.second = dest;
|
||||
|
||||
layerinfo.push_back (newpair);
|
||||
}
|
||||
}
|
||||
|
||||
/* now reset the layers without holding the region lock */
|
||||
|
||||
for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
|
||||
x->first->set_layer (x->second);
|
||||
}
|
||||
|
||||
region->set_layer (target_layer);
|
||||
|
||||
#if 0
|
||||
/* now check all dependents */
|
||||
|
||||
for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
|
||||
check_dependents (x->first, false);
|
||||
}
|
||||
|
||||
check_dependents (region, false);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
|
||||
{
|
||||
|
|
@ -1817,3 +2133,129 @@ Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
|
|||
region->set_last_layer_op (++layer_op_counter);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
|
||||
{
|
||||
bool moved = false;
|
||||
nframes_t new_pos;
|
||||
|
||||
if (region->locked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_shuffling = true;
|
||||
|
||||
{
|
||||
RegionLock rlock (const_cast<Playlist*> (this));
|
||||
|
||||
|
||||
if (dir > 0) {
|
||||
|
||||
RegionList::iterator next;
|
||||
|
||||
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
|
||||
if ((*i) == region) {
|
||||
next = i;
|
||||
++next;
|
||||
|
||||
if (next != regions.end()) {
|
||||
|
||||
if ((*next)->locked()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((*next)->position() != region->last_frame() + 1) {
|
||||
/* they didn't used to touch, so after shuffle,
|
||||
just have them swap positions.
|
||||
*/
|
||||
new_pos = (*next)->position();
|
||||
} else {
|
||||
/* they used to touch, so after shuffle,
|
||||
make sure they still do. put the earlier
|
||||
region where the later one will end after
|
||||
it is moved.
|
||||
*/
|
||||
new_pos = region->position() + (*next)->length();
|
||||
}
|
||||
|
||||
(*next)->set_position (region->position(), this);
|
||||
region->set_position (new_pos, this);
|
||||
|
||||
/* avoid a full sort */
|
||||
|
||||
regions.erase (i); // removes the region from the list */
|
||||
next++;
|
||||
regions.insert (next, region); // adds it back after next
|
||||
|
||||
moved = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
RegionList::iterator prev = regions.end();
|
||||
|
||||
for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
|
||||
if ((*i) == region) {
|
||||
|
||||
if (prev != regions.end()) {
|
||||
|
||||
if ((*prev)->locked()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (region->position() != (*prev)->last_frame() + 1) {
|
||||
/* they didn't used to touch, so after shuffle,
|
||||
just have them swap positions.
|
||||
*/
|
||||
new_pos = region->position();
|
||||
} else {
|
||||
/* they used to touch, so after shuffle,
|
||||
make sure they still do. put the earlier
|
||||
one where the later one will end after
|
||||
*/
|
||||
new_pos = (*prev)->position() + region->length();
|
||||
}
|
||||
|
||||
region->set_position ((*prev)->position(), this);
|
||||
(*prev)->set_position (new_pos, this);
|
||||
|
||||
/* avoid a full sort */
|
||||
|
||||
regions.erase (i); // remove region
|
||||
regions.insert (prev, region); // insert region before prev
|
||||
|
||||
moved = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_shuffling = false;
|
||||
|
||||
if (moved) {
|
||||
|
||||
relayer ();
|
||||
check_dependents (region, false);
|
||||
|
||||
notify_modified();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
|
||||
{
|
||||
RegionLock rlock (const_cast<Playlist*> (this));
|
||||
|
||||
if (regions.size() > 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@
|
|||
#include <ardour/ladspa_plugin.h>
|
||||
#include <ardour/plugin_manager.h>
|
||||
|
||||
#ifdef HAVE_AUDIOUNITS
|
||||
#include <ardour/audio_unit.h>
|
||||
#endif
|
||||
|
||||
#include <pbd/stl_delete.h>
|
||||
|
||||
#include "i18n.h"
|
||||
|
|
@ -66,7 +70,21 @@ vector<string>
|
|||
Plugin::get_presets()
|
||||
{
|
||||
vector<string> labels;
|
||||
lrdf_uris* set_uris = lrdf_get_setting_uris(unique_id());
|
||||
uint32_t id;
|
||||
std::string unique (unique_id());
|
||||
|
||||
/* XXX problem: AU plugins don't have numeric ID's.
|
||||
Solution: they have a different method of providing presets.
|
||||
XXX sub-problem: implement it.
|
||||
*/
|
||||
|
||||
if (!isdigit (unique[0])) {
|
||||
return labels;
|
||||
}
|
||||
|
||||
id = atol (unique.c_str());
|
||||
|
||||
lrdf_uris* set_uris = lrdf_get_setting_uris(id);
|
||||
|
||||
if (set_uris) {
|
||||
for (uint32_t i = 0; i < (uint32_t) set_uris->count; ++i) {
|
||||
|
|
@ -108,6 +126,20 @@ Plugin::save_preset (string name, string domain)
|
|||
{
|
||||
lrdf_portvalue portvalues[parameter_count()];
|
||||
lrdf_defaults defaults;
|
||||
uint32_t id;
|
||||
std::string unique (unique_id());
|
||||
|
||||
/* XXX problem: AU plugins don't have numeric ID's.
|
||||
Solution: they have a different method of providing/saving presets.
|
||||
XXX sub-problem: implement it.
|
||||
*/
|
||||
|
||||
if (!isdigit (unique[0])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
id = atol (unique.c_str());
|
||||
|
||||
defaults.count = parameter_count();
|
||||
defaults.items = portvalues;
|
||||
|
||||
|
|
@ -126,7 +158,7 @@ Plugin::save_preset (string name, string domain)
|
|||
|
||||
string source(string_compose("file:%1/.%2/rdf/ardour-presets.n3", envvar, domain));
|
||||
|
||||
free(lrdf_add_preset(source.c_str(), name.c_str(), unique_id(), &defaults));
|
||||
free(lrdf_add_preset(source.c_str(), name.c_str(), id, &defaults));
|
||||
|
||||
string path = string_compose("%1/.%2", envvar, domain);
|
||||
if (g_mkdir_with_parents (path.c_str(), 0775)) {
|
||||
|
|
@ -149,7 +181,7 @@ Plugin::save_preset (string name, string domain)
|
|||
}
|
||||
|
||||
PluginPtr
|
||||
ARDOUR::find_plugin(Session& session, string name, long unique_id, PluginType type)
|
||||
ARDOUR::find_plugin(Session& session, string identifier, PluginType type)
|
||||
{
|
||||
PluginManager *mgr = PluginManager::the_manager();
|
||||
PluginInfoList plugs;
|
||||
|
|
@ -162,14 +194,12 @@ ARDOUR::find_plugin(Session& session, string name, long unique_id, PluginType ty
|
|||
#ifdef VST_SUPPORT
|
||||
case ARDOUR::VST:
|
||||
plugs = mgr->vst_plugin_info();
|
||||
unique_id = 0; // VST plugins don't have a unique id.
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_AUDIOUNITS
|
||||
case ARDOUR::AudioUnit:
|
||||
plugs = AUPluginInfo::discover ();
|
||||
unique_id = 0; // Neither do AU.
|
||||
plugs = mgr->au_plugin_info();
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
|
@ -178,10 +208,10 @@ ARDOUR::find_plugin(Session& session, string name, long unique_id, PluginType ty
|
|||
}
|
||||
|
||||
PluginInfoList::iterator i;
|
||||
|
||||
for (i = plugs.begin(); i != plugs.end(); ++i) {
|
||||
if ((name == "" || (*i)->name == name) &&
|
||||
(unique_id == 0 || (*i)->unique_id == unique_id)) {
|
||||
return (*i)->load (session);
|
||||
if (identifier == (*i)->unique_id){
|
||||
return (*i)->load (session);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -606,17 +606,10 @@ PluginInsert::get_state(void)
|
|||
XMLNode&
|
||||
PluginInsert::state (bool full)
|
||||
{
|
||||
char buf[256];
|
||||
XMLNode& node = Processor::state (full);
|
||||
|
||||
node.add_property ("type", _plugins[0]->state_node_name());
|
||||
snprintf(buf, sizeof(buf), "%s", _plugins[0]->name());
|
||||
node.add_property("id", string(buf));
|
||||
if (_plugins[0]->state_node_name() == "ladspa") {
|
||||
char buf[32];
|
||||
snprintf (buf, sizeof (buf), "%ld", _plugins[0]->get_info()->unique_id);
|
||||
node.add_property("unique-id", string(buf));
|
||||
}
|
||||
node.add_property("unique-id", _plugins[0]->unique_id());
|
||||
node.add_property("count", string_compose("%1", _plugins.size()));
|
||||
node.add_child_nocopy (_plugins[0]->get_state());
|
||||
|
||||
|
|
@ -648,7 +641,6 @@ PluginInsert::set_state(const XMLNode& node)
|
|||
XMLNodeIterator niter;
|
||||
XMLPropertyList plist;
|
||||
const XMLProperty *prop;
|
||||
long unique = 0;
|
||||
ARDOUR::PluginType type;
|
||||
|
||||
if ((prop = node.property ("type")) == 0) {
|
||||
|
|
@ -666,24 +658,16 @@ PluginInsert::set_state(const XMLNode& node)
|
|||
<< endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
prop = node.property ("unique-id");
|
||||
if (prop != 0) {
|
||||
unique = atol(prop->value().c_str());
|
||||
}
|
||||
|
||||
if ((prop = node.property ("id")) == 0) {
|
||||
error << _("XML node describing insert is missing the `id' field") << endmsg;
|
||||
return -1;
|
||||
if (prop == 0) {
|
||||
error << _("Plugin has no unique ID field") << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
boost::shared_ptr<Plugin> plugin;
|
||||
|
||||
if (unique != 0) {
|
||||
plugin = find_plugin (_session, "", unique, type);
|
||||
} else {
|
||||
plugin = find_plugin (_session, prop->value(), 0, type);
|
||||
}
|
||||
plugin = find_plugin (_session, prop->value(), type);
|
||||
|
||||
if (plugin == 0) {
|
||||
error << string_compose(_("Found a reference to a plugin (\"%1\") that is unknown.\n"
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@
|
|||
#include <ardour/vst_plugin.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_AUDIOUNITS
|
||||
#include <ardour/audio_unit.h>
|
||||
#endif
|
||||
|
||||
#include <pbd/error.h>
|
||||
#include <pbd/stl_delete.h>
|
||||
|
||||
|
|
@ -84,10 +88,23 @@ PluginManager::PluginManager ()
|
|||
vst_path = s;
|
||||
}
|
||||
|
||||
refresh ();
|
||||
if (_manager == 0) {
|
||||
_manager = this;
|
||||
}
|
||||
|
||||
/* the plugin manager is constructed too early to use Profile */
|
||||
|
||||
if (getenv ("ARDOUR_SAE")) {
|
||||
ladspa_plugin_whitelist.push_back (1203); // single band parametric
|
||||
ladspa_plugin_whitelist.push_back (1772); // caps compressor
|
||||
ladspa_plugin_whitelist.push_back (1913); // fast lookahead limiter
|
||||
ladspa_plugin_whitelist.push_back (1075); // simple RMS expander
|
||||
ladspa_plugin_whitelist.push_back (1061); // feedback delay line (max 5s)
|
||||
ladspa_plugin_whitelist.push_back (1216); // gverb
|
||||
ladspa_plugin_whitelist.push_back (2150); // tap pitch shifter
|
||||
}
|
||||
|
||||
refresh ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -99,6 +116,9 @@ PluginManager::refresh ()
|
|||
vst_refresh ();
|
||||
}
|
||||
#endif // VST_SUPPORT
|
||||
#ifdef HAVE_AUDIOUNITS
|
||||
au_refresh ();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -113,6 +133,7 @@ PluginManager::ladspa_refresh ()
|
|||
ladspa_discover_from_path (ladspa_path);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
PluginManager::add_ladspa_directory (string path)
|
||||
{
|
||||
|
|
@ -248,6 +269,12 @@ PluginManager::ladspa_discover (string path)
|
|||
break;
|
||||
}
|
||||
|
||||
if (!ladspa_plugin_whitelist.empty()) {
|
||||
if (find (ladspa_plugin_whitelist.begin(), ladspa_plugin_whitelist.end(), descriptor->UniqueID) == ladspa_plugin_whitelist.end()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
PluginInfoPtr info(new LadspaPluginInfo);
|
||||
info->name = descriptor->Name;
|
||||
info->category = get_ladspa_category(descriptor->UniqueID);
|
||||
|
|
@ -257,7 +284,10 @@ PluginManager::ladspa_discover (string path)
|
|||
info->n_inputs = ChanCount();
|
||||
info->n_outputs = ChanCount();
|
||||
info->type = ARDOUR::LADSPA;
|
||||
info->unique_id = descriptor->UniqueID;
|
||||
|
||||
char buf[32];
|
||||
snprintf (buf, sizeof (buf), "%lu", descriptor->UniqueID);
|
||||
info->unique_id = buf;
|
||||
|
||||
for (uint32_t n=0; n < descriptor->PortCount; ++n) {
|
||||
if ( LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[n]) ) {
|
||||
|
|
@ -294,7 +324,7 @@ PluginManager::get_ladspa_category (uint32_t plugin_id)
|
|||
lrdf_statement* matches1 = lrdf_matches (&pattern);
|
||||
|
||||
if (!matches1) {
|
||||
return _("Unknown");
|
||||
return _("");
|
||||
}
|
||||
|
||||
pattern.subject = matches1->object;
|
||||
|
|
@ -306,7 +336,7 @@ PluginManager::get_ladspa_category (uint32_t plugin_id)
|
|||
lrdf_free_statements(matches1);
|
||||
|
||||
if (!matches2) {
|
||||
return _("Unknown");
|
||||
return _("");
|
||||
}
|
||||
|
||||
string label = matches2->object;
|
||||
|
|
@ -315,6 +345,22 @@ PluginManager::get_ladspa_category (uint32_t plugin_id)
|
|||
return label;
|
||||
}
|
||||
|
||||
#ifdef HAVE_AUDIOUNITS
|
||||
void
|
||||
PluginManager::au_refresh ()
|
||||
{
|
||||
au_discover();
|
||||
}
|
||||
|
||||
int
|
||||
PluginManager::au_discover ()
|
||||
{
|
||||
_au_plugin_info = AUPluginInfo::discover();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef VST_SUPPORT
|
||||
|
||||
void
|
||||
|
|
@ -373,6 +419,7 @@ int
|
|||
PluginManager::vst_discover (string path)
|
||||
{
|
||||
FSTInfo* finfo;
|
||||
char buf[32];
|
||||
|
||||
if ((finfo = fst_get_info (const_cast<char *> (path.c_str()))) == 0) {
|
||||
warning << "Cannot get VST information from " << path << endmsg;
|
||||
|
|
@ -395,6 +442,9 @@ PluginManager::vst_discover (string path)
|
|||
info->name = finfo->name;
|
||||
}
|
||||
|
||||
|
||||
snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
|
||||
info->unique_id = buf;
|
||||
info->category = "VST";
|
||||
info->path = path;
|
||||
// need to set info->creator but FST doesn't provide it
|
||||
|
|
|
|||
302
libs/ardour/rb_effect.cc
Normal file
302
libs/ardour/rb_effect.cc
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
Copyright (C) 2004-2007 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 <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include <pbd/error.h>
|
||||
#include <rubberband/RubberBandStretcher.h>
|
||||
|
||||
#include <ardour/types.h>
|
||||
#include <ardour/stretch.h>
|
||||
#include <ardour/pitch.h>
|
||||
#include <ardour/audiofilesource.h>
|
||||
#include <ardour/session.h>
|
||||
#include <ardour/audioregion.h>
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
using namespace RubberBand;
|
||||
|
||||
Pitch::Pitch (Session& s, TimeFXRequest& req)
|
||||
: RBEffect (s, req)
|
||||
{
|
||||
}
|
||||
|
||||
Stretch::Stretch (Session& s, TimeFXRequest& req)
|
||||
: RBEffect (s, req)
|
||||
{
|
||||
}
|
||||
|
||||
RBEffect::RBEffect (Session& s, TimeFXRequest& req)
|
||||
: Filter (s)
|
||||
, tsr (req)
|
||||
|
||||
{
|
||||
tsr.progress = 0.0f;
|
||||
}
|
||||
|
||||
RBEffect::~RBEffect ()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
RBEffect::run (boost::shared_ptr<AudioRegion> region)
|
||||
{
|
||||
SourceList nsrcs;
|
||||
nframes_t done;
|
||||
int ret = -1;
|
||||
const nframes_t bufsize = 256;
|
||||
gain_t* gain_buffer = 0;
|
||||
Sample** buffers = 0;
|
||||
char suffix[32];
|
||||
string new_name;
|
||||
string::size_type at;
|
||||
nframes_t pos = 0;
|
||||
int avail = 0;
|
||||
|
||||
RubberBandStretcher stretcher (session.frame_rate(), region->n_channels(),
|
||||
RubberBandStretcher::DefaultOptions,
|
||||
tsr.time_fraction, tsr.pitch_fraction);
|
||||
|
||||
stretcher.setExpectedInputDuration(region->length());
|
||||
stretcher.setDebugLevel(1);
|
||||
|
||||
tsr.progress = 0.0f;
|
||||
tsr.done = false;
|
||||
|
||||
uint32_t channels = region->n_channels();
|
||||
nframes_t duration = region->length();
|
||||
|
||||
/* the name doesn't need to be super-precise, but allow for 2 fractional
|
||||
digits just to disambiguate close but not identical FX
|
||||
*/
|
||||
|
||||
if (tsr.time_fraction == 1.0) {
|
||||
snprintf (suffix, sizeof (suffix), "@%d", (int) floor (tsr.pitch_fraction * 100.0f));
|
||||
} else if (tsr.pitch_fraction == 1.0) {
|
||||
snprintf (suffix, sizeof (suffix), "@%d", (int) floor (tsr.time_fraction * 100.0f));
|
||||
} else {
|
||||
snprintf (suffix, sizeof (suffix), "@%d-%d",
|
||||
(int) floor (tsr.time_fraction * 100.0f),
|
||||
(int) floor (tsr.pitch_fraction * 100.0f));
|
||||
}
|
||||
|
||||
/* create new sources */
|
||||
|
||||
if (make_new_sources (region, nsrcs, suffix)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
gain_buffer = new gain_t[bufsize];
|
||||
buffers = new float *[channels];
|
||||
|
||||
for (uint32_t i = 0; i < channels; ++i) {
|
||||
buffers[i] = new float[bufsize];
|
||||
}
|
||||
|
||||
/* we read from the master (original) sources for the region,
|
||||
not the ones currently in use, in case it's already been
|
||||
subject to timefx. */
|
||||
|
||||
/* study first, process afterwards. */
|
||||
|
||||
pos = 0;
|
||||
avail = 0;
|
||||
done = 0;
|
||||
|
||||
try {
|
||||
while (pos < duration && !tsr.cancel) {
|
||||
|
||||
nframes_t this_read = 0;
|
||||
|
||||
for (uint32_t i = 0; i < channels; ++i) {
|
||||
|
||||
this_read = 0;
|
||||
nframes_t this_time;
|
||||
|
||||
this_time = min(bufsize, duration - pos);
|
||||
|
||||
this_read = region->master_read_at
|
||||
(buffers[i],
|
||||
buffers[i],
|
||||
gain_buffer,
|
||||
pos + region->position(),
|
||||
this_time,
|
||||
i);
|
||||
|
||||
if (this_read != this_time) {
|
||||
error << string_compose
|
||||
(_("tempoize: error reading data from %1"),
|
||||
nsrcs[i]->name()) << endmsg;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
pos += this_read;
|
||||
done += this_read;
|
||||
|
||||
tsr.progress = ((float) done / duration) * 0.75;
|
||||
|
||||
stretcher.study(buffers, this_read, pos == duration);
|
||||
}
|
||||
|
||||
done = 0;
|
||||
pos = 0;
|
||||
|
||||
while (pos < duration && !tsr.cancel) {
|
||||
|
||||
nframes_t this_read = 0;
|
||||
|
||||
for (uint32_t i = 0; i < channels; ++i) {
|
||||
|
||||
this_read = 0;
|
||||
nframes_t this_time;
|
||||
|
||||
this_time = min(bufsize, duration - pos);
|
||||
|
||||
this_read = region->master_read_at
|
||||
(buffers[i],
|
||||
buffers[i],
|
||||
gain_buffer,
|
||||
pos + region->position(),
|
||||
this_time,
|
||||
i);
|
||||
|
||||
if (this_read != this_time) {
|
||||
error << string_compose
|
||||
(_("tempoize: error reading data from %1"),
|
||||
nsrcs[i]->name()) << endmsg;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
pos += this_read;
|
||||
done += this_read;
|
||||
|
||||
tsr.progress = 0.75 + ((float) done / duration) * 0.25;
|
||||
|
||||
stretcher.process(buffers, this_read, pos == duration);
|
||||
|
||||
int avail = 0;
|
||||
|
||||
while ((avail = stretcher.available()) > 0) {
|
||||
|
||||
this_read = min(bufsize, uint32_t(avail));
|
||||
|
||||
stretcher.retrieve(buffers, this_read);
|
||||
|
||||
for (uint32_t i = 0; i < nsrcs.size(); ++i) {
|
||||
|
||||
if (nsrcs[i]->write(buffers[i], this_read) !=
|
||||
this_read) {
|
||||
error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while ((avail = stretcher.available()) >= 0) {
|
||||
|
||||
uint32_t this_read = min(bufsize, uint32_t(avail));
|
||||
|
||||
stretcher.retrieve(buffers, this_read);
|
||||
|
||||
for (uint32_t i = 0; i < nsrcs.size(); ++i) {
|
||||
|
||||
if (nsrcs[i]->write(buffers[i], this_read) !=
|
||||
this_read) {
|
||||
error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (runtime_error& err) {
|
||||
error << _("timefx code failure. please notify ardour-developers.") << endmsg;
|
||||
error << err.what() << endmsg;
|
||||
goto out;
|
||||
}
|
||||
|
||||
new_name = region->name();
|
||||
at = new_name.find ('@');
|
||||
|
||||
// remove any existing stretch indicator
|
||||
|
||||
if (at != string::npos && at > 2) {
|
||||
new_name = new_name.substr (0, at - 1);
|
||||
}
|
||||
|
||||
new_name += suffix;
|
||||
|
||||
ret = finish (region, nsrcs, new_name);
|
||||
|
||||
/* now reset ancestral data for each new region */
|
||||
|
||||
for (vector<boost::shared_ptr<AudioRegion> >::iterator x = results.begin(); x != results.end(); ++x) {
|
||||
nframes64_t astart = (*x)->ancestral_start();
|
||||
nframes64_t alength = (*x)->ancestral_length();
|
||||
nframes_t start;
|
||||
nframes_t length;
|
||||
|
||||
// note: tsr.time_fraction is a percentage of original length. 100 = no change,
|
||||
// 50 is half as long, 200 is twice as long, etc.
|
||||
|
||||
|
||||
float stretch = (*x)->stretch() * (tsr.time_fraction/100.0);
|
||||
float shift = (*x)->shift() * tsr.pitch_fraction;
|
||||
|
||||
start = (nframes_t) floor (astart + ((astart - (*x)->start()) / stretch));
|
||||
length = (nframes_t) floor (alength / stretch);
|
||||
|
||||
(*x)->set_ancestral_data (start, length, stretch, shift);
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
if (gain_buffer) {
|
||||
delete [] gain_buffer;
|
||||
}
|
||||
|
||||
if (buffers) {
|
||||
for (uint32_t i = 0; i < channels; ++i) {
|
||||
delete buffers[i];
|
||||
}
|
||||
delete [] buffers;
|
||||
}
|
||||
|
||||
if (ret || tsr.cancel) {
|
||||
for (SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) {
|
||||
(*si)->mark_for_remove ();
|
||||
}
|
||||
}
|
||||
|
||||
tsr.done = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -365,6 +365,8 @@ Region::set_length (nframes_t len, void *src)
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
_last_length = _length;
|
||||
_length = len;
|
||||
|
||||
_flags = Region::Flag (_flags & ~WholeFile);
|
||||
|
|
@ -443,6 +445,7 @@ Region::special_set_position (nframes_t pos)
|
|||
a way to store its "natural" or "captured" position.
|
||||
*/
|
||||
|
||||
_position = _position;
|
||||
_position = pos;
|
||||
}
|
||||
|
||||
|
|
@ -454,6 +457,7 @@ Region::set_position (nframes_t pos, void *src)
|
|||
}
|
||||
|
||||
if (_position != pos) {
|
||||
_last_position = _position;
|
||||
_position = pos;
|
||||
|
||||
/* check that the new _position wouldn't make the current
|
||||
|
|
@ -463,6 +467,7 @@ Region::set_position (nframes_t pos, void *src)
|
|||
*/
|
||||
|
||||
if (max_frames - _length < _position) {
|
||||
_last_length = _length;
|
||||
_length = max_frames - _position;
|
||||
}
|
||||
}
|
||||
|
|
@ -482,6 +487,7 @@ Region::set_position_on_top (nframes_t pos, void *src)
|
|||
}
|
||||
|
||||
if (_position != pos) {
|
||||
_last_position = _position;
|
||||
_position = pos;
|
||||
}
|
||||
|
||||
|
|
@ -499,7 +505,7 @@ Region::set_position_on_top (nframes_t pos, void *src)
|
|||
}
|
||||
|
||||
void
|
||||
Region::nudge_position (long n, void *src)
|
||||
Region::nudge_position (nframes64_t n, void *src)
|
||||
{
|
||||
if (_flags & Locked) {
|
||||
return;
|
||||
|
|
@ -509,6 +515,8 @@ Region::nudge_position (long n, void *src)
|
|||
return;
|
||||
}
|
||||
|
||||
_last_position = _position;
|
||||
|
||||
if (n > 0) {
|
||||
if (_position > max_frames - n) {
|
||||
_position = max_frames;
|
||||
|
|
@ -527,11 +535,12 @@ Region::nudge_position (long n, void *src)
|
|||
}
|
||||
|
||||
void
|
||||
Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st)
|
||||
Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
|
||||
{
|
||||
_ancestral_length = l;
|
||||
_ancestral_start = s;
|
||||
_stretch = st;
|
||||
_shift = sh;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -723,10 +732,16 @@ Region::trim_to_internal (nframes_t position, nframes_t length, void *src)
|
|||
what_changed = Change (what_changed|StartChanged);
|
||||
}
|
||||
if (_length != length) {
|
||||
if (!_frozen) {
|
||||
_last_length = _length;
|
||||
}
|
||||
_length = length;
|
||||
what_changed = Change (what_changed|LengthChanged);
|
||||
}
|
||||
if (_position != position) {
|
||||
if (!_frozen) {
|
||||
_last_position = _position;
|
||||
}
|
||||
_position = position;
|
||||
what_changed = Change (what_changed|PositionChanged);
|
||||
}
|
||||
|
|
@ -867,14 +882,16 @@ Region::adjust_to_sync (nframes_t pos)
|
|||
{
|
||||
int sync_dir;
|
||||
nframes_t offset = sync_offset (sync_dir);
|
||||
|
||||
// cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
|
||||
|
||||
if (sync_dir > 0) {
|
||||
if (max_frames - pos > offset) {
|
||||
pos += offset;
|
||||
pos -= offset;
|
||||
}
|
||||
} else {
|
||||
if (pos > offset) {
|
||||
pos -= offset;
|
||||
pos += offset;
|
||||
} else {
|
||||
pos = 0;
|
||||
}
|
||||
|
|
@ -893,6 +910,24 @@ Region::sync_position() const
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Region::raise ()
|
||||
{
|
||||
boost::shared_ptr<Playlist> pl (playlist());
|
||||
if (pl) {
|
||||
pl->raise_region (shared_from_this ());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Region::lower ()
|
||||
{
|
||||
boost::shared_ptr<Playlist> pl (playlist());
|
||||
if (pl) {
|
||||
pl->lower_region (shared_from_this ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Region::raise_to_top ()
|
||||
|
|
@ -945,6 +980,8 @@ Region::state (bool full_state)
|
|||
node->add_property ("ancestral-length", buf);
|
||||
snprintf (buf, sizeof (buf), "%.12g", _stretch);
|
||||
node->add_property ("stretch", buf);
|
||||
snprintf (buf, sizeof (buf), "%.12g", _shift);
|
||||
node->add_property ("shift", buf);
|
||||
|
||||
switch (_first_edit) {
|
||||
case EditChangesNothing:
|
||||
|
|
@ -1017,9 +1054,11 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
|
|||
sscanf (prop->value().c_str(), "%" PRIu32, &val);
|
||||
if (val != _length) {
|
||||
what_changed = Change (what_changed|LengthChanged);
|
||||
_last_length = _length;
|
||||
_length = val;
|
||||
}
|
||||
} else {
|
||||
_last_length = _length;
|
||||
_length = 1;
|
||||
}
|
||||
|
||||
|
|
@ -1027,9 +1066,11 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
|
|||
sscanf (prop->value().c_str(), "%" PRIu32, &val);
|
||||
if (val != _position) {
|
||||
what_changed = Change (what_changed|PositionChanged);
|
||||
_last_position = _position;
|
||||
_position = val;
|
||||
}
|
||||
} else {
|
||||
_last_position = _position;
|
||||
_position = 0;
|
||||
}
|
||||
|
||||
|
|
@ -1076,6 +1117,12 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
|
|||
_stretch = 1.0;
|
||||
}
|
||||
|
||||
if ((prop = node.property ("shift")) != 0) {
|
||||
_shift = atof (prop->value());
|
||||
} else {
|
||||
_shift = 1.0;
|
||||
}
|
||||
|
||||
/* note: derived classes set flags */
|
||||
|
||||
if (_extra_xml) {
|
||||
|
|
@ -1128,6 +1175,8 @@ void
|
|||
Region::freeze ()
|
||||
{
|
||||
_frozen++;
|
||||
_last_length = _length;
|
||||
_last_position = _position;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1261,27 +1310,46 @@ Region::source_equivalent (boost::shared_ptr<const Region> other) const
|
|||
bool
|
||||
Region::verify_length (nframes_t len)
|
||||
{
|
||||
for (uint32_t n=0; n < _sources.size(); ++n) {
|
||||
if (_start > _sources[n]->length() - len) {
|
||||
return false;
|
||||
}
|
||||
if (source() && source()->destructive()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nframes_t maxlen = 0;
|
||||
|
||||
for (uint32_t n=0; n < _sources.size(); ++n) {
|
||||
maxlen = max (maxlen, _sources[n]->length() - _start);
|
||||
}
|
||||
|
||||
len = min (len, maxlen);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Region::verify_start_and_length (nframes_t new_start, nframes_t new_length)
|
||||
Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
|
||||
{
|
||||
for (uint32_t n=0; n < _sources.size(); ++n) {
|
||||
if (new_length > _sources[n]->length() - new_start) {
|
||||
return false;
|
||||
}
|
||||
if (source() && source()->destructive()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nframes_t maxlen = 0;
|
||||
|
||||
for (uint32_t n=0; n < _sources.size(); ++n) {
|
||||
maxlen = max (maxlen, _sources[n]->length() - new_start);
|
||||
}
|
||||
|
||||
new_length = min (new_length, maxlen);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Region::verify_start (nframes_t pos)
|
||||
{
|
||||
if (source() && source()->destructive()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (uint32_t n=0; n < _sources.size(); ++n) {
|
||||
if (pos > _sources[n]->length() - _length) {
|
||||
return false;
|
||||
|
|
@ -1293,6 +1361,10 @@ Region::verify_start (nframes_t pos)
|
|||
bool
|
||||
Region::verify_start_mutable (nframes_t& new_start)
|
||||
{
|
||||
if (source() && source()->destructive()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (uint32_t n=0; n < _sources.size(); ++n) {
|
||||
if (new_start > _sources[n]->length() - _length) {
|
||||
new_start = _sources[n]->length() - _length;
|
||||
|
|
|
|||
|
|
@ -80,10 +80,11 @@ Route::init ()
|
|||
_muted = false;
|
||||
_soloed = false;
|
||||
_solo_safe = false;
|
||||
_recordable = true;
|
||||
_active = true;
|
||||
_phase_invert = false;
|
||||
_denormal_protection = false;
|
||||
order_keys[strdup (N_("signal"))] = order_key_cnt++;
|
||||
_active = true;
|
||||
_silent = false;
|
||||
_meter_point = MeterPostFader;
|
||||
_initial_delay = 0;
|
||||
|
|
@ -1662,10 +1663,14 @@ Route::add_processor_from_xml (const XMLNode& node)
|
|||
if ((prop = node.property ("type")) != 0) {
|
||||
|
||||
boost::shared_ptr<Processor> processor;
|
||||
bool have_insert = false;
|
||||
|
||||
if (prop->value() == "ladspa" || prop->value() == "Ladspa" || prop->value() == "vst") {
|
||||
|
||||
if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
|
||||
prop->value() == "vst" ||
|
||||
prop->value() == "audiounit") {
|
||||
|
||||
processor.reset (new PluginInsert(_session, node));
|
||||
have_insert = true;
|
||||
|
||||
} else if (prop->value() == "port") {
|
||||
|
||||
|
|
@ -1674,19 +1679,20 @@ Route::add_processor_from_xml (const XMLNode& node)
|
|||
} else if (prop->value() == "send") {
|
||||
|
||||
processor.reset (new Send (_session, node));
|
||||
have_insert = true;
|
||||
|
||||
} else {
|
||||
|
||||
error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
|
||||
}
|
||||
|
||||
|
||||
add_processor (processor);
|
||||
|
||||
} else {
|
||||
error << _("Processor XML node has no type property") << endmsg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
catch (failed_constructor &err) {
|
||||
warning << _("processor could not be created. Ignored.") << endmsg;
|
||||
return;
|
||||
|
|
@ -1732,7 +1738,8 @@ Route::_set_state (const XMLNode& node, bool call_base)
|
|||
if ((prop = node.property (X_("denormal-protection"))) != 0) {
|
||||
set_denormal_protection (prop->value()=="yes"?true:false, this);
|
||||
}
|
||||
|
||||
|
||||
_active = true;
|
||||
if ((prop = node.property (X_("active"))) != 0) {
|
||||
set_active (prop->value() == "yes");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,6 +97,14 @@ static const int CPU_CACHE_ALIGN = 64;
|
|||
static const int CPU_CACHE_ALIGN = 16; /* arguably 32 on most arches, but it matters less */
|
||||
#endif
|
||||
|
||||
bool Session::_disable_all_loaded_plugins = false;
|
||||
|
||||
Session::compute_peak_t Session::compute_peak = 0;
|
||||
Session::find_peaks_t Session::find_peaks = 0;
|
||||
Session::apply_gain_to_buffer_t Session::apply_gain_to_buffer = 0;
|
||||
Session::mix_buffers_with_gain_t Session::mix_buffers_with_gain = 0;
|
||||
Session::mix_buffers_no_gain_t Session::mix_buffers_no_gain = 0;
|
||||
|
||||
sigc::signal<int> Session::AskAboutPendingState;
|
||||
sigc::signal<void> Session::SendFeedback;
|
||||
|
||||
|
|
@ -105,9 +113,9 @@ sigc::signal<void> Session::StartTimeChanged;
|
|||
sigc::signal<void> Session::EndTimeChanged;
|
||||
|
||||
Session::Session (AudioEngine &eng,
|
||||
string fullpath,
|
||||
string snapshot_name,
|
||||
string* mix_template)
|
||||
const string& fullpath,
|
||||
const string& snapshot_name,
|
||||
string mix_template)
|
||||
|
||||
: _engine (eng),
|
||||
_scratch_buffers(new BufferSet()),
|
||||
|
|
@ -127,62 +135,29 @@ Session::Session (AudioEngine &eng,
|
|||
_click_io ((IO*) 0),
|
||||
main_outs (0)
|
||||
{
|
||||
bool new_session;
|
||||
|
||||
if (!eng.connected()) {
|
||||
throw failed_constructor();
|
||||
}
|
||||
|
||||
cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (1)" << endl;
|
||||
|
||||
n_physical_outputs = _engine.n_physical_outputs();
|
||||
n_physical_inputs = _engine.n_physical_inputs();
|
||||
|
||||
first_stage_init (fullpath, snapshot_name);
|
||||
|
||||
initialize_start_and_end_locations(0, compute_initial_length ());
|
||||
|
||||
if(mix_template) {
|
||||
// try and create a new session directory
|
||||
try
|
||||
{
|
||||
if(!_session_dir->create()) {
|
||||
// an existing session.
|
||||
// throw a_more_meaningful_exception()
|
||||
destroy ();
|
||||
throw failed_constructor ();
|
||||
}
|
||||
}
|
||||
catch(sys::filesystem_error& ex)
|
||||
{
|
||||
new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
|
||||
if (new_session) {
|
||||
if (create (new_session, mix_template, compute_initial_length())) {
|
||||
cerr << "create failed\n";
|
||||
destroy ();
|
||||
throw failed_constructor ();
|
||||
}
|
||||
|
||||
if(!create_session_file_from_template (*mix_template)) {
|
||||
destroy ();
|
||||
throw failed_constructor ();
|
||||
}
|
||||
|
||||
cerr << "Creating session " << fullpath
|
||||
<<" using template" << *mix_template
|
||||
<< endl;
|
||||
} else {
|
||||
// must be an existing session
|
||||
try
|
||||
{
|
||||
// ensure the necessary session subdirectories exist
|
||||
// in case the directory structure has changed etc.
|
||||
_session_dir->create();
|
||||
}
|
||||
catch(sys::filesystem_error& ex)
|
||||
{
|
||||
destroy ();
|
||||
throw failed_constructor ();
|
||||
}
|
||||
|
||||
cerr << "Loading session " << fullpath
|
||||
<< " using snapshot " << snapshot_name << " (1)"
|
||||
<< endl;
|
||||
}
|
||||
|
||||
if (second_stage_init (false)) {
|
||||
|
||||
if (second_stage_init (new_session)) {
|
||||
destroy ();
|
||||
throw failed_constructor ();
|
||||
}
|
||||
|
|
@ -228,6 +203,8 @@ Session::Session (AudioEngine &eng,
|
|||
main_outs (0)
|
||||
|
||||
{
|
||||
bool new_session;
|
||||
|
||||
if (!eng.connected()) {
|
||||
throw failed_constructor();
|
||||
}
|
||||
|
|
@ -247,11 +224,13 @@ Session::Session (AudioEngine &eng,
|
|||
|
||||
first_stage_init (fullpath, snapshot_name);
|
||||
|
||||
initialize_start_and_end_locations(0, initial_length);
|
||||
|
||||
if (!_session_dir->create () || !create_session_file ()) {
|
||||
destroy ();
|
||||
throw failed_constructor ();
|
||||
new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
|
||||
|
||||
if (new_session) {
|
||||
if (create (new_session, string(), initial_length)) {
|
||||
destroy ();
|
||||
throw failed_constructor ();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -286,7 +265,7 @@ Session::Session (AudioEngine &eng,
|
|||
Config->set_input_auto_connect (input_ac);
|
||||
Config->set_output_auto_connect (output_ac);
|
||||
|
||||
if (second_stage_init (true)) {
|
||||
if (second_stage_init (new_session)) {
|
||||
destroy ();
|
||||
throw failed_constructor ();
|
||||
}
|
||||
|
|
@ -3273,7 +3252,7 @@ Session::midi_path_from_name (string name)
|
|||
|
||||
return spath;
|
||||
}
|
||||
|
||||
|
||||
boost::shared_ptr<MidiSource>
|
||||
Session::create_midi_source_for_session (MidiDiskstream& ds)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -233,10 +233,6 @@ Session::butler_thread_work ()
|
|||
}
|
||||
}
|
||||
|
||||
//for (i = diskstreams.begin(); i != diskstreams.end(); ++i) {
|
||||
// cerr << "BEFORE " << (*i)->name() << ": pb = " << (*i)->playback_buffer_load() << " cp = " << (*i)->capture_buffer_load() << endl;
|
||||
//}
|
||||
|
||||
if (transport_work_requested()) {
|
||||
butler_transport_work ();
|
||||
}
|
||||
|
|
@ -249,10 +245,23 @@ Session::butler_thread_work ()
|
|||
|
||||
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader ();
|
||||
|
||||
// for (i = dsl->begin(); i != dsl->end(); ++i) {
|
||||
// cerr << "BEFORE " << (*i)->name() << ": pb = " << (*i)->playback_buffer_load() << " cp = " << (*i)->capture_buffer_load() << endl;
|
||||
// }
|
||||
|
||||
for (i = dsl->begin(); !transport_work_requested() && butler_should_run && i != dsl->end(); ++i) {
|
||||
|
||||
boost::shared_ptr<Diskstream> ds = *i;
|
||||
|
||||
/* don't read inactive tracks */
|
||||
|
||||
/*IO* io = ds->io();
|
||||
|
||||
if (ds->io() && !ds->io()->active()) {
|
||||
cerr << "Skip inactive diskstream " << ds->io()->name() << endl;
|
||||
continue;
|
||||
}*/
|
||||
|
||||
switch (ds->do_refill ()) {
|
||||
case 0:
|
||||
bytes += ds->read_data_count();
|
||||
|
|
@ -294,6 +303,9 @@ Session::butler_thread_work ()
|
|||
|
||||
for (i = dsl->begin(); !transport_work_requested() && butler_should_run && i != dsl->end(); ++i) {
|
||||
// cerr << "write behind for " << (*i)->name () << endl;
|
||||
|
||||
/* note that we still try to flush diskstreams attached to inactive routes
|
||||
*/
|
||||
|
||||
switch ((*i)->do_flush (Session::ButlerContext)) {
|
||||
case 0:
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ static const char* event_names[] = {
|
|||
"SetDiskstreamSpeed",
|
||||
"Locate",
|
||||
"LocateRoll",
|
||||
"LocateRollLocate",
|
||||
"SetLoop",
|
||||
"PunchIn",
|
||||
"PunchOut",
|
||||
|
|
@ -351,6 +352,13 @@ Session::process_event (Event* ev)
|
|||
_send_smpte_update = true;
|
||||
break;
|
||||
|
||||
case Event::LocateRollLocate:
|
||||
// locate is handled by ::request_roll_at_and_return()
|
||||
_requested_return_frame = ev->target_frame;
|
||||
set_transport_speed (ev->speed, true);
|
||||
break;
|
||||
|
||||
|
||||
case Event::SetTransportSpeed:
|
||||
set_transport_speed (ev->speed, ev->yes_or_no);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -428,6 +428,10 @@ AudioExportSpecification::process (nframes_t nframes)
|
|||
int
|
||||
Session::start_audio_export (AudioExportSpecification& spec)
|
||||
{
|
||||
if (!_engine.connected()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (spec.prepare (current_block_size, frame_rate())) {
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ Session::process (nframes_t nframes)
|
|||
{
|
||||
MIDI::Manager::instance()->cycle_start(nframes);
|
||||
|
||||
_silent = false;
|
||||
|
||||
if (synced_to_jack() && waiting_to_start) {
|
||||
if ( _engine.transport_state() == AudioEngine::TransportRolling) {
|
||||
actually_start_transport ();
|
||||
|
|
@ -302,7 +304,7 @@ Session::process_with_events (nframes_t nframes)
|
|||
}
|
||||
|
||||
if (!process_can_proceed()) {
|
||||
no_roll (nframes, 0);
|
||||
_silent = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -317,8 +319,8 @@ Session::process_with_events (nframes_t nframes)
|
|||
Event* this_event;
|
||||
Events::iterator the_next_one;
|
||||
|
||||
if (post_transport_work & (PostTransportLocate|PostTransportStop)) {
|
||||
no_roll (nframes, 0);
|
||||
if (!process_can_proceed()) {
|
||||
_silent = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -494,7 +496,7 @@ Session::follow_slave (nframes_t nframes, nframes_t offset)
|
|||
<< endl;
|
||||
#endif
|
||||
|
||||
if (Config->get_timecode_source_is_synced()) {
|
||||
if (_slave->is_always_synced() || Config->get_timecode_source_is_synced()) {
|
||||
|
||||
/* if the TC source is synced, then we assume that its
|
||||
speed is binary: 0.0 or 1.0
|
||||
|
|
@ -642,7 +644,7 @@ Session::follow_slave (nframes_t nframes, nframes_t offset)
|
|||
slave_state = Stopped;
|
||||
}
|
||||
|
||||
if (slave_state == Running && !Config->get_timecode_source_is_synced()) {
|
||||
if (slave_state == Running && !_slave->is_always_synced() && !Config->get_timecode_source_is_synced()) {
|
||||
|
||||
|
||||
if (_transport_speed != 0.0f) {
|
||||
|
|
@ -743,67 +745,64 @@ Session::process_without_events (nframes_t nframes)
|
|||
long frames_moved;
|
||||
nframes_t offset = 0;
|
||||
|
||||
{
|
||||
if (post_transport_work & (PostTransportLocate|PostTransportStop)) {
|
||||
no_roll (nframes, 0);
|
||||
return;
|
||||
}
|
||||
if (!process_can_proceed()) {
|
||||
_silent = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_exporting && _slave) {
|
||||
if (!follow_slave (nframes, 0)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_transport_speed == 0) {
|
||||
no_roll (nframes, 0);
|
||||
if (!_exporting && _slave) {
|
||||
if (!follow_slave (nframes, 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
send_midi_time_code_for_cycle(nframes);
|
||||
}
|
||||
|
||||
if (_transport_speed == 0) {
|
||||
no_roll (nframes, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (actively_recording()) {
|
||||
if (actively_recording()) {
|
||||
stop_limit = max_frames;
|
||||
} else {
|
||||
if (Config->get_stop_at_session_end()) {
|
||||
stop_limit = current_end_frame();
|
||||
} else {
|
||||
stop_limit = max_frames;
|
||||
} else {
|
||||
if (Config->get_stop_at_session_end()) {
|
||||
stop_limit = current_end_frame();
|
||||
} else {
|
||||
stop_limit = max_frames;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (maybe_stop (stop_limit)) {
|
||||
no_roll (nframes, 0);
|
||||
return;
|
||||
}
|
||||
if (maybe_stop (stop_limit)) {
|
||||
no_roll (nframes, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (maybe_sync_start (nframes, offset)) {
|
||||
return;
|
||||
}
|
||||
if (maybe_sync_start (nframes, offset)) {
|
||||
return;
|
||||
}
|
||||
|
||||
click (_transport_frame, nframes, offset);
|
||||
click (_transport_frame, nframes, offset);
|
||||
|
||||
prepare_diskstreams ();
|
||||
prepare_diskstreams ();
|
||||
|
||||
frames_moved = (long) floor (_transport_speed * nframes);
|
||||
frames_moved = (long) floor (_transport_speed * nframes);
|
||||
|
||||
if (process_routes (nframes, offset)) {
|
||||
no_roll (nframes, offset);
|
||||
return;
|
||||
}
|
||||
if (process_routes (nframes, offset)) {
|
||||
no_roll (nframes, offset);
|
||||
return;
|
||||
}
|
||||
|
||||
commit_diskstreams (nframes, session_needs_butler);
|
||||
commit_diskstreams (nframes, session_needs_butler);
|
||||
|
||||
if (frames_moved < 0) {
|
||||
decrement_transport_position (-frames_moved);
|
||||
} else {
|
||||
increment_transport_position (frames_moved);
|
||||
}
|
||||
if (frames_moved < 0) {
|
||||
decrement_transport_position (-frames_moved);
|
||||
} else {
|
||||
increment_transport_position (frames_moved);
|
||||
}
|
||||
|
||||
maybe_stop (stop_limit);
|
||||
check_declick_out ();
|
||||
|
||||
} /* implicit release of route lock */
|
||||
maybe_stop (stop_limit);
|
||||
check_declick_out ();
|
||||
|
||||
if (session_needs_butler)
|
||||
summon_butler ();
|
||||
|
|
|
|||
|
|
@ -418,48 +418,105 @@ Session::setup_raid_path (string path)
|
|||
last_rr_session_dir = session_dirs.begin();
|
||||
}
|
||||
|
||||
void
|
||||
Session::initialize_start_and_end_locations (nframes_t start, nframes_t end)
|
||||
int
|
||||
Session::create (bool& new_session, const string& mix_template, nframes_t initial_length)
|
||||
{
|
||||
start_location->set_end (start);
|
||||
string dir;
|
||||
|
||||
if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session dir \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir = session_directory().peak_path().to_string();
|
||||
|
||||
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session peakfile dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir = session_directory().sound_path().to_string();
|
||||
|
||||
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir = session_directory().midi_path().to_string();
|
||||
|
||||
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir = session_directory().dead_sound_path().to_string();
|
||||
|
||||
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session dead sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir = session_directory().export_path().to_string();
|
||||
|
||||
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session export dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* check new_session so we don't overwrite an existing one */
|
||||
|
||||
if (!mix_template.empty()) {
|
||||
std::string in_path = mix_template;
|
||||
|
||||
ifstream in(in_path.c_str());
|
||||
|
||||
if (in){
|
||||
string out_path = _path;
|
||||
out_path += _name;
|
||||
out_path += statefile_suffix;
|
||||
|
||||
ofstream out(out_path.c_str());
|
||||
|
||||
if (out){
|
||||
out << in.rdbuf();
|
||||
|
||||
// okay, session is set up. Treat like normal saved
|
||||
// session from now on.
|
||||
|
||||
new_session = false;
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
error << string_compose (_("Could not open %1 for writing mix template"), out_path)
|
||||
<< endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
error << string_compose (_("Could not open mix template %1 for reading"), in_path)
|
||||
<< endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* set initial start + end point */
|
||||
|
||||
start_location->set_end (0);
|
||||
_locations.add (start_location);
|
||||
|
||||
end_location->set_end (end);
|
||||
end_location->set_end (initial_length);
|
||||
_locations.add (end_location);
|
||||
}
|
||||
|
||||
bool
|
||||
Session::create_session_file ()
|
||||
{
|
||||
_state_of_the_state = Clean;
|
||||
|
||||
if (save_state (_current_snapshot_name)) {
|
||||
error << "Could not create new session file" << endmsg;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
save_state ("");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
Session::create_session_file_from_template (const string& template_path)
|
||||
{
|
||||
sys::path session_file_path(_session_dir->root_path());
|
||||
|
||||
session_file_path /= _name + statefile_suffix;
|
||||
|
||||
try
|
||||
{
|
||||
sys::copy_file (template_path, session_file_path);
|
||||
}
|
||||
catch(sys::filesystem_error& ex)
|
||||
{
|
||||
error << string_compose (_("Could not use session template %1 to create new session (%2)."),
|
||||
template_path, ex.what())
|
||||
<< endmsg;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
Session::load_diskstreams (const XMLNode& node)
|
||||
|
|
@ -2767,7 +2824,7 @@ Session::restore_history (string snapshot_name)
|
|||
const string xml_filename = snapshot_name + history_suffix;
|
||||
const sys::path xml_path = _session_dir->root_path() / xml_filename;
|
||||
|
||||
info << string_compose(_("Loading history from '%1'."), xml_path.to_string()) << endmsg;
|
||||
cerr << "Loading history from " << xml_path.to_string() << endmsg;
|
||||
|
||||
if (!sys::exists (xml_path)) {
|
||||
info << string_compose (_("%1: no history file \"%2\" for this session."),
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include <glibmm/thread.h>
|
||||
#include <pbd/pthread_utils.h>
|
||||
#include <pbd/memento_command.h>
|
||||
#include <pbd/stacktrace.h>
|
||||
|
||||
#include <midi++/mmc.h>
|
||||
#include <midi++/port.h>
|
||||
|
|
@ -392,17 +393,35 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
|
|||
update_latency_compensation (true, abort);
|
||||
}
|
||||
|
||||
if ((Config->get_slave_source() == None && Config->get_auto_return()) || (post_transport_work & PostTransportLocate) || synced_to_jack()) {
|
||||
if ((Config->get_slave_source() == None && Config->get_auto_return()) ||
|
||||
(post_transport_work & PostTransportLocate) ||
|
||||
(_requested_return_frame >= 0) ||
|
||||
synced_to_jack()) {
|
||||
|
||||
if (pending_locate_flush) {
|
||||
flush_all_inserts ();
|
||||
}
|
||||
|
||||
if (((Config->get_slave_source() == None && Config->get_auto_return()) || synced_to_jack()) && !(post_transport_work & PostTransportLocate)) {
|
||||
if (((Config->get_slave_source() == None && Config->get_auto_return()) ||
|
||||
synced_to_jack() ||
|
||||
_requested_return_frame >= 0) &&
|
||||
!(post_transport_work & PostTransportLocate)) {
|
||||
|
||||
_transport_frame = last_stop_frame;
|
||||
bool do_locate = false;
|
||||
|
||||
if (_requested_return_frame >= 0) {
|
||||
_transport_frame = _requested_return_frame;
|
||||
_requested_return_frame = -1;
|
||||
do_locate = true;
|
||||
} else {
|
||||
_transport_frame = last_stop_frame;
|
||||
}
|
||||
|
||||
if (synced_to_jack() && !play_loop) {
|
||||
do_locate = true;
|
||||
}
|
||||
|
||||
if (do_locate) {
|
||||
// cerr << "non-realtimestop: transport locate to " << _transport_frame << endl;
|
||||
_engine.transport_locate (_transport_frame);
|
||||
}
|
||||
|
|
@ -478,7 +497,9 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
|
|||
|
||||
}
|
||||
|
||||
PositionChanged (_transport_frame); /* EMIT SIGNAL */
|
||||
nframes_t tf = _transport_frame;
|
||||
|
||||
PositionChanged (tf); /* EMIT SIGNAL */
|
||||
TransportStateChange (); /* EMIT SIGNAL */
|
||||
|
||||
/* and start it up again if relevant */
|
||||
|
|
@ -1202,6 +1223,14 @@ Session::setup_auto_play ()
|
|||
merge_event (ev);
|
||||
}
|
||||
|
||||
void
|
||||
Session::request_roll_at_and_return (nframes_t start, nframes_t return_to)
|
||||
{
|
||||
request_locate (start, false);
|
||||
Event *ev = new Event (Event::LocateRollLocate, Event::Add, Event::Immediate, return_to, 1.0);
|
||||
queue_event (ev);
|
||||
}
|
||||
|
||||
void
|
||||
Session::request_bounded_roll (nframes_t start, nframes_t end)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -345,7 +345,8 @@ SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, n
|
|||
|
||||
// FIXME: assumes tempo never changes after start
|
||||
const double frames_per_beat = _session.tempo_map().tempo_at(_timeline_position).frames_per_beat(
|
||||
_session.engine().frame_rate());
|
||||
_session.engine().frame_rate(),
|
||||
_session.tempo_map().meter_at(_timeline_position));
|
||||
|
||||
const uint64_t start_ticks = (uint64_t)((start / frames_per_beat) * _ppqn);
|
||||
|
||||
|
|
@ -456,8 +457,9 @@ SMFSource::append_event_unlocked(const MidiEvent& ev)
|
|||
assert(ev.time() >= _last_ev_time);
|
||||
|
||||
// FIXME: assumes tempo never changes after start
|
||||
const double frames_per_beat = _session.tempo_map().tempo_at
|
||||
(_timeline_position).frames_per_beat(_session.engine().frame_rate());
|
||||
const double frames_per_beat = _session.tempo_map().tempo_at(_timeline_position).frames_per_beat(
|
||||
_session.engine().frame_rate(),
|
||||
_session.tempo_map().meter_at(_timeline_position));
|
||||
|
||||
const uint32_t delta_time = (uint32_t)((ev.time() - _last_ev_time) / frames_per_beat * _ppqn);
|
||||
|
||||
|
|
@ -888,7 +890,8 @@ SMFSource::load_model(bool lock, bool force_reload)
|
|||
|
||||
// FIXME: assumes tempo never changes after start
|
||||
const double frames_per_beat = _session.tempo_map().tempo_at(_timeline_position).frames_per_beat(
|
||||
_session.engine().frame_rate());
|
||||
_session.engine().frame_rate(),
|
||||
_session.tempo_map().meter_at(_timeline_position));
|
||||
|
||||
uint32_t delta_t = 0;
|
||||
int ret;
|
||||
|
|
|
|||
|
|
@ -33,33 +33,27 @@ using namespace std;
|
|||
const char * const sndfile_header_formats_strings[SNDFILE_HEADER_FORMATS+1] = {
|
||||
N_("WAV"),
|
||||
N_("AIFF"),
|
||||
N_("raw (no header)"),
|
||||
N_("PAF (Ensoniq Paris)"),
|
||||
N_("AU (Sun/NeXT)"),
|
||||
N_("IRCAM"),
|
||||
N_("CAF"),
|
||||
N_("W64 (64 bit WAV)"),
|
||||
N_("raw (no header)"),
|
||||
0
|
||||
};
|
||||
|
||||
const char* const sndfile_file_endings_strings[SNDFILE_HEADER_FORMATS+1] = {
|
||||
N_(".wav"),
|
||||
N_(".aiff"),
|
||||
N_(".raw"),
|
||||
N_(".paf"),
|
||||
N_(".au"),
|
||||
N_(".ircam"),
|
||||
N_(".caf"),
|
||||
N_(".w64"),
|
||||
N_(".raw"),
|
||||
0
|
||||
};
|
||||
|
||||
int sndfile_header_formats[SNDFILE_HEADER_FORMATS] = {
|
||||
SF_FORMAT_WAV,
|
||||
SF_FORMAT_AIFF,
|
||||
SF_FORMAT_RAW,
|
||||
SF_FORMAT_PAF,
|
||||
SF_FORMAT_AU,
|
||||
SF_FORMAT_IRCAM,
|
||||
SF_FORMAT_W64
|
||||
SF_FORMAT_CAF,
|
||||
SF_FORMAT_W64,
|
||||
SF_FORMAT_RAW
|
||||
};
|
||||
|
||||
const char * const sndfile_bitdepth_formats_strings[SNDFILE_BITDEPTH_FORMATS+1] = {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ peak_thread_work ()
|
|||
if (SourceFactory::files_with_peaks.empty()) {
|
||||
goto wait;
|
||||
}
|
||||
|
||||
|
||||
boost::shared_ptr<AudioSource> as (SourceFactory::files_with_peaks.front().lock());
|
||||
SourceFactory::files_with_peaks.pop_front ();
|
||||
SourceFactory::peak_building_lock.unlock ();
|
||||
|
|
@ -68,7 +68,6 @@ peak_thread_work ()
|
|||
if (!as) {
|
||||
continue;
|
||||
}
|
||||
|
||||
as->setup_peakfile ();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
52
libs/ardour/st_pitch.cc
Normal file
52
libs/ardour/st_pitch.cc
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright (C) 2004-2007 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 <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include <pbd/error.h>
|
||||
|
||||
#include <ardour/types.h>
|
||||
#include <ardour/pitch.h>
|
||||
#include <ardour/audiofilesource.h>
|
||||
#include <ardour/session.h>
|
||||
#include <ardour/audioregion.h>
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
|
||||
Pitch::Pitch (Session& s, TimeFXRequest& req)
|
||||
: Filter (s)
|
||||
, tsr (req)
|
||||
|
||||
{
|
||||
tsr.progress = 0.0f;
|
||||
}
|
||||
|
||||
int
|
||||
Pitch::run (boost::shared_ptr<Region> region)
|
||||
{
|
||||
tsr.progress = 1.0f;
|
||||
tsr.done = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@ using namespace ARDOUR;
|
|||
using namespace PBD;
|
||||
using namespace soundtouch;
|
||||
|
||||
Stretch::Stretch (Session& s, TimeStretchRequest& req)
|
||||
Stretch::Stretch (Session& s, TimeFXRequest& req)
|
||||
: Filter (s)
|
||||
, tsr (req)
|
||||
{
|
||||
|
|
@ -45,7 +45,7 @@ Stretch::Stretch (Session& s, TimeStretchRequest& req)
|
|||
of opposite sign to the length change.
|
||||
*/
|
||||
|
||||
percentage = -tsr.fraction;
|
||||
percentage = -tsr.time_fraction;
|
||||
|
||||
st.setSampleRate (s.frame_rate());
|
||||
st.setChannels (1);
|
||||
|
|
@ -64,14 +64,8 @@ Stretch::~Stretch ()
|
|||
}
|
||||
|
||||
int
|
||||
Stretch::run (boost::shared_ptr<Region> r)
|
||||
Stretch::run (boost::shared_ptr<Region> a_region)
|
||||
{
|
||||
boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (r);
|
||||
|
||||
if (!region) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SourceList nsrcs;
|
||||
nframes_t total_frames;
|
||||
nframes_t done;
|
||||
|
|
@ -85,6 +79,8 @@ Stretch::run (boost::shared_ptr<Region> r)
|
|||
|
||||
tsr.progress = 0.0f;
|
||||
tsr.done = false;
|
||||
|
||||
boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion>(a_region);
|
||||
|
||||
total_frames = region->length() * region->n_channels();
|
||||
done = 0;
|
||||
|
|
@ -93,7 +89,7 @@ Stretch::run (boost::shared_ptr<Region> r)
|
|||
digits just to disambiguate close but not identical stretches.
|
||||
*/
|
||||
|
||||
snprintf (suffix, sizeof (suffix), "@%d", (int) floor (tsr.fraction * 100.0f));
|
||||
snprintf (suffix, sizeof (suffix), "@%d", (int) floor (tsr.time_fraction * 100.0f));
|
||||
|
||||
/* create new sources */
|
||||
|
||||
|
|
@ -109,12 +105,9 @@ Stretch::run (boost::shared_ptr<Region> r)
|
|||
try {
|
||||
for (uint32_t i = 0; i < nsrcs.size(); ++i) {
|
||||
|
||||
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (nsrcs[i]);
|
||||
boost::shared_ptr<AudioSource> asrc
|
||||
= boost::dynamic_pointer_cast<AudioSource>(nsrcs[i]);
|
||||
|
||||
if (!afs) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nframes_t pos = 0;
|
||||
nframes_t this_read = 0;
|
||||
|
||||
|
|
@ -131,7 +124,7 @@ Stretch::run (boost::shared_ptr<Region> r)
|
|||
*/
|
||||
|
||||
if ((this_read = region->master_read_at (buffer, buffer, gain_buffer, pos + region->position(), this_time)) != this_time) {
|
||||
error << string_compose (_("tempoize: error reading data from %1"), afs->name()) << endmsg;
|
||||
error << string_compose (_("tempoize: error reading data from %1"), asrc->name()) << endmsg;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -143,8 +136,8 @@ Stretch::run (boost::shared_ptr<Region> r)
|
|||
st.putSamples (buffer, this_read);
|
||||
|
||||
while ((this_read = st.receiveSamples (buffer, bufsize)) > 0 && !tsr.cancel) {
|
||||
if (afs->write (buffer, this_read) != this_read) {
|
||||
error << string_compose (_("error writing tempo-adjusted data to %1"), afs->name()) << endmsg;
|
||||
if (asrc->write (buffer, this_read) != this_read) {
|
||||
error << string_compose (_("error writing tempo-adjusted data to %1"), asrc->name()) << endmsg;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
|
@ -155,8 +148,8 @@ Stretch::run (boost::shared_ptr<Region> r)
|
|||
}
|
||||
|
||||
while (!tsr.cancel && (this_read = st.receiveSamples (buffer, bufsize)) > 0) {
|
||||
if (afs->write (buffer, this_read) != this_read) {
|
||||
error << string_compose (_("error writing tempo-adjusted data to %1"), afs->name()) << endmsg;
|
||||
if (asrc->write (buffer, this_read) != this_read) {
|
||||
error << string_compose (_("error writing tempo-adjusted data to %1"), asrc->name()) << endmsg;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
|
@ -184,25 +177,20 @@ Stretch::run (boost::shared_ptr<Region> r)
|
|||
/* now reset ancestral data for each new region */
|
||||
|
||||
for (vector<boost::shared_ptr<Region> >::iterator x = results.begin(); x != results.end(); ++x) {
|
||||
|
||||
boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (*x);
|
||||
|
||||
assert (region != 0);
|
||||
|
||||
nframes64_t astart = region->ancestral_start();
|
||||
nframes64_t alength = region->ancestral_length();
|
||||
nframes64_t astart = (*x)->ancestral_start();
|
||||
nframes64_t alength = (*x)->ancestral_length();
|
||||
nframes_t start;
|
||||
nframes_t length;
|
||||
|
||||
// note: tsr.fraction is a percentage of original length. 100 = no change,
|
||||
// 50 is half as long, 200 is twice as long, etc.
|
||||
|
||||
float stretch = region->stretch() * (tsr.fraction/100.0);
|
||||
float stretch = (*x)->stretch() * (tsr.time_fraction/100.0);
|
||||
|
||||
start = (nframes_t) floor (astart + ((astart - region->start()) / stretch));
|
||||
start = (nframes_t) floor (astart + ((astart - (*x)->start()) / stretch));
|
||||
length = (nframes_t) floor (alength / stretch);
|
||||
|
||||
region->set_ancestral_data (start, length, stretch);
|
||||
(*x)->set_ancestral_data (start, length, stretch, (*x)->shift());
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
@ -43,12 +43,17 @@ Tempo TempoMap::_default_tempo (120.0);
|
|||
|
||||
const double Meter::ticks_per_beat = 1920.0;
|
||||
|
||||
double Tempo::frames_per_beat (nframes_t sr, const Meter& meter) const
|
||||
{
|
||||
return ((60.0 * sr) / (_beats_per_minute * meter.note_divisor()/_note_type));
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
double
|
||||
Meter::frames_per_bar (const Tempo& tempo, nframes_t sr) const
|
||||
{
|
||||
return ((60.0 * sr * _beats_per_bar) / tempo.beats_per_minute());
|
||||
return ((60.0 * sr * _beats_per_bar) / (tempo.beats_per_minute() * _note_type/tempo.note_type()));
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
|
@ -86,6 +91,16 @@ TempoSection::TempoSection (const XMLNode& node)
|
|||
error << _("TempoSection XML node has an illegal \"beats_per_minute\" value") << endmsg;
|
||||
throw failed_constructor();
|
||||
}
|
||||
|
||||
if ((prop = node.property ("note-type")) == 0) {
|
||||
/* older session, make note type be quarter by default */
|
||||
_note_type = 4.0;
|
||||
} else {
|
||||
if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 1.0) {
|
||||
error << _("TempoSection XML node has an illegal \"note-type\" value") << endmsg;
|
||||
throw failed_constructor();
|
||||
}
|
||||
}
|
||||
|
||||
if ((prop = node.property ("movable")) == 0) {
|
||||
error << _("TempoSection XML node has no \"movable\" property") << endmsg;
|
||||
|
|
@ -109,6 +124,8 @@ TempoSection::get_state() const
|
|||
root->add_property ("start", buf);
|
||||
snprintf (buf, sizeof (buf), "%f", _beats_per_minute);
|
||||
root->add_property ("beats-per-minute", buf);
|
||||
snprintf (buf, sizeof (buf), "%f", _note_type);
|
||||
root->add_property ("note-type", buf);
|
||||
snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
|
||||
root->add_property ("movable", buf);
|
||||
|
||||
|
|
@ -210,7 +227,7 @@ TempoMap::TempoMap (nframes_t fr)
|
|||
start.beats = 1;
|
||||
start.ticks = 0;
|
||||
|
||||
TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute());
|
||||
TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute(), _default_tempo.note_type());
|
||||
MeterSection *m = new MeterSection (start, _default_meter.beats_per_bar(), _default_meter.note_divisor());
|
||||
|
||||
t->set_movable (false);
|
||||
|
|
@ -359,7 +376,7 @@ TempoMap::add_tempo (const Tempo& tempo, BBT_Time where)
|
|||
|
||||
where.ticks = 0;
|
||||
|
||||
do_insert (new TempoSection (where, tempo.beats_per_minute()));
|
||||
do_insert (new TempoSection (where, tempo.beats_per_minute(), tempo.note_type()));
|
||||
}
|
||||
|
||||
StateChanged (Change (0));
|
||||
|
|
@ -614,7 +631,7 @@ TempoMap::bbt_time_with_metric (nframes_t frame, BBT_Time& bbt, const Metric& me
|
|||
|
||||
const double beats_per_bar = metric.meter().beats_per_bar();
|
||||
const double frames_per_bar = metric.meter().frames_per_bar (metric.tempo(), _frame_rate);
|
||||
const double beat_frames = metric.tempo().frames_per_beat (_frame_rate);
|
||||
const double beat_frames = metric.tempo().frames_per_beat (_frame_rate, metric.meter());
|
||||
|
||||
/* now compute how far beyond that point we actually are. */
|
||||
|
||||
|
|
@ -667,7 +684,7 @@ TempoMap::count_frames_between ( const BBT_Time& start, const BBT_Time& end) con
|
|||
+ start.ticks/Meter::ticks_per_beat;
|
||||
|
||||
|
||||
start_frame = m.frame() + (nframes_t) rint( beat_offset * m.tempo().frames_per_beat(_frame_rate));
|
||||
start_frame = m.frame() + (nframes_t) rint( beat_offset * m.tempo().frames_per_beat(_frame_rate, m.meter()));
|
||||
|
||||
m = metric_at(end);
|
||||
|
||||
|
|
@ -676,7 +693,7 @@ TempoMap::count_frames_between ( const BBT_Time& start, const BBT_Time& end) con
|
|||
beat_offset = bar_offset * m.meter().beats_per_bar() - (m.start().beats -1) + (end.beats - 1)
|
||||
+ end.ticks/Meter::ticks_per_beat;
|
||||
|
||||
end_frame = m.frame() + (nframes_t) rint(beat_offset * m.tempo().frames_per_beat(_frame_rate));
|
||||
end_frame = m.frame() + (nframes_t) rint(beat_offset * m.tempo().frames_per_beat(_frame_rate, m.meter()));
|
||||
|
||||
frames = end_frame - start_frame;
|
||||
|
||||
|
|
@ -697,7 +714,7 @@ TempoMap::count_frames_between_metrics (const Meter& meter, const Tempo& tempo,
|
|||
double beat_frames = 0;
|
||||
|
||||
beats_per_bar = meter.beats_per_bar();
|
||||
beat_frames = tempo.frames_per_beat (_frame_rate);
|
||||
beat_frames = tempo.frames_per_beat (_frame_rate,meter);
|
||||
|
||||
frames = 0;
|
||||
|
||||
|
|
@ -1088,7 +1105,7 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
|
|||
|
||||
beats_per_bar = meter->beats_per_bar ();
|
||||
frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
|
||||
beat_frames = tempo->frames_per_beat (_frame_rate);
|
||||
beat_frames = tempo->frames_per_beat (_frame_rate, *meter);
|
||||
|
||||
if (meter->frame() > tempo->frame()) {
|
||||
bar = meter->start().bars;
|
||||
|
|
@ -1198,7 +1215,7 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
|
|||
|
||||
beats_per_bar = meter->beats_per_bar ();
|
||||
frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
|
||||
beat_frames = tempo->frames_per_beat (_frame_rate);
|
||||
beat_frames = tempo->frames_per_beat (_frame_rate, *meter);
|
||||
|
||||
++i;
|
||||
}
|
||||
|
|
@ -1304,7 +1321,7 @@ TempoMap::dump (std::ostream& o) const
|
|||
for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
|
||||
|
||||
if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
|
||||
o << "Tempo @ " << *i << ' ' << t->beats_per_minute() << " BPM at " << t->start() << " frame= " << t->frame() << " (move? "
|
||||
o << "Tempo @ " << *i << ' ' << t->beats_per_minute() << " BPM (denom = " << t->note_type() << ") at " << t->start() << " frame= " << t->frame() << " (move? "
|
||||
<< t->movable() << ')' << endl;
|
||||
} else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
|
||||
o << "Meter @ " << *i << ' ' << m->beats_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ VSTPlugin::get_state()
|
|||
{
|
||||
XMLNode *root = new XMLNode (state_node_name());
|
||||
LocaleGuard lg (X_("POSIX"));
|
||||
|
||||
|
||||
if (_plugin->flags & effFlagsProgramChunks) {
|
||||
|
||||
/* fetch the current chunk */
|
||||
|
|
@ -418,10 +418,12 @@ VSTPlugin::activate ()
|
|||
_plugin->dispatcher (_plugin, effMainsChanged, 0, 1, NULL, 0.0f);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
string
|
||||
VSTPlugin::unique_id() const
|
||||
{
|
||||
return _plugin->uniqueID;
|
||||
char buf[32];
|
||||
snprintf (buf, sizeof (buf), "%d", _plugin->uniqueID);
|
||||
return string (buf);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue