Add UpmixerB.
authorCarl Hetherington <cth@carlh.net>
Fri, 18 Sep 2015 21:33:20 +0000 (22:33 +0100)
committerCarl Hetherington <cth@carlh.net>
Fri, 18 Sep 2015 21:33:20 +0000 (22:33 +0100)
ChangeLog
src/lib/audio_delay.cc [new file with mode: 0644]
src/lib/audio_delay.h [new file with mode: 0644]
src/lib/audio_processor.cc
src/lib/upmixer_b.cc [new file with mode: 0644]
src/lib/upmixer_b.h [new file with mode: 0644]
src/lib/wscript
test/audio_processor_delay_test.cc [new file with mode: 0644]
test/wscript

index a0856e8e28ecfa45e8c8141db26d08ea7652a9ab..37ac15d07bf1e3cd5bb672dfe9ccade31bd14931 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2015-09-18  Carl Hetherington  <cth@carlh.net>
+
+       * Add another upmixer which is a simpler
+       matrix-type thing with no filtering
+       (apart from Lfe).
+
 2015-09-17  Carl Hetherington  <cth@carlh.net>
 
        * Version 2.3.4 released.
diff --git a/src/lib/audio_delay.cc b/src/lib/audio_delay.cc
new file mode 100644 (file)
index 0000000..076d10d
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+    Copyright (C) 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
+    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_delay.h"
+#include "audio_buffers.h"
+#include "dcpomatic_assert.h"
+#include <iostream>
+
+using std::cout;
+using boost::shared_ptr;
+
+AudioDelay::AudioDelay (int samples)
+       : _samples (samples)
+{
+
+}
+
+shared_ptr<AudioBuffers>
+AudioDelay::run (shared_ptr<const AudioBuffers> in)
+{
+       /* You can't call this with varying channel counts */
+       DCPOMATIC_ASSERT (!_tail || in->channels() == _tail->channels());
+
+       shared_ptr<AudioBuffers> out (new AudioBuffers (in->channels(), in->frames()));
+
+       if (in->frames() > _samples) {
+
+               if (!_tail) {
+                       /* No tail; use silence */
+                       out->make_silent (0, _samples);
+               } else {
+                       /* Copy tail */
+                       out->copy_from (_tail.get(), _samples, 0, 0);
+               }
+
+               /* Copy in to out */
+               out->copy_from (in.get(), in->frames() - _samples, 0, _samples);
+
+               /* Keep tail */
+               if (!_tail) {
+                       _tail.reset (new AudioBuffers (in->channels(), _samples));
+               }
+               _tail->copy_from (in.get(), _samples, in->frames() - _samples, 0);
+
+       } else {
+
+               /* First part of the tail into the output */
+               if (_tail) {
+                       out->copy_from (_tail.get(), out->frames(), 0, 0);
+               } else {
+                       out->make_silent ();
+                       _tail.reset (new AudioBuffers (out->channels(), _samples));
+                       _tail->make_silent ();
+               }
+
+               /* Shuffle the tail down */
+               _tail->move (out->frames(), 0, _tail->frames() - out->frames());
+
+               /* Copy input into the tail */
+               _tail->copy_from (in.get(), in->frames(), 0, _tail->frames() - in->frames());
+       }
+
+       return out;
+}
+
+void
+AudioDelay::flush ()
+{
+       _tail.reset ();
+}
diff --git a/src/lib/audio_delay.h b/src/lib/audio_delay.h
new file mode 100644 (file)
index 0000000..0072915
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+    Copyright (C) 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
+    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 <boost/shared_ptr.hpp>
+
+class AudioBuffers;
+
+class AudioDelay
+{
+public:
+       AudioDelay (int samples);
+       boost::shared_ptr<AudioBuffers> run (boost::shared_ptr<const AudioBuffers> in);
+       void flush ();
+
+private:
+       boost::shared_ptr<AudioBuffers> _tail;
+       int _samples;
+};
index f350cc2aa0404553ce8f11ff8a8dbe10e99c143e..1e8e3e4c6f2d9095c50c5b9c039c457cf6d0f316 100644 (file)
@@ -20,6 +20,7 @@
 #include "audio_processor.h"
 #include "mid_side_decoder.h"
 #include "upmixer_a.h"
+#include "upmixer_b.h"
 
 using std::string;
 using std::list;
@@ -31,6 +32,7 @@ AudioProcessor::setup_audio_processors ()
 {
        _all.push_back (new MidSideDecoder ());
        _all.push_back (new UpmixerA (48000));
+       _all.push_back (new UpmixerB (48000));
 }
 
 AudioProcessor const *
