mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-06 14:54:56 +01:00
do tempo estimation within AudioSources, after capture and upon import
we read 10 seconds from the middle of the data; not infallible but a reasonable first pass at a heuristic.
This commit is contained in:
parent
40f6859905
commit
6d92be80c1
6 changed files with 69 additions and 9 deletions
|
|
@ -95,6 +95,8 @@ class LIBARDOUR_API AudioSource : virtual public Source, public ARDOUR::AudioRea
|
|||
/** @return true if the each source sample s must be clamped to -1 < s < 1 */
|
||||
virtual bool clamped_at_unity () const = 0;
|
||||
|
||||
void estimate_tempo ();
|
||||
|
||||
protected:
|
||||
static bool _build_missing_peakfiles;
|
||||
static bool _build_peakfiles;
|
||||
|
|
|
|||
|
|
@ -156,6 +156,8 @@ public:
|
|||
bool get_segment_descriptor (TimelineRange const &, SegmentDescriptor&);
|
||||
int set_segment_descriptor (SegmentDescriptor const &, bool replace = false);
|
||||
|
||||
void copy_segment_descriptors (Source const & other);
|
||||
|
||||
protected:
|
||||
DataType _type;
|
||||
Flag _flags;
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@
|
|||
#include "ardour/rc_configuration.h"
|
||||
#include "ardour/runtime_functions.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/utils.h"
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
|
|
@ -131,6 +132,46 @@ AudioSource::~AudioSource ()
|
|||
delete [] peak_leftovers;
|
||||
}
|
||||
|
||||
void
|
||||
AudioSource::estimate_tempo ()
|
||||
{
|
||||
/* CALLER MUST HOLD WRITER LOCK */
|
||||
|
||||
const samplecnt_t ten_seconds = _session.sample_rate() * 10;
|
||||
|
||||
if (length().samples() < ten_seconds) {
|
||||
return;
|
||||
}
|
||||
|
||||
samplecnt_t data_size = ten_seconds;
|
||||
std::unique_ptr<Sample[]> data (new Sample[data_size]);
|
||||
|
||||
/* Read ten seconds from the middle of the data */
|
||||
|
||||
if (read_unlocked (data.get(), std::max ((samplecnt_t) 0, (length().samples() - data_size) / 2), data_size) == data_size) {
|
||||
|
||||
double tempo;
|
||||
double beatcount;
|
||||
Temporal::Tempo t (120, 4);
|
||||
Temporal::Meter m (4, 4);
|
||||
TimelineRange r (timepos_t (0), timepos_t (0) + length(), 0);
|
||||
|
||||
estimate_audio_tempo_source (r, shared_from_this(), data.get(), data_size, _session.sample_rate(), tempo, m, beatcount);
|
||||
t = Temporal::Tempo (tempo, 4);
|
||||
|
||||
SegmentDescriptor sd;
|
||||
|
||||
sd.set_tempo (t);
|
||||
sd.set_meter (m);
|
||||
sd.set_position (0);
|
||||
sd.set_duration (length().samples());
|
||||
|
||||
/* One segment descriptor to rule them all */
|
||||
|
||||
set_segment_descriptor (sd, true);
|
||||
}
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
AudioSource::get_state () const
|
||||
{
|
||||
|
|
@ -1166,9 +1207,14 @@ AudioSource::available_peaks (double zoom_factor) const
|
|||
void
|
||||
AudioSource::mark_streaming_write_completed (const WriterLock& lock, Temporal::timecnt_t const &)
|
||||
{
|
||||
Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
|
||||
estimate_tempo ();
|
||||
|
||||
if (_peaks_built) {
|
||||
PeaksReady (); /* EMIT SIGNAL */
|
||||
{
|
||||
Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
|
||||
|
||||
if (_peaks_built) {
|
||||
PeaksReady (); /* EMIT SIGNAL */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -329,6 +329,8 @@ SndFileSource::SndFileSource (Session& s, const AudioFileSource& other, const st
|
|||
tbuf.modtime = statbuf.st_mtime; // = time ((time_t*) 0);
|
||||
g_utime (path.c_str(), &tbuf);
|
||||
}
|
||||
|
||||
copy_segment_descriptors (other);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -582,3 +582,9 @@ Source::set_segment_descriptor (SegmentDescriptor const & sr, bool replace)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
Source::copy_segment_descriptors (Source const & other)
|
||||
{
|
||||
segment_descriptors = other.segment_descriptors;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
|
|||
|
||||
} else {
|
||||
try {
|
||||
Source* src = new SndFileSource (s, node);
|
||||
Source* src = new SndFileSource (s, node);
|
||||
std::shared_ptr<Source> ret (src);
|
||||
BOOST_MARK_SOURCE (ret);
|
||||
if (setup_peakfile (ret, defer_peaks)) {
|
||||
|
|
@ -214,7 +214,7 @@ SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
|
|||
|
||||
#ifdef HAVE_COREAUDIO
|
||||
try {
|
||||
Source* src = new CoreAudioSource (s, node);
|
||||
Source* src = new CoreAudioSource (s, node);
|
||||
std::shared_ptr<Source> ret (src);
|
||||
BOOST_MARK_SOURCE (ret);
|
||||
|
||||
|
|
@ -252,13 +252,14 @@ SourceFactory::createExternal (DataType type, Session& s, const string& path,
|
|||
{
|
||||
if (type == DataType::AUDIO) {
|
||||
try {
|
||||
Source* src = new SndFileSource (s, path, chn, flags);
|
||||
AudioSource* src = new SndFileSource (s, path, chn, flags);
|
||||
std::shared_ptr<Source> ret (src);
|
||||
BOOST_MARK_SOURCE (ret);
|
||||
if (setup_peakfile (ret, defer_peaks)) {
|
||||
throw failed_constructor ();
|
||||
}
|
||||
ret->check_for_analysis_data_on_disk ();
|
||||
src->estimate_tempo ();
|
||||
if (announce) {
|
||||
SourceCreated (ret);
|
||||
}
|
||||
|
|
@ -268,13 +269,14 @@ SourceFactory::createExternal (DataType type, Session& s, const string& path,
|
|||
|
||||
#ifdef HAVE_COREAUDIO
|
||||
try {
|
||||
Source* src = new CoreAudioSource (s, path, chn, flags);
|
||||
AudioSource* src = new CoreAudioSource (s, path, chn, flags);
|
||||
std::shared_ptr<Source> ret (src);
|
||||
BOOST_MARK_SOURCE (ret);
|
||||
if (setup_peakfile (ret, defer_peaks)) {
|
||||
throw failed_constructor ();
|
||||
}
|
||||
ret->check_for_analysis_data_on_disk ();
|
||||
src->estimate_tempo ();
|
||||
if (announce) {
|
||||
SourceCreated (ret);
|
||||
}
|
||||
|
|
@ -415,8 +417,7 @@ SourceFactory::createFromPlaylist (DataType type, Session& s, std::shared_ptr<Pl
|
|||
start = timecnt_t::zero (Temporal::AudioTime);
|
||||
}
|
||||
|
||||
Source* src = new AudioPlaylistSource (s, orig, name, ap, chn, start, len, Source::Flag (0));
|
||||
|
||||
AudioSource* src = new AudioPlaylistSource (s, orig, name, ap, chn, start, len, Source::Flag (0));
|
||||
std::shared_ptr<Source> ret (src);
|
||||
|
||||
if (setup_peakfile (ret, defer_peaks)) {
|
||||
|
|
@ -424,6 +425,7 @@ SourceFactory::createFromPlaylist (DataType type, Session& s, std::shared_ptr<Pl
|
|||
}
|
||||
|
||||
ret->check_for_analysis_data_on_disk ();
|
||||
src->estimate_tempo ();
|
||||
SourceCreated (ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue