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:
David Robillard 2008-01-10 21:20:59 +00:00
parent 73dd9d37e7
commit bb457bb960
168 changed files with 11821 additions and 5338 deletions

View file

@ -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')))

View file

@ -48,6 +48,8 @@ namespace ARDOUR {
int cleanup ();
std::string get_ardour_revision ();
const layer_t max_layer = UCHAR_MAX;
microseconds_t get_microseconds ();

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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 */

View file

@ -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;

View file

@ -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 */

View file

@ -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 ();

View file

@ -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; }

View file

@ -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 ();

View 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__ */

View file

@ -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*);

View file

@ -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

View file

@ -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
};

View 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__ */

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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];

View file

@ -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--; } }

View file

@ -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__ */

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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()) {

View file

@ -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;
}

View file

@ -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();

View file

@ -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();
}

View file

@ -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

View file

@ -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;
}

View file

@ -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 {

View file

@ -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

View file

@ -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);
}

View file

@ -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];

View file

@ -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);

View file

@ -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;
}

View file

@ -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)
);
}

View file

@ -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 */

View file

@ -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

View file

@ -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)
{

View file

@ -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

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -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"

View file

@ -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
View 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;
}

View file

@ -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;

View file

@ -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");
}

View file

@ -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)
{

View file

@ -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:

View file

@ -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;

View file

@ -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;
}

View file

@ -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 ();

View file

@ -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."),

View file

@ -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)
{

View file

@ -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;

View file

@ -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] = {

View file

@ -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
View 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;
}

View file

@ -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:

View file

@ -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()

View file

@ -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);
}