Audacity 3.2.0
DownmixStage.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 DownmixStage.cpp
6
7 Dominic Mazzoni
8 Markus Meyer
9 Vaughan Johnson
10
11*******************************************************************/
12
13#include "DownmixStage.h"
14
15#include <cassert>
16#include <numeric>
17
18#include "SampleCount.h"
19#include "DownmixSource.h"
20
21#define stackAllocate(T, count) static_cast<T*>(alloca(count * sizeof(T)))
22
23namespace
24{
25
26void MixBuffers(unsigned numChannels,
27 const unsigned char *channelFlags, const float *volumes,
28 const float &src, AudioGraph::Buffers &dests, int len)
29{
30 const auto pSrc = &src;
31 for (unsigned int c = 0; c < numChannels; c++) {
32 if (!channelFlags[c])
33 continue;
34 auto dest = &dests.GetWritePosition(c);
35 for (int j = 0; j < len; ++j)
36 dest[j] += pSrc[j] * volumes[c]; // the actual mixing process
37 }
38}
39
40}
41
42DownmixStage::DownmixStage(std::vector<std::unique_ptr<DownmixSource>> downmixSources,
43 size_t numChannels,
44 size_t bufferSize,
45 ApplyVolume applyGain)
46 : mDownmixSources(std::move(downmixSources))
47 // PRL: Bug2536: see other comments below for the last, padding argument
48 // TODO: more-than-two-channels
49 // Issue 3565 workaround: allocate one extra buffer when applying a
50 // GVerb effect stage. It is simply discarded
51 // See also issue 3854, when the number of out channels expected by the
52 // plug-in is yet larger
53 , mFloatBuffers { 3, bufferSize, 1, 1 }
54 , mNumChannels(numChannels)
55 , mApplyVolume(applyGain)
56{
57
58}
59
61
62bool DownmixStage::AcceptsBuffers(const Buffers& buffers) const
63{
64 return buffers.Channels() == mNumChannels &&
65 AcceptsBlockSize(buffers.BlockSize());
66}
67
68bool DownmixStage::AcceptsBlockSize(size_t blockSize) const
69{
70 return blockSize <= mFloatBuffers.BufferSize();
71}
72
73std::optional<size_t> DownmixStage::Acquire(Buffers& data, size_t maxToProcess)
74{
75 // TODO: more-than-two-channels
76 auto maxChannels = std::max(2u, mFloatBuffers.Channels());
77 const auto channelFlags = stackAllocate(unsigned char, mNumChannels);
78 const auto volumes = stackAllocate(float, mNumChannels);
80 std::fill(volumes, volumes + mNumChannels, 1.0f);
81
82 size_t maxOut = 0;
83 for (auto c = 0;c < data.Channels(); ++c)
84 data.ClearBuffer(c, maxToProcess);
85
86 for (auto& downmixSource : mDownmixSources)
87 {
88 auto oResult = downmixSource->GetDownstream().Acquire(mFloatBuffers, maxToProcess);
89 // One of MixVariableRates or MixSameRate assigns into mTemp[*][*]
90 // which are the sources for the CopySamples calls, and they copy into
91 // mBuffer[*][*]
92 if (!oResult)
93 return 0;
94 const auto result = *oResult;
95 maxOut = std::max(maxOut, result);
96
97 // Insert effect stages here! Passing them all channels of the track
98
99 const auto limit = std::min<size_t>(downmixSource->NChannels(), maxChannels);
100 for (size_t j = 0; j < limit; ++j)
101 {
102 const auto pFloat = (const float*)mFloatBuffers.GetReadPosition(j);
104 {
105 for (size_t c = 0; c < mNumChannels; ++c)
106 {
107 if (mNumChannels > 1)
108 volumes[c] = downmixSource->GetChannelGain(c);
109 else
110 volumes[c] = downmixSource->GetChannelGain(j);
111 }
113 mNumChannels == 1 &&
114 downmixSource->CanMakeMono())
115 {
116 volumes[0] /= static_cast<float>(limit);
117 }
118 }
119
120 downmixSource->FindChannelFlags(channelFlags, mNumChannels, j);
121 MixBuffers(mNumChannels, channelFlags, volumes, *pFloat, data, result);
122 }
123
124 downmixSource->GetDownstream().Release();
125 mFloatBuffers.Advance(result);
127 }
128
129 // MB: this doesn't take warping into account, replaced with code based on mSamplePos
130 //mT += (maxOut / mRate);
131
132 assert(maxOut <= maxToProcess);
133 return maxOut;
134}
136{
137 return std::accumulate(
138 mDownmixSources.begin(), mDownmixSources.end(), sampleCount { 0 },
139 [](sampleCount sum, const auto& source) {
140 return std::max(sum, source->GetDownstream().Remaining());
141 });
142}
143
145{
146 return true;
147}
#define stackAllocate(T, count)
Accumulates (non-interleaved) data during effect processing.
size_t BlockSize() const
float & GetWritePosition(unsigned iChannel)
Get writable position for one channel.
void Advance(size_t count)
Move the positions.
size_t BufferSize() const
size_t Rotate()
Shift all data at and after the old position to position 0.
unsigned Channels() const
void ClearBuffer(unsigned iChannel, size_t n)
constSamplePtr GetReadPosition(unsigned iChannel) const
Get accumulated data for one channel.
sampleCount Remaining() const override
Result includes any amount Acquired and not yet Released.
AudioGraph::Buffers mFloatBuffers
Definition: DownmixStage.h:33
std::vector< std::unique_ptr< DownmixSource > > mDownmixSources
Definition: DownmixStage.h:31
std::optional< size_t > Acquire(Buffers &data, size_t maxToProcess) override
Occupy vacant space in Buffers with some data.
bool AcceptsBuffers(const Buffers &buffers) const override
DownmixStage(std::vector< std::unique_ptr< DownmixSource > > downmixSources, size_t numChannels, size_t bufferSize, ApplyVolume applyGain)
bool Release() override
Caller is done examining last Acquire()d positions.
~DownmixStage() override
bool AcceptsBlockSize(size_t blockSize) const override
size_t mNumChannels
Definition: DownmixStage.h:34
ApplyVolume mApplyVolume
Definition: DownmixStage.h:35
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:19
void MixBuffers(unsigned numChannels, const unsigned char *channelFlags, const float *volumes, const float &src, AudioGraph::Buffers &dests, int len)
STL namespace.