summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2015-06-03 13:17:37 +0100
committerCarl Hetherington <cth@carlh.net>2015-06-03 13:17:37 +0100
commitfa61fc99549264810e17fcd35abffe9e8ddab5b2 (patch)
tree855ce952ed8b416bbab33cd6debbd0f2b7379597 /src
parent3b67c79bf4534e72a7eceaa6e566e7b7c949e4f7 (diff)
Various work on audio mapping.
Fix everything up so that the audio mapping view in the audio panel reflects the processor (or lack of).
Diffstat (limited to 'src')
-rw-r--r--src/lib/audio_content.cc29
-rw-r--r--src/lib/audio_content.h1
-rw-r--r--src/lib/audio_mapping.cc109
-rw-r--r--src/lib/audio_mapping.h36
-rw-r--r--src/lib/audio_processor.h26
-rw-r--r--src/lib/audio_stream.cc5
-rw-r--r--src/lib/ffmpeg_content.cc2
-rw-r--r--src/lib/film.cc60
-rw-r--r--src/lib/film.h4
-rw-r--r--src/lib/mid_side_decoder.cc30
-rw-r--r--src/lib/mid_side_decoder.h8
-rw-r--r--src/lib/player.cc6
-rw-r--r--src/lib/single_stream_audio_content.cc5
-rw-r--r--src/lib/upmixer_a.cc26
-rw-r--r--src/lib/upmixer_a.h4
-rw-r--r--src/wx/audio_mapping_view.cc138
-rw-r--r--src/wx/audio_mapping_view.h27
-rw-r--r--src/wx/audio_panel.cc21
-rw-r--r--src/wx/dcp_panel.cc4
-rw-r--r--src/wx/timeline.cc2
20 files changed, 317 insertions, 226 deletions
diff --git a/src/lib/audio_content.cc b/src/lib/audio_content.cc
index 3ea31f673..b6749d20b 100644
--- a/src/lib/audio_content.cc
+++ b/src/lib/audio_content.cc
@@ -171,10 +171,10 @@ AudioContent::set_audio_mapping (AudioMapping mapping)
{
int c = 0;
BOOST_FOREACH (AudioStreamPtr i, audio_streams ()) {
- AudioMapping stream_mapping (i->channels ());
+ AudioMapping stream_mapping (i->channels (), MAX_DCP_AUDIO_CHANNELS);
for (int j = 0; j < i->channels(); ++j) {
for (int k = 0; k < MAX_DCP_AUDIO_CHANNELS; ++k) {
- stream_mapping.set (j, static_cast<dcp::Channel> (k), mapping.get (c, static_cast<dcp::Channel> (k)));
+ stream_mapping.set (j, k, mapping.get (c, k));
}
++c;
}
@@ -192,16 +192,15 @@ AudioContent::audio_mapping () const
channels += i->channels ();
}
- AudioMapping merged (channels);
+ AudioMapping merged (channels, MAX_DCP_AUDIO_CHANNELS);
int c = 0;
int s = 0;
BOOST_FOREACH (AudioStreamPtr i, audio_streams ()) {
AudioMapping mapping = i->mapping ();
- for (int j = 0; j < mapping.content_channels(); ++j) {
- merged.set_name (c, String::compose ("%1:%2", s + 1, j + 1));
+ for (int j = 0; j < mapping.input_channels(); ++j) {
for (int k = 0; k < MAX_DCP_AUDIO_CHANNELS; ++k) {
- merged.set (c, static_cast<dcp::Channel> (k), mapping.get (j, static_cast<dcp::Channel> (k)));
+ merged.set (c, k, mapping.get (j, k));
}
++c;
}
@@ -289,6 +288,7 @@ AudioContent::processing_description () const
return "";
}
+/** @return true if any stream in this content has a sampling rate of more than 48kHz */
bool
AudioContent::has_rate_above_48k () const
{
@@ -300,3 +300,20 @@ AudioContent::has_rate_above_48k () const
return false;
}
+
+/** @return User-visible names of each of our audio channels */
+vector<string>
+AudioContent::audio_channel_names () const
+{
+ vector<string> n;
+
+ int t = 1;
+ BOOST_FOREACH (AudioStreamPtr i, audio_streams ()) {
+ for (int j = 0; j < i->channels(); ++j) {
+ n.push_back (String::compose ("%1:%2", t, j + 1));
+ }
+ ++t;
+ }
+
+ return n;
+}
diff --git a/src/lib/audio_content.h b/src/lib/audio_content.h
index 79dba9fda..63ce3d0fa 100644
--- a/src/lib/audio_content.h
+++ b/src/lib/audio_content.h
@@ -65,6 +65,7 @@ public:
boost::filesystem::path audio_analysis_path () const;
int resampled_audio_frame_rate () const;
bool has_rate_above_48k () const;
+ std::vector<std::string> audio_channel_names () const;
boost::signals2::connection analyse_audio (boost::function<void()>);
diff --git a/src/lib/audio_mapping.cc b/src/lib/audio_mapping.cc
index 65eb5fc96..fc3909a8a 100644
--- a/src/lib/audio_mapping.cc
+++ b/src/lib/audio_mapping.cc
@@ -35,63 +35,52 @@ using boost::shared_ptr;
using boost::dynamic_pointer_cast;
AudioMapping::AudioMapping ()
- : _content_channels (0)
+ : _input_channels (0)
+ , _output_channels (0)
{
}
-/** Create an empty AudioMapping for a given channel count.
- * @param channels Number of channels.
+/** Create an empty AudioMapping.
+ * @param input_channels Number of input channels.
+ * @param output_channels Number of output channels.
*/
-AudioMapping::AudioMapping (int channels)
+AudioMapping::AudioMapping (int input_channels, int output_channels)
{
- setup (channels);
+ setup (input_channels, output_channels);
}
void
-AudioMapping::setup (int c)
+AudioMapping::setup (int input_channels, int output_channels)
{
- _content_channels = c;
+ _input_channels = input_channels;
+ _output_channels = output_channels;
- _gain.resize (_content_channels);
- for (int i = 0; i < _content_channels; ++i) {
- _gain[i].resize (MAX_DCP_AUDIO_CHANNELS);
+ _gain.resize (_input_channels);
+ for (int i = 0; i < _input_channels; ++i) {
+ _gain[i].resize (_output_channels);
}
- _name.resize (_content_channels);
-
make_zero ();
}
void
AudioMapping::make_zero ()
{
- for (int i = 0; i < _content_channels; ++i) {
- for (int j = 0; j < MAX_DCP_AUDIO_CHANNELS; ++j) {
+ for (int i = 0; i < _input_channels; ++i) {
+ for (int j = 0; j < _output_channels; ++j) {
_gain[i][j] = 0;
}
}
}
-void
-AudioMapping::make_default ()
+AudioMapping::AudioMapping (cxml::ConstNodePtr node, int state_version)
{
- make_zero ();
-
- if (_content_channels == 1) {
- /* Mono -> Centre */
- set (0, dcp::CENTRE, 1);
+ if (state_version < 32) {
+ setup (node->number_child<int> ("ContentChannels"), MAX_DCP_AUDIO_CHANNELS);
} else {
- /* 1:1 mapping */
- for (int i = 0; i < min (_content_channels, MAX_DCP_AUDIO_CHANNELS); ++i) {
- set (i, static_cast<dcp::Channel> (i), 1);
- }
+ setup (node->number_child<int> ("InputChannels"), node->number_child<int> ("OutputChannels"));
}
-}
-
-AudioMapping::AudioMapping (cxml::ConstNodePtr node, int state_version)
-{
- setup (node->number_child<int> ("ContentChannels"));
if (state_version <= 5) {
/* Old-style: on/off mapping */
@@ -102,38 +91,47 @@ AudioMapping::AudioMapping (cxml::ConstNodePtr node, int state_version)
} else {
list<cxml::NodePtr> const c = node->node_children ("Gain");
for (list<cxml::NodePtr>::const_iterator i = c.begin(); i != c.end(); ++i) {
- set (
- (*i)->number_attribute<int> ("Content"),
- static_cast<dcp::Channel> ((*i)->number_attribute<int> ("DCP")),
- raw_convert<float> ((*i)->content ())
- );
+ if (state_version < 32) {
+ set (
+ (*i)->number_attribute<int> ("Content"),
+ static_cast<dcp::Channel> ((*i)->number_attribute<int> ("DCP")),
+ raw_convert<float> ((*i)->content ())
+ );
+ } else {
+ set (
+ (*i)->number_attribute<int> ("Input"),
+ (*i)->number_attribute<int> ("Output"),
+ raw_convert<float> ((*i)->content ())
+ );
+ }
}
}
}
void
-AudioMapping::set (int c, dcp::Channel d, float g)
+AudioMapping::set (int input_channel, int output_channel, float g)
{
- _gain[c][d] = g;
+ _gain[input_channel][output_channel] = g;
}
float
-AudioMapping::get (int c, dcp::Channel d) const
+AudioMapping::get (int input_channel, int output_channel) const
{
- return _gain[c][d];
+ return _gain[input_channel][output_channel];
}
void
AudioMapping::as_xml (xmlpp::Node* node) const
{
- node->add_child ("ContentChannels")->add_child_text (raw_convert<string> (_content_channels));
+ node->add_child ("InputChannels")->add_child_text (raw_convert<string> (_input_channels));
+ node->add_child ("OutputChannels")->add_child_text (raw_convert<string> (_output_channels));
- for (int c = 0; c < _content_channels; ++c) {
- for (int d = 0; d < MAX_DCP_AUDIO_CHANNELS; ++d) {
+ for (int c = 0; c < _input_channels; ++c) {
+ for (int d = 0; d < _output_channels; ++d) {
xmlpp::Element* t = node->add_child ("Gain");
- t->set_attribute ("Content", raw_convert<string> (c));
- t->set_attribute ("DCP", raw_convert<string> (d));
- t->add_child_text (raw_convert<string> (get (c, static_cast<dcp::Channel> (d))));
+ t->set_attribute ("Input", raw_convert<string> (c));
+ t->set_attribute ("Output", raw_convert<string> (d));
+ t->add_child_text (raw_convert<string> (get (c, d)));
}
}
}
@@ -145,9 +143,10 @@ string
AudioMapping::digest () const
{
MD5Digester digester;
- digester.add (_content_channels);
- for (int i = 0; i < _content_channels; ++i) {
- for (int j = 0; j < MAX_DCP_AUDIO_CHANNELS; ++j) {
+ digester.add (_input_channels);
+ digester.add (_output_channels);
+ for (int i = 0; i < _input_channels; ++i) {
+ for (int j = 0; j < _output_channels; ++j) {
digester.add (_gain[i][j]);
}
}
@@ -155,17 +154,17 @@ AudioMapping::digest () const
return digester.get ();
}
-list<dcp::Channel>
-AudioMapping::mapped_dcp_channels () const
+list<int>
+AudioMapping::mapped_output_channels () const
{
static float const minus_96_db = 0.000015849;
- list<dcp::Channel> mapped;
+ list<int> mapped;
for (vector<vector<float> >::const_iterator i = _gain.begin(); i != _gain.end(); ++i) {
for (size_t j = 0; j < i->size(); ++j) {
if (abs ((*i)[j]) > minus_96_db) {
- mapped.push_back ((dcp::Channel) j);
+ mapped.push_back (j);
}
}
}
@@ -185,9 +184,3 @@ AudioMapping::unmap_all ()
}
}
}
-
-void
-AudioMapping::set_name (int channel, string name)
-{
- _name[channel] = name;
-}
diff --git a/src/lib/audio_mapping.h b/src/lib/audio_mapping.h
index e37beaeb2..57169cc1e 100644
--- a/src/lib/audio_mapping.h
+++ b/src/lib/audio_mapping.h
@@ -38,49 +38,43 @@ namespace cxml {
}
/** @class AudioMapping.
- * @brief A many-to-many mapping from some content channels to DCP channels.
- *
- * The number of content channels is set on construction and fixed,
- * and then each of those content channels are mapped to each DCP channel
- * by a linear gain.
+ * @brief A many-to-many mapping of audio channels.
*/
class AudioMapping
{
public:
AudioMapping ();
- AudioMapping (int channels);
+ AudioMapping (int input_channels, int output_channels);
AudioMapping (cxml::ConstNodePtr, int);
/* Default copy constructor is fine */
void as_xml (xmlpp::Node *) const;
- void make_default ();
+ void make_zero ();
- void set (int, dcp::Channel, float);
- float get (int, dcp::Channel) const;
+ void set (int input_channel, int output_channel, float);
+ float get (int input_channel, int output_channel) const;
- int content_channels () const {
- return _content_channels;
+ int input_channels () const {
+ return _input_channels;
}
- void set_name (int channel, std::string name);
- std::string name (int channel) const {
- return _name[channel];
+ int output_channels () const {
+ return _output_channels;
}
-
+
std::string digest () const;
- std::list<dcp::Channel> mapped_dcp_channels () const;
+ std::list<int> mapped_output_channels () const;
void unmap_all ();
private:
- void setup (int);
- void make_zero ();
-
- int _content_channels;
+ void setup (int input_channels, int output_channels);
+
+ int _input_channels;
+ int _output_channels;
std::vector<std::vector<float> > _gain;
- std::vector<std::string> _name;
};
#endif
diff --git a/src/lib/audio_processor.h b/src/lib/audio_processor.h
index 610e973a0..114756f91 100644
--- a/src/lib/audio_processor.h
+++ b/src/lib/audio_processor.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-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
@@ -17,6 +17,10 @@
*/
+/** @file src/lib/audio_processor.h
+ * @brief AudioProcessor class.
+ */
+
#ifndef DCPOMATIC_AUDIO_PROCESSOR_H
#define DCPOMATIC_AUDIO_PROCESSOR_H
@@ -24,21 +28,39 @@
#include <boost/shared_ptr.hpp>
#include <list>
#include <string>
+#include <vector>
class AudioBuffers;
+class AudioMapping;
+/** @class AudioProcessor
+ * @brief A parent class for processors of audio data.
+ *
+ * These are used to process data before it goes into the DCP, for things like
+ * stereo -> 5.1 upmixing.
+ */
class AudioProcessor
{
public:
virtual ~AudioProcessor () {}
+ /** @return User-visible (translated) name */
virtual std::string name () const = 0;
+ /** @return An internal identifier */
virtual std::string id () const = 0;
+ /** @return Number of input channels */
virtual ChannelCount in_channels () const = 0;
- virtual int out_channels (int) const = 0;
+ /** @return Number of output channels */
+ virtual int out_channels () const = 0;
+ /** @return A clone of this AudioProcessor for operation at the specified sampling rate */
virtual boost::shared_ptr<AudioProcessor> clone (int sampling_rate) const = 0;
+ /** Process some data, returning the processed result */
virtual boost::shared_ptr<AudioBuffers> run (boost::shared_ptr<const AudioBuffers>) = 0;
virtual void flush () {}
+ /** Make the supplied audio mapping into a sensible default for this processor */
+ virtual void make_audio_mapping_default (AudioMapping& mapping) const = 0;
+ /** @return the user-visible (translated) names of each of our inputs, in order */
+ virtual std::vector<std::string> input_names () const = 0;
static std::list<AudioProcessor const *> all ();
static void setup_audio_processors ();
diff --git a/src/lib/audio_stream.cc b/src/lib/audio_stream.cc
index a4fa8bd9b..bf55e0255 100644
--- a/src/lib/audio_stream.cc
+++ b/src/lib/audio_stream.cc
@@ -19,11 +19,12 @@
#include "audio_stream.h"
#include "audio_mapping.h"
+#include "util.h"
AudioStream::AudioStream (int frame_rate, int channels)
: _frame_rate (frame_rate)
{
- _mapping = AudioMapping (channels);
+ _mapping = AudioMapping (channels, MAX_DCP_AUDIO_CHANNELS);
}
AudioStream::AudioStream (int frame_rate, AudioMapping mapping)
@@ -51,5 +52,5 @@ int
AudioStream::channels () const
{
boost::mutex::scoped_lock lm (_mutex);
- return _mapping.content_channels ();
+ return _mapping.input_channels ();
}
diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc
index 1278c4c10..9dc4afab9 100644
--- a/src/lib/ffmpeg_content.cc
+++ b/src/lib/ffmpeg_content.cc
@@ -173,7 +173,7 @@ FFmpegContent::examine (shared_ptr<Job> job)
if (!_audio_streams.empty ()) {
AudioMapping m = _audio_streams.front()->mapping ();
- m.make_default ();
+ film->make_audio_mapping_default (m);
_audio_streams.front()->set_mapping (m);
}
diff --git a/src/lib/film.cc b/src/lib/film.cc
index 0e55ec1d3..90bfad6a2 100644
--- a/src/lib/film.cc
+++ b/src/lib/film.cc
@@ -595,11 +595,11 @@ Film::isdcf_name (bool if_created_now) const
/* Find all mapped channels */
- list<dcp::Channel> mapped;
+ list<int> mapped;
for (ContentList::const_iterator i = cl.begin(); i != cl.end(); ++i) {
shared_ptr<const AudioContent> ac = dynamic_pointer_cast<const AudioContent> (*i);
if (ac) {
- list<dcp::Channel> c = ac->audio_mapping().mapped_dcp_channels ();
+ list<int> c = ac->audio_mapping().mapped_output_channels ();
copy (c.begin(), c.end(), back_inserter (mapped));
}
}
@@ -611,13 +611,13 @@ Film::isdcf_name (bool if_created_now) const
int non_lfe = 0;
int lfe = 0;
- for (list<dcp::Channel>::const_iterator i = mapped.begin(); i != mapped.end(); ++i) {
- if (static_cast<int> (*i) >= audio_channels()) {
+ for (list<int>::const_iterator i = mapped.begin(); i != mapped.end(); ++i) {
+ if (*i >= audio_channels()) {
/* This channel is mapped but is not included in the DCP */
continue;
}
- if ((*i) == dcp::LFE) {
+ if (static_cast<dcp::Channel> (*i) == dcp::LFE) {
++lfe;
} else {
++non_lfe;
@@ -1160,3 +1160,53 @@ Film::subtitle_language () const
return all;
}
+
+/** Change the gains of the supplied AudioMapping to make it a default
+ * for this film. The defaults are guessed based on what processor (if any)
+ * is in use and the number of input channels.
+ */
+void
+Film::make_audio_mapping_default (AudioMapping& mapping) const
+{
+ if (audio_processor ()) {
+ audio_processor()->make_audio_mapping_default (mapping);
+ } else {
+ mapping.make_zero ();
+ if (mapping.input_channels() == 1) {
+ /* Mono -> Centre */
+ mapping.set (0, static_cast<int> (dcp::CENTRE), 1);
+ } else {
+ /* 1:1 mapping */
+ for (int i = 0; i < min (mapping.input_channels(), mapping.output_channels()); ++i) {
+ mapping.set (i, i, 1);
+ }
+ }
+ }
+}
+
+/** @return The names of the channels that audio contents' outputs are passed into;
+ * this is either the DCP or a AudioProcessor.
+ */
+vector<string>
+Film::audio_output_names () const
+{
+ if (audio_processor ()) {
+ return audio_processor()->input_names ();
+ }
+
+ vector<string> n;
+ n.push_back (_("L"));
+ n.push_back (_("R"));
+ n.push_back (_("C"));
+ n.push_back (_("Lfe"));
+ n.push_back (_("Ls"));
+ n.push_back (_("Rs"));
+ n.push_back (_("HI"));
+ n.push_back (_("VI"));
+ n.push_back (_("Lc"));
+ n.push_back (_("Rc"));
+ n.push_back (_("BsL"));
+ n.push_back (_("BsR"));
+
+ return vector<string> (n.begin(), n.begin() + audio_channels ());
+}
diff --git a/src/lib/film.h b/src/lib/film.h
index 8d7d2e0fb..6008160cd 100644
--- a/src/lib/film.h
+++ b/src/lib/film.h
@@ -48,6 +48,7 @@ class Playlist;
class AudioContent;
class Screen;
class AudioProcessor;
+class AudioMapping;
struct isdcf_name_test;
/** @class Film
@@ -137,6 +138,9 @@ public:
std::string subtitle_language () const;
+ void make_audio_mapping_default (AudioMapping & mapping) const;
+ std::vector<std::string> audio_output_names () const;
+
/** Identifiers for the parts of our state;
used for signalling changes.
*/
diff --git a/src/lib/mid_side_decoder.cc b/src/lib/mid_side_decoder.cc
index be82f6754..fe6282261 100644
--- a/src/lib/mid_side_decoder.cc
+++ b/src/lib/mid_side_decoder.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-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
@@ -19,10 +19,13 @@
#include "mid_side_decoder.h"
#include "audio_buffers.h"
+#include "audio_mapping.h"
#include "i18n.h"
using std::string;
+using std::min;
+using std::vector;
using boost::shared_ptr;
string
@@ -44,7 +47,7 @@ MidSideDecoder::in_channels () const
}
int
-MidSideDecoder::out_channels (int) const
+MidSideDecoder::out_channels () const
{
return 3;
}
@@ -70,3 +73,26 @@ MidSideDecoder::run (shared_ptr<const AudioBuffers> in)
return out;
}
+
+void
+MidSideDecoder::make_audio_mapping_default (AudioMapping& mapping) const
+{
+ /* Just map the first two input channels to our M/S */
+ mapping.make_zero ();
+ for (int i = 0; i < min (2, mapping.input_channels()); ++i) {
+ mapping.set (i, i, 1);
+ }
+}
+
+vector<string>
+MidSideDecoder::input_names () const
+{
+ vector<string> n;
+
+ /// TRANSLATORS: this is the name of the `mid' channel for mid-side decoding
+ n.push_back (_("Mid"));
+ /// TRANSLATORS: this is the name of the `side' channel for mid-side decoding
+ n.push_back (_("Side"));
+
+ return n;
+}
diff --git a/src/lib/mid_side_decoder.h b/src/lib/mid_side_decoder.h
index dac6cb7d9..197c7b33b 100644
--- a/src/lib/mid_side_decoder.h
+++ b/src/lib/mid_side_decoder.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-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
@@ -25,9 +25,9 @@ public:
std::string name () const;
std::string id () const;
ChannelCount in_channels () const;
- int out_channels (int) const;
+ int out_channels () const;
boost::shared_ptr<AudioProcessor> clone (int) const;
boost::shared_ptr<AudioBuffers> run (boost::shared_ptr<const AudioBuffers>);
+ void make_audio_mapping_default (AudioMapping& mapping) const;
+ std::vector<std::string> input_names () const;
};
-
-
diff --git a/src/lib/player.cc b/src/lib/player.cc
index 1a55a8472..ac5a70570 100644
--- a/src/lib/player.cc
+++ b/src/lib/player.cc
@@ -455,14 +455,14 @@ Player::get_audio (DCPTime time, DCPTime length, bool accurate)
shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), all.audio->frames()));
dcp_mapped->make_silent ();
AudioMapping map = j->mapping ();
- for (int i = 0; i < map.content_channels(); ++i) {
+ for (int i = 0; i < map.input_channels(); ++i) {
for (int j = 0; j < _film->audio_channels(); ++j) {
- if (map.get (i, static_cast<dcp::Channel> (j)) > 0) {
+ if (map.get (i, j) > 0) {
dcp_mapped->accumulate_channel (
all.audio.get(),
i,
j,
- map.get (i, static_cast<dcp::Channel> (j))
+ map.get (i, j)
);
}
}
diff --git a/src/lib/single_stream_audio_content.cc b/src/lib/single_stream_audio_content.cc
index a38ef0e1e..f978fa423 100644
--- a/src/lib/single_stream_audio_content.cc
+++ b/src/lib/single_stream_audio_content.cc
@@ -60,11 +60,14 @@ SingleStreamAudioContent::as_xml (xmlpp::Node* node) const
void
SingleStreamAudioContent::take_from_audio_examiner (shared_ptr<AudioExaminer> examiner)
{
+ shared_ptr<const Film> film = _film.lock ();
+ DCPOMATIC_ASSERT (film);
+
{
boost::mutex::scoped_lock lm (_mutex);
_audio_stream.reset (new AudioStream (examiner->audio_frame_rate(), examiner->audio_channels ()));
AudioMapping m = _audio_stream->mapping ();
- m.make_default ();
+ film->make_audio_mapping_default (m);
_audio_stream->set_mapping (m);
}
diff --git a/src/lib/upmixer_a.cc b/src/lib/upmixer_a.cc
index dce08fe37..1edc0104d 100644
--- a/src/lib/upmixer_a.cc
+++ b/src/lib/upmixer_a.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-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
@@ -19,10 +19,13 @@
#include "upmixer_a.h"
#include "audio_buffers.h"
+#include "audio_mapping.h"
#include "i18n.h"
using std::string;
+using std::min;
+using std::vector;
using boost::shared_ptr;
UpmixerA::UpmixerA (int sampling_rate)
@@ -56,7 +59,7 @@ UpmixerA::in_channels () const
}
int
-UpmixerA::out_channels (int) const
+UpmixerA::out_channels () const
{
return 6;
}
@@ -107,3 +110,22 @@ UpmixerA::flush ()
_ls.flush ();
_rs.flush ();
}
+
+void
+UpmixerA::make_audio_mapping_default (AudioMapping& mapping) const
+{
+ /* Just map the first two input channels to our L/R */
+ mapping.make_zero ();
+ for (int i = 0; i < min (2, mapping.input_channels()); ++i) {
+ mapping.set (i, i, 1);
+ }
+}
+
+vector<string>
+UpmixerA::input_names () const
+{
+ vector<string> n;
+ n.push_back (_("Upmix L"));
+ n.push_back (_("Upmix R"));
+ return n;
+}
diff --git a/src/lib/upmixer_a.h b/src/lib/upmixer_a.h
index 32e3f5fb6..9a927b0cf 100644
--- a/src/lib/upmixer_a.h
+++ b/src/lib/upmixer_a.h
@@ -28,10 +28,12 @@ public:
std::string name () const;
std::string id () const;
ChannelCount in_channels () const;
- int out_channels (int) const;
+ int out_channels () const;
boost::shared_ptr<AudioProcessor> clone (int) const;
boost::shared_ptr<AudioBuffers> run (boost::shared_ptr<const AudioBuffers>);
void flush ();
+ void make_audio_mapping_default (AudioMapping& mapping) const;
+ std::vector<std::string> input_names () const;
private:
BandPassAudioFilter _left;
diff --git a/src/wx/audio_mapping_view.cc b/src/wx/audio_mapping_view.cc
index c61ce7f06..8f55043be 100644
--- a/src/wx/audio_mapping_view.cc
+++ b/src/wx/audio_mapping_view.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-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
@@ -37,6 +37,7 @@ using std::cout;
using std::list;
using std::string;
using std::max;
+using std::vector;
using boost::shared_ptr;
using boost::lexical_cast;
@@ -125,8 +126,7 @@ AudioMappingView::AudioMappingView (wxWindow* parent)
_grid->EnableEditing (false);
_grid->SetCellHighlightPenWidth (0);
_grid->SetDefaultRenderer (new NoSelectionStringRenderer);
-
- set_column_labels ();
+ _grid->AutoSize ();
_sizer = new wxBoxSizer (wxVERTICAL);
_sizer->Add (_grid, 1, wxEXPAND | wxALL);
@@ -148,8 +148,9 @@ AudioMappingView::AudioMappingView (wxWindow* parent)
Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&AudioMappingView::edit, this), ID_edit);
}
+/** Called when any gain value has changed */
void
-AudioMappingView::map_changed ()
+AudioMappingView::map_values_changed ()
{
update_cells ();
Changed (_map);
@@ -163,7 +164,7 @@ AudioMappingView::left_click (wxGridEvent& ev)
return;
}
- dcp::Channel d = static_cast<dcp::Channel> (ev.GetCol() - 1);
+ int const d = ev.GetCol() - 1;
if (_map.get (ev.GetRow(), d) > 0) {
_map.set (ev.GetRow(), d, 0);
@@ -171,7 +172,7 @@ AudioMappingView::left_click (wxGridEvent& ev)
_map.set (ev.GetRow(), d, 1);
}
- map_changed ();
+ map_values_changed ();
}
void
@@ -189,33 +190,33 @@ AudioMappingView::right_click (wxGridEvent& ev)
void
AudioMappingView::off ()
{
- _map.set (_menu_row, static_cast<dcp::Channel> (_menu_column - 1), 0);
- map_changed ();
+ _map.set (_menu_row, _menu_column - 1, 0);
+ map_values_changed ();
}
void
AudioMappingView::full ()
{
- _map.set (_menu_row, static_cast<dcp::Channel> (_menu_column - 1), 1);
- map_changed ();
+ _map.set (_menu_row, _menu_column - 1, 1);
+ map_values_changed ();
}
void
AudioMappingView::minus6dB ()
{
- _map.set (_menu_row, static_cast<dcp::Channel> (_menu_column - 1), pow (10, -6.0 / 20));
- map_changed ();
+ _map.set (_menu_row, _menu_column - 1, pow (10, -6.0 / 20));
+ map_values_changed ();
}
void
AudioMappingView::edit ()
{
- dcp::Channel d = static_cast<dcp::Channel> (_menu_column - 1);
+ int const d = _menu_column - 1;
AudioGainDialog* dialog = new AudioGainDialog (this, _menu_row, _menu_column - 1, _map.get (_menu_row, d));
if (dialog->ShowModal () == wxID_OK) {
_map.set (_menu_row, d, dialog->value ());
- map_changed ();
+ map_values_changed ();
}
dialog->Destroy ();
@@ -229,104 +230,51 @@ AudioMappingView::set (AudioMapping map)
}
void
-AudioMappingView::update_cells ()
+AudioMappingView::set_input_channels (vector<string> const & names)
{
- if (_grid->GetNumberRows ()) {
- _grid->DeleteRows (0, _grid->GetNumberRows ());
+ for (int i = 0; i < _grid->GetNumberRows(); ++i) {
+ _grid->SetCellValue (i, 0, std_to_wx (names[i]));
}
-
- _grid->InsertRows (0, _map.content_channels ());
-
- for (int i = 0; i < _map.content_channels(); ++i) {
- for (int j = 0; j < MAX_DCP_AUDIO_CHANNELS; ++j) {
- _grid->SetCellRenderer (i, j + 1, new ValueRenderer);
- }
- }
-
- for (int i = 0; i < _map.content_channels(); ++i) {
- _grid->SetCellValue (i, 0, wxString::Format (wxT("%d"), i + 1));
-
- for (int j = 1; j < _grid->GetNumberCols(); ++j) {
- _grid->SetCellValue (i, j, std_to_wx (raw_convert<string> (_map.get (i, static_cast<dcp::Channel> (j - 1)))));
- }
- }
-
- _grid->AutoSize ();
}
-/** @param c Number of DCP channels */
void
-AudioMappingView::set_channels (int c)
+AudioMappingView::set_output_channels (vector<string> const & names)
{
- c++;
+ int const o = names.size() + 1;
+ if (o < _grid->GetNumberCols ()) {
+ _grid->DeleteCols (o, _grid->GetNumberCols() - o);
+ } else if (o > _grid->GetNumberCols ()) {
+ _grid->InsertCols (_grid->GetNumberCols(), o - _grid->GetNumberCols());
+ }
+
+ _grid->SetColLabelValue (0, _("Content"));
- if (c < _grid->GetNumberCols ()) {
- _grid->DeleteCols (c, _grid->GetNumberCols() - c);
- } else if (c > _grid->GetNumberCols ()) {
- _grid->InsertCols (_grid->GetNumberCols(), c - _grid->GetNumberCols());
- set_column_labels ();
+ for (size_t i = 0; i < names.size(); ++i) {
+ _grid->SetColLabelValue (i + 1, std_to_wx (names[i]));
}
update_cells ();
}
void
-AudioMappingView::set_column_labels ()
+AudioMappingView::update_cells ()
{
- int const c = _grid->GetNumberCols ();
-
- _grid->SetColLabelValue (0, _("Content"));
-
-#if MAX_DCP_AUDIO_CHANNELS != 12
-#warning AudioMappingView::set_column_labels() is expecting the wrong MAX_DCP_AUDIO_CHANNELS
-#endif
-
- if (c > 0) {
- _grid->SetColLabelValue (1, _("L"));
- }
-
- if (c > 1) {
- _grid->SetColLabelValue (2, _("R"));
- }
-
- if (c > 2) {
- _grid->SetColLabelValue (3, _("C"));
- }
-
- if (c > 3) {
- _grid->SetColLabelValue (4, _("Lfe"));
- }
-
- if (c > 4) {
- _grid->SetColLabelValue (5, _("Ls"));
- }
-
- if (c > 5) {
- _grid->SetColLabelValue (6, _("Rs"));
- }
-
- if (c > 6) {
- _grid->SetColLabelValue (7, _("HI"));
- }
-
- if (c > 7) {
- _grid->SetColLabelValue (8, _("VI"));
- }
-
- if (c > 8) {
- _grid->SetColLabelValue (9, _("Lc"));
+ if (_grid->GetNumberRows ()) {
+ _grid->DeleteRows (0, _grid->GetNumberRows ());
}
- if (c > 9) {
- _grid->SetColLabelValue (10, _("Rc"));
- }
+ _grid->InsertRows (0, _map.input_channels ());
- if (c > 10) {
- _grid->SetColLabelValue (11, _("BsL"));
+ for (int i = 0; i < _map.input_channels(); ++i) {
+ for (int j = 0; j < _map.output_channels(); ++j) {
+ _grid->SetCellRenderer (i, j + 1, new ValueRenderer);
+ }
}
-
- if (c > 11) {
- _grid->SetColLabelValue (12, _("BsR"));
+
+ for (int i = 0; i < _map.input_channels(); ++i) {
+ for (int j = 1; j < _grid->GetNumberCols(); ++j) {
+ _grid->SetCellValue (i, j, std_to_wx (raw_convert<string> (_map.get (i, j - 1))));
+ }
}
_grid->AutoSize ();
@@ -351,7 +299,7 @@ AudioMappingView::mouse_moved (wxMouseEvent& ev)
if (row != _last_tooltip_row || column != _last_tooltip_column) {
wxString s;
- float const gain = _map.get (row, static_cast<dcp::Channel> (column - 1));
+ float const gain = _map.get (row, column - 1);
if (gain == 0) {
s = wxString::Format (_("No audio will be passed from content channel %d to DCP channel %d."), row + 1, column);
} else if (gain == 1) {
diff --git a/src/wx/audio_mapping_view.h b/src/wx/audio_mapping_view.h
index 7ed699463..4210d7554 100644
--- a/src/wx/audio_mapping_view.h
+++ b/src/wx/audio_mapping_view.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-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
@@ -18,10 +18,8 @@
*/
/** @file src/wx/audio_mapping_view.h
- * @brief AudioMappingView class
+ * @brief AudioMappingView class.
*
- * This class displays the mapping of one set of audio channels to another,
- * with gain values on each node of the map.
*/
#include <boost/signals2.hpp>
@@ -29,13 +27,29 @@
#include <wx/grid.h>
#include "lib/audio_mapping.h"
+/** @class AudioMappingView
+ * @brief This class displays the mapping of one set of audio channels to another,
+ * with gain values on each node of the map.
+ *
+ * The AudioMapping passed to set() describes the actual channel mapping,
+ * and the names passed to set_input_channels() and set_output_channels() are
+ * used to label the rows and columns.
+ *
+ * The display's row count is equal to the AudioMapping's input channel count,
+ * and the column count is equal to the number of name passed to
+ * set_output_channels(). Any other output channels in the AudioMapping are
+ * hidden from view. Thus input channels are never hidden but output channels
+ * might be.
+ */
+
class AudioMappingView : public wxPanel
{
public:
AudioMappingView (wxWindow *);
void set (AudioMapping);
- void set_channels (int);
+ void set_input_channels (std::vector<std::string> const & names);
+ void set_output_channels (std::vector<std::string> const & names);
boost::signals2::signal<void (AudioMapping)> Changed;
@@ -43,9 +57,8 @@ private:
void left_click (wxGridEvent &);
void right_click (wxGridEvent &);
void mouse_moved (wxMouseEvent &);
- void set_column_labels ();
void update_cells ();
- void map_changed ();
+ void map_values_changed ();
void off ();
void full ();
diff --git a/src/wx/audio_panel.cc b/src/wx/audio_panel.cc
index c34a67032..436e6db4c 100644
--- a/src/wx/audio_panel.cc
+++ b/src/wx/audio_panel.cc
@@ -110,8 +110,8 @@ AudioPanel::film_changed (Film::Property property)
{
switch (property) {
case Film::AUDIO_CHANNELS:
- _mapping->set_channels (_parent->film()->audio_channels ());
- _sizer->Layout ();
+ case Film::AUDIO_PROCESSOR:
+ _mapping->set_output_channels (_parent->film()->audio_output_names ());
break;
case Film::VIDEO_FRAME_RATE:
setup_description ();
@@ -124,17 +124,14 @@ AudioPanel::film_changed (Film::Property property)
void
AudioPanel::film_content_changed (int property)
{
- AudioContentList ac = _parent->selected_audio ();
- shared_ptr<AudioContent> acs;
- shared_ptr<FFmpegContent> fcs;
- if (ac.size() == 1) {
- acs = ac.front ();
- fcs = dynamic_pointer_cast<FFmpegContent> (acs);
- }
-
if (property == AudioContentProperty::AUDIO_STREAMS) {
- _mapping->set (acs ? acs->audio_mapping () : AudioMapping ());
- _sizer->Layout ();
+ AudioContentList ac = _parent->selected_audio ();
+ if (ac.size() == 1) {
+ _mapping->set (ac.front()->audio_mapping());
+ _mapping->set_input_channels (ac.front()->audio_channel_names ());
+ } else {
+ _mapping->set (AudioMapping ());
+ }
setup_description ();
}
}
diff --git a/src/wx/dcp_panel.cc b/src/wx/dcp_panel.cc
index 7a5f0554f..022fe9a06 100644
--- a/src/wx/dcp_panel.cc
+++ b/src/wx/dcp_panel.cc
@@ -696,7 +696,5 @@ DCPPanel::audio_processor_changed ()
}
string const s = string_client_data (_audio_processor->GetClientObject (_audio_processor->GetSelection ()));
- if (s != "none") {
- _film->set_audio_processor (AudioProcessor::from_id (s));
- }
+ _film->set_audio_processor (AudioProcessor::from_id (s));
}
diff --git a/src/wx/timeline.cc b/src/wx/timeline.cc
index c1713bb61..b0197ad3d 100644
--- a/src/wx/timeline.cc
+++ b/src/wx/timeline.cc
@@ -115,7 +115,7 @@ Timeline::recreate_views ()
}
shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (*i);
- if (ac && !ac->audio_mapping().mapped_dcp_channels().empty ()) {
+ if (ac && !ac->audio_mapping().mapped_output_channels().empty ()) {
_views.push_back (shared_ptr<TimelineView> (new TimelineAudioContentView (*this, *i)));
}