diff options
| author | Carl Hetherington <cth@carlh.net> | 2014-07-13 20:44:45 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2014-07-13 20:44:45 +0100 |
| commit | 3ddd928233130695d7f4eeee47a71409d8c04de7 (patch) | |
| tree | 9f616a27fc6492b30536a2a366cf9e7211a87a3d /src/lib | |
| parent | e8c5f14cb6736bdfa3610b2559c6c331c1c56984 (diff) | |
Very basic audio processing framework.
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/audio_content.cc | 40 | ||||
| -rw-r--r-- | src/lib/audio_content.h | 11 | ||||
| -rw-r--r-- | src/lib/audio_decoder.cc | 11 | ||||
| -rw-r--r-- | src/lib/audio_decoder.h | 1 | ||||
| -rw-r--r-- | src/lib/audio_mapping.cc | 2 | ||||
| -rw-r--r-- | src/lib/audio_processor.cc | 50 | ||||
| -rw-r--r-- | src/lib/audio_processor.h | 50 | ||||
| -rw-r--r-- | src/lib/channel_count.h | 49 | ||||
| -rw-r--r-- | src/lib/mid_side_decoder.cc | 72 | ||||
| -rw-r--r-- | src/lib/mid_side_decoder.h | 33 | ||||
| -rw-r--r-- | src/lib/util.cc | 2 | ||||
| -rw-r--r-- | src/lib/wscript | 2 |
12 files changed, 321 insertions, 2 deletions
diff --git a/src/lib/audio_content.cc b/src/lib/audio_content.cc index 6317aa4cb..d02728b00 100644 --- a/src/lib/audio_content.cc +++ b/src/lib/audio_content.cc @@ -26,6 +26,7 @@ #include "exceptions.h" #include "config.h" #include "frame_rate_change.h" +#include "audio_processor.h" #include "i18n.h" @@ -42,11 +43,13 @@ int const AudioContentProperty::AUDIO_FRAME_RATE = 202; int const AudioContentProperty::AUDIO_GAIN = 203; int const AudioContentProperty::AUDIO_DELAY = 204; int const AudioContentProperty::AUDIO_MAPPING = 205; +int const AudioContentProperty::AUDIO_PROCESSOR = 206; AudioContent::AudioContent (shared_ptr<const Film> f) : Content (f) , _audio_gain (0) , _audio_delay (Config::instance()->default_audio_delay ()) + , _audio_processor (0) { } @@ -55,6 +58,7 @@ AudioContent::AudioContent (shared_ptr<const Film> f, DCPTime s) : Content (f, s) , _audio_gain (0) , _audio_delay (Config::instance()->default_audio_delay ()) + , _audio_processor (0) { } @@ -63,15 +67,20 @@ AudioContent::AudioContent (shared_ptr<const Film> f, boost::filesystem::path p) : Content (f, p) , _audio_gain (0) , _audio_delay (Config::instance()->default_audio_delay ()) + , _audio_processor (0) { } AudioContent::AudioContent (shared_ptr<const Film> f, cxml::ConstNodePtr node) : Content (f, node) + , _audio_processor (0) { _audio_gain = node->number_child<float> ("AudioGain"); _audio_delay = node->number_child<int> ("AudioDelay"); + if (node->optional_string_child ("AudioProcessor")) { + _audio_processor = AudioProcessor::from_id (node->string_child ("AudioProcessor")); + } } AudioContent::AudioContent (shared_ptr<const Film> f, vector<shared_ptr<Content> > c) @@ -94,6 +103,7 @@ AudioContent::AudioContent (shared_ptr<const Film> f, vector<shared_ptr<Content> _audio_gain = ref->audio_gain (); _audio_delay = ref->audio_delay (); + _audio_processor = ref->audio_processor (); } void @@ -102,6 +112,9 @@ AudioContent::as_xml (xmlpp::Node* node) const boost::mutex::scoped_lock lm (_mutex); node->add_child("AudioGain")->add_child_text (raw_convert<string> (_audio_gain)); node->add_child("AudioDelay")->add_child_text (raw_convert<string> (_audio_delay)); + if (_audio_processor) { + node->add_child("AudioProcessor")->add_child_text (_audio_processor->id ()); + } } @@ -127,6 +140,22 @@ AudioContent::set_audio_delay (int d) signal_changed (AudioContentProperty::AUDIO_DELAY); } +void +AudioContent::set_audio_processor (AudioProcessor const * p) +{ + { + boost::mutex::scoped_lock lm (_mutex); + _audio_processor = p; + } + + /* The channel count might have changed, so reset the mapping */ + AudioMapping m (processed_audio_channels ()); + m.make_default (); + set_audio_mapping (m); + + signal_changed (AudioContentProperty::AUDIO_PROCESSOR); +} + boost::signals2::connection AudioContent::analyse_audio (boost::function<void()> finished) { @@ -196,3 +225,14 @@ AudioContent::resampled_audio_frame_rate () const return rint (t); } + +int +AudioContent::processed_audio_channels () const +{ + if (!audio_processor ()) { + return audio_channels (); + } + + return audio_processor()->out_channels (audio_channels ()); +} + diff --git a/src/lib/audio_content.h b/src/lib/audio_content.h index 131ced61a..540839d69 100644 --- a/src/lib/audio_content.h +++ b/src/lib/audio_content.h @@ -31,6 +31,8 @@ namespace cxml { class Node; } +class AudioProcessor; + class AudioContentProperty { public: @@ -40,6 +42,7 @@ public: static int const AUDIO_GAIN; static int const AUDIO_DELAY; static int const AUDIO_MAPPING; + static int const AUDIO_PROCESSOR; }; /** @class AudioContent @@ -70,11 +73,13 @@ public: virtual boost::filesystem::path audio_analysis_path () const; int resampled_audio_frame_rate () const; + int processed_audio_channels () const; boost::signals2::connection analyse_audio (boost::function<void()>); void set_audio_gain (double); void set_audio_delay (int); + void set_audio_processor (AudioProcessor const *); double audio_gain () const { boost::mutex::scoped_lock lm (_mutex); @@ -86,11 +91,17 @@ public: return _audio_delay; } + AudioProcessor const * audio_processor () const { + boost::mutex::scoped_lock lm (_mutex); + return _audio_processor; + } + private: /** Gain to apply to audio in dB */ double _audio_gain; /** Delay to apply to audio (positive moves audio later) in milliseconds */ int _audio_delay; + AudioProcessor const * _audio_processor; }; #endif diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index 97a088791..19f31d30a 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -24,6 +24,7 @@ #include "resampler.h" #include "util.h" #include "film.h" +#include "audio_processor.h" #include "i18n.h" @@ -43,13 +44,17 @@ AudioDecoder::AudioDecoder (shared_ptr<const AudioContent> content) _resampler.reset (new Resampler (content->audio_frame_rate(), content->resampled_audio_frame_rate(), content->audio_channels ())); } + if (content->audio_processor ()) { + _processor = content->audio_processor()->clone (); + } + reset_decoded_audio (); } void AudioDecoder::reset_decoded_audio () { - _decoded_audio = ContentAudio (shared_ptr<AudioBuffers> (new AudioBuffers (_audio_content->audio_channels(), 0)), 0); + _decoded_audio = ContentAudio (shared_ptr<AudioBuffers> (new AudioBuffers (_audio_content->processed_audio_channels(), 0)), 0); } shared_ptr<ContentAudio> @@ -125,6 +130,10 @@ AudioDecoder::audio (shared_ptr<const AudioBuffers> data, ContentTime time) data = _resampler->run (data); } + if (_processor) { + data = _processor->run (data); + } + AudioFrame const frame_rate = _audio_content->resampled_audio_frame_rate (); if (_seek_reference) { diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index 0553d7c81..045efc002 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -61,6 +61,7 @@ protected: boost::shared_ptr<const AudioContent> _audio_content; boost::shared_ptr<Resampler> _resampler; + boost::shared_ptr<AudioProcessor> _processor; boost::optional<AudioFrame> _audio_position; /** Currently-available decoded audio data */ ContentAudio _decoded_audio; diff --git a/src/lib/audio_mapping.cc b/src/lib/audio_mapping.cc index b3757c5f1..e86e2e2ac 100644 --- a/src/lib/audio_mapping.cc +++ b/src/lib/audio_mapping.cc @@ -40,7 +40,7 @@ AudioMapping::AudioMapping () } -/** Create a default AudioMapping for a given channel count. +/** Create an empty AudioMapping for a given channel count. * @param channels Number of channels. */ AudioMapping::AudioMapping (int channels) diff --git a/src/lib/audio_processor.cc b/src/lib/audio_processor.cc new file mode 100644 index 000000000..27146806b --- /dev/null +++ b/src/lib/audio_processor.cc @@ -0,0 +1,50 @@ +/* + 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 "mid_side_decoder.h" + +using std::string; +using std::list; + +list<AudioProcessor const *> AudioProcessor::_all; + +void +AudioProcessor::setup_audio_processors () +{ + _all.push_back (new MidSideDecoder ()); +} + +AudioProcessor const * +AudioProcessor::from_id (string id) +{ + for (list<AudioProcessor const *>::const_iterator i = _all.begin(); i != _all.end(); ++i) { + if ((*i)->id() == id) { + return *i; + } + } + + return 0; +} + +list<AudioProcessor const *> +AudioProcessor::all () +{ + return _all; +} diff --git a/src/lib/audio_processor.h b/src/lib/audio_processor.h new file mode 100644 index 000000000..7ff9f0ec6 --- /dev/null +++ b/src/lib/audio_processor.h @@ -0,0 +1,50 @@ +/* + 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. + +*/ + +#ifndef DCPOMATIC_AUDIO_PROCESSOR_H +#define DCPOMATIC_AUDIO_PROCESSOR_H + +#include <list> +#include <string> +#include <boost/shared_ptr.hpp> +#include "channel_count.h" + +class AudioBuffers; + +class AudioProcessor +{ +public: + virtual ~AudioProcessor () {} + + virtual std::string name () const = 0; + 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<AudioBuffers> run (boost::shared_ptr<const AudioBuffers>) = 0; + + static std::list<AudioProcessor const *> all (); + static void setup_audio_processors (); + static AudioProcessor const * from_id (std::string); + +private: + static std::list<AudioProcessor const *> _all; +}; + +#endif diff --git a/src/lib/channel_count.h b/src/lib/channel_count.h new file mode 100644 index 000000000..4247fc063 --- /dev/null +++ b/src/lib/channel_count.h @@ -0,0 +1,49 @@ +/* + 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. + +*/ + +#ifndef DCPOMATIC_CHANNEL_COUNT_H +#define DCPOMATIC_CHANNEL_COUNT_H + +class ChannelCount +{ +public: + ChannelCount () + : min (0) + , max (0) + {} + + ChannelCount (int n) + : min (n) + , max (n) + {} + + ChannelCount (int min_, int max_) + : min (min_) + , max (max_) + {} + + bool includes (int c) { + return min <= c && c <= max; + } + + int min; + int max; +}; + +#endif diff --git a/src/lib/mid_side_decoder.cc b/src/lib/mid_side_decoder.cc new file mode 100644 index 000000000..a518a4389 --- /dev/null +++ b/src/lib/mid_side_decoder.cc @@ -0,0 +1,72 @@ +/* + 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 "mid_side_decoder.h" +#include "audio_buffers.h" + +#include "i18n.h" + +using std::string; +using boost::shared_ptr; + +string +MidSideDecoder::name () const +{ + return _("Mid-side decoder"); +} + +string +MidSideDecoder::id () const +{ + return N_("mid-side-decoder"); +} + +ChannelCount +MidSideDecoder::in_channels () const +{ + return ChannelCount (2); +} + +int +MidSideDecoder::out_channels (int) const +{ + return 3; +} + +shared_ptr<AudioProcessor> +MidSideDecoder::clone () const +{ + return shared_ptr<AudioProcessor> (new MidSideDecoder ()); +} + +shared_ptr<AudioBuffers> +MidSideDecoder::run (shared_ptr<const AudioBuffers> in) +{ + shared_ptr<AudioBuffers> out (new AudioBuffers (3, in->frames ())); + for (int i = 0; i < in->frames(); ++i) { + float const left = in->data()[0][i]; + float const right = in->data()[1][i]; + float const mid = (left + right) / 2; + out->data()[0][i] = left - mid; + out->data()[1][i] = right - mid; + out->data()[2][i] = mid; + } + + return out; +} diff --git a/src/lib/mid_side_decoder.h b/src/lib/mid_side_decoder.h new file mode 100644 index 000000000..a6d2721b6 --- /dev/null +++ b/src/lib/mid_side_decoder.h @@ -0,0 +1,33 @@ +/* + 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" + +class MidSideDecoder : public AudioProcessor +{ +public: + std::string name () const; + std::string id () const; + ChannelCount in_channels () const; + int out_channels (int) const; + boost::shared_ptr<AudioProcessor> clone () const; + boost::shared_ptr<AudioBuffers> run (boost::shared_ptr<const AudioBuffers>); +}; + + diff --git a/src/lib/util.cc b/src/lib/util.cc index 55df5cc83..dd39e286e 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -72,6 +72,7 @@ extern "C" { #include "video_content.h" #include "rect.h" #include "md5_digester.h" +#include "audio_processor.h" #ifdef DCPOMATIC_WINDOWS #include "stack.hpp" #endif @@ -336,6 +337,7 @@ dcpomatic_setup () Scaler::setup_scalers (); Filter::setup_filters (); SoundProcessor::setup_sound_processors (); + AudioProcessor::setup_audio_processors (); ui_thread = boost::this_thread::get_id (); } diff --git a/src/lib/wscript b/src/lib/wscript index d96bb7f96..60150f4da 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -8,6 +8,7 @@ sources = """ audio_content.cc audio_decoder.cc audio_mapping.cc + audio_processor.cc cinema.cc colour_conversion.cc config.cc @@ -55,6 +56,7 @@ sources = """ log.cc magick_image_proxy.cc md5_digester.cc + mid_side_decoder.cc player.cc player_video.cc playlist.cc |
