summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2014-07-15 13:15:02 +0100
committerCarl Hetherington <cth@carlh.net>2014-07-15 13:15:02 +0100
commit7f38d676e69639a7825e506618613051651968cf (patch)
treefcbdaf6d1536c58bfffe739d26c7c9bf676f8695 /src
parente5f79c57e1123754b1325f964123fcb56a2572b3 (diff)
Add simple stereo-5.1 upmixer.
Diffstat (limited to 'src')
-rw-r--r--src/lib/audio_buffers.cc26
-rw-r--r--src/lib/audio_buffers.h4
-rw-r--r--src/lib/audio_decoder.cc5
-rw-r--r--src/lib/audio_filter.cc6
-rw-r--r--src/lib/audio_filter.h2
-rw-r--r--src/lib/audio_processor.cc2
-rw-r--r--src/lib/audio_processor.h3
-rw-r--r--src/lib/mid_side_decoder.cc2
-rw-r--r--src/lib/mid_side_decoder.h2
-rw-r--r--src/lib/single_stream_audio_content.cc5
-rw-r--r--src/lib/upmixer_a.cc109
-rw-r--r--src/lib/upmixer_a.h43
-rw-r--r--src/lib/wscript1
-rw-r--r--src/wx/audio_panel.cc2
14 files changed, 206 insertions, 6 deletions
diff --git a/src/lib/audio_buffers.cc b/src/lib/audio_buffers.cc
index 4ada94db8..56ca7a94b 100644
--- a/src/lib/audio_buffers.cc
+++ b/src/lib/audio_buffers.cc
@@ -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;
+}
diff --git a/src/lib/audio_buffers.h b/src/lib/audio_buffers.h
index 51488c39a..8cd67aaa7 100644
--- a/src/lib/audio_buffers.h
+++ b/src/lib/audio_buffers.h
@@ -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);
diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc
index 19f31d30a..e4f98c678 100644
--- a/src/lib/audio_decoder.cc
+++ b/src/lib/audio_decoder.cc
@@ -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 ();
+ }
}
diff --git a/src/lib/audio_filter.cc b/src/lib/audio_filter.cc
index 0cd2b18fb..59b5684ea 100644
--- a/src/lib/audio_filter.cc
+++ b/src/lib/audio_filter.cc
@@ -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)
{
diff --git a/src/lib/audio_filter.h b/src/lib/audio_filter.h
index 9dfcec58b..f361c27d2 100644
--- a/src/lib/audio_filter.h
+++ b/src/lib/audio_filter.h
@@ -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;
diff --git a/src/lib/audio_processor.cc b/src/lib/audio_processor.cc
index 27146806b..f350cc2aa 100644
--- a/src/lib/audio_processor.cc
+++ b/src/lib/audio_processor.cc
@@ -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 *
diff --git a/src/lib/audio_processor.h b/src/lib/audio_processor.h
index 7ff9f0ec6..9b332e7fe 100644
--- a/src/lib/audio_processor.h
+++ b/src/lib/audio_processor.h
@@ -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 ();
diff --git a/src/lib/mid_side_decoder.cc b/src/lib/mid_side_decoder.cc
index a518a4389..be82f6754 100644
--- a/src/lib/mid_side_decoder.cc
+++ b/src/lib/mid_side_decoder.cc
@@ -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 ());
}
diff --git a/src/lib/mid_side_decoder.h b/src/lib/mid_side_decoder.h
index a6d2721b6..dac6cb7d9 100644
--- a/src/lib/mid_side_decoder.h
+++ b/src/lib/mid_side_decoder.h
@@ -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>);
};
diff --git a/src/lib/single_stream_audio_content.cc b/src/lib/single_stream_audio_content.cc
index ac4da25ee..521597606 100644
--- a/src/lib/single_stream_audio_content.cc
+++ b/src/lib/single_stream_audio_content.cc
@@ -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
index 000000000..dce08fe37
--- /dev/null
+++ b/src/lib/upmixer_a.cc
@@ -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
index 000000000..32e3f5fb6
--- /dev/null
+++ b/src/lib/upmixer_a.h
@@ -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;
+};
diff --git a/src/lib/wscript b/src/lib/wscript
index ee8a59c0b..66a25be0a 100644
--- a/src/lib/wscript
+++ b/src/lib/wscript
@@ -85,6 +85,7 @@ sources = """
types.cc
ui_signaller.cc
update.cc
+ upmixer_a.cc
util.cc
video_content.cc
video_decoder.cc
diff --git a/src/wx/audio_panel.cc b/src/wx/audio_panel.cc
index b19142ec5..e27e10752 100644
--- a/src/wx/audio_panel.cc
+++ b/src/wx/audio_panel.cc
@@ -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));