summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2008-01-25 05:35:46 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2008-01-25 05:35:46 +0000
commitd3f64c28489d2358498b9d7dcfc6fa4228ebd63e (patch)
tree8195496c9330bb4fb279d282598da6dc5c98a361 /libs
parent28e6ad009158ddaea80fd5d800befcbf58ce47ee (diff)
meet rhythm ferret: cute, furry and always on time (ardour build now requires fftw3 & fftw3f, no exceptions, ever)
git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@2959 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/SConscript9
-rw-r--r--libs/ardour/ardour/audioanalyser.h74
-rw-r--r--libs/ardour/ardour/audioregion.h26
-rw-r--r--libs/ardour/ardour/audiosource.h17
-rw-r--r--libs/ardour/ardour/plugin_manager.h2
-rw-r--r--libs/ardour/ardour/region.h3
-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/transient_detector.h52
-rw-r--r--libs/ardour/audioanalyser.cc157
-rw-r--r--libs/ardour/audioregion.cc187
-rw-r--r--libs/ardour/audiosource.cc50
-rw-r--r--libs/ardour/region_factory.cc2
-rw-r--r--libs/ardour/session.cc4
-rw-r--r--libs/ardour/session_state.cc48
-rw-r--r--libs/ardour/transient_detector.cc62
17 files changed, 589 insertions, 112 deletions
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index 733feb2c00..dada73ff43 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -93,6 +93,7 @@ sndfilesource.cc
source.cc
source_factory.cc
tempo.cc
+transient_detector.cc
utils.cc
version.cc
mix.cc
@@ -267,11 +268,15 @@ 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'] ])
+ ardour.Merge ([ libraries['rubberband']])
timefx_sources += [ 'rb_effect.cc' ]
else:
ardour.Merge ([ libraries['soundtouch'] ])
diff --git a/libs/ardour/ardour/audioanalyser.h b/libs/ardour/ardour/audioanalyser.h
new file mode 100644
index 0000000000..aac2600ba6
--- /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 boost::shared_ptr<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, boost::shared_ptr<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 934b396a8e..e35b041a08 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>
@@ -59,6 +60,7 @@ class AudioRegion : public Region
bool speed_mismatch (float) const;
boost::shared_ptr<AudioSource> source (uint32_t n=0) const { if (n < sources.size()) return sources[n]; else return sources[0]; }
+ const SourceList& get_sources() const { return sources; }
void set_scale_amplitude (gain_t);
gain_t scale_amplitude() const { return _scale_amplitude; }
@@ -82,11 +84,16 @@ 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,
- nframes_t read_frames = 0,
- nframes_t skip_frames = 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;
nframes_t master_read_at (Sample *buf, Sample *mixdown_buf,
float *gain_buf,
@@ -146,7 +153,7 @@ class AudioRegion : public Region
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<const AudioRegion>);
AudioRegion (boost::shared_ptr<AudioSource>, const XMLNode&);
@@ -161,10 +168,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;
bool verify_start (nframes_t position);
bool verify_length (nframes_t& length);
diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h
index b7097154aa..e8ef3a0fa2 100644
--- a/libs/ardour/ardour/audiosource.h
+++ b/libs/ardour/ardour/audiosource.h
@@ -57,7 +57,8 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
virtual nframes_t natural_position() const { return 0; }
- /* 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 length() const {
return _length;
@@ -65,6 +66,15 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
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);
@@ -112,6 +122,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;
@@ -146,6 +159,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/plugin_manager.h b/libs/ardour/ardour/plugin_manager.h
index dd50a079e3..b7e9fc23d8 100644
--- a/libs/ardour/ardour/plugin_manager.h
+++ b/libs/ardour/ardour/plugin_manager.h
@@ -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; }
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index 3aae8c4767..e75fb43acc 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -27,6 +27,7 @@
#include <pbd/statefuldestructible.h>
#include <ardour/ardour.h>
+#include <ardour/readable.h>
class XMLNode;
@@ -40,7 +41,7 @@ enum RegionEditState {
EditChangesID = 2
};
-class Region : public PBD::StatefulDestructible, public boost::enable_shared_from_this<Region>
+class Region : public PBD::StatefulDestructible, public Readable, public boost::enable_shared_from_this<Region>
{
public:
enum Flag {
diff --git a/libs/ardour/ardour/region_factory.h b/libs/ardour/ardour/region_factory.h
index 197983a29d..b944202c36 100644
--- a/libs/ardour/ardour/region_factory.h
+++ b/libs/ardour/ardour/region_factory.h
@@ -49,7 +49,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 20457069d9..acb9f5f53f 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -252,6 +252,9 @@ class Session : public PBD::StatefulDestructible
std::string peak_dir () const;
std::string dead_sound_dir () const;
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 7ffa616a40..6e6561f22f 100644
--- a/libs/ardour/ardour/source.h
+++ b/libs/ardour/ardour/source.h
@@ -28,13 +28,14 @@
#include <pbd/statefuldestructible.h>
#include <ardour/ardour.h>
+#include <ardour/readable.h>
namespace ARDOUR {
class Session;
class Playlist;
-class Source : public PBD::StatefulDestructible
+class Source : public PBD::StatefulDestructible, public ARDOUR::Readable
{
public:
Source (Session&, std::string name);
diff --git a/libs/ardour/ardour/transient_detector.h b/libs/ardour/ardour/transient_detector.h
new file mode 100644
index 0000000000..45172d8f54
--- /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, boost::shared_ptr<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..ea91510f94
--- /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) {
+ return -1;
+ }
+
+ if ((bufsize = plugin->getPreferredBlockSize ()) == 0) {
+ bufsize = 65536;
+ }
+
+ if ((stepsize = plugin->getPreferredStepSize()) == 0) {
+ 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, boost::shared_ptr<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 61ccc203b0..ebf42255cc 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>
@@ -110,15 +111,15 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
listen_to_my_curves ();
}
-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 (start, length, name, layer, flags),
_fade_in (0.0, 2.0, 1.0, false),
_fade_out (0.0, 2.0, 1.0, false),
_envelope (0.0, 2.0, 1.0, false)
{
/* basic AudioRegion constructor */
-
- 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);
master_sources.push_back (*i);
(*i)->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted));
@@ -437,12 +438,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
@@ -455,13 +464,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 */
}
@@ -484,14 +496,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()) {
@@ -500,7 +514,9 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
return 0; /* "read nothing" */
}
- _read_data_count += srcs[chan_n]->read_data_count();
+ if (!raw) {
+ _read_data_count += srcs[chan_n]->read_data_count();
+ }
} else {
@@ -512,37 +528,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.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.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
@@ -553,65 +573,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.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.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.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.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) {
- 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) {
- buf[n] += mixdown_buffer[n];
- }
- }
-
return to_read;
}
diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc
index a71c927f62..68bfff10ee 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"
@@ -917,3 +920,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/region_factory.cc b/libs/ardour/region_factory.cc
index 631c27b42f..5cab802801 100644
--- a/libs/ardour/region_factory.cc
+++ b/libs/ardour/region_factory.cc
@@ -90,7 +90,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)
{
boost::shared_ptr<AudioRegion> arp (new AudioRegion (srcs, start, length, name, layer, flags));
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp));
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 29995c6676..ad629f5d6e 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -34,6 +34,7 @@
#include <glibmm/thread.h>
#include <glibmm/miscutils.h>
+#include <glibmm/fileutils.h>
#include <pbd/error.h>
#include <glibmm/thread.h>
@@ -290,7 +291,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 20f2e06d84..265be63960 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -469,19 +469,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 = peak_dir ();
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;
}
@@ -492,7 +487,7 @@ Session::create (bool& new_session, const string& mix_template, nframes_t initia
dir = sound_dir ();
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;
+ error << string_compose(_("Session: cannot create session sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
return -1;
}
}
@@ -500,17 +495,39 @@ Session::create (bool& new_session, const string& mix_template, nframes_t initia
dir = dead_sound_dir ();
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 = export_dir ();
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 */
@@ -559,7 +576,6 @@ Session::create (bool& new_session, const string& mix_template, nframes_t initia
_state_of_the_state = Clean;
-
save_state ("");
return 0;
@@ -2045,6 +2061,14 @@ Session::automation_dir () const
}
string
+Session::analysis_dir () const
+{
+ string res = _path;
+ res += "analysis/";
+ return res;
+}
+
+string
Session::template_dir ()
{
string path = get_user_ardour_path();
@@ -2808,7 +2832,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/transient_detector.cc b/libs/ardour/transient_detector.cc
new file mode 100644
index 0000000000..e4692b9c95
--- /dev/null
+++ b/libs/ardour/transient_detector.cc
@@ -0,0 +1,62 @@
+#include <ardour/transient_detector.h>
+
+#include "i18n.h"
+
+using namespace Vamp;
+using namespace ARDOUR;
+using namespace std;
+
+TransientDetector::TransientDetector (float sr)
+ : AudioAnalyser (sr, X_("vamp-example-plugins:percussiononsets"))
+{
+ cerr << "plugin in constructor = " << plugin << endl;
+}
+
+TransientDetector::~TransientDetector()
+{
+}
+
+int
+TransientDetector::run (const std::string& path, boost::shared_ptr<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, 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);
+ }
+}