diff --git a/src/lib/upmixer_b.cc b/src/lib/upmixer_b.cc
new file mode 100644 (file)
index 0000000..9340582
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+    Copyright (C) 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
+    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_b.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;
+
+UpmixerB::UpmixerB (int sampling_rate)
+       : _lfe (0.02, 20.0 / sampling_rate, 150.0 / sampling_rate)
+       , _delay (0.02 * sampling_rate)
+{
+
+}
+
+string
+UpmixerB::name () const
+{
+       return _("Stereo to 5.1 up-mixer B");
+}
+
+
+string
+UpmixerB::id () const
+{
+       return N_("stereo-5.1-upmix-b");
+}
+
+int
+UpmixerB::out_channels () const
+{
+       return 6;
+}
+
+shared_ptr<AudioProcessor>
+UpmixerB::clone (int sampling_rate) const
+{
+       return shared_ptr<AudioProcessor> (new UpmixerB (sampling_rate));
+}
+
+shared_ptr<AudioBuffers>
+UpmixerB::run (shared_ptr<const AudioBuffers> in, int channels)
+{
+       shared_ptr<AudioBuffers> out (new AudioBuffers (channels, in->frames()));
+
+       /* L + R minus 6dB (in terms of amplitude) */
+       shared_ptr<AudioBuffers> in_LR = in->channel(0);
+       in_LR->accumulate_frames (in->channel(1).get(), 0, 0, in->frames());
+       in_LR->apply_gain (-6);
+
+       if (channels > 0) {
+               /* L = Lt */
+               out->copy_channel_from (in.get(), 0, 0);
+       }
+
+       if (channels > 1) {
+               /* R = Rt */
+               out->copy_channel_from (in.get(), 1, 1);
+       }
+
+       if (channels > 2) {
+               /* C = L + R minus 3dB */
+               out->copy_channel_from (in_LR.get(), 0, 2);
+       }
+
+       if (channels > 3) {
+               /* Lfe is filtered C */
+               out->copy_channel_from (_lfe.run(in_LR).get(), 0, 3);
+       }
+
+       shared_ptr<AudioBuffers> S;
+       if (channels > 4) {
+               /* Ls is L - R with some delay */
+               shared_ptr<AudioBuffers> sub (new AudioBuffers (1, in->frames()));
+               sub->copy_channel_from (in.get(), 0, 0);
+               float* p = sub->data (0);
+               float const * q = in->data (1);
+               for (int i = 0; i < in->frames(); ++i) {
+                       *p++ -= *q++;
+               }
+               S = _delay.run (sub);
+               out->copy_channel_from (S.get(), 0, 4);
+       }
+
+       if (channels > 5) {
+               /* Rs = Ls */
+               out->copy_channel_from (S.get(), 0, 5);
+       }
+
+       return out;
+}
+
+void
+UpmixerB::flush ()
+{
+       _lfe.flush ();
+       _delay.flush ();
+}
+
+void
+UpmixerB::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>
+UpmixerB::input_names () const
+{
+       vector<string> n;
+       n.push_back (_("Upmix L"));
+       n.push_back (_("Upmix R"));
+       return n;
+}
diff --git a/src/lib/upmixer_b.h b/src/lib/upmixer_b.h
new file mode 100644 (file)
index 0000000..f128e1d
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+    Copyright (C) 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
+    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.
+
+*/
+
+/** @file  src/lib/upmixer_b.h
+ *  @brief UpmixerB class.
+ */
+
+#include "audio_processor.h"
+#include "audio_filter.h"
+#include "audio_delay.h"
+
+class UpmixerB : public AudioProcessor
+{
+public:
+       UpmixerB (int sampling_rate);
+
+       std::string name () const;
+       std::string id () const;
+       int out_channels () const;
+       boost::shared_ptr<AudioProcessor> clone (int) const;
+       boost::shared_ptr<AudioBuffers> run (boost::shared_ptr<const AudioBuffers>, int channels);
+       void flush ();
+       void make_audio_mapping_default (AudioMapping& mapping) const;
+       std::vector<std::string> input_names () const;
+
+private:
+       BandPassAudioFilter _lfe;
+       AudioDelay _delay;
+};
index f0646910b13bdf744b721bee6f4f74582cdebc49..a95905578ecc494458b0c9906ac7fd4e9e60c48d 100644 (file)
@@ -26,6 +26,7 @@ sources = """
           audio_content.cc
           audio_decoder.cc
           audio_decoder_stream.cc
+          audio_delay.cc
           audio_filter.cc
           audio_mapping.cc
           audio_point.cc
@@ -122,6 +123,7 @@ sources = """
           upload_job.cc
           uploader.cc
           upmixer_a.cc
