summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2008-01-10 21:20:59 +0000
committerDavid Robillard <d@drobilla.net>2008-01-10 21:20:59 +0000
commitbb457bb960c5bd7ed538f9d31477293415739f68 (patch)
tree84324a63b87c03589cd165b9e474296eaebb4772 /libs
parent73dd9d37e7d715e0d78c0e51569968f9494dac7f (diff)
Merge libs/ardour and gtk2_ardour with 2.0-ongoing R2837.
git-svn-id: svn://localhost/ardour2/trunk@2883 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/SConscript28
-rw-r--r--libs/ardour/ardour/ardour.h2
-rw-r--r--libs/ardour/ardour/audio_buffer.h1
-rw-r--r--libs/ardour/ardour/audio_unit.h68
-rw-r--r--libs/ardour/ardour/audioengine.h10
-rw-r--r--libs/ardour/ardour/audioregion.h19
-rw-r--r--libs/ardour/ardour/audiosource.h13
-rw-r--r--libs/ardour/ardour/configuration_vars.h4
-rw-r--r--libs/ardour/ardour/crossfade.h6
-rw-r--r--libs/ardour/ardour/ladspa_plugin.h2
-rw-r--r--libs/ardour/ardour/location.h2
-rw-r--r--libs/ardour/ardour/pitch.h62
-rw-r--r--libs/ardour/ardour/playlist.h18
-rw-r--r--libs/ardour/ardour/plugin.h6
-rw-r--r--libs/ardour/ardour/plugin_manager.h7
-rw-r--r--libs/ardour/ardour/rb_effect.h42
-rw-r--r--libs/ardour/ardour/region.h26
-rw-r--r--libs/ardour/ardour/route.h2
-rw-r--r--libs/ardour/ardour/session.h74
-rw-r--r--libs/ardour/ardour/silentfilesource.h10
-rw-r--r--libs/ardour/ardour/slave.h2
-rw-r--r--libs/ardour/ardour/sndfile_helpers.h2
-rw-r--r--libs/ardour/ardour/source.h2
-rw-r--r--libs/ardour/ardour/stretch.h33
-rw-r--r--libs/ardour/ardour/tempo.h20
-rw-r--r--libs/ardour/ardour/types.h7
-rw-r--r--libs/ardour/ardour/vst_plugin.h2
-rw-r--r--libs/ardour/audio_buffer.cc2
-rw-r--r--libs/ardour/audio_diskstream.cc15
-rw-r--r--libs/ardour/audio_playlist.cc20
-rw-r--r--libs/ardour/audio_port.cc11
-rw-r--r--libs/ardour/audio_unit.cc535
-rw-r--r--libs/ardour/audioengine.cc58
-rw-r--r--libs/ardour/audiofilesource.cc7
-rw-r--r--libs/ardour/audioregion.cc72
-rw-r--r--libs/ardour/audiosource.cc106
-rw-r--r--libs/ardour/auditioner.cc15
-rw-r--r--libs/ardour/crossfade.cc9
-rw-r--r--libs/ardour/enums.cc2
-rw-r--r--libs/ardour/import.cc82
-rw-r--r--libs/ardour/io.cc7
-rw-r--r--libs/ardour/jack_audio_port.cc4
-rw-r--r--libs/ardour/jack_midi_port.cc4
-rw-r--r--libs/ardour/ladspa_plugin.cc8
-rw-r--r--libs/ardour/meter.cc2
-rw-r--r--libs/ardour/midi_buffer.cc14
-rw-r--r--libs/ardour/midi_port.cc33
-rw-r--r--libs/ardour/playlist.cc590
-rw-r--r--libs/ardour/plugin.cc48
-rw-r--r--libs/ardour/plugin_insert.cc28
-rw-r--r--libs/ardour/plugin_manager.cc58
-rw-r--r--libs/ardour/rb_effect.cc302
-rw-r--r--libs/ardour/region.cc94
-rw-r--r--libs/ardour/route.cc19
-rw-r--r--libs/ardour/session.cc85
-rw-r--r--libs/ardour/session_butler.cc20
-rw-r--r--libs/ardour/session_events.cc8
-rw-r--r--libs/ardour/session_export.cc4
-rw-r--r--libs/ardour/session_process.cc97
-rw-r--r--libs/ardour/session_state.cc121
-rw-r--r--libs/ardour/session_transport.cc37
-rw-r--r--libs/ardour/smf_source.cc11
-rw-r--r--libs/ardour/sndfile_helpers.cc20
-rw-r--r--libs/ardour/source_factory.cc3
-rw-r--r--libs/ardour/st_pitch.cc52
-rw-r--r--libs/ardour/st_stretch.cc (renamed from libs/ardour/stretch.cc)48
-rw-r--r--libs/ardour/tempo.cc37
-rw-r--r--libs/ardour/vst_plugin.cc8
68 files changed, 2428 insertions, 738 deletions
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index 6661ea16a2..6a05bb2295 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -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')))
diff --git a/libs/ardour/ardour/ardour.h b/libs/ardour/ardour/ardour.h
index 6e7b494441..fcec83394f 100644
--- a/libs/ardour/ardour/ardour.h
+++ b/libs/ardour/ardour/ardour.h
@@ -48,6 +48,8 @@ namespace ARDOUR {
int cleanup ();
std::string get_ardour_revision ();
+
+ const layer_t max_layer = UCHAR_MAX;
microseconds_t get_microseconds ();
diff --git a/libs/ardour/ardour/audio_buffer.h b/libs/ardour/ardour/audio_buffer.h
index 09bf5946fa..1f6c2f63bf 100644
--- a/libs/ardour/ardour/audio_buffer.h
+++ b/libs/ardour/ardour/audio_buffer.h
@@ -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);
diff --git a/libs/ardour/ardour/audio_unit.h b/libs/ardour/ardour/audio_unit.h
index 7b31b1937f..b0e4d34c28 100644
--- a/libs/ardour/ardour/audio_unit.h
+++ b/libs/ardour/ardour/audio_unit.h
@@ -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; }
-
+ 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;
+
+ 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:
- CAComponent* comp;
- CAAudioUnit* unit;
-
- AudioBufferList* in_list;
- AudioBufferList* out_list;
+ 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;
+ PluginPtr load (Session& session);
static PluginInfoList discover ();
- PluginPtr load (Session& session);
+ 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;
diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h
index dc7ae8e000..88f1111a6c 100644
--- a/libs/ardour/ardour/audioengine.h
+++ b/libs/ardour/ardour/audioengine.h
@@ -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);
diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h
index ba2bbaee22..b84d197c3f 100644
--- a/libs/ardour/ardour/audioregion.h
+++ b/libs/ardour/ardour/audioregion.h
@@ -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 */
diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h
index f02b28d9f5..93708a5b07 100644
--- a/libs/ardour/ardour/audiosource.h
+++ b/libs/ardour/ardour/audiosource.h
@@ -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;
diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h
index edae45a56a..aa27a3ef24 100644
--- a/libs/ardour/ardour/configuration_vars.h
+++ b/libs/ardour/ardour/configuration_vars.h
@@ -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 */
diff --git a/libs/ardour/ardour/crossfade.h b/libs/ardour/ardour/crossfade.h
index 78a137bde3..9ba3689e82 100644
--- a/libs/ardour/ardour/crossfade.h
+++ b/libs/ardour/ardour/crossfade.h
@@ -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 ();
diff --git a/libs/ardour/ardour/ladspa_plugin.h b/libs/ardour/ardour/ladspa_plugin.h
index e466e53215..7c0b0b2abe 100644
--- a/libs/ardour/ardour/ladspa_plugin.h
+++ b/libs/ardour/ardour/ladspa_plugin.h
@@ -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; }
diff --git a/libs/ardour/ardour/location.h b/libs/ardour/ardour/location.h
index 5ffb716598..53d9489823 100644
--- a/libs/ardour/ardour/location.h
+++ b/libs/ardour/ardour/location.h
@@ -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 ();
diff --git a/libs/ardour/ardour/pitch.h b/libs/ardour/ardour/pitch.h
new file mode 100644
index 0000000000..38d8380f5d
--- /dev/null
+++ b/libs/ardour/ardour/pitch.h
@@ -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__ */
diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h
index f2e07aa067..3f328de005 100644
--- a/libs/ardour/ardour/playlist.h
+++ b/libs/ardour/ardour/playlist.h
@@ -95,6 +95,7 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
void partition (nframes_t start, nframes_t end, bool just_top_level);
void duplicate (boost::shared_ptr<Region>, nframes_t position, float times);
void nudge_after (nframes_t start, nframes_t distance, bool forwards);
+ void shuffle (boost::shared_ptr<Region>, int dir);
boost::shared_ptr<Playlist> cut (list<AudioRange>&, bool result_is_hidden = true);
boost::shared_ptr<Playlist> copy (list<AudioRange>&, bool result_is_hidden = true);
@@ -102,9 +103,12 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
RegionList* regions_at (nframes_t frame);
RegionList* regions_touched (nframes_t start, nframes_t end);
+ RegionList* regions_to_read (nframes_t start, nframes_t end);
boost::shared_ptr<Region> find_region (const PBD::ID&) const;
boost::shared_ptr<Region> top_region_at (nframes_t frame);
boost::shared_ptr<Region> find_next_region (nframes_t frame, RegionPoint point, int dir);
+ nframes64_t find_next_region_boundary (nframes64_t frame, int dir);
+ bool region_is_shuffle_constrained (boost::shared_ptr<Region>);
template<class T> void foreach_region (T *t, void (T::*func)(boost::shared_ptr<Region>, void *), void *arg);
template<class T> void foreach_region (T *t, void (T::*func)(boost::shared_ptr<Region>));
@@ -124,6 +128,8 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
void freeze ();
void thaw ();
+ void raise_region (boost::shared_ptr<Region>);
+ void lower_region (boost::shared_ptr<Region>);
void raise_region_to_top (boost::shared_ptr<Region>);
void lower_region_to_bottom (boost::shared_ptr<Region>);
@@ -182,6 +188,7 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
bool first_set_state;
bool _hidden;
bool _splicing;
+ bool _shuffling;
bool _nudging;
uint32_t _refcnt;
EditMode _edit_mode;
@@ -227,12 +234,12 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
void sort_regions ();
- void possibly_splice ();
- void possibly_splice_unlocked();
- void core_splice ();
- void splice_locked ();
- void splice_unlocked ();
+ void possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude = boost::shared_ptr<Region>());
+ void possibly_splice_unlocked(nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude = boost::shared_ptr<Region>());
+ void core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude);
+ void splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude);
+ void splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude);
virtual void finalize_split_region (boost::shared_ptr<Region> original, boost::shared_ptr<Region> left, boost::shared_ptr<Region> right) {}
@@ -258,6 +265,7 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
boost::shared_ptr<Playlist> cut (nframes_t start, nframes_t cnt, bool result_is_hidden);
boost::shared_ptr<Playlist> copy (nframes_t start, nframes_t cnt, bool result_is_hidden);
+ int move_region_to_layer (layer_t, boost::shared_ptr<Region> r, int dir);
void relayer ();
void unset_freeze_parent (Playlist*);
diff --git a/libs/ardour/ardour/plugin.h b/libs/ardour/ardour/plugin.h
index 830ed7c025..d721476db7 100644
--- a/libs/ardour/ardour/plugin.h
+++ b/libs/ardour/ardour/plugin.h
@@ -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
diff --git a/libs/ardour/ardour/plugin_manager.h b/libs/ardour/ardour/plugin_manager.h
index bce723d857..64b871104b 100644
--- a/libs/ardour/ardour/plugin_manager.h
+++ b/libs/ardour/ardour/plugin_manager.h
@@ -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
};
diff --git a/libs/ardour/ardour/rb_effect.h b/libs/ardour/ardour/rb_effect.h
new file mode 100644
index 0000000000..bde0422335
--- /dev/null
+++ b/libs/ardour/ardour/rb_effect.h
@@ -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__ */
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index c246da9cce..76b41a04cb 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -96,11 +96,17 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
nframes_t length() const { return _length; }
layer_t layer () const { return _layer; }
+ /* these two are valid ONLY during a StateChanged signal handler */
+
+ nframes_t last_position() const { return _last_position; }
+ nframes_t last_length() const { return _last_length; }
+
nframes64_t ancestral_start () const { return _ancestral_start; }
nframes64_t ancestral_length () const { return _ancestral_length; }
float stretch() const { return _stretch; }
+ float shift() const { return _shift; }
- void set_ancestral_data (nframes64_t start, nframes64_t length, float stretch);
+ void set_ancestral_data (nframes64_t start, nframes64_t length, float stretch, float shift);
nframes_t sync_offset(int& dir) const;
nframes_t sync_position() const;
@@ -129,7 +135,7 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
void thaw (const string& why);
bool covers (nframes_t frame) const {
- return first_frame() <= frame && frame < last_frame();
+ return first_frame() <= frame && frame <= last_frame();
}
OverlapType coverage (nframes_t start, nframes_t end) const {
@@ -149,7 +155,7 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
void set_position (nframes_t, void *src);
void set_position_on_top (nframes_t, void *src);
void special_set_position (nframes_t);
- void nudge_position (long, void *src);
+ void nudge_position (nframes64_t, void *src);
bool at_natural_position () const;
void move_to_natural_position (void *src);
@@ -160,6 +166,8 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
void trim_to (nframes_t position, nframes_t length, void *src);
void set_layer (layer_t l); /* ONLY Playlist can call this */
+ void raise ();
+ void lower ();
void raise_to_top ();
void lower_to_bottom ();
@@ -232,10 +240,11 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
void maybe_uncopy ();
void first_edit ();
- virtual bool verify_start (nframes_t);
- virtual bool verify_start_and_length (nframes_t, nframes_t);
- virtual bool verify_start_mutable (nframes_t&_start);
- virtual bool verify_length (nframes_t);
+ bool verify_start (nframes_t);
+ bool verify_start_and_length (nframes_t, nframes_t&);
+ bool verify_start_mutable (nframes_t&_start);
+ bool verify_length (nframes_t);
+
virtual void recompute_at_start () = 0;
virtual void recompute_at_end () = 0;
@@ -243,7 +252,9 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
Flag _flags;
nframes_t _start;
nframes_t _length;
+ nframes_t _last_length;
nframes_t _position;
+ nframes_t _last_position;
nframes_t _sync_position;
layer_t _layer;
mutable RegionEditState _first_edit;
@@ -251,6 +262,7 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
nframes64_t _ancestral_start;
nframes64_t _ancestral_length;
float _stretch;
+ float _shift;
mutable uint32_t _read_data_count; ///< modified in read()
Change _pending_changed;
uint64_t _last_layer_op; ///< timestamp
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index fc17af06ee..d2e40501f1 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -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);
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index d0add4e2aa..90a9563ad1 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -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
diff --git a/libs/ardour/ardour/silentfilesource.h b/libs/ardour/ardour/silentfilesource.h
index 92ef076a9b..e0103185c2 100644
--- a/libs/ardour/ardour/silentfilesource.h
+++ b/libs/ardour/ardour/silentfilesource.h
@@ -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
diff --git a/libs/ardour/ardour/slave.h b/libs/ardour/ardour/slave.h
index 73b66ca20e..509f8fa9d2 100644
--- a/libs/ardour/ardour/slave.h
+++ b/libs/ardour/ardour/slave.h
@@ -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;
diff --git a/libs/ardour/ardour/sndfile_helpers.h b/libs/ardour/ardour/sndfile_helpers.h
index 26a93ad124..cf6b15f3a4 100644
--- a/libs/ardour/ardour/sndfile_helpers.h
+++ b/libs/ardour/ardour/sndfile_helpers.h
@@ -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];
diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h
index 6f323dd878..869111bb07 100644
--- a/libs/ardour/ardour/source.h
+++ b/libs/ardour/ardour/source.h
@@ -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--; } }
diff --git a/libs/ardour/ardour/stretch.h b/libs/ardour/ardour/stretch.h
index 4d00c9b17b..020d03270d 100644
--- a/libs/ardour/ardour/stretch.h
+++ b/libs/ardour/ardour/stretch.h
@@ -21,31 +21,46 @@
#define __ardour_stretch_h__
#include <ardour/filter.h>
-#include <soundtouch/SoundTouch.h>
namespace ARDOUR {
+ class AudioRegion;
+}
+
+#ifdef USE_RUBBERBAND
-class AudioRegion;
+#include <ardour/rb_effect.h>
+
+namespace ARDOUR {
-struct TimeStretchRequest : public InterThreadInfo {
- float fraction;
- bool quick_seek;
- bool antialias;
+class Stretch : public RBEffect {
+ public:
+ Stretch (ARDOUR::Session&, TimeFXRequest&);
+ ~Stretch() {}
};
+} /* namespace */
+
+#else
+
+#include <soundtouch/SoundTouch.h>
+
+namespace ARDOUR {
+
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__ */
diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h
index 2d8462a751..72f24c1054 100644
--- a/libs/ardour/ardour/tempo.h
+++ b/libs/ardour/ardour/tempo.h
@@ -40,27 +40,29 @@ using std::list;
using std::vector;
namespace ARDOUR {
-
+class Meter;
class Tempo {
public:
- Tempo (double bpm)
- : _beats_per_minute (bpm) {}
+ Tempo (double bpm, double type=4.0) // defaulting to quarter note
+ : _beats_per_minute (bpm), _note_type(type) {}
Tempo (const Tempo& other) {
_beats_per_minute = other._beats_per_minute;
+ _note_type = other._note_type;
}
void operator= (const Tempo& other) {
if (&other != this) {
_beats_per_minute = other._beats_per_minute;
+ _note_type = other._note_type;
}
}
- double beats_per_minute () const { return _beats_per_minute; }
- double frames_per_beat (nframes_t sr) const {
- return ((60.0 * sr) / _beats_per_minute);
- }
+ double beats_per_minute () const { return _beats_per_minute;}
+ double note_type () const { return _note_type;}
+ double frames_per_beat (nframes_t sr, const Meter& meter) const;
protected:
double _beats_per_minute;
+ double _note_type;
};
class Meter {
@@ -149,8 +151,8 @@ class MeterSection : public MetricSection, public Meter {
class TempoSection : public MetricSection, public Tempo {
public:
- TempoSection (const BBT_Time& start, double qpm)
- : MetricSection (start), Tempo (qpm) {}
+ TempoSection (const BBT_Time& start, double qpm, double note_type)
+ : MetricSection (start), Tempo (qpm, note_type) {}
TempoSection (const XMLNode&);
static const string xml_state_node_name;
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index 0d32d35c7d..d7961babbd 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -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);
diff --git a/libs/ardour/ardour/vst_plugin.h b/libs/ardour/ardour/vst_plugin.h
index 1622df0c1a..3a05360f15 100644
--- a/libs/ardour/ardour/vst_plugin.h
+++ b/libs/ardour/ardour/vst_plugin.h
@@ -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;
diff --git a/libs/ardour/audio_buffer.cc b/libs/ardour/audio_buffer.cc
index 4871035e80..8444304832 100644
--- a/libs/ardour/audio_buffer.cc
+++ b/libs/ardour/audio_buffer.cc
@@ -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);
diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc
index bc42cb0b5b..bc4a352c45 100644
--- a/libs/ardour/audio_diskstream.cc
+++ b/libs/ardour/audio_diskstream.cc
@@ -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()) {
diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc
index 0631c9121b..1506d204f1 100644
--- a/libs/ardour/audio_playlist.cc
+++ b/libs/ardour/audio_playlist.cc
@@ -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;
}
diff --git a/libs/ardour/audio_port.cc b/libs/ardour/audio_port.cc
index 66d31c63fe..714be28f34 100644
--- a/libs/ardour/audio_port.cc
+++ b/libs/ardour/audio_port.cc
@@ -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();
diff --git a/libs/ardour/audio_unit.cc b/libs/ardour/audio_unit.cc
index dfcffb8cfe..f86e784169 100644
--- a/libs/ardour/audio_unit.cc
+++ b/libs/ardour/audio_unit.cc
@@ -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;
- }
-}
-AUPluginInfo::~AUPluginInfo ()
-{
- if (desc) {
- delete desc;
+ if (buffers) {
+ free (buffers);
}
}
-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 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 */
- 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);
+ 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);
-}
-
-void
-AUPluginInfo::setup_nchannels (CAComponentDescription& comp_desc)
-{
- CAAudioUnit unit;
-
- CAAudioUnit::Open (comp_desc, unit);
-
- if (unit.SupportsNumChannels()) {
- n_inputs = n_outputs = 0;
+ string str = CFStringRefToStdString(itemName);
+ string::size_type colon = str.find (':');
+
+ 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();
+}
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index 91ff8b8d35..08d18c7cab 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -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
diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc
index 1284dd343b..81ad45e08a 100644
--- a/libs/ardour/audiofilesource.cc
+++ b/libs/ardour/audiofilesource.cc
@@ -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;
}
diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc
index 8034f3ddac..301351fe71 100644
--- a/libs/ardour/audioregion.cc
+++ b/libs/ardour/audioregion.cc
@@ -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 {
diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc
index a2ce7209f6..ce8aa95964 100644
--- a/libs/ardour/audiosource.cc
+++ b/libs/ardour/audiosource.cc
@@ -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,9 +249,16 @@ 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;
double expected_peaks;
@@ -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) {
@@ -678,6 +679,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;
uint32_t peaks_computed;
@@ -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
diff --git a/libs/ardour/auditioner.cc b/libs/ardour/auditioner.cc
index 6085501470..d6f63c2f9d 100644
--- a/libs/ardour/auditioner.cc
+++ b/libs/ardour/auditioner.cc
@@ -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);
}
diff --git a/libs/ardour/crossfade.cc b/libs/ardour/crossfade.cc
index 508e6515c9..f7711b3224 100644
--- a/libs/ardour/crossfade.cc
+++ b/libs/ardour/crossfade.cc
@@ -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];
diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc
index f2d2e92169..9f2ce4fab9 100644
--- a/libs/ardour/enums.cc
+++ b/libs/ardour/enums.cc
@@ -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);
diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc
index a8fb4050f9..91e5b9850c 100644
--- a/libs/ardour/import.cc
+++ b/libs/ardour/import.cc
@@ -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;
}
+
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index 89c342e9cf..7a2ae2aad9 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -307,12 +307,12 @@ void
IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset)
{
assert(outs.available() >= n_inputs());
-
- outs.set_count(n_inputs());
- if (outs.count() == ChanCount::ZERO)
+ if (n_inputs() == ChanCount::ZERO)
return;
+ outs.set_count(n_inputs());
+
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)
);
}
+
diff --git a/libs/ardour/jack_audio_port.cc b/libs/ardour/jack_audio_port.cc
index 3a0b34ab19..b2ddb6d48e 100644
--- a/libs/ardour/jack_audio_port.cc
+++ b/libs/ardour/jack_audio_port.cc
@@ -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 */
diff --git a/libs/ardour/jack_midi_port.cc b/libs/ardour/jack_midi_port.cc
index 7dbb8655f6..c9471c9d0c 100644
--- a/libs/ardour/jack_midi_port.cc
+++ b/libs/ardour/jack_midi_port.cc
@@ -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
diff --git a/libs/ardour/ladspa_plugin.cc b/libs/ardour/ladspa_plugin.cc
index 0614e3334d..696ada3b81 100644
--- a/libs/ardour/ladspa_plugin.cc
+++ b/libs/ardour/ladspa_plugin.cc
@@ -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)
{
diff --git a/libs/ardour/meter.cc b/libs/ardour/meter.cc
index d108374ba0..f85fd3ec33 100644
--- a/libs/ardour/meter.cc
+++ b/libs/ardour/meter.cc
@@ -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
diff --git a/libs/ardour/midi_buffer.cc b/libs/ardour/midi_buffer.cc
index a629fe458f..1ca6a5db72 100644
--- a/libs/ardour/midi_buffer.cc
+++ b/libs/ardour/midi_buffer.cc
@@ -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;
}
}
diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc
index 7590c42e0b..3e8dea4f62 100644
--- a/libs/ardour/midi_port.cc
+++ b/libs/ardour/midi_port.cc
@@ -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 (bufsize);
+ _buffer = new MidiBuffer (capacity);
- 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;
}
diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc
index 8d20d8539d..04649a56fe 100644
--- a/libs/ardour/playlist.cc
+++ b/libs/ardour/playlist.cc
@@ -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)) {
- return;
- }
+ remove_region_internal (region);
+
+ _splicing = old_sp;
}
void
-Playlist::possibly_splice ()
+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;
+ }
+
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;
+}
+
/***********************************************************************/
@@ -1686,6 +1902,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)
{
/* does nothing useful if layering mode is later=higher */
@@ -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;
+}
diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc
index bc5688c318..7f3f21b1fe 100644
--- a/libs/ardour/plugin.cc
+++ b/libs/ardour/plugin.cc
@@ -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);
}
}
diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc
index 3faebd7179..4153f26e85 100644
--- a/libs/ardour/plugin_insert.cc
+++ b/libs/ardour/plugin_insert.cc
@@ -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"
diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc
index dac8a9eead..d866a0d49f 100644
--- a/libs/ardour/plugin_manager.cc
+++ b/libs/ardour/plugin_manager.cc
@@ -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
diff --git a/libs/ardour/rb_effect.cc b/libs/ardour/rb_effect.cc
new file mode 100644
index 0000000000..0de5a5bf4a
--- /dev/null
+++ b/libs/ardour/rb_effect.cc
@@ -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;
+}
+
+
+
+
+
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index ecc7b5e305..0505985aea 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -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)
{
+ if (source() && source()->destructive()) {
+ return true;
+ }
+
+ nframes_t maxlen = 0;
+
for (uint32_t n=0; n < _sources.size(); ++n) {
- if (_start > _sources[n]->length() - len) {
- return false;
- }
+ 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)
{
+ if (source() && source()->destructive()) {
+ return true;
+ }
+
+ nframes_t maxlen = 0;
+
for (uint32_t n=0; n < _sources.size(); ++n) {
- if (new_length > _sources[n]->length() - new_start) {
- return false;
- }
+ 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;
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 8193d4ed77..084c4e58b5 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -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");
}
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index e155800d23..a7f85a5c84 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -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)
- {
- 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)
- {
+ 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 ();
}
-
- 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)
{
diff --git a/libs/ardour/session_butler.cc b/libs/ardour/session_butler.cc
index afb284b0f4..148ff92739 100644
--- a/libs/ardour/session_butler.cc
+++ b/libs/ardour/session_butler.cc
@@ -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:
diff --git a/libs/ardour/session_events.cc b/libs/ardour/session_events.cc
index bf1d9f1a09..f1355b331b 100644
--- a/libs/ardour/session_events.cc
+++ b/libs/ardour/session_events.cc
@@ -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;
diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc
index b0addd21f6..b1058f2e7e 100644
--- a/libs/ardour/session_export.cc
+++ b/libs/ardour/session_export.cc
@@ -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;
}
diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc
index 44b63e0875..6476ab30f7 100644
--- a/libs/ardour/session_process.cc
+++ b/libs/ardour/session_process.cc
@@ -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 (!_exporting && _slave) {
- if (!follow_slave (nframes, 0)) {
- return;
- }
- }
+ if (!process_can_proceed()) {
+ _silent = true;
+ 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()) {
- stop_limit = max_frames;
+ if (actively_recording()) {
+ stop_limit = max_frames;
+ } else {
+ if (Config->get_stop_at_session_end()) {
+ stop_limit = current_end_frame();
} else {
- if (Config->get_stop_at_session_end()) {
- stop_limit = current_end_frame();
- } else {
- stop_limit = max_frames;
- }
+ 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;
- }
-
- commit_diskstreams (nframes, session_needs_butler);
+ if (process_routes (nframes, offset)) {
+ no_roll (nframes, offset);
+ return;
+ }
- if (frames_moved < 0) {
- decrement_transport_position (-frames_moved);
- } else {
- increment_transport_position (frames_moved);
- }
+ commit_diskstreams (nframes, session_needs_butler);
- maybe_stop (stop_limit);
- check_declick_out ();
+ if (frames_moved < 0) {
+ decrement_transport_position (-frames_moved);
+ } else {
+ increment_transport_position (frames_moved);
+ }
- } /* implicit release of route lock */
+ maybe_stop (stop_limit);
+ check_declick_out ();
if (session_needs_butler)
summon_butler ();
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index 877047d93a..fa4b103958 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -418,49 +418,106 @@ 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);
- _locations.add (start_location);
+ string dir;
- end_location->set_end (end);
- _locations.add (end_location);
-}
+ 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;
+ }
-bool
-Session::create_session_file ()
-{
- _state_of_the_state = Clean;
+ dir = session_directory().peak_path().to_string();
- if (save_state (_current_snapshot_name)) {
- error << "Could not create new session file" << endmsg;
- return false;
+ 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;
}
- return true;
-}
-bool
-Session::create_session_file_from_template (const string& template_path)
-{
- sys::path session_file_path(_session_dir->root_path());
+ dir = session_directory().sound_path().to_string();
- session_file_path /= _name + statefile_suffix;
+ 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();
- try
- {
- sys::copy_file (template_path, session_file_path);
+ 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;
}
- 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;
+
+ 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;
}
- return true;
+
+ 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 (initial_length);
+ _locations.add (end_location);
+
+ _state_of_the_state = Clean;
+
+
+ save_state ("");
+
+ return 0;
}
+
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."),
diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc
index 2776fbf41d..1398872b36 100644
--- a/libs/ardour/session_transport.cc
+++ b/libs/ardour/session_transport.cc
@@ -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 */
@@ -1203,6 +1224,14 @@ Session::setup_auto_play ()
}
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)
{
request_stop ();
diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc
index b8d82bdb9d..29f36cc2cd 100644
--- a/libs/ardour/smf_source.cc
+++ b/libs/ardour/smf_source.cc
@@ -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;
diff --git a/libs/ardour/sndfile_helpers.cc b/libs/ardour/sndfile_helpers.cc
index 96dc2c7779..58a51f8bbe 100644
--- a/libs/ardour/sndfile_helpers.cc
+++ b/libs/ardour/sndfile_helpers.cc
@@ -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] = {
diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc
index 89d4e3ed79..661beef40b 100644
--- a/libs/ardour/source_factory.cc
+++ b/libs/ardour/source_factory.cc
@@ -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 ();
}
}
diff --git a/libs/ardour/st_pitch.cc b/libs/ardour/st_pitch.cc
new file mode 100644
index 0000000000..3999c1a746
--- /dev/null
+++ b/libs/ardour/st_pitch.cc
@@ -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;
+}
diff --git a/libs/ardour/stretch.cc b/libs/ardour/st_stretch.cc
index 64b741d1af..e96cd79f2d 100644
--- a/libs/ardour/stretch.cc
+++ b/libs/ardour/st_stretch.cc
@@ -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:
diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc
index cd59e93054..780f5c6a5d 100644
--- a/libs/ardour/tempo.cc
+++ b/libs/ardour/tempo.cc
@@ -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()
diff --git a/libs/ardour/vst_plugin.cc b/libs/ardour/vst_plugin.cc
index ac0e6849f9..5969d91982 100644
--- a/libs/ardour/vst_plugin.cc
+++ b/libs/ardour/vst_plugin.cc
@@ -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);
}