summaryrefslogtreecommitdiff
path: root/libs/ardour
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2008-02-02 03:57:35 +0000
committerDavid Robillard <d@drobilla.net>2008-02-02 03:57:35 +0000
commit9f63ab9931e6478472853bdda58da47ea29ac125 (patch)
tree7edfb1d16f580e93501c24fa9f9648fe415f3745 /libs/ardour
parent85ea9028b52eefb34184deb0fbd4d3c7632a2c38 (diff)
Merge with trunk R2978.
git-svn-id: svn://localhost/ardour2/branches/3.0@2988 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour')
-rw-r--r--libs/ardour/SConscript21
-rw-r--r--libs/ardour/ardour/audioanalyser.h74
-rw-r--r--libs/ardour/ardour/audioregion.h24
-rw-r--r--libs/ardour/ardour/audiosource.h17
-rw-r--r--libs/ardour/ardour/cycles.h10
-rw-r--r--libs/ardour/ardour/lv2_plugin.h45
-rw-r--r--libs/ardour/ardour/midi_region.h8
-rw-r--r--libs/ardour/ardour/midi_source.h11
-rw-r--r--libs/ardour/ardour/plugin_manager.h6
-rw-r--r--libs/ardour/ardour/readable.h20
-rw-r--r--libs/ardour/ardour/region.h7
-rw-r--r--libs/ardour/ardour/region_factory.h2
-rw-r--r--libs/ardour/ardour/session.h3
-rw-r--r--libs/ardour/ardour/source.h3
-rw-r--r--libs/ardour/ardour/tempo.h20
-rw-r--r--libs/ardour/ardour/transient_detector.h52
-rw-r--r--libs/ardour/audioanalyser.cc157
-rw-r--r--libs/ardour/audioregion.cc283
-rw-r--r--libs/ardour/audiosource.cc50
-rw-r--r--libs/ardour/globals.cc11
-rw-r--r--libs/ardour/ladspa_plugin.cc1
-rw-r--r--libs/ardour/lv2_plugin.cc163
-rw-r--r--libs/ardour/midi_diskstream.cc2
-rw-r--r--libs/ardour/midi_region.cc6
-rw-r--r--libs/ardour/midi_source.cc4
-rw-r--r--libs/ardour/plugin_manager.cc3
-rw-r--r--libs/ardour/port.cc4
-rw-r--r--libs/ardour/quantize.cc6
-rw-r--r--libs/ardour/region.cc16
-rw-r--r--libs/ardour/region_factory.cc2
-rw-r--r--libs/ardour/resampled_source.cc2
-rw-r--r--libs/ardour/session.cc4
-rw-r--r--libs/ardour/session_state.cc46
-rw-r--r--libs/ardour/source_factory.cc2
-rw-r--r--libs/ardour/tempo.cc289
-rw-r--r--libs/ardour/transient_detector.cc61
36 files changed, 1115 insertions, 320 deletions
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index bb66118b53..c407917263 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -31,6 +31,7 @@ amp.cc
audio_buffer.cc
auto_bundle.cc
user_bundle.cc
+audioanalyser.cc
audio_diskstream.cc
audio_library.cc
audio_playlist.cc
@@ -134,6 +135,7 @@ tape_file_matcher.cc
template_utils.cc
tempo.cc
track.cc
+transient_detector.cc
utils.cc
version.cc
""")
@@ -162,6 +164,7 @@ if ardour['LIBLO']:
ardour.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
ardour.Append(CXXFLAGS="-DDATA_DIR=\\\"" + os.path.join (final_prefix, 'share') + "\\\"")
ardour.Append(CXXFLAGS="-DMODULE_DIR=\\\"" + os.path.join (final_prefix, env['LIBDIR']) + "\\\"")
+ardour.Append(CXXFLAGS="-DVAMP_DIR=\\\"" + os.path.join (final_prefix, env['LIBDIR'], 'ardour2', 'vamp') + "\\\"")
ardour.Append(CXXFLAGS="-DCONFIG_DIR=\\\"" + final_config_prefix + "\\\"")
ardour.Append(CXXFLAGS="-DLOCALEDIR=\\\"" + os.path.join (final_prefix, 'share', 'locale') + "\\\"")
@@ -304,15 +307,19 @@ ardour.Merge ([
libraries['pbd'],
libraries['midi++2'],
libraries['glib2'],
- libraries['glibmm2']
+ libraries['glibmm2'],
+ libraries['vamp'],
+ libraries['vamphost'],
+ libraries['fftw3f'],
+ libraries['fftw3'],
])
-#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['RUBBERBAND']:
+ ardour.Merge ([ libraries['rubberband']])
+ timefx_sources += [ 'rb_effect.cc' ]
+else:
+ ardour.Merge ([ libraries['soundtouch'] ])
+ timefx_sources += [ 'st_stretch.cc', 'st_pitch.cc' ]
if ardour['LV2']:
ardour.Merge ([ libraries['slv2'] ])
diff --git a/libs/ardour/ardour/audioanalyser.h b/libs/ardour/ardour/audioanalyser.h
new file mode 100644
index 0000000000..dbd8a52d5a
--- /dev/null
+++ b/libs/ardour/ardour/audioanalyser.h
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) 2008 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_audioanalyser_h__
+#define __ardour_audioanalyser_h__
+
+#include <vector>
+#include <string>
+#include <ostream>
+#include <fstream>
+#include <vamp-sdk/Plugin.h>
+#include <ardour/audioregion.h>
+
+namespace ARDOUR {
+
+class Readable;
+class Session;
+
+class AudioAnalyser {
+
+ public:
+ typedef Vamp::Plugin AnalysisPlugin;
+ typedef std::string AnalysisPluginKey;
+
+ AudioAnalyser (float sample_rate, AnalysisPluginKey key);
+ virtual ~AudioAnalyser();
+
+ /* analysis object should provide a run method
+ that accepts a path to write the results to (optionally empty)
+ a Readable* to read data from
+ and a reference to a type-specific container to return the
+ results.
+ */
+
+ void reset ();
+
+ protected:
+ float sample_rate;
+ AnalysisPlugin* plugin;
+ AnalysisPluginKey plugin_key;
+
+ nframes64_t bufsize;
+ nframes64_t stepsize;
+
+ int initialize_plugin (AnalysisPluginKey name, float sample_rate);
+ int analyse (const std::string& path, Readable*, uint32_t channel);
+
+ /* instances of an analysis object will have this method called
+ whenever there are results to process. if out is non-null,
+ the data should be written to the stream it points to.
+ */
+
+ virtual int use_features (Vamp::Plugin::FeatureSet&, std::ostream*) = 0;
+};
+
+} /* namespace */
+
+#endif /* __ardour_audioanalyser_h__ */
diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h
index b84d197c3f..2c5630aec0 100644
--- a/libs/ardour/ardour/audioregion.h
+++ b/libs/ardour/ardour/audioregion.h
@@ -21,6 +21,7 @@
#define __ardour_audio_region_h__
#include <vector>
+#include <list>
#include <pbd/fastlog.h>
#include <pbd/undo.h>
@@ -75,6 +76,11 @@ class AudioRegion : public Region
nframes_t offset, nframes_t cnt,
uint32_t chan_n=0, double samples_per_unit= 1.0) const;
+ /* Readable interface */
+
+ virtual nframes64_t read (Sample*, nframes64_t pos, nframes64_t cnt, int channel) const;
+ virtual nframes64_t readable_length() const { return length(); }
+
virtual nframes_t read_at (Sample *buf, Sample *mixdown_buf,
float *gain_buf, nframes_t position, nframes_t cnt,
uint32_t chan_n = 0,
@@ -128,12 +134,14 @@ class AudioRegion : public Region
void resume_fade_in ();
void resume_fade_out ();
+ int get_transients (std::vector<nframes64_t>&, bool force_new = false);
+
private:
friend class RegionFactory;
AudioRegion (boost::shared_ptr<AudioSource>, nframes_t start, nframes_t length);
AudioRegion (boost::shared_ptr<AudioSource>, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
- AudioRegion (SourceList &, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
+ AudioRegion (const SourceList &, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
AudioRegion (boost::shared_ptr<const AudioRegion>, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
AudioRegion (boost::shared_ptr<AudioSource>, const XMLNode&);
AudioRegion (SourceList &, const XMLNode&);
@@ -148,10 +156,11 @@ 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,
- nframes_t read_frames = 0,
- nframes_t skip_frames = 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,
+ bool raw = false) const;
void recompute_at_start ();
void recompute_at_end ();
@@ -178,6 +187,11 @@ class AudioRegion : public Region
AudioRegion (boost::shared_ptr<const AudioRegion>);
int set_live_state (const XMLNode&, Change&, bool send);
+
+ std::vector<nframes64_t> _transients;
+ bool valid_transients;
+ void invalidate_transients ();
+ void cleanup_transients (std::vector<nframes64_t>&);
};
} /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h
index 93708a5b07..b11174abe8 100644
--- a/libs/ardour/ardour/audiosource.h
+++ b/libs/ardour/ardour/audiosource.h
@@ -50,10 +50,20 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
AudioSource (Session&, const XMLNode&);
virtual ~AudioSource ();
- /* returns the number of items in this `audio_source' */
+ nframes64_t readable_length() const { return _length; }
+ uint32_t n_channels() const { return 1; }
virtual nframes_t available_peaks (double zoom) const;
+ /* stopgap until nframes_t becomes nframes64_t. this function is needed by the Readable interface */
+
+ virtual nframes64_t read (Sample *dst, nframes64_t start, nframes64_t cnt, int channel) const {
+ /* XXX currently ignores channel, assuming that source is always mono, which
+ historically has been true.
+ */
+ return read (dst, (nframes_t) start, (nframes_t) cnt);
+ }
+
virtual nframes_t read (Sample *dst, nframes_t start, nframes_t cnt) const;
virtual nframes_t write (Sample *src, nframes_t cnt);
@@ -101,6 +111,9 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
int prepare_for_peakfile_writes ();
void done_with_peakfile_writes (bool done = true);
+ std::vector<nframes64_t> transients;
+ std::string get_transients_path() const;
+
protected:
static bool _build_missing_peakfiles;
static bool _build_peakfiles;
@@ -134,6 +147,8 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
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);
+ int load_transients (const std::string&);
+
private:
int peakfile;
nframes_t peak_leftover_cnt;
diff --git a/libs/ardour/ardour/cycles.h b/libs/ardour/ardour/cycles.h
index f1422880b8..0d1ac154dd 100644
--- a/libs/ardour/ardour/cycles.h
+++ b/libs/ardour/ardour/cycles.h
@@ -186,17 +186,7 @@ static inline cycles_t get_cycles (void)
/* begin mach */
#elif defined(__APPLE__)
-#ifdef HAVE_WEAK_COREAUDIO
#include <CoreAudio/HostTime.h>
-#else // Due to MacTypes.h and libgnomecanvasmm Rect conflict
-typedef unsigned long long UInt64;
-
-extern UInt64
-AudioGetCurrentHostTime();
-
-extern UInt64
-AudioConvertHostTimeToNanos(UInt64 inHostTime);
-#endif
typedef UInt64 cycles_t;
static inline cycles_t get_cycles (void)
diff --git a/libs/ardour/ardour/lv2_plugin.h b/libs/ardour/ardour/lv2_plugin.h
index 40b3c669fa..777f285e9d 100644
--- a/libs/ardour/ardour/lv2_plugin.h
+++ b/libs/ardour/ardour/lv2_plugin.h
@@ -37,20 +37,21 @@
namespace ARDOUR {
class AudioEngine;
class Session;
+struct LV2World;
class LV2Plugin : public ARDOUR::Plugin
{
public:
- LV2Plugin (ARDOUR::AudioEngine&, ARDOUR::Session&, SLV2Plugin plugin, nframes_t sample_rate);
+ LV2Plugin (ARDOUR::AudioEngine&, ARDOUR::Session&, ARDOUR::LV2World&, SLV2Plugin plugin, nframes_t sample_rate);
LV2Plugin (const LV2Plugin &);
~LV2Plugin ();
/* Plugin interface */
std::string unique_id() const;
- const char* label() const { return slv2_plugin_get_name(_plugin); }
- const char* name() const { return slv2_plugin_get_name(_plugin); }
- const char* maker() const { return slv2_plugin_get_author_name(_plugin); }
+ const char* label() const { return slv2_value_as_string(_name); }
+ const char* name() const { return slv2_value_as_string(_name); }
+ const char* maker() const { return _author ? slv2_value_as_string(_author) : "Unknown"; }
uint32_t parameter_count() const { return slv2_plugin_get_num_ports(_plugin); }
float default_value (uint32_t port);
nframes_t signal_latency() const;
@@ -58,6 +59,9 @@ class LV2Plugin : public ARDOUR::Plugin
float get_parameter (uint32_t port) const;
int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const;
uint32_t nth_parameter (uint32_t port, bool& ok) const;
+
+ SLV2Plugin slv2_plugin() { return _plugin; }
+ SLV2Port slv2_port(uint32_t i) { return slv2_plugin_get_port_by_index(_plugin, i); }
std::set<Parameter> automatable() const;
@@ -105,29 +109,56 @@ class LV2Plugin : public ARDOUR::Plugin
private:
void* _module;
+ LV2World& _world;
SLV2Plugin _plugin;
- SLV2Template _template;
+ SLV2Value _name;
+ SLV2Value _author;
SLV2Instance _instance;
nframes_t _sample_rate;
float* _control_data;
float* _shadow_data;
+ float* _defaults;
float* _latency_control_port;
bool _was_activated;
vector<bool> _port_is_input;
- void init (SLV2Plugin plugin, nframes_t rate);
+ void init (LV2World& world, SLV2Plugin plugin, nframes_t rate);
void run (nframes_t nsamples);
void latency_compute_run ();
};
+
+/** The SLV2World, and various cached (as symbols, fast) URIs.
+ *
+ * This object represents everything ardour 'knows' about LV2
+ * (ie understood extensions/features/etc)
+ */
+struct LV2World {
+ LV2World();
+ ~LV2World();
+
+ SLV2World world;
+ SLV2Value input_class;
+ SLV2Value output_class;
+ SLV2Value audio_class;
+ SLV2Value control_class;
+ SLV2Value event_class;
+ SLV2Value in_place_broken;
+ SLV2Value integer;
+ SLV2Value toggled;
+ SLV2Value srate;
+};
+
+
class LV2PluginInfo : public PluginInfo {
public:
- LV2PluginInfo (void* slv2_plugin);;
+ LV2PluginInfo (void* slv2_world, void* slv2_plugin);;
~LV2PluginInfo ();;
static PluginInfoList discover (void* slv2_world);
PluginPtr load (Session& session);
+ void* _lv2_world;
void* _slv2_plugin;
};
diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h
index 869436e423..50c6b8bce7 100644
--- a/libs/ardour/ardour/midi_region.h
+++ b/libs/ardour/ardour/midi_region.h
@@ -50,6 +50,10 @@ class MidiRegion : public Region
~MidiRegion();
boost::shared_ptr<MidiSource> midi_source (uint32_t n=0) const;
+
+ /* Stub Readable interface */
+ virtual nframes64_t read (Sample*, nframes64_t pos, nframes64_t cnt, int channel) const { return 0; }
+ virtual nframes64_t readable_length() const { return length(); }
nframes_t read_at (MidiRingBuffer& dst,
nframes_t position,
@@ -86,11 +90,11 @@ class MidiRegion : public Region
MidiRegion (boost::shared_ptr<MidiSource>, nframes_t start, nframes_t length);
MidiRegion (boost::shared_ptr<MidiSource>, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
- MidiRegion (SourceList &, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
+ MidiRegion (const SourceList &, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
MidiRegion (boost::shared_ptr<const MidiRegion>, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
MidiRegion (boost::shared_ptr<const MidiRegion>);
MidiRegion (boost::shared_ptr<MidiSource>, const XMLNode&);
- MidiRegion (SourceList &, const XMLNode&);
+ MidiRegion (const SourceList &, const XMLNode&);
private:
nframes_t _read_at (const SourceList&, MidiRingBuffer& dst,
diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h
index c83debec3d..323fc8b5a1 100644
--- a/libs/ardour/ardour/midi_source.h
+++ b/libs/ardour/ardour/midi_source.h
@@ -49,8 +49,15 @@ class MidiSource : public Source
MidiSource (Session& session, const XMLNode&);
virtual ~MidiSource ();
- virtual nframes_t read (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const;
- virtual nframes_t write (MidiRingBuffer& src, nframes_t cnt);
+ /* Stub Readable interface */
+ virtual nframes64_t read (Sample*, nframes64_t pos, nframes64_t cnt, int channel) const { return 0; }
+ virtual nframes64_t readable_length() const { return length(); }
+ virtual uint32_t n_channels () const { return 1; }
+
+ // FIXME: integrate this with the Readable::read interface somehow
+ virtual nframes_t midi_read (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const;
+ virtual nframes_t midi_write (MidiRingBuffer& src, nframes_t cnt);
+
virtual void append_event_unlocked(const MidiEvent& ev) = 0;
virtual void mark_for_remove() = 0;
diff --git a/libs/ardour/ardour/plugin_manager.h b/libs/ardour/ardour/plugin_manager.h
index dd50a079e3..892c8bd75a 100644
--- a/libs/ardour/ardour/plugin_manager.h
+++ b/libs/ardour/ardour/plugin_manager.h
@@ -28,7 +28,7 @@
#include <ardour/plugin.h>
#ifdef HAVE_SLV2
-#include <slv2/slv2.h>
+#include <ardour/lv2_plugin.h>
#endif
namespace ARDOUR {
@@ -40,6 +40,8 @@ class PluginManager {
PluginManager ();
~PluginManager ();
+ /* realtime plugin APIs */
+
ARDOUR::PluginInfoList &vst_plugin_info () { return _vst_plugin_info; }
ARDOUR::PluginInfoList &ladspa_plugin_info () { return _ladspa_plugin_info; }
ARDOUR::PluginInfoList &lv2_plugin_info () { return _lv2_plugin_info; }
@@ -59,7 +61,7 @@ class PluginManager {
ARDOUR::PluginInfoList _au_plugin_info;
#ifdef HAVE_SLV2
- SLV2World _lv2_world;
+ LV2World* _lv2_world;
#endif
std::map<uint32_t, std::string> rdf_type;
diff --git a/libs/ardour/ardour/readable.h b/libs/ardour/ardour/readable.h
new file mode 100644
index 0000000000..e072a1c95e
--- /dev/null
+++ b/libs/ardour/ardour/readable.h
@@ -0,0 +1,20 @@
+#ifndef __ardour_readable_h__
+#define __ardour_readable_h__
+
+#include <ardour/types.h>
+
+namespace ARDOUR {
+
+class Readable {
+ public:
+ Readable () {}
+ virtual ~Readable() {}
+
+ virtual nframes64_t read (Sample*, nframes64_t pos, nframes64_t cnt, int channel) const = 0;
+ virtual nframes64_t readable_length() const = 0;
+ virtual uint32_t n_channels () const = 0;
+};
+
+}
+
+#endif /* __ardour_readable_h__ */
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index 76b41a04cb..da07c580b4 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -29,6 +29,7 @@
#include <ardour/ardour.h>
#include <ardour/data_type.h>
#include <ardour/automatable.h>
+#include <ardour/readable.h>
class XMLNode;
@@ -43,7 +44,7 @@ enum RegionEditState {
EditChangesID = 2
};
-class Region : public Automatable, public boost::enable_shared_from_this<Region>
+class Region : public Automatable, public boost::enable_shared_from_this<Region>, public Readable
{
public:
typedef std::vector<boost::shared_ptr<Source> > SourceList;
@@ -217,13 +218,13 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length,
const string& name, DataType type, layer_t = 0, Flag flags = DefaultFlags);
- Region (SourceList& srcs, nframes_t start, nframes_t length,
+ Region (const SourceList& srcs, nframes_t start, nframes_t length,
const string& name, DataType type, layer_t = 0, Flag flags = DefaultFlags);
Region (boost::shared_ptr<const Region>, nframes_t start, nframes_t length, const string& name, layer_t = 0, Flag flags = DefaultFlags);
Region (boost::shared_ptr<const Region>);
Region (boost::shared_ptr<Source> src, const XMLNode&);
- Region (SourceList& srcs, const XMLNode&);
+ Region (const SourceList& srcs, const XMLNode&);
/* this one is for derived types of derived types */
diff --git a/libs/ardour/ardour/region_factory.h b/libs/ardour/ardour/region_factory.h
index e6b9e5dde6..59749613ac 100644
--- a/libs/ardour/ardour/region_factory.h
+++ b/libs/ardour/ardour/region_factory.h
@@ -48,7 +48,7 @@ class RegionFactory {
nframes_t length, std::string name,
layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
static boost::shared_ptr<Region> create (boost::shared_ptr<Source>, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
- static boost::shared_ptr<Region> create (SourceList &, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
+ static boost::shared_ptr<Region> create (const SourceList &, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
static boost::shared_ptr<Region> create (boost::shared_ptr<Region>);
static boost::shared_ptr<Region> create (Session&, XMLNode&, bool);
static boost::shared_ptr<Region> create (SourceList &, const XMLNode&);
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index c6b913b979..d27df2f7ea 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -261,6 +261,9 @@ class Session : public PBD::StatefulDestructible
const SessionDirectory& session_directory () const { return *(_session_dir.get()); }
std::string automation_dir () const;
+ std::string analysis_dir() const;
+
+ int ensure_subdirs ();
Glib::ustring peak_path (Glib::ustring) const;
diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h
index aa8bc0ca1f..174e58c61b 100644
--- a/libs/ardour/ardour/source.h
+++ b/libs/ardour/ardour/source.h
@@ -30,13 +30,14 @@
#include <ardour/ardour.h>
#include <ardour/session_object.h>
#include <ardour/data_type.h>
+#include <ardour/readable.h>
namespace ARDOUR {
class Session;
class Playlist;
-class Source : public SessionObject
+class Source : public SessionObject, public ARDOUR::Readable
{
public:
Source (Session&, const std::string& name, DataType type);
diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h
index 72f24c1054..dc49f5cdef 100644
--- a/libs/ardour/ardour/tempo.h
+++ b/libs/ardour/ardour/tempo.h
@@ -109,6 +109,9 @@ class MetricSection {
public:
MetricSection (const BBT_Time& start)
: _start (start), _frame (0), _movable (true) {}
+ MetricSection (nframes_t start)
+ : _frame (start), _movable (true) {}
+
virtual ~MetricSection() {}
const BBT_Time& start() const { return _start; }
@@ -142,6 +145,8 @@ class MeterSection : public MetricSection, public Meter {
public:
MeterSection (const BBT_Time& start, double bpb, double note_type)
: MetricSection (start), Meter (bpb, note_type) {}
+ MeterSection (nframes_t start, double bpb, double note_type)
+ : MetricSection (start), Meter (bpb, note_type) {}
MeterSection (const XMLNode&);
static const string xml_state_node_name;
@@ -153,6 +158,8 @@ class TempoSection : public MetricSection, public Tempo {
public:
TempoSection (const BBT_Time& start, double qpm, double note_type)
: MetricSection (start), Tempo (qpm, note_type) {}
+ TempoSection (nframes_t start, double qpm, double note_type)
+ : MetricSection (start), Tempo (qpm, note_type) {}
TempoSection (const XMLNode&);
static const string xml_state_node_name;
@@ -165,7 +172,6 @@ typedef list<MetricSection*> Metrics;
class TempoMap : public PBD::StatefulDestructible
{
public:
-
TempoMap (nframes_t frame_rate);
~TempoMap();
@@ -207,9 +213,14 @@ class TempoMap : public PBD::StatefulDestructible
const Tempo& tempo_at (nframes_t);
const Meter& meter_at (nframes_t);
+ const TempoSection& tempo_section_at (nframes_t);
+
void add_tempo(const Tempo&, BBT_Time where);
void add_meter(const Meter&, BBT_Time where);
+ void add_tempo(const Tempo&, nframes_t where);
+ void add_meter(const Meter&, nframes_t where);
+
void move_tempo (TempoSection&, const BBT_Time& to);
void move_meter (MeterSection&, const BBT_Time& to);
@@ -267,6 +278,8 @@ class TempoMap : public PBD::StatefulDestructible
Metric metric_at (nframes_t) const;
void bbt_time_with_metric (nframes_t, BBT_Time&, const Metric&) const;
+ void change_existing_tempo_at (nframes_t, double bpm, double note_type);
+
sigc::signal<void,ARDOUR::Change> StateChanged;
private:
@@ -280,8 +293,7 @@ class TempoMap : public PBD::StatefulDestructible
BBT_Time last_bbt;
mutable Glib::RWLock lock;
- void timestamp_metrics ();
-
+ void timestamp_metrics (bool use_bbt);
nframes_t round_to_type (nframes_t fr, int dir, BBTPointType);
@@ -298,7 +310,7 @@ class TempoMap : public PBD::StatefulDestructible
nframes_t count_frames_between_metrics (const Meter&, const Tempo&, const BBT_Time&, const BBT_Time&) const;
int move_metric_section (MetricSection&, const BBT_Time& to);
- void do_insert (MetricSection* section);
+ void do_insert (MetricSection* section, bool with_bbt);
};
}; /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/transient_detector.h b/libs/ardour/ardour/transient_detector.h
new file mode 100644
index 0000000000..c65bae3ed5
--- /dev/null
+++ b/libs/ardour/ardour/transient_detector.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2008 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_transient_detector_h__
+#define __ardour_transient_detector_h__
+
+#include <ardour/audioanalyser.h>
+
+namespace ARDOUR {
+
+class AudioSource;
+class Session;
+
+class TransientDetector : public AudioAnalyser
+{
+
+ public:
+ TransientDetector (float sample_rate);
+ ~TransientDetector();
+
+ void set_threshold (float);
+ void set_sensitivity (float);
+
+ float get_threshold () const;
+ float get_sensitivity () const;
+
+ int run (const std::string& path, Readable*, uint32_t channel, std::vector<nframes64_t>& results);
+
+ protected:
+ std::vector<nframes64_t>* current_results;
+ int use_features (Vamp::Plugin::FeatureSet&, std::ostream*);
+};
+
+} /* namespace */
+
+#endif /* __ardour_audioanalyser_h__ */
diff --git a/libs/ardour/audioanalyser.cc b/libs/ardour/audioanalyser.cc
new file mode 100644
index 0000000000..4cc99a5d5e
--- /dev/null
+++ b/libs/ardour/audioanalyser.cc
@@ -0,0 +1,157 @@
+#include <vamp-sdk/hostext/PluginLoader.h>
+#include <glibmm/miscutils.h>
+#include <glibmm/fileutils.h>
+#include <glib/gstdio.h> // for g_remove()
+
+#include <pbd/error.h>
+
+#include <ardour/audioanalyser.h>
+#include <ardour/readable.h>
+#include <ardour/readable.h>
+
+#include "i18n.h"
+
+using namespace std;
+using namespace Vamp;
+using namespace PBD;
+using namespace ARDOUR;
+
+AudioAnalyser::AudioAnalyser (float sr, AnalysisPluginKey key)
+ : sample_rate (sr)
+ , plugin (0)
+ , plugin_key (key)
+{
+}
+
+AudioAnalyser::~AudioAnalyser ()
+{
+}
+
+int
+AudioAnalyser::initialize_plugin (AnalysisPluginKey key, float sr)
+{
+ using namespace Vamp::HostExt;
+
+ PluginLoader* loader (PluginLoader::getInstance());
+
+ plugin = loader->loadPlugin (key, sr, PluginLoader::ADAPT_ALL);
+
+ if (!plugin) {
+ error << string_compose (_("VAMP Plugin \"%1\" could not be loaded"), key) << endmsg;
+ return -1;
+ }
+
+ /* we asked for the buffering adapter, so set the blocksize to
+ something that makes for efficient disk i/o
+ */
+
+ bufsize = 65536;
+ stepsize = bufsize;
+
+ if (plugin->getMinChannelCount() > 1) {
+ delete plugin;
+ return -1;
+ }
+
+ if (!plugin->initialise (1, stepsize, bufsize)) {
+ delete plugin;
+ return -1;
+ }
+
+ return 0;
+}
+
+void
+AudioAnalyser::reset ()
+{
+ if (plugin) {
+ plugin->reset ();
+ }
+}
+
+int
+AudioAnalyser::analyse (const string& path, Readable* src, uint32_t channel)
+{
+ ofstream ofile;
+ Plugin::FeatureSet onsets;
+ int ret = -1;
+ bool done = false;
+ Sample* data = 0;
+ nframes64_t len = src->readable_length();
+ nframes64_t pos = 0;
+ float* bufs[1] = { 0 };
+
+ if (!path.empty()) {
+ ofile.open (path.c_str());
+ if (!ofile) {
+ goto out;
+ }
+ }
+
+ /* create VAMP percussion onset plugin and initialize */
+
+ if (plugin == 0) {
+ if (initialize_plugin (plugin_key, sample_rate)) {
+ goto out;
+ }
+ }
+
+ data = new Sample[bufsize];
+ bufs[0] = data;
+
+ while (!done) {
+
+ nframes64_t to_read;
+
+ /* read from source */
+
+ to_read = min ((len - pos), bufsize);
+
+ if (src->read (data, pos, to_read, channel) != to_read) {
+ cerr << "bad read\n";
+ goto out;
+ }
+
+ /* zero fill buffer if necessary */
+
+ if (to_read != bufsize) {
+ memset (data + to_read, 0, (bufsize - to_read));
+ }
+
+ onsets = plugin->process (bufs, RealTime::fromSeconds ((double) pos / sample_rate));
+
+ if (use_features (onsets, (path.empty() ? &ofile : 0))) {
+ goto out;
+ }
+
+ pos += stepsize;
+
+ if (pos >= len) {
+ done = true;
+ }
+ }
+
+ /* finish up VAMP plugin */
+
+ onsets = plugin->getRemainingFeatures ();
+
+ if (use_features (onsets, (path.empty() ? &ofile : 0))) {
+ goto out;
+ }
+
+ ret = 0;
+
+ out:
+ /* works even if it has not been opened */
+ ofile.close ();
+
+ if (ret) {
+ g_remove (path.c_str());
+ }
+ if (data) {
+ delete data;
+ }
+
+ return ret;
+}
+
diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc
index 86abd4beaa..822fe2cb72 100644
--- a/libs/ardour/audioregion.cc
+++ b/libs/ardour/audioregion.cc
@@ -20,6 +20,7 @@
#include <cmath>
#include <climits>
#include <cfloat>
+#include <algorithm>
#include <set>
@@ -42,6 +43,7 @@
#include <ardour/audiofilesource.h>
#include <ardour/region_factory.h>
#include <ardour/runtime_functions.h>
+#include <ardour/transient_detector.h>
#include "i18n.h"
#include <locale.h>
@@ -64,6 +66,7 @@ void
AudioRegion::init ()
{
_scale_amplitude = 1.0;
+ valid_transients = false;
set_default_fades ();
set_default_envelope ();
@@ -112,7 +115,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
}
/* Basic AudioRegion constructor (many channels) */
-AudioRegion::AudioRegion (SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
+AudioRegion::AudioRegion (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
: Region (srcs, start, length, name, DataType::AUDIO, layer, flags)
, _fade_in (new AutomationList(Parameter(FadeInAutomation), 0.0, 2.0, 1.0))
, _fade_out (new AutomationList(Parameter(FadeOutAutomation), 0.0, 2.0, 1.0))
@@ -121,7 +124,6 @@ AudioRegion::AudioRegion (SourceList& srcs, nframes_t start, nframes_t length, c
init ();
}
-
/** Create a new AudioRegion, that is part of an existing one */
AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
: Region (other, offset, length, name, layer, flags)
@@ -170,6 +172,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t
}
_scale_amplitude = other->_scale_amplitude;
+ valid_transients = false;
assert(_type == DataType::AUDIO);
}
@@ -181,6 +184,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
, _envelope (new AutomationList(Parameter(EnvelopeAutomation), 0.0, 2.0, 1.0))
{
_scale_amplitude = other->_scale_amplitude;
+ valid_transients = false;
_envelope = other->_envelope;
set_default_fades ();
@@ -202,6 +206,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& nod
}
init ();
+ valid_transients = false;
if (set_state (node)) {
throw failed_constructor();
@@ -230,6 +235,13 @@ AudioRegion::~AudioRegion ()
}
void
+AudioRegion::invalidate_transients ()
+{
+ valid_transients = false;
+ _transients.clear ();
+}
+
+void
AudioRegion::listen_to_my_curves ()
{
_envelope->StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
@@ -273,12 +285,20 @@ AudioRegion::read_peaks (PeakData *buf, nframes_t npeaks, nframes_t offset, nfra
}
}
+nframes64_t
+AudioRegion::read (Sample* buf, nframes64_t position, nframes64_t cnt, int channel) const
+{
+ /* raw read, no fades, no gain, nada */
+ return _read_at (_sources, buf, 0, 0, _position + position, cnt, channel, 0, 0, true);
+}
+
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, read_frames, skip_frames);
+ /* regular diskstream/butler read complete with fades etc */
+ return _read_at (_sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, read_frames, skip_frames, false);
}
nframes_t
@@ -291,13 +311,16 @@ AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_bu
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, nframes_t read_frames, nframes_t skip_frames) const
+ uint32_t chan_n,
+ nframes_t read_frames,
+ nframes_t skip_frames,
+ bool raw) const
{
nframes_t internal_offset;
nframes_t buf_offset;
nframes_t to_read;
- if (muted()) {
+ if (muted() && !raw) {
return 0; /* read nothing */
}
@@ -320,14 +343,16 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
return 0; /* read nothing */
}
- if (opaque()) {
+ if (opaque() || raw) {
/* overwrite whatever is there */
mixdown_buffer = buf + buf_offset;
} else {
mixdown_buffer += buf_offset;
}
- _read_data_count = 0;
+ if (!raw) {
+ _read_data_count = 0;
+ }
if (chan_n < n_channels()) {
@@ -336,7 +361,9 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
return 0; /* "read nothing" */
}
- _read_data_count += src->read_data_count();
+ if (!raw) {
+ _read_data_count += src->read_data_count();
+ }
} else {
@@ -348,37 +375,41 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
/* no fades required */
- goto merge;
+ if (!raw) {
+ goto merge;
+ }
}
/* fade in */
- if (_flags & FadeIn) {
-
- nframes_t fade_in_length = (nframes_t) _fade_in->back()->when;
-
- /* see if this read is within the fade in */
-
- if (internal_offset < fade_in_length) {
-
- nframes_t limit;
-
- limit = min (to_read, fade_in_length - internal_offset);
-
- _fade_in->curve().get_vector (internal_offset, internal_offset+limit, gain_buffer, limit);
-
- for (nframes_t n = 0; n < limit; ++n) {
- mixdown_buffer[n] *= gain_buffer[n];
+ if (!raw) {
+
+ if (_flags & FadeIn) {
+
+ nframes_t fade_in_length = (nframes_t) _fade_in->back()->when;
+
+ /* see if this read is within the fade in */
+
+ if (internal_offset < fade_in_length) {
+
+ nframes_t limit;
+
+ limit = min (to_read, fade_in_length - internal_offset);
+
+ _fade_in->curve().get_vector (internal_offset, internal_offset+limit, gain_buffer, limit);
+
+ for (nframes_t n = 0; n < limit; ++n) {
+ mixdown_buffer[n] *= gain_buffer[n];
+ }
}
}
- }
-
- /* fade out */
-
- if (_flags & FadeOut) {
-
- /* see if some part of this read is within the fade out */
-
+
+ /* fade out */
+
+ if (_flags & FadeOut) {
+
+ /* see if some part of this read is within the fade out */
+
/* ................. >| REGION
_length
@@ -389,65 +420,66 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
|--------------|
^internal_offset
^internal_offset + to_read
-
- we need the intersection of [internal_offset,internal_offset+to_read] with
- [_length - fade_out_length, _length]
-
+
+ we need the intersection of [internal_offset,internal_offset+to_read] with
+ [_length - fade_out_length, _length]
+
*/
- nframes_t fade_out_length = (nframes_t) _fade_out->back()->when;
- nframes_t fade_interval_start = max(internal_offset, _length-fade_out_length);
- nframes_t fade_interval_end = min(internal_offset + to_read, _length);
-
- if (fade_interval_end > fade_interval_start) {
- /* (part of the) the fade out is in this buffer */
+ nframes_t fade_out_length = (nframes_t) _fade_out->back()->when;
+ nframes_t fade_interval_start = max(internal_offset, _length-fade_out_length);
+ nframes_t fade_interval_end = min(internal_offset + to_read, _length);
- nframes_t limit = fade_interval_end - fade_interval_start;
- nframes_t curve_offset = fade_interval_start - (_length-fade_out_length);
- nframes_t fade_offset = fade_interval_start - internal_offset;
-
- _fade_out->curve().get_vector (curve_offset,curve_offset+limit, gain_buffer, limit);
-
- for (nframes_t n = 0, m = fade_offset; n < limit; ++n, ++m) {
- mixdown_buffer[m] *= gain_buffer[n];
- }
- }
-
- }
-
- /* Regular gain curves */
-
- if (envelope_active()) {
- _envelope->curve().get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read);
+ if (fade_interval_end > fade_interval_start) {
+ /* (part of the) the fade out is in this buffer */
+
+ nframes_t limit = fade_interval_end - fade_interval_start;
+ nframes_t curve_offset = fade_interval_start - (_length-fade_out_length);
+ nframes_t fade_offset = fade_interval_start - internal_offset;
+
+ _fade_out->curve().get_vector (curve_offset,curve_offset+limit, gain_buffer, limit);
+
+ for (nframes_t n = 0, m = fade_offset; n < limit; ++n, ++m) {
+ mixdown_buffer[m] *= gain_buffer[n];
+ }
+ }
+
+ }
- if (_scale_amplitude != 1.0f) {
- for (nframes_t n = 0; n < to_read; ++n) {
- mixdown_buffer[n] *= gain_buffer[n] * _scale_amplitude;
+ /* Regular gain curves */
+
+ if (envelope_active()) {
+ _envelope->curve().get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read);
+
+ if (_scale_amplitude != 1.0f) {
+ for (nframes_t n = 0; n < to_read; ++n) {
+ mixdown_buffer[n] *= gain_buffer[n] * _scale_amplitude;
+ }
+ } else {
+ for (nframes_t n = 0; n < to_read; ++n) {
+ mixdown_buffer[n] *= gain_buffer[n];
+ }
}
- } else {
+ } else if (_scale_amplitude != 1.0f) {
+ Session::apply_gain_to_buffer (mixdown_buffer, to_read, _scale_amplitude);
+ }
+
+ merge:
+
+ if (!opaque()) {
+
+ /* gack. the things we do for users.
+ */
+
+ buf += buf_offset;
+
for (nframes_t n = 0; n < to_read; ++n) {
- mixdown_buffer[n] *= gain_buffer[n];
+ buf[n] += mixdown_buffer[n];
}
- }
- } else if (_scale_amplitude != 1.0f) {
- apply_gain_to_buffer (mixdown_buffer, to_read, _scale_amplitude);
+ }
}
- merge:
-
- if (!opaque()) {
-
- /* gack. the things we do for users.
- */
-
- buf += buf_offset;
-
- for (nframes_t n = 0; n < to_read; ++n) {
- buf[n] += mixdown_buffer[n];
- }
- }
-
return to_read;
}
@@ -1224,6 +1256,93 @@ AudioRegion::audio_source (uint32_t n) const
return boost::dynamic_pointer_cast<AudioSource>(source(n));
}
+void
+AudioRegion::cleanup_transients (vector<nframes64_t>& t)
+{
+ sort (t.begin(), t.end());
+
+ /* remove duplicates or other things that are too close */
+
+ vector<nframes64_t>::iterator i = t.begin();
+ nframes64_t curr = (*i);
+
+ /* XXX force a 3msec gap - use a config variable */
+
+ nframes64_t gap_frames = (nframes64_t) floor (3.0 * (playlist()->session().frame_rate() / 1000.0));
+
+ ++i;
+
+ while (i != t.end()) {
+ if (((*i) == curr) || (((*i) - curr) < gap_frames)) {
+ i = t.erase (i);
+ } else {
+ ++i;
+ curr = *i;
+ }
+ }
+}
+
+int
+AudioRegion::get_transients (vector<nframes64_t>& results, bool force_new)
+{
+ if (!playlist()) {
+ return -1;
+ }
+
+ if (valid_transients && !force_new) {
+ results = _transients;
+ return 0;
+ }
+
+ TransientDetector t (playlist()->session().frame_rate());
+ bool existing_results = !results.empty();
+
+ _transients.clear ();
+ valid_transients = false;
+
+ for (uint32_t i = 0; i < n_channels(); ++i) {
+
+ vector<nframes64_t> these_results;
+
+ t.reset ();
+
+ if (t.run ("", this, i, these_results)) {
+ return -1;
+ }
+
+ /* translate all transients to give absolute position */
+
+ for (vector<nframes64_t>::iterator i = these_results.begin(); i != these_results.end(); ++i) {
+ (*i) += _position;
+ }
+
+ /* merge */
+
+ _transients.insert (_transients.end(), these_results.begin(), these_results.end());
+ }
+
+ if (!results.empty()) {
+ if (existing_results) {
+
+ /* merge our transients into the existing ones, then clean up
+ those.
+ */
+
+ results.insert (results.end(), _transients.begin(), _transients.end());
+ cleanup_transients (results);
+ }
+
+ /* make sure ours are clean too */
+
+ cleanup_transients (_transients);
+ }
+
+ valid_transients = true;
+
+ return 0;
+}
+
+
extern "C" {
int region_read_peaks_from_c (void *arg, uint32_t npeaks, uint32_t start, uint32_t cnt, intptr_t data, uint32_t n_chan, double samples_per_unit)
diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc
index ce8aa95964..80116988d5 100644
--- a/libs/ardour/audiosource.cc
+++ b/libs/ardour/audiosource.cc
@@ -27,10 +27,12 @@
#include <ctime>
#include <cmath>
#include <iomanip>
+#include <fstream>
#include <algorithm>
#include <vector>
#include <glibmm/fileutils.h>
+#include <glibmm/miscutils.h>
#include <pbd/xml++.h>
#include <pbd/pthread_utils.h>
@@ -38,6 +40,7 @@
#include <ardour/audiosource.h>
#include <ardour/cycle_timer.h>
#include <ardour/session.h>
+#include <ardour/transient_detector.h>
#include "i18n.h"
@@ -916,3 +919,50 @@ AudioSource::update_length (nframes_t pos, nframes_t cnt)
}
}
+int
+AudioSource::load_transients (const string& path)
+{
+ ifstream file (path.c_str());
+
+ if (!file) {
+ return -1;
+ }
+
+ transients.clear ();
+
+ stringstream strstr;
+ double val;
+
+ while (file.good()) {
+ file >> val;
+
+ if (!file.fail()) {
+ nframes64_t frame = (nframes64_t) floor (val * _session.frame_rate());
+ transients.push_back (frame);
+ }
+ }
+
+ return 0;
+}
+
+string
+AudioSource::get_transients_path () const
+{
+ vector<string> parts;
+ string s;
+
+ /* old sessions may not have the analysis directory */
+
+ _session.ensure_subdirs ();
+
+ s = _session.analysis_dir ();
+ parts.push_back (s);
+
+ s = _id.to_s();
+ s += '.';
+ s += X_("transients");
+ parts.push_back (s);
+
+ return Glib::build_filename (parts);
+}
+
diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc
index 7405077cf3..6bb21a419c 100644
--- a/libs/ardour/globals.cc
+++ b/libs/ardour/globals.cc
@@ -285,6 +285,17 @@ ARDOUR::init (bool use_vst, bool try_optimization)
return -1;
}
#endif
+
+ /* Make VAMP look in our library ahead of anything else */
+
+ char *p = getenv ("VAMP_PATH");
+ string vamppath = VAMP_DIR;
+ if (p) {
+ vamppath += ':';
+ vamppath += p;
+ }
+ setenv ("VAMP_PATH", vamppath.c_str(), 1);
+
setup_hardware_optimization (try_optimization);
diff --git a/libs/ardour/ladspa_plugin.cc b/libs/ardour/ladspa_plugin.cc
index ccc12f8cf8..29f2d16767 100644
--- a/libs/ardour/ladspa_plugin.cc
+++ b/libs/ardour/ladspa_plugin.cc
@@ -467,7 +467,6 @@ LadspaPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& des
desc.label = port_names()[which];
-
return 0;
}
diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc
index 5df3756364..e58e5ed140 100644
--- a/libs/ardour/lv2_plugin.cc
+++ b/libs/ardour/lv2_plugin.cc
@@ -43,16 +43,18 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
-LV2Plugin::LV2Plugin (AudioEngine& e, Session& session, SLV2Plugin plugin, nframes_t rate)
+LV2Plugin::LV2Plugin (AudioEngine& e, Session& session, LV2World& world, SLV2Plugin plugin, nframes_t rate)
: Plugin (e, session)
+ , _world(world)
{
- init (plugin, rate);
+ init (world, plugin, rate);
}
LV2Plugin::LV2Plugin (const LV2Plugin &other)
: Plugin (other)
+ , _world(other._world)
{
- init (other._plugin, other._sample_rate);
+ init (other._world, other._plugin, other._sample_rate);
for (uint32_t i = 0; i < parameter_count(); ++i) {
_control_data[i] = other._shadow_data[i];
@@ -61,24 +63,30 @@ LV2Plugin::LV2Plugin (const LV2Plugin &other)
}
void
-LV2Plugin::init (SLV2Plugin plugin, nframes_t rate)
+LV2Plugin::init (LV2World& world, SLV2Plugin plugin, nframes_t rate)
{
+ _world = world;
_plugin = plugin;
- _template = slv2_plugin_get_template(plugin);
_control_data = 0;
_shadow_data = 0;
_latency_control_port = 0;
_was_activated = false;
_instance = slv2_plugin_instantiate(plugin, rate, NULL);
+ _name = slv2_plugin_get_name(plugin);
+ assert(_name);
+ _author = slv2_plugin_get_author_name(plugin);
if (_instance == 0) {
error << _("LV2: Failed to instantiate plugin ") << slv2_plugin_get_uri(plugin) << endl;
throw failed_constructor();
}
- if (slv2_plugin_has_feature(plugin, "http://lv2plug.in/ns/lv2core#inPlaceBroken")) {
- error << string_compose(_("LV2: \"%1\" cannot be used, since it cannot do inplace processing"), slv2_plugin_get_name(plugin)) << endmsg;
+ if (slv2_plugin_has_feature(plugin, world.in_place_broken)) {
+ error << string_compose(_("LV2: \"%1\" cannot be used, since it cannot do inplace processing"),
+ slv2_value_as_string(_name));
+ slv2_value_free(_name);
+ slv2_value_free(_author);
throw failed_constructor();
}
@@ -88,14 +96,21 @@ LV2Plugin::init (SLV2Plugin plugin, nframes_t rate)
_control_data = new float[num_ports];
_shadow_data = new float[num_ports];
+ _defaults = new float[num_ports];
const bool latent = slv2_plugin_has_latency(plugin);
- uint32_t latency_port = (latent ? slv2_plugin_get_latency_port(plugin) : 0);
+ uint32_t latency_port = (latent ? slv2_plugin_get_latency_port_index(plugin) : 0);
for (uint32_t i = 0; i < num_ports; ++i) {
if (parameter_is_control(i)) {
+ SLV2Port port = slv2_plugin_get_port_by_index(plugin, i);
+ SLV2Value def;
+ slv2_port_get_range(plugin, port, &def, NULL, NULL);
+ _defaults[i] = def ? slv2_value_as_float(def) : 0.0f;
+ slv2_value_free(def);
+
slv2_instance_connect_port (_instance, i, &_control_data[i]);
-
+
if (latent && i == latency_port) {
_latency_control_port = &_control_data[i];
*_latency_control_port = 0;
@@ -104,6 +119,8 @@ LV2Plugin::init (SLV2Plugin plugin, nframes_t rate)
if (parameter_is_input(i)) {
_shadow_data[i] = default_value (i);
}
+ } else {
+ _defaults[i] = 0.0f;
}
}
@@ -118,6 +135,8 @@ LV2Plugin::~LV2Plugin ()
GoingAway (); /* EMIT SIGNAL */
slv2_instance_free(_instance);
+ slv2_value_free(_name);
+ slv2_value_free(_author);
if (_control_data) {
delete [] _control_data;
@@ -131,15 +150,14 @@ LV2Plugin::~LV2Plugin ()
string
LV2Plugin::unique_id() const
{
- return slv2_plugin_get_uri(_plugin);
+ return slv2_value_as_uri(slv2_plugin_get_uri(_plugin));
}
float
LV2Plugin::default_value (uint32_t port)
{
- return slv2_port_get_default_value(_plugin,
- slv2_plugin_get_port_by_index(_plugin, port));
+ return _defaults[port];
}
void
@@ -276,15 +294,16 @@ LV2Plugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& desc)
{
SLV2Port port = slv2_plugin_get_port_by_index(_plugin, which);
- #define LV2_URI "http://lv2plug.in/ns/lv2core#"
+ SLV2Value def, min, max;
+ slv2_port_get_range(_plugin, port, &def, &min, &max);
- desc.integer_step = slv2_port_has_property(_plugin, port, LV2_URI "integer");
- desc.toggled = slv2_port_has_property(_plugin, port, LV2_URI "toggled");
+ desc.integer_step = slv2_port_has_property(_plugin, port, _world.integer);
+ desc.toggled = slv2_port_has_property(_plugin, port, _world.toggled);
desc.logarithmic = false; // TODO (LV2 extension)
- desc.sr_dependent = slv2_port_has_property(_plugin, port, LV2_URI "sampleRate");
- desc.label = slv2_port_get_name(_plugin, port);
- desc.lower = slv2_port_get_minimum_value(_plugin, port);
- desc.upper = slv2_port_get_maximum_value(_plugin, port);
+ desc.sr_dependent = slv2_port_has_property(_plugin, port, _world.srate);
+ desc.label = slv2_value_as_string(slv2_port_get_name(_plugin, port));
+ desc.lower = min ? slv2_value_as_float(min) : 0.0f;
+ desc.upper = max ? slv2_value_as_float(max) : 1.0f;
desc.min_unbound = false; // TODO (LV2 extension)
desc.max_unbound = false; // TODO (LV2 extension)
@@ -299,6 +318,10 @@ LV2Plugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& desc)
desc.largestep = delta/10.0f;
}
+ slv2_value_free(def);
+ slv2_value_free(min);
+ slv2_value_free(max);
+
return 0;
}
@@ -307,8 +330,11 @@ string
LV2Plugin::describe_parameter (Parameter which)
{
if (which.type() == PluginAutomation && which.id() < parameter_count()) {
- return slv2_port_get_name(_plugin,
- slv2_plugin_get_port_by_index(_plugin, which));
+ SLV2Value name = slv2_port_get_name(_plugin,
+ slv2_plugin_get_port_by_index(_plugin, which));
+ string ret(slv2_value_as_string(name));
+ slv2_value_free(name);
+ return ret;
} else {
return "??";
}
@@ -377,29 +403,29 @@ LV2Plugin::connect_and_run (BufferSet& bufs, uint32_t& in_index, uint32_t& out_i
bool
LV2Plugin::parameter_is_control (uint32_t param) const
{
- SLV2PortSignature sig = slv2_template_get_port(_template, param);
- return (slv2_port_signature_get_type(sig) == SLV2_PORT_DATA_TYPE_CONTROL);
+ SLV2Port port = slv2_plugin_get_port_by_index(_plugin, param);
+ return slv2_port_is_a(_plugin, port, _world.control_class);
}
bool
LV2Plugin::parameter_is_audio (uint32_t param) const
{
- SLV2PortSignature sig = slv2_template_get_port(_template, param);
- return (slv2_port_signature_get_type(sig) == SLV2_PORT_DATA_TYPE_AUDIO);
+ SLV2Port port = slv2_plugin_get_port_by_index(_plugin, param);
+ return slv2_port_is_a(_plugin, port, _world.audio_class);
}
bool
LV2Plugin::parameter_is_output (uint32_t param) const
{
- SLV2PortSignature sig = slv2_template_get_port(_template, param);
- return (slv2_port_signature_get_direction(sig) == SLV2_PORT_DIRECTION_OUTPUT);
+ SLV2Port port = slv2_plugin_get_port_by_index(_plugin, param);
+ return slv2_port_is_a(_plugin, port, _world.output_class);
}
bool
LV2Plugin::parameter_is_input (uint32_t param) const
{
- SLV2PortSignature sig = slv2_template_get_port(_template, param);
- return (slv2_port_signature_get_direction(sig) == SLV2_PORT_DIRECTION_INPUT);
+ SLV2Port port = slv2_plugin_get_port_by_index(_plugin, param);
+ return slv2_port_is_a(_plugin, port, _world.input_class);
}
void
@@ -418,9 +444,7 @@ void
LV2Plugin::run (nframes_t nframes)
{
for (uint32_t i = 0; i < parameter_count(); ++i) {
- SLV2PortSignature sig = slv2_template_get_port(_template, i);
- if (slv2_port_signature_get_type(sig) == SLV2_PORT_DATA_TYPE_CONTROL
- && slv2_port_signature_get_direction(sig) == SLV2_PORT_DIRECTION_INPUT) {
+ if (parameter_is_control(i) && parameter_is_input(i)) {
_control_data[i] = _shadow_data[i];
}
}
@@ -472,8 +496,34 @@ LV2Plugin::latency_compute_run ()
deactivate ();
}
-LV2PluginInfo::LV2PluginInfo (void* slv2_plugin)
- : _slv2_plugin(slv2_plugin)
+LV2World::LV2World()
+ : world(slv2_world_new())
+{
+ slv2_world_load_all(world);
+ input_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_INPUT);
+ output_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_OUTPUT);
+ control_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_CONTROL);
+ audio_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_AUDIO);
+ event_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_EVENT);
+ in_place_broken = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "inPlaceBroken");
+ integer = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "integer");
+ toggled = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "toggled");
+ srate = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "sampleRate");
+}
+
+LV2World::~LV2World()
+{
+ slv2_value_free(input_class);
+ slv2_value_free(output_class);
+ slv2_value_free(control_class);
+ slv2_value_free(audio_class);
+ slv2_value_free(event_class);
+ slv2_value_free(in_place_broken);
+}
+
+LV2PluginInfo::LV2PluginInfo (void* lv2_world, void* slv2_plugin)
+ : _lv2_world(lv2_world)
+ , _slv2_plugin(slv2_plugin)
{
}
@@ -484,12 +534,11 @@ LV2PluginInfo::~LV2PluginInfo()
PluginPtr
LV2PluginInfo::load (Session& session)
{
- SLV2Plugin p = (SLV2Plugin)_slv2_plugin;
-
try {
PluginPtr plugin;
- plugin.reset (new LV2Plugin (session.engine(), session, p, session.frame_rate()));
+ plugin.reset (new LV2Plugin (session.engine(), session,
+ *(LV2World*)_lv2_world, (SLV2Plugin)_slv2_plugin, session.frame_rate()));
plugin->set_info(PluginInfoPtr(new LV2PluginInfo(*this)));
return plugin;
@@ -503,40 +552,42 @@ LV2PluginInfo::load (Session& session)
}
PluginInfoList
-LV2PluginInfo::discover (void* slv2_world)
+LV2PluginInfo::discover (void* lv2_world)
{
PluginInfoList plugs;
- SLV2Plugins plugins = slv2_world_get_all_plugins((SLV2World)slv2_world);
+ LV2World* world = (LV2World*)lv2_world;
+ SLV2Plugins plugins = slv2_world_get_all_plugins(world->world);
for (unsigned i=0; i < slv2_plugins_size(plugins); ++i) {
SLV2Plugin p = slv2_plugins_get_at(plugins, i);
- LV2PluginInfoPtr info (new LV2PluginInfo(p));
+ LV2PluginInfoPtr info (new LV2PluginInfo(lv2_world, p));
- info->name = slv2_plugin_get_name(p);
+ SLV2Value name = slv2_plugin_get_name(p);
+ info->name = string(slv2_value_as_string(name));
+ slv2_value_free(name);
SLV2PluginClass pclass = slv2_plugin_get_class(p);
- info->category = slv2_plugin_class_get_label(pclass);
+ SLV2Value label = slv2_plugin_class_get_label(pclass);
+ info->category = slv2_value_as_string(label);
- char* author_name = slv2_plugin_get_author_name(p);
- info->creator = author_name ? string(author_name) : "Unknown";
- free(author_name);
+ SLV2Value author_name = slv2_plugin_get_author_name(p);
+ info->creator = author_name ? string(slv2_value_as_string(author_name)) : "Unknown";
+ slv2_value_free(author_name);
info->path = "/NOPATH"; // Meaningless for LV2
- SLV2Template io = slv2_plugin_get_template(p);
-
- info->n_inputs.set_audio(slv2_template_get_num_ports_of_type(io,
- SLV2_PORT_DIRECTION_INPUT, SLV2_PORT_DATA_TYPE_AUDIO));
- info->n_outputs.set_audio(slv2_template_get_num_ports_of_type(io,
- SLV2_PORT_DIRECTION_OUTPUT, SLV2_PORT_DATA_TYPE_AUDIO));
+ info->n_inputs.set_audio(slv2_plugin_get_num_ports_of_class(p,
+ world->input_class, world->audio_class, NULL));
+ info->n_inputs.set_midi(slv2_plugin_get_num_ports_of_class(p,
+ world->input_class, world->event_class, NULL));
- info->n_inputs.set_midi(slv2_template_get_num_ports_of_type(io,
- SLV2_PORT_DIRECTION_INPUT, SLV2_PORT_DATA_TYPE_MIDI));
- info->n_outputs.set_midi(slv2_template_get_num_ports_of_type(io,
- SLV2_PORT_DIRECTION_OUTPUT, SLV2_PORT_DATA_TYPE_MIDI));
+ info->n_outputs.set_audio(slv2_plugin_get_num_ports_of_class(p,
+ world->output_class, world->audio_class, NULL));
+ info->n_outputs.set_midi(slv2_plugin_get_num_ports_of_class(p,
+ world->output_class, world->event_class, NULL));
- info->unique_id = slv2_plugin_get_uri(p);
+ info->unique_id = slv2_value_as_uri(slv2_plugin_get_uri(p));
info->index = 0; // Meaningless for LV2
plugs.push_back (info);
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc
index 3a2842be7a..ea340598ac 100644
--- a/libs/ardour/midi_diskstream.cc
+++ b/libs/ardour/midi_diskstream.cc
@@ -933,7 +933,7 @@ MidiDiskstream::do_flush (Session::RunContext context, bool force_flush)
assert(!destructive());
if (record_enabled() && _session.transport_frame() - _last_flush_frame > disk_io_chunk_frames) {
- if ((!_write_source) || _write_source->write (*_capture_buf, to_write) != to_write) {
+ if ((!_write_source) || _write_source->midi_write (*_capture_buf, to_write) != to_write) {
error << string_compose(_("MidiDiskstream %1: cannot write to disk"), _id) << endmsg;
return -1;
} else {
diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc
index cc1ba4b2a8..b0b7e4575f 100644
--- a/libs/ardour/midi_region.cc
+++ b/libs/ardour/midi_region.cc
@@ -65,7 +65,7 @@ MidiRegion::MidiRegion (boost::shared_ptr<MidiSource> src, nframes_t start, nfra
}
/* Basic MidiRegion constructor (many channels) */
-MidiRegion::MidiRegion (SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
+MidiRegion::MidiRegion (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
: Region (srcs, start, length, name, DataType::MIDI, layer, flags)
{
assert(_name.find("/") == string::npos);
@@ -100,7 +100,7 @@ MidiRegion::MidiRegion (boost::shared_ptr<MidiSource> src, const XMLNode& node)
assert(_type == DataType::MIDI);
}
-MidiRegion::MidiRegion (SourceList& srcs, const XMLNode& node)
+MidiRegion::MidiRegion (const SourceList& srcs, const XMLNode& node)
: Region (srcs, node)
{
if (set_state (node)) {
@@ -171,7 +171,7 @@ MidiRegion::_read_at (const SourceList& srcs, MidiRingBuffer& dst, nframes_t pos
boost::shared_ptr<MidiSource> src = midi_source(chan_n);
src->set_note_mode(mode);
- if (src->read (dst, _start + internal_offset, to_read, _position) != to_read) {
+ if (src->midi_read (dst, _start + internal_offset, to_read, _position) != to_read) {
return 0; /* "read nothing" */
}
diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc
index f072c2a7ef..794959328a 100644
--- a/libs/ardour/midi_source.cc
+++ b/libs/ardour/midi_source.cc
@@ -101,7 +101,7 @@ MidiSource::set_state (const XMLNode& node)
}
nframes_t
-MidiSource::read (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const
+MidiSource::midi_read (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const
{
Glib::Mutex::Lock lm (_lock);
if (_model) {
@@ -114,7 +114,7 @@ MidiSource::read (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t
}
nframes_t
-MidiSource::write (MidiRingBuffer& dst, nframes_t cnt)
+MidiSource::midi_write (MidiRingBuffer& dst, nframes_t cnt)
{
Glib::Mutex::Lock lm (_lock);
return write_unlocked (dst, cnt);
diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc
index ae5d6f52ee..6ff780a25f 100644
--- a/libs/ardour/plugin_manager.cc
+++ b/libs/ardour/plugin_manager.cc
@@ -110,8 +110,7 @@ PluginManager::PluginManager ()
}
#ifdef HAVE_SLV2
- _lv2_world = slv2_world_new();
- slv2_world_load_all(_lv2_world);
+ _lv2_world = new LV2World();
#endif
refresh ();
diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc
index 1c79e0c438..7aadb9183f 100644
--- a/libs/ardour/port.cc
+++ b/libs/ardour/port.cc
@@ -296,8 +296,8 @@ PortFacade::disconnect (Port& other)
int
PortFacade::disconnect_all ()
{
- int reta;
- int retb;
+ int reta = 0;
+ int retb = 0;
if (_ext_port) {
reta = _ext_port->disconnect_all ();
diff --git a/libs/ardour/quantize.cc b/libs/ardour/quantize.cc
index de3ed4ef22..ccbda9711a 100644
--- a/libs/ardour/quantize.cc
+++ b/libs/ardour/quantize.cc
@@ -71,9 +71,9 @@ Quantize::run (boost::shared_ptr<Region> r)
for (MidiModel::Notes::iterator i = model->notes().begin(); i != model->notes().end(); ++i) {
const double new_time = lrint((*i)->time() / q_frames) * q_frames;
- const double new_dur = (((*i)->time() != 0 && new_dur < (q_frames * 1.5))
- ? q_frames
- : lrint((*i)->duration() / q_frames) * q_frames);
+ double new_dur = lrint((*i)->duration() / q_frames) * q_frames;
+ if (new_dur == 0.0)
+ new_dur = q_frames;
(*i)->set_time(new_time);
(*i)->set_duration(new_dur);
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index 6d92c0bc88..054e85cd2f 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -99,7 +99,7 @@ Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length
}
/** Basic Region constructor (many sources) */
-Region::Region (SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
+Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
: Automatable(srcs.front()->session(), name)
, _type(type)
, _flags(flags)
@@ -117,13 +117,13 @@ Region::Region (SourceList& srcs, nframes_t start, nframes_t length, const strin
set<boost::shared_ptr<Source> > unique_srcs;
- for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
+ for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
_sources.push_back (*i);
(*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
unique_srcs.insert (*i);
}
- for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
+ for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
_master_sources.push_back (*i);
if (unique_srcs.find (*i) == unique_srcs.end()) {
(*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
@@ -222,7 +222,7 @@ Region::Region (boost::shared_ptr<const Region> other)
assert(_sources.size() > 0);
}
-Region::Region (SourceList& srcs, const XMLNode& node)
+Region::Region (const SourceList& srcs, const XMLNode& node)
: Automatable(srcs.front()->session(), X_("error: XML did not reset this"))
, _type(DataType::NIL) // to be loaded from XML
, _flags(Flag(0))
@@ -239,13 +239,13 @@ Region::Region (SourceList& srcs, const XMLNode& node)
{
set<boost::shared_ptr<Source> > unique_srcs;
- for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
+ for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
_sources.push_back (*i);
(*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
unique_srcs.insert (*i);
}
- for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
+ for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
_master_sources.push_back (*i);
if (unique_srcs.find (*i) == unique_srcs.end()) {
(*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
@@ -974,9 +974,9 @@ Region::state (bool full_state)
node->add_property ("length", buf);
snprintf (buf, sizeof (buf), "%u", _position);
node->add_property ("position", buf);
- snprintf (buf, sizeof (buf), "%lu", _ancestral_start);
+ snprintf (buf, sizeof (buf), "%Ld", _ancestral_start);
node->add_property ("ancestral-start", buf);
- snprintf (buf, sizeof (buf), "%lu", _ancestral_length);
+ snprintf (buf, sizeof (buf), "%Ld", _ancestral_length);
node->add_property ("ancestral-length", buf);
snprintf (buf, sizeof (buf), "%.12g", _stretch);
node->add_property ("stretch", buf);
diff --git a/libs/ardour/region_factory.cc b/libs/ardour/region_factory.cc
index a0aa3be759..bd4b0873a7 100644
--- a/libs/ardour/region_factory.cc
+++ b/libs/ardour/region_factory.cc
@@ -106,7 +106,7 @@ RegionFactory::create (Session& session, XMLNode& node, bool yn)
}
boost::shared_ptr<Region>
-RegionFactory::create (SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Region::Flag flags, bool announce)
+RegionFactory::create (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Region::Flag flags, bool announce)
{
if (srcs.empty()) {
return boost::shared_ptr<Region>();
diff --git a/libs/ardour/resampled_source.cc b/libs/ardour/resampled_source.cc
index 8330196d8a..b5d23fb4a2 100644
--- a/libs/ardour/resampled_source.cc
+++ b/libs/ardour/resampled_source.cc
@@ -38,7 +38,7 @@ ResampledImportableSource::ResampledImportableSource (const std::string& path,
/* Initialize the sample rate converter. */
- int src_type;
+ int src_type = SRC_LINEAR;
switch (srcq) {
case SrcBest:
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index dbec881b0b..c6ace87b73 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -33,6 +33,7 @@
#include <glibmm/thread.h>
#include <glibmm/miscutils.h>
+#include <glibmm/fileutils.h>
#include <pbd/error.h>
#include <glibmm/thread.h>
@@ -148,7 +149,8 @@ Session::Session (AudioEngine &eng,
first_stage_init (fullpath, snapshot_name);
- new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
+ new_session = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
+
if (new_session) {
if (create (new_session, mix_template, compute_initial_length())) {
destroy ();
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index 4b7e0875ee..d18b9cedd7 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -432,19 +432,14 @@ Session::setup_raid_path (string path)
}
int
-Session::create (bool& new_session, const string& mix_template, nframes_t initial_length)
+Session::ensure_subdirs ()
{
string dir;
- if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
- error << string_compose(_("Session: cannot create session dir \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
- return -1;
- }
-
dir = session_directory().peak_path().to_string();
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
- error << string_compose(_("Session: cannot create session peakfile dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
+ error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
return -1;
}
@@ -465,17 +460,39 @@ Session::create (bool& new_session, const string& mix_template, nframes_t initia
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;
+ error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
return -1;
}
dir = session_directory().export_path().to_string();
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
- error << string_compose(_("Session: cannot create session export dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
+ error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
+ return -1;
+ }
+
+ dir = analysis_dir ();
+
+ if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
+ error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+Session::create (bool& new_session, const string& mix_template, nframes_t initial_length)
+{
+
+ if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
+ error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
return -1;
}
+ if (ensure_subdirs ()) {
+ return -1;
+ }
/* check new_session so we don't overwrite an existing one */
@@ -524,7 +541,6 @@ Session::create (bool& new_session, const string& mix_template, nframes_t initia
_state_of_the_state = Clean;
-
save_state ("");
return 0;
@@ -1979,6 +1995,14 @@ Session::automation_dir () const
return res;
}
+string
+Session::analysis_dir () const
+{
+ string res = _path;
+ res += "analysis/";
+ return res;
+}
+
int
Session::load_bundles (XMLNode const & node)
{
@@ -2544,7 +2568,7 @@ Session::cleanup_sources (Session::cleanup_report& rep)
newpath += dead_sound_dir_name;
if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
- error << string_compose(_("Session: cannot create session peakfile dir \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
+ error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
return -1;
}
diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc
index 661beef40b..02c35d2188 100644
--- a/libs/ardour/source_factory.cc
+++ b/libs/ardour/source_factory.cc
@@ -40,7 +40,7 @@ using namespace PBD;
sigc::signal<void,boost::shared_ptr<Source> > SourceFactory::SourceCreated;
Glib::Cond* SourceFactory::PeaksToBuild;
-Glib::StaticMutex SourceFactory::peak_building_lock;
+Glib::StaticMutex SourceFactory::peak_building_lock = GLIBMM_STATIC_MUTEX_INIT;
std::list<boost::weak_ptr<AudioSource> > SourceFactory::files_with_peaks;
static void
diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc
index 780f5c6a5d..b2865fc399 100644
--- a/libs/ardour/tempo.cc
+++ b/libs/ardour/tempo.cc
@@ -268,7 +268,7 @@ TempoMap::move_metric_section (MetricSection& section, const BBT_Time& when)
section.set_start (corrected);
metrics->sort (cmp);
- timestamp_metrics ();
+ timestamp_metrics (true);
return 0;
}
@@ -345,16 +345,22 @@ TempoMap::remove_meter (const MeterSection& tempo)
}
void
-TempoMap::do_insert (MetricSection* section)
+TempoMap::do_insert (MetricSection* section, bool with_bbt)
{
Metrics::iterator i;
for (i = metrics->begin(); i != metrics->end(); ++i) {
- if ((*i)->start() < section->start()) {
- continue;
+ if (with_bbt) {
+ if ((*i)->start() < section->start()) {
+ continue;
+ }
+ } else {
+ if ((*i)->frame() < section->frame()) {
+ continue;
+ }
}
-
+
metrics->insert (i, section);
break;
}
@@ -363,7 +369,7 @@ TempoMap::do_insert (MetricSection* section)
metrics->insert (metrics->end(), section);
}
- timestamp_metrics ();
+ timestamp_metrics (with_bbt);
}
void
@@ -376,7 +382,18 @@ TempoMap::add_tempo (const Tempo& tempo, BBT_Time where)
where.ticks = 0;
- do_insert (new TempoSection (where, tempo.beats_per_minute(), tempo.note_type()));
+ do_insert (new TempoSection (where, tempo.beats_per_minute(), tempo.note_type()), true);
+ }
+
+ StateChanged (Change (0));
+}
+
+void
+TempoMap::add_tempo (const Tempo& tempo, nframes_t where)
+{
+ {
+ Glib::RWLock::WriterLock lm (lock);
+ do_insert (new TempoSection (where, tempo.beats_per_minute(), tempo.note_type()), false);
}
StateChanged (Change (0));
@@ -399,7 +416,7 @@ TempoMap::replace_tempo (TempoSection& existing, const Tempo& replacement)
*((Tempo *) ts) = replacement;
replaced = true;
- timestamp_metrics ();
+ timestamp_metrics (true);
break;
}
}
@@ -432,7 +449,18 @@ TempoMap::add_meter (const Meter& meter, BBT_Time where)
where.ticks = 0;
- do_insert (new MeterSection (where, meter.beats_per_bar(), meter.note_divisor()));
+ do_insert (new MeterSection (where, meter.beats_per_bar(), meter.note_divisor()), true);
+ }
+
+ StateChanged (Change (0));
+}
+
+void
+TempoMap::add_meter (const Meter& meter, nframes_t where)
+{
+ {
+ Glib::RWLock::WriterLock lm (lock);
+ do_insert (new MeterSection (where, meter.beats_per_bar(), meter.note_divisor()), false);
}
StateChanged (Change (0));
@@ -454,7 +482,7 @@ TempoMap::replace_meter (MeterSection& existing, const Meter& replacement)
*((Meter*) ms) = replacement;
replaced = true;
- timestamp_metrics ();
+ timestamp_metrics (true);
break;
}
}
@@ -465,6 +493,49 @@ TempoMap::replace_meter (MeterSection& existing, const Meter& replacement)
}
}
+void
+TempoMap::change_existing_tempo_at (nframes_t where, double beats_per_minute, double note_type)
+{
+ Tempo newtempo (beats_per_minute, note_type);
+
+ TempoSection* prev;
+ TempoSection* first;
+ Metrics::iterator i;
+
+ /* find the TempoSection immediately preceding "where"
+ */
+
+ for (first = 0, i = metrics->begin(), prev = 0; i != metrics->end(); ++i) {
+
+ if ((*i)->frame() > where) {
+ break;
+ }
+
+ TempoSection* t;
+
+ if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
+ if (!first) {
+ first = t;
+ }
+ prev = t;
+ }
+ }
+
+ if (!prev) {
+ if (!first) {
+ error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
+ return;
+ }
+
+ prev = first;
+ }
+
+ /* reset */
+
+ *((Tempo*)prev) = newtempo;
+ StateChanged (Change (0));
+}
+
const MeterSection&
TempoMap::first_meter () const
{
@@ -498,43 +569,84 @@ TempoMap::first_tempo () const
}
void
-TempoMap::timestamp_metrics ()
+TempoMap::timestamp_metrics (bool use_bbt)
{
Metrics::iterator i;
const Meter* meter;
const Tempo* tempo;
Meter *m;
Tempo *t;
- nframes_t current;
- nframes_t section_frames;
- BBT_Time start;
- BBT_Time end;
meter = &first_meter ();
tempo = &first_tempo ();
- current = 0;
- for (i = metrics->begin(); i != metrics->end(); ++i) {
-
- end = (*i)->start();
+ if (use_bbt) {
- section_frames = count_frames_between_metrics (*meter, *tempo, start, end);
+ nframes_t current = 0;
+ nframes_t section_frames;
+ BBT_Time start;
+ BBT_Time end;
- current += section_frames;
+ for (i = metrics->begin(); i != metrics->end(); ++i) {
+
+ end = (*i)->start();
+
+ section_frames = count_frames_between_metrics (*meter, *tempo, start, end);
+
+ current += section_frames;
+
+ start = end;
+
+ (*i)->set_frame (current);
+
+ if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
+ tempo = t;
+ } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
+ meter = m;
+ } else {
+ fatal << _("programming error: unhandled MetricSection type") << endmsg;
+ /*NOTREACHED*/
+ }
+ }
- start = end;
+ } else {
- (*i)->set_frame (current);
+ bool first = true;
- if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
- tempo = t;
- } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
- meter = m;
- } else {
- fatal << _("programming error: unhandled MetricSection type") << endmsg;
- /*NOTREACHED*/
+ for (i = metrics->begin(); i != metrics->end(); ++i) {
+
+ BBT_Time bbt;
+
+ bbt_time_with_metric ((*i)->frame(), bbt, Metric (*meter, *tempo));
+
+ // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
+
+ if (first) {
+ first = false;
+ } else {
+ if (bbt.beats != 1 || bbt.ticks != 0) {
+ bbt.bars += 1;
+ bbt.beats = 1;
+ bbt.ticks = 0;
+ }
+ }
+
+ // cerr << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << endl;
+
+ (*i)->set_start (bbt);
+
+ if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
+ tempo = t;
+ } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
+ meter = m;
+ } else {
+ fatal << _("programming error: unhandled MetricSection type") << endmsg;
+ /*NOTREACHED*/
+ }
}
}
+
+ // dump (cerr);
}
TempoMap::Metric
@@ -666,17 +778,15 @@ TempoMap::bbt_time_with_metric (nframes_t frame, BBT_Time& bbt, const Metric& me
nframes_t
TempoMap::count_frames_between ( const BBT_Time& start, const BBT_Time& end) const
{
-
- /* for this to work with fractional measure types, start and end have to "legal" BBT types,
- that means that the beats and ticks should be inside a bar
+ /* for this to work with fractional measure types, start and end have to be "legal" BBT types,
+ that means that the beats and ticks should be inside a bar
*/
-
nframes_t frames = 0;
nframes_t start_frame = 0;
nframes_t end_frame = 0;
- Metric m = metric_at(start);
+ Metric m = metric_at (start);
uint32_t bar_offset = start.bars - m.start().bars;
@@ -939,67 +1049,6 @@ TempoMap::round_to_beat_subdivision (nframes_t fr, int sub_num)
}
return frame_time (the_beat);
-
-
-
- /*****************************
- XXX just keeping this for reference
-
- TempoMap::BBTPointList::iterator i;
- TempoMap::BBTPointList *more_zoomed_bbt_points;
- nframes_t frame_one_beats_worth;
- nframes_t pos = 0;
- nframes_t next_pos = 0 ;
- double tempo = 1;
- double frames_one_subdivisions_worth;
- bool fr_has_changed = false;
-
- int n;
-
- frame_one_beats_worth = (nframes_t) ::floor ((double) _frame_rate * 60 / 20 ); //one beat @ 20 bpm
- {
- Glib::RWLock::ReaderLock lm (lock);
- more_zoomed_bbt_points = get_points((fr >= frame_one_beats_worth) ?
- fr - frame_one_beats_worth : 0, fr+frame_one_beats_worth );
- }
- if (more_zoomed_bbt_points == 0 || more_zoomed_bbt_points->empty()) {
- return fr;
- }
-
- for (i = more_zoomed_bbt_points->begin(); i != more_zoomed_bbt_points->end(); i++) {
- if ((*i).frame <= fr) {
- pos = (*i).frame;
- tempo = (*i).tempo->beats_per_minute();
-
- } else {
- i++;
- next_pos = (*i).frame;
- break;
- }
- }
- frames_one_subdivisions_worth = ((double) _frame_rate * 60 / (sub_num * tempo));
-
- for (n = sub_num; n > 0; n--) {
- if (fr >= (pos + ((n - 0.5) * frames_one_subdivisions_worth))) {
- fr = (nframes_t) round(pos + (n * frames_one_subdivisions_worth));
- if (fr > next_pos) {
- fr = next_pos; //take care of fractional beats that don't match the subdivision asked
- }
- fr_has_changed = true;
- break;
- }
- }
-
- if (!fr_has_changed) {
- fr = pos;
- }
-
- delete more_zoomed_bbt_points;
- return fr ;
-
- ******************************/
-
-
}
nframes_t
@@ -1051,6 +1100,12 @@ TempoMap::round_to_type (nframes_t frame, int dir, BBTPointType type)
}
+ /*
+ cerr << "for " << frame << " round to " << bbt << " using "
+ << metric.start()
+ << endl;
+ */
+
return metric.frame() + count_frames_between (metric.start(), bbt);
}
@@ -1148,6 +1203,7 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
if (beat == 1) {
if (current >= lower) {
+ // cerr << "Add Bar at " << bar << "|1" << " @ " << current << endl;
points->push_back (BBTPoint (*meter, *tempo,(nframes_t)rint(current), Bar, bar, 1));
}
@@ -1159,6 +1215,7 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
while (beat <= ceil( beats_per_bar) && beat_frame < limit) {
if (beat_frame >= lower) {
+ // cerr << "Add Beat at " << bar << '|' << beat << " @ " << beat_frame << endl;
points->push_back (BBTPoint (*meter, *tempo, (nframes_t) rint(beat_frame), Beat, bar, beat));
}
beat_frame += beat_frames;
@@ -1167,7 +1224,7 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
beat++;
}
- if (beat > ceil(beats_per_bar) ) {
+ if (beat > ceil(beats_per_bar) || i != metrics->end()) {
/* we walked an entire bar. its
important to move `current' forward
@@ -1185,10 +1242,15 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
so we subtract the possible extra fraction from the current
*/
- current -= beat_frames * (ceil(beats_per_bar)-beats_per_bar);
+ if (beat > ceil (beats_per_bar)) {
+ /* next bar goes where the numbers suggest */
+ current -= beat_frames * (ceil(beats_per_bar)-beats_per_bar);
+ } else {
+ /* next bar goes where the next metric is */
+ current = limit;
+ }
bar++;
beat = 1;
-
}
}
@@ -1225,6 +1287,33 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
return points;
}
+const TempoSection&
+TempoMap::tempo_section_at (nframes_t frame)
+{
+ Glib::RWLock::ReaderLock lm (lock);
+ Metrics::iterator i;
+ TempoSection* prev = 0;
+
+ for (i = metrics->begin(); i != metrics->end(); ++i) {
+ TempoSection* t;
+
+ if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+
+ if ((*i)->frame() > frame) {
+ break;
+ }
+
+ prev = t;
+ }
+ }
+
+ if (prev == 0) {
+ fatal << endmsg;
+ }
+
+ return *prev;
+}
+
const Tempo&
TempoMap::tempo_at (nframes_t frame)
{
@@ -1303,7 +1392,7 @@ TempoMap::set_state (const XMLNode& node)
MetricSectionSorter cmp;
metrics->sort (cmp);
- timestamp_metrics ();
+ timestamp_metrics (true);
}
}
diff --git a/libs/ardour/transient_detector.cc b/libs/ardour/transient_detector.cc
new file mode 100644
index 0000000000..b85700dd90
--- /dev/null
+++ b/libs/ardour/transient_detector.cc
@@ -0,0 +1,61 @@
+#include <ardour/transient_detector.h>
+
+#include "i18n.h"
+
+using namespace Vamp;
+using namespace ARDOUR;
+using namespace std;
+
+TransientDetector::TransientDetector (float sr)
+ : AudioAnalyser (sr, X_("libardourvampplugins:percussiononsets"))
+{
+}
+
+TransientDetector::~TransientDetector()
+{
+}
+
+int
+TransientDetector::run (const std::string& path, Readable* src, uint32_t channel, vector<nframes64_t>& results)
+{
+ current_results = &results;
+ int ret = analyse (path, src, channel);
+ current_results = 0;
+ return ret;
+}
+
+int
+TransientDetector::use_features (Plugin::FeatureSet& features, ostream* out)
+{
+ const Plugin::FeatureList& fl (features[0]);
+
+ for (Plugin::FeatureList::const_iterator f = fl.begin(); f != fl.end(); ++f) {
+
+ if ((*f).hasTimestamp) {
+
+ if (out) {
+ (*out) << (*f).timestamp.toString() << endl;
+ }
+
+ current_results->push_back (RealTime::realTime2Frame ((*f).timestamp, (nframes_t) floor(sample_rate)));
+ }
+ }
+
+ return 0;
+}
+
+void
+TransientDetector::set_threshold (float val)
+{
+ if (plugin) {
+ plugin->setParameter ("threshold", val);
+ }
+}
+
+void
+TransientDetector::set_sensitivity (float val)
+{
+ if (plugin) {
+ plugin->setParameter ("sensitivity", val);
+ }
+}