+          upmixer_b.cc
           util.cc
           video_content.cc
           video_content_scale.cc
diff --git a/test/audio_processor_delay_test.cc b/test/audio_processor_delay_test.cc
new file mode 100644 (file)
index 0000000..b3948a7
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+    Copyright (C) 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
+    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 "lib/audio_delay.h"
+#include "lib/audio_buffers.h"
+#include <boost/test/unit_test.hpp>
+#include <cmath>
+
+using std::cerr;
+using std::cout;
+using boost::shared_ptr;
+
+#define CHECK_SAMPLE(c,f,r) \
+       if (fabs(out->data(c)[f] - (r)) > 0.1) {                        \
+               cerr << "Sample " << f << " at line " << __LINE__ << " is " << out->data(c)[f] << " not " << r << "; difference is " << fabs(out->data(c)[f] - (r)) << "\n"; \
+               BOOST_REQUIRE (fabs(out->data(c)[f] - (r)) <= 0.1);     \
+       }
+
+/** Block size greater than delay */
+BOOST_AUTO_TEST_CASE (audio_processor_delay_test1)
+{
+       AudioDelay delay (64);
+
+       int const C = 2;
+
+       shared_ptr<AudioBuffers> in (new AudioBuffers (C, 256));
+       for (int i = 0; i < C; ++i) {
+               for (int j = 0; j < 256; ++j) {
+                       in->data(i)[j] = j;
+               }
+       }
+
+       shared_ptr<AudioBuffers> out = delay.run (in);
+       BOOST_REQUIRE_EQUAL (out->frames(), in->frames());
+
+       /* Silence at the start */
+       for (int i = 0; i < C; ++i) {
+               for (int j = 0; j < 64; ++j) {
+                       CHECK_SAMPLE (i, j, 0);
+               }
+       }
+
+       /* Then the delayed data */
+       for (int i = 0; i < C; ++i) {
+               for (int j = 64; j < 256; ++j) {
+                       CHECK_SAMPLE (i, j, j - 64);
+               }
+       }
+
+       /* Feed some more in */
+       for (int i = 0; i < C; ++i) {
+               for (int j = 0; j < 256; ++j) {
+                       in->data(i)[j] = j + 256;
+               }
+       }
+       out = delay.run (in);
+
+       /* Check again */
+       for (int i = 0; i < C; ++i) {
+               for (int j = 256; j < 512; ++j) {
+                       CHECK_SAMPLE (i, j - 256, j - 64);
+               }
+       }
+}
+
+/** Block size less than delay */
+BOOST_AUTO_TEST_CASE (audio_processor_delay_test2)
+{
+       AudioDelay delay (256);
+
+       int const C = 2;
+
+       /* Feeding 4 blocks of 64 should give silence each time */
+
+       for (int i = 0; i < 4; ++i) {
+               cout << "i=" << i << "\n";
+               shared_ptr<AudioBuffers> in (new AudioBuffers (C, 64));
+               for (int j = 0; j < C; ++j) {
+                       for (int k = 0; k < 64; ++k) {
+                               in->data(j)[k] = k + i * 64;
+                       }
+               }
+
+               shared_ptr<AudioBuffers> out = delay.run (in);
+               BOOST_REQUIRE_EQUAL (out->frames(), in->frames());
+
+               /* Check for silence */
+               for (int j = 0; j < C; ++j) {
+                       for (int k = 0; k < 64; ++k) {
+                               CHECK_SAMPLE (j, k, 0);
+                       }
+               }
+       }
+
+       /* Now feed 4 blocks of silence and we should see the data */
+       for (int i = 0; i < 4; ++i) {
+               /* Feed some silence */
+               shared_ptr<AudioBuffers> in (new AudioBuffers (C, 64));
+               in->make_silent ();
+               shared_ptr<AudioBuffers> out = delay.run (in);
+
+               /* Should now see the delayed data */
+               for (int j = 0; j < C; ++j) {
+                       for (int k = 0; k < 64; ++k) {
+                               CHECK_SAMPLE (j, k, k + i * 64);
+                       }
+               }
+       }
+}
index 8707c15622a52a0ef57d75c7ff491dc0d65af2f0..1a1038e8dba8f2cacb5ec441cdfa5afd82b0946f 100644 (file)
@@ -44,6 +44,7 @@ def build(bld):
                  audio_filter_test.cc
                  audio_mapping_test.cc
                  audio_processor_test.cc
+                 audio_processor_delay_test.cc
                  black_fill_test.cc
                  client_server_test.cc
                  colour_conversion_test.cc