Add simple stereo-5.1 upmixer.
authorCarl Hetherington <cth@carlh.net>
Tue, 15 Jul 2014 12:15:02 +0000 (13:15 +0100)
committerCarl Hetherington <cth@carlh.net>
Tue, 15 Jul 2014 12:15:02 +0000 (13:15 +0100)
15 files changed:
src/lib/audio_buffers.cc
src/lib/audio_buffers.h
src/lib/audio_decoder.cc
src/lib/audio_filter.cc
src/lib/audio_filter.h
src/lib/audio_processor.cc
src/lib/audio_processor.h
src/lib/mid_side_decoder.cc
src/lib/mid_side_decoder.h
src/lib/single_stream_audio_content.cc
src/lib/upmixer_a.cc [new file with mode: 0644]
src/lib/upmixer_a.h [new file with mode: 0644]
src/lib/wscript
src/wx/audio_panel.cc
test/wscript

index 4ada94db867b59d4fe7425fc6b048e0a251ae721..56ca7a94b18c5860e3800f03740baa2c09480d59 100644 (file)
@@ -285,3 +285,29 @@ AudioBuffers::apply_gain (float dB)
                }
        }
 }
+
+/** @param c Channel index.
+ *  @return AudioBuffers object containing only channel `c' from this AudioBuffers.
+ */
+shared_ptr<AudioBuffers>
+AudioBuffers::channel (int c) const
+{
+       shared_ptr<AudioBuffers> o (new AudioBuffers (1, frames ()));
+       o->copy_channel_from (this, c, 0);
+       return o;
+}
+
+void
+AudioBuffers::copy_channel_from (AudioBuffers const * from, int from_channel, int to_channel)
+{
+       assert (from->frames() == frames());
+       memcpy (data(to_channel), from->data(from_channel), frames() * sizeof (float));
+}
+
+shared_ptr<AudioBuffers>
+AudioBuffers::clone () const
+{
+       shared_ptr<AudioBuffers> b (new AudioBuffers (channels (), frames ()));
+       b->copy_from (this, frames (), 0, 0);
+       return b;
+}
index 51488c39a45dff7e83445f2ede7d0dbce5b1a2a5..8cd67aaa729d52afc42a8ff5b11f3d42327de414 100644 (file)
@@ -39,6 +39,9 @@ public:
 
        AudioBuffers & operator= (AudioBuffers const &);
 
+       boost::shared_ptr<AudioBuffers> clone () const;
+       boost::shared_ptr<AudioBuffers> channel (int) const;
+
        void ensure_size (int);
 
        float** data () const {
@@ -64,6 +67,7 @@ public:
        void apply_gain (float);
 
        void copy_from (AudioBuffers const * from, int frames_to_copy, int read_offset, int write_offset);
+       void copy_channel_from (AudioBuffers const * from, int from_channel, int to_channel);
        void move (int from, int to, int frames);
        void accumulate_channel (AudioBuffers const * from, int from_channel, int to_channel, float gain = 1);
        void accumulate_frames (AudioBuffers const *, int read_offset, int write_offset, int frames);
index 19f31d30ac3f50fc08ac1ce68757da6b0b011255..e4f98c678ad3a150987431f7f587428a07603b10 100644 (file)
@@ -45,7 +45,7 @@ AudioDecoder::AudioDecoder (shared_ptr<const AudioContent> content)
        }
 
        if (content->audio_processor ()) {
-               _processor = content->audio_processor()->clone ();
+               _processor = content->audio_processor()->clone (content->resampled_audio_frame_rate ());
        }
 
        reset_decoded_audio ();
@@ -215,4 +215,7 @@ AudioDecoder::seek (ContentTime t, bool accurate)
        if (accurate) {
                _seek_reference = t;
        }
+       if (_processor) {
+               _processor->flush ();
+       }
 }
index 0cd2b18fb99499f0705188608100c9dbae77874e..59b5684ea62e2cd7e447599b215c6d1b6a44fc0e 100644 (file)
@@ -100,6 +100,12 @@ AudioFilter::run (shared_ptr<AudioBuffers> in)
        return out;
 }
 
+void
+AudioFilter::flush ()
+{
+       _tail.reset ();
+}
+
 LowPassAudioFilter::LowPassAudioFilter (float transition_bandwidth, float cutoff)
        : AudioFilter (transition_bandwidth)
 {
index 9dfcec58bbe589d9325cf9ef45b5cfc3af206e72..f361c27d2cf837508e53887ec7b97600b9310b68 100644 (file)
@@ -37,6 +37,8 @@ public:
 
        boost::shared_ptr<AudioBuffers> run (boost::shared_ptr<AudioBuffers> in);
 
+       void flush ();
+
 protected:
        friend class audio_filter_impulse_kernel_test;
        friend class audio_filter_impulse_input_test;
index 27146806b540e7a75049b0f68426fa8161b0cbb5..f350cc2aa0404553ce8f11ff8a8dbe10e99c143e 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "audio_processor.h"
 #include "mid_side_decoder.h"
+#include "upmixer_a.h"
 
 using std::string;
 using std::list;
@@ -29,6 +30,7 @@ void
 AudioProcessor::setup_audio_processors ()
 {
        _all.push_back (new MidSideDecoder ());
+       _all.push_back (new UpmixerA (48000));
 }
 
 AudioProcessor const *
index 7ff9f0ec61a9a5cec6fb06ad86674ce06e712a54..9b332e7fec50c955d7bc62a6bb27a49d0a440b34 100644 (file)
@@ -36,8 +36,9 @@ public:
        virtual std::string id () const = 0;
        virtual ChannelCount in_channels () const = 0;
        virtual int out_channels (int) const = 0;
-       virtual boost::shared_ptr<AudioProcessor> clone () const = 0;
+       virtual boost::shared_ptr<AudioProcessor> clone (int sampling_rate) const = 0;
        virtual boost::shared_ptr<AudioBuffers> run (boost::shared_ptr<const AudioBuffers>) = 0;
+       virtual void flush () {}
 
        static std::list<AudioProcessor const *> all ();
        static void setup_audio_processors ();
index a518a43894fae0e42eeafea2a393f18d85a9c98d..be82f67542a2e3f5109d08bf6c503398ea7a12c4 100644 (file)
@@ -50,7 +50,7 @@ MidSideDecoder::out_channels (int) const
 }
 
 shared_ptr<AudioProcessor>
-MidSideDecoder::clone () const
+MidSideDecoder::clone (int) const
 {
        return shared_ptr<AudioProcessor> (new MidSideDecoder ());
 }
index a6d2721b6ba832ad3b19466e1614a1b34dc53128..dac6cb7d9a7516dc159c65f46d4fd5cea6746e40 100644 (file)
@@ -26,7 +26,7 @@ public:
        std::string id () const;
        ChannelCount in_channels () const;
        int out_channels (int) const;
-       boost::shared_ptr<AudioProcessor> clone () const;
+       boost::shared_ptr<AudioProcessor> clone (int) const;
        boost::shared_ptr<AudioBuffers> run (boost::shared_ptr<const AudioBuffers>);
 };
 
index ac4da25ee720aa2253bd62262d703e28fd09cad6..52159760645ce12a5b27fcea2c650a78ef21e29b 100644 (file)
@@ -23,6 +23,7 @@
 #include "film.h"
 
 using std::string;
+using std::cout;
 using boost::shared_ptr;
 using dcp::raw_convert;
 
@@ -92,10 +93,12 @@ SingleStreamAudioContent::take_from_audio_examiner (shared_ptr<AudioExaminer> ex
        signal_changed (AudioContentProperty::AUDIO_LENGTH);
        signal_changed (AudioContentProperty::AUDIO_FRAME_RATE);
 
+       int const p = processed_audio_channels ();
+
        {
                boost::mutex::scoped_lock lm (_mutex);
                /* XXX: do this in signal_changed...? */
-               _audio_mapping = AudioMapping (_audio_channels);
+               _audio_mapping = AudioMapping (p);
                _audio_mapping.make_default ();
        }
        
diff --git a/src/lib/upmixer_a.cc b/src/lib/upmixer_a.cc
new file mode 100644 (file)
index 0000000..dce08fe
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+    Copyright (C) 2014 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "upmixer_a.h"
+#include "audio_buffers.h"
+
+#include "i18n.h"
+
+using std::string;
+using boost::shared_ptr;
+
+UpmixerA::UpmixerA (int sampling_rate)
+       : _left (0.02, 1900.0 / sampling_rate, 4800.0 / sampling_rate)
+       , _right (0.02, 1900.0 / sampling_rate, 4800.0 / sampling_rate)
+       , _centre (0.02, 150.0 / sampling_rate, 1900.0 / sampling_rate)
+       , _lfe (0.02, 20.0 / sampling_rate, 150.0 / sampling_rate)
+       , _ls (0.02, 4800.0 / sampling_rate, 20000.0 / sampling_rate)
+       , _rs (0.02, 4800.0 / sampling_rate, 20000.0 / sampling_rate)
+{
+
+}
+
+string
+UpmixerA::name () const
+{
+       return _("Stereo to 5.1 up-mixer A");
+}
+
+
+string
+UpmixerA::id () const
+{
+       return N_("stereo-5.1-upmix-a");
+}
+
+ChannelCount
+UpmixerA::in_channels () const
+{
+       return ChannelCount (2);
+}
+
+int
+UpmixerA::out_channels (int) const
+{
+       return 6;
+}
+
+shared_ptr<AudioProcessor>
+UpmixerA::clone (int sampling_rate) const
+{
+       return shared_ptr<AudioProcessor> (new UpmixerA (sampling_rate));
+}
+
+shared_ptr<AudioBuffers>
+UpmixerA::run (shared_ptr<const AudioBuffers> in)
+{
+       /* Input L and R */
+       shared_ptr<AudioBuffers> in_L = in->channel (0);
+       shared_ptr<AudioBuffers> in_R = in->channel (1);
+
+       /* Mix of L and R */
+       shared_ptr<AudioBuffers> in_LR = in_L->clone ();
+       in_LR->accumulate_frames (in_R.get(), 0, 0, in_R->frames ());
+       in_LR->apply_gain (0.5);
+
+       /* Run filters */
+       shared_ptr<AudioBuffers> L = _left.run (in_L);
+       shared_ptr<AudioBuffers> R = _right.run (in_R);
+       shared_ptr<AudioBuffers> C = _centre.run (in_LR);
+       shared_ptr<AudioBuffers> Lfe = _lfe.run (in_LR);
+       shared_ptr<AudioBuffers> Ls = _ls.run (in_L);
+       shared_ptr<AudioBuffers> Rs = _rs.run (in_R);
+
+       shared_ptr<AudioBuffers> out (new AudioBuffers (6, in->frames ()));
+       out->copy_channel_from (L.get(), 0, 0);
+       out->copy_channel_from (R.get(), 0, 1);
+       out->copy_channel_from (C.get(), 0, 2);
+       out->copy_channel_from (Lfe.get(), 0, 3);
+       out->copy_channel_from (Ls.get(), 0, 4);
+       out->copy_channel_from (Rs.get(), 0, 5);
+       return out;
+}
+
+void
+UpmixerA::flush ()
+{
+       _left.flush ();
+       _right.flush ();
+       _centre.flush ();
+       _lfe.flush ();
+       _ls.flush ();
+       _rs.flush ();
+}
diff --git a/src/lib/upmixer_a.h b/src/lib/upmixer_a.h
new file mode 100644 (file)
index 0000000..32e3f5f
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+    Copyright (C) 2014 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "audio_processor.h"
+#include "audio_filter.h"
+
+class UpmixerA : public AudioProcessor
+{
+public:
+       UpmixerA (int sampling_rate);
+       
+       std::string name () const;
+       std::string id () const;
+       ChannelCount in_channels () const;
+       int out_channels (int) const;
+       boost::shared_ptr<AudioProcessor> clone (int) const;
+       boost::shared_ptr<AudioBuffers> run (boost::shared_ptr<const AudioBuffers>);
+       void flush ();
+
+private:
+       BandPassAudioFilter _left;
+       BandPassAudioFilter _right;
+       BandPassAudioFilter _centre;
+       BandPassAudioFilter _lfe;
+       BandPassAudioFilter _ls;
+       BandPassAudioFilter _rs;
+};
index ee8a59c0befb912ab6d043f1ec1be757ef461e55..66a25be0af71bd187641087d9215205555b97e4b 100644 (file)
@@ -85,6 +85,7 @@ sources = """
           types.cc
           ui_signaller.cc
           update.cc
+          upmixer_a.cc
           util.cc
           video_content.cc
           video_decoder.cc
index b19142ec5b0942c7cbe8daef411c9eed816dc779..e27e10752abb64c4135f4f5ce431f74a2944b0f3 100644 (file)
@@ -84,7 +84,7 @@ AudioPanel::AudioPanel (ContentPanel* p)
        add_label_to_grid_bag_sizer (grid, this, _("Stream"), true, wxGBPosition (r, 0));
        _stream = new wxChoice (this, wxID_ANY);
        grid->Add (_stream, wxGBPosition (r, 1));
-       _description = add_label_to_grid_bag_sizer (grid, this, "", false, wxGBPosition (r, 3));
+       _description = add_label_to_grid_bag_sizer (grid, this, "", false, wxGBPosition (r, 2), wxGBSpan (1, 2));
        ++r;
 
        add_label_to_grid_bag_sizer (grid, this, _("Process with"), true, wxGBPosition (r, 0));
index 5bf7ea80eedbc707380bd68e2f70d37c18a9badd..59e003ac225a5dcc8583c1fbbb281e2248b4ab51 100644 (file)
@@ -54,6 +54,7 @@ def build(bld):
                  subrip_test.cc
                  test.cc
                  threed_test.cc
+                 upmixer_a_test.cc
                  util_test.cc
                  xml_subtitle_test.cc
                  """