/* Copyright (C) 2015-2021 Carl Hetherington This file is part of DCP-o-matic. DCP-o-matic 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. DCP-o-matic 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 DCP-o-matic. If not, see . */ #include "upmixer_b.h" #include "audio_buffers.h" #include "audio_mapping.h" #include "i18n.h" using std::string; using std::make_shared; using std::min; using std::vector; using std::shared_ptr; UpmixerB::UpmixerB(int sampling_rate) : _lfe(0.01, 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 UpmixerB::clone(int sampling_rate) const { return make_shared(sampling_rate); } shared_ptr UpmixerB::do_run(shared_ptr in, int channels) { auto out = make_shared(channels, in->frames()); /* L + R minus 6dB (in terms of amplitude) */ auto in_LR = in->channel(0); in_LR->accumulate_frames(in->channel(1).get(), in->frames(), 0, 0); 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 S; if (channels > 4) { /* Ls is L - R with some delay */ auto sub = make_shared(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 UpmixerB::input_names() const { return { NamedChannel(_("Upmix L"), 0), NamedChannel(_("Upmix R"), 1) }; }