Various work on audio mapping.
authorCarl Hetherington <cth@carlh.net>
Wed, 3 Jun 2015 12:17:37 +0000 (13:17 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 3 Jun 2015 12:17:37 +0000 (13:17 +0100)
Fix everything up so that the audio mapping view in
the audio panel reflects the processor (or lack of).

22 files changed:
src/lib/audio_content.cc
src/lib/audio_content.h
src/lib/audio_mapping.cc
src/lib/audio_mapping.h
src/lib/audio_processor.h
src/lib/audio_stream.cc
src/lib/ffmpeg_content.cc
src/lib/film.cc
src/lib/film.h
src/lib/mid_side_decoder.cc
src/lib/mid_side_decoder.h
src/lib/player.cc
src/lib/single_stream_audio_content.cc
src/lib/upmixer_a.cc
src/lib/upmixer_a.h
src/wx/audio_mapping_view.cc
src/wx/audio_mapping_view.h
src/wx/audio_panel.cc
src/wx/dcp_panel.cc
src/wx/timeline.cc
test/audio_mapping_test.cc
test/stream_test.cc

index 3ea31f673457f4200642f29ab8640c04ce240512..b6749d20be0f44794dadd81abdedb9b7878fdedd 100644 (file)
@@ -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;
+}
index 79dba9fdaf340716c0ca8745ae5890c8ce2b6c32..63ce3d0fa420f84048005d6ce52f5d624fb487da 100644 (file)
@@ -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()>);
 
index 65eb5fc962c77baa42b7fb4ca5faec9b78a47190..fc3909a8aa0ab5240dd7d17b968bf102e2783d70 100644 (file)
@@ -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;
-}
index e37beaeb26eb77dce33fd0a75a7ab8dee51d1086..57169cc1e7d8c13c21208691d344ec1e8fe2431b 100644 (file)
@@ -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
index 610e973a0cbd729681e6aaf0c9b3e6ee4e5e53c5..114756f9113617eed2ed7118b71074efdb5af6db 100644 (file)
@@ -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
 
 */
 
+/** @file  src/lib/audio_processor.h
+ *  @brief AudioProcessor class.
+ */
+
 #ifndef DCPOMATIC_AUDIO_PROCESSOR_H
 #define DCPOMATIC_AUDIO_PROCESSOR_H
 
 #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 ();
index a4fa8bd9b8472c84ecbd84b8734f3957922b379c..bf55e025502aeac06d9fefeff44c438d9a23f598 100644 (file)
 
 #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 ();
 }
index 1278c4c10767125d38ebbee063d7b086c8d77b7d..9dc4afab9b3b1233d7f6d60301fccadef72475e9 100644 (file)
@@ -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);
                }
 
index 0e55ec1d3b86233d36ad708bdc108c57c70bd618..90bfad6a2cbba3c7d0b80e8e2fd08c58920b5b98 100644 (file)
@@ -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 ());
+}
index 8d7d2e0fbdbfa65e96da76bea174e661af56d04f..6008160cd36682ed8fa5b0f69a8ad2c0a54115f5 100644 (file)
@@ -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.
        */
index be82f67542a2e3f5109d08bf6c503398ea7a12c4..fe628226151e652f66ee12096d03c4ef295557fb 100644 (file)
@@ -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
 
 #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;
+}
index dac6cb7d9a7516dc159c65f46d4fd5cea6746e40..197c7b33bcf453ab783f66b5221bb492f6137be8 100644 (file)
@@ -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;
 };
-
-       
index 1a55a84728c886549ba8eaf518c8904297e45374..ac5a705708c7db2d3227937f98b9593d372fb83a 100644 (file)
@@ -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)
                                                        );
                                        }
                                }
index a38ef0e1e8ed2a6e2c8ac6b23fa04ec6ee3fccac..f978fa423150f912eee111a23a5b3e505c10c303 100644 (file)
@@ -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);
        }
 
index dce08fe37431212f33bfa11d2c8527e2662c5ae9..1edc0104db5337b6583addc9f396f354e48481ab 100644 (file)
@@ -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
 
 #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;
+}
index 32e3f5fb625c4b7875c5407dc509acfe180e09e1..9a927b0cff42b9fd9fef54bea20c9ab32a7074fd 100644 (file)
@@ -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;
index c61ce7f06fdb6e1c003c80b002adb4f79eedc0d8..8f55043befc8134eb1df2459b9db043b150df4df 100644 (file)
@@ -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) {
index 7ed6994633c111a7813951ae92c78dcca3023410..4210d755493de61d39e54a8f7756e8a2cb5102e0 100644 (file)
@@ -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
 */
 
 /** @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>
 #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 ();
index c34a67032b04dca916d564cc3918ec96da9c6aa2..436e6db4ca2a309a5e3197017998e3b62b8a2839 100644 (file)
@@ -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 ();
        }
 }
index 7a5f0554f00bb836fe87b8e8d300bb972207c3ae..022fe9a062f0b31cbc0662563aa2c8f1a2bbf9b4 100644 (file)
@@ -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));
 }
index c1713bb61262e2bcc27047a60eadb2b9186baf47..b0197ad3dd12a19abb2b357b517197b5b69d9c05 100644 (file)
@@ -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)));
                }
 
index fc597b91df10e4ca9dadaf8303a4b7cb844de983..14c6d031d8a7a306a8654e71849534a09dd0237e 100644 (file)
 BOOST_AUTO_TEST_CASE (audio_mapping_test)
 {
        AudioMapping none;
-       BOOST_CHECK_EQUAL (none.content_channels(), 0);
+       BOOST_CHECK_EQUAL (none.input_channels(), 0);
 
-       AudioMapping four (4);
-       BOOST_CHECK_EQUAL (four.content_channels(), 4);
-       four.make_default ();
+       AudioMapping four (4, MAX_DCP_AUDIO_CHANNELS);
+       BOOST_CHECK_EQUAL (four.input_channels(), 4);
 
-       for (int i = 0; i < 4; ++i) {
-               for (int j = 0; j < MAX_DCP_AUDIO_CHANNELS; ++j) {
-                       BOOST_CHECK_EQUAL (four.get (i, static_cast<dcp::Channel> (j)), i == j ? 1 : 0);
-               }
-       }
-
-       four.set (0, dcp::RIGHT, 1);
-       BOOST_CHECK_EQUAL (four.get (0, dcp::RIGHT), 1);
+       four.set (0, 1, 1);
+       BOOST_CHECK_EQUAL (four.get (0, 1), 1);
 }
index de2108066bbc5c3147903bacdb17cbe759dafc61..800bbd049c0c64cc1401378b39d4fca963d40a36 100644 (file)
@@ -76,13 +76,13 @@ BOOST_AUTO_TEST_CASE (stream_test)
        BOOST_CHECK_EQUAL (a.frame_rate(), 44100);
        BOOST_CHECK_EQUAL (a.channels(), 2);
        BOOST_CHECK_EQUAL (a.name, "hello there world");
-       BOOST_CHECK_EQUAL (a.mapping().content_channels(), 2);
+       BOOST_CHECK_EQUAL (a.mapping().input_channels(), 2);
 
-       BOOST_CHECK_EQUAL (a.mapping().get (0, dcp::LEFT), 1);
-       BOOST_CHECK_EQUAL (a.mapping().get (0, dcp::RIGHT), 0);
-       BOOST_CHECK_EQUAL (a.mapping().get (0, dcp::CENTRE), 1);
-       BOOST_CHECK_EQUAL (a.mapping().get (1, dcp::LEFT), 0);
-       BOOST_CHECK_EQUAL (a.mapping().get (1, dcp::RIGHT), 1);
-       BOOST_CHECK_EQUAL (a.mapping().get (1, dcp::CENTRE), 1);
+       BOOST_CHECK_EQUAL (a.mapping().get (0, static_cast<int> (dcp::LEFT)), 1);
+       BOOST_CHECK_EQUAL (a.mapping().get (0, static_cast<int> (dcp::RIGHT)), 0);
+       BOOST_CHECK_EQUAL (a.mapping().get (0, static_cast<int> (dcp::CENTRE)), 1);
+       BOOST_CHECK_EQUAL (a.mapping().get (1, static_cast<int> (dcp::LEFT)), 0);
+       BOOST_CHECK_EQUAL (a.mapping().get (1, static_cast<int> (dcp::RIGHT)), 1);
+       BOOST_CHECK_EQUAL (a.mapping().get (1, static_cast<int> (dcp::CENTRE)), 1);
 }