summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2015-09-02 11:20:24 +0100
committerCarl Hetherington <cth@carlh.net>2015-09-14 10:20:41 +0100
commitd2bd0c628fd0616fe3b7dd02bd955b2c07ab48d5 (patch)
treee974870e7e4b6014520b461a19a7b336eb7617a3 /src/lib
parentc138f4050bffbdc97edca8a824297f155dc62da3 (diff)
Add option to analyse audio automatically when content is added (#673).
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/analyse_audio_job.h5
-rw-r--r--src/lib/config.cc3
-rw-r--r--src/lib/config.h9
-rw-r--r--src/lib/film.cc29
-rw-r--r--src/lib/film.h2
-rw-r--r--src/lib/job.cc13
-rw-r--r--src/lib/job.h2
-rw-r--r--src/lib/job_manager.cc63
-rw-r--r--src/lib/job_manager.h16
9 files changed, 120 insertions, 22 deletions
diff --git a/src/lib/analyse_audio_job.h b/src/lib/analyse_audio_job.h
index d484bff2c..d9b90ec66 100644
--- a/src/lib/analyse_audio_job.h
+++ b/src/lib/analyse_audio_job.h
@@ -28,6 +28,7 @@
class AudioBuffers;
class AudioAnalysis;
class Playlist;
+class AudioPoint;
/** @class AnalyseAudioJob
* @brief A job to analyse the audio of a film and make a note of its
@@ -46,6 +47,10 @@ public:
std::string json_name () const;
void run ();
+ boost::shared_ptr<const Playlist> playlist () const {
+ return _playlist;
+ }
+
private:
void analyse (boost::shared_ptr<const AudioBuffers>);
diff --git a/src/lib/config.cc b/src/lib/config.cc
index fc71a72f3..20386368e 100644
--- a/src/lib/config.cc
+++ b/src/lib/config.cc
@@ -97,6 +97,7 @@ Config::set_defaults ()
_check_for_test_updates = false;
_maximum_j2k_bandwidth = 250000000;
_log_types = Log::TYPE_GENERAL | Log::TYPE_WARNING | Log::TYPE_ERROR;
+ _automatic_audio_analysis = false;
#ifdef DCPOMATIC_WINDOWS
_win32_console = false;
#endif
@@ -231,6 +232,7 @@ Config::read ()
_allow_any_dcp_frame_rate = f.optional_bool_child ("AllowAnyDCPFrameRate");
_log_types = f.optional_number_child<int> ("LogTypes").get_value_or (Log::TYPE_GENERAL | Log::TYPE_WARNING | Log::TYPE_ERROR);
+ _automatic_audio_analysis = f.optional_bool_child ("AutomaticAudioAnalysis").get_value_or (false);
#ifdef DCPOMATIC_WINDOWS
_win32_console = f.optional_bool_child ("Win32Console").get_value_or (false);
#endif
@@ -375,6 +377,7 @@ Config::write () const
root->add_child("MaximumJ2KBandwidth")->add_child_text (raw_convert<string> (_maximum_j2k_bandwidth));
root->add_child("AllowAnyDCPFrameRate")->add_child_text (_allow_any_dcp_frame_rate ? "1" : "0");
root->add_child("LogTypes")->add_child_text (raw_convert<string> (_log_types));
+ root->add_child("AutomaticAudioAnalysis")->add_child_text (_automatic_audio_analysis ? "1" : "0");
#ifdef DCPOMATIC_WINDOWS
root->add_child("Win32Console")->add_child_text (_win32_console ? "1" : "0");
#endif
diff --git a/src/lib/config.h b/src/lib/config.h
index fc63c518c..2f68ea31c 100644
--- a/src/lib/config.h
+++ b/src/lib/config.h
@@ -226,6 +226,10 @@ public:
return _log_types;
}
+ bool automatic_audio_analysis () const {
+ return _automatic_audio_analysis;
+ }
+
#ifdef DCPOMATIC_WINDOWS
bool win32_console () const {
return _win32_console;
@@ -407,6 +411,10 @@ public:
maybe_set (_log_types, t);
}
+ void set_automatic_audio_analysis (bool a) {
+ maybe_set (_automatic_audio_analysis, a);
+ }
+
#ifdef DCPOMATIC_WINDOWS
void set_win32_console (bool c) {
maybe_set (_win32_console, c);
@@ -505,6 +513,7 @@ private:
/** maximum allowed J2K bandwidth in bits per second */
int _maximum_j2k_bandwidth;
int _log_types;
+ bool _automatic_audio_analysis;
#ifdef DCPOMATIC_WINDOWS
bool _win32_console;
#endif
diff --git a/src/lib/film.cc b/src/lib/film.cc
index 685fc7658..231ac92e1 100644
--- a/src/lib/film.cc
+++ b/src/lib/film.cc
@@ -162,8 +162,12 @@ Film::Film (boost::filesystem::path dir, bool log)
Film::~Film ()
{
- for (list<boost::signals2::connection>::const_iterator i = _job_connections.begin(); i != _job_connections.end(); ++i) {
- i->disconnect ();
+ BOOST_FOREACH (boost::signals2::connection& i, _job_connections) {
+ i.disconnect ();
+ }
+
+ BOOST_FOREACH (boost::signals2::connection& i, _audio_analysis_connections) {
+ i.disconnect ();
}
}
@@ -947,8 +951,19 @@ Film::maybe_add_content (weak_ptr<Job> j, weak_ptr<Content> c)
}
shared_ptr<Content> content = c.lock ();
- if (content) {
- add_content (content);
+ if (!content) {
+ return;
+ }
+
+ add_content (content);
+ if (Config::instance()->automatic_audio_analysis ()) {
+ shared_ptr<Playlist> playlist (new Playlist);
+ playlist->add (content);
+ boost::signals2::connection c;
+ JobManager::instance()->analyse_audio (
+ shared_from_this (), playlist, c, bind (&Film::audio_analysis_finished, this)
+ );
+ _audio_analysis_connections.push_back (c);
}
}
@@ -1233,3 +1248,9 @@ Film::remove_content (ContentList c)
{
_playlist->remove (c);
}
+
+void
+Film::audio_analysis_finished ()
+{
+ /* XXX */
+}
diff --git a/src/lib/film.h b/src/lib/film.h
index 2165eed23..aa7be939e 100644
--- a/src/lib/film.h
+++ b/src/lib/film.h
@@ -296,6 +296,7 @@ private:
void playlist_changed ();
void playlist_content_changed (boost::weak_ptr<Content>, int, bool frequent);
void maybe_add_content (boost::weak_ptr<Job>, boost::weak_ptr<Content>);
+ void audio_analysis_finished ();
/** Log to write to */
boost::shared_ptr<Log> _log;
@@ -345,6 +346,7 @@ private:
boost::signals2::scoped_connection _playlist_changed_connection;
boost::signals2::scoped_connection _playlist_content_changed_connection;
std::list<boost::signals2::connection> _job_connections;
+ std::list<boost::signals2::connection> _audio_analysis_connections;
friend struct paths_test;
friend struct film_metadata_test;
diff --git a/src/lib/job.cc b/src/lib/job.cc
index 784defc91..37bf462fc 100644
--- a/src/lib/job.cc
+++ b/src/lib/job.cc
@@ -39,6 +39,7 @@ using std::list;
using std::cout;
using boost::shared_ptr;
using boost::optional;
+using boost::function;
#define LOG_ERROR_NC(...) _film->log()->log (__VA_ARGS__, Log::TYPE_ERROR);
@@ -434,3 +435,15 @@ Job::resume ()
_pause_changed.notify_all ();
}
}
+
+void
+Job::when_finished (boost::signals2::connection& connection, function<void()> finished)
+{
+ boost::mutex::scoped_lock lm (_state_mutex);
+ if (_state == FINISHED_OK || _state == FINISHED_ERROR || _state == FINISHED_CANCELLED) {
+ finished ();
+ } else {
+ connection = Finished.connect (finished);
+ }
+}
+
diff --git a/src/lib/job.h b/src/lib/job.h
index 1caa5a904..32e71d658 100644
--- a/src/lib/job.h
+++ b/src/lib/job.h
@@ -80,6 +80,8 @@ public:
return _film;
}
+ void when_finished (boost::signals2::connection& connection, boost::function<void()> finished);
+
boost::signals2::signal<void()> Progress;
/** Emitted from the UI thread when the job is finished */
boost::signals2::signal<void()> Finished;
diff --git a/src/lib/job_manager.cc b/src/lib/job_manager.cc
index e3f91f4fc..3748fa353 100644
--- a/src/lib/job_manager.cc
+++ b/src/lib/job_manager.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
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
@@ -21,23 +21,28 @@
* @brief A simple scheduler for jobs.
*/
-#include <iostream>
-#include <boost/thread.hpp>
#include "job_manager.h"
#include "job.h"
#include "cross.h"
+#include "analyse_audio_job.h"
+#include "film.h"
+#include <boost/thread.hpp>
+#include <boost/foreach.hpp>
+#include <iostream>
using std::string;
using std::list;
using std::cout;
using boost::shared_ptr;
using boost::weak_ptr;
+using boost::function;
+using boost::dynamic_pointer_cast;
+using boost::optional;
JobManager* JobManager::_instance = 0;
JobManager::JobManager ()
: _terminate (false)
- , _last_active_jobs (false)
, _scheduler (0)
{
@@ -113,7 +118,7 @@ JobManager::scheduler ()
{
while (true) {
- bool active_jobs = false;
+ optional<string> active_job;
{
boost::mutex::scoped_lock lm (_mutex);
@@ -121,29 +126,28 @@ JobManager::scheduler ()
return;
}
- for (list<shared_ptr<Job> >::iterator i = _jobs.begin(); i != _jobs.end(); ++i) {
+ BOOST_FOREACH (shared_ptr<Job> i, _jobs) {
- if (!(*i)->finished ()) {
- active_jobs = true;
+ if (!i->finished ()) {
+ active_job = i->json_name ();
}
- if ((*i)->running ()) {
+ if (i->running ()) {
/* Something is already happening */
break;
}
- if ((*i)->is_new()) {
- (*i)->start ();
-
+ if (i->is_new()) {
+ i->start ();
/* Only start one job at once */
break;
}
}
}
- if (active_jobs != _last_active_jobs) {
- _last_active_jobs = active_jobs;
- emit (boost::bind (boost::ref (ActiveJobsChanged), active_jobs));
+ if (active_job != _last_active_job) {
+ _last_active_job = active_job;
+ emit (boost::bind (boost::ref (ActiveJobsChanged), active_job));
}
dcpomatic_sleep (1);
@@ -167,3 +171,32 @@ JobManager::drop ()
delete _instance;
_instance = 0;
}
+
+void
+JobManager::analyse_audio (
+ shared_ptr<const Film> film,
+ shared_ptr<const Playlist> playlist,
+ boost::signals2::connection& connection,
+ function<void()> ready
+ )
+{
+ shared_ptr<AnalyseAudioJob> job;
+
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+
+ BOOST_FOREACH (shared_ptr<Job> i, _jobs) {
+ shared_ptr<AnalyseAudioJob> a = dynamic_pointer_cast<AnalyseAudioJob> (i);
+ if (a && film->audio_analysis_path (a->playlist ()) == film->audio_analysis_path (playlist)) {
+ i->when_finished (connection, ready);
+ return;
+ }
+ }
+
+ job.reset (new AnalyseAudioJob (film, playlist));
+ connection = job->Finished.connect (ready);
+ _jobs.push_back (job);
+ }
+
+ emit (boost::bind (boost::ref (JobAdded), weak_ptr<Job> (job)));
+}
diff --git a/src/lib/job_manager.h b/src/lib/job_manager.h
index 3cd8be6d6..7de7862a1 100644
--- a/src/lib/job_manager.h
+++ b/src/lib/job_manager.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
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
@@ -28,6 +28,9 @@
#include <list>
class Job;
+class Film;
+class Playlist;
+
extern void wait_for_jobs ();
/** @class JobManager
@@ -42,8 +45,15 @@ public:
bool work_to_do () const;
bool errors () const;
+ void analyse_audio (
+ boost::shared_ptr<const Film> film,
+ boost::shared_ptr<const Playlist> playlist,
+ boost::signals2::connection& connection,
+ boost::function<void()> ready
+ );
+
boost::signals2::signal<void (boost::weak_ptr<Job>)> JobAdded;
- boost::signals2::signal<void (bool)> ActiveJobsChanged;
+ boost::signals2::signal<void (boost::optional<std::string>)> ActiveJobsChanged;
static JobManager* instance ();
static void drop ();
@@ -61,7 +71,7 @@ private:
std::list<boost::shared_ptr<Job> > _jobs;
bool _terminate;
- bool _last_active_jobs;
+ boost::optional<std::string> _last_active_job;
boost::thread* _scheduler;
static JobManager* _instance;