29template<
typename T,
typename F> std::vector<T>
32 std::vector<T> result( dim1 );
33 for (
auto &row : result)
38template<
typename T> std::vector<std::vector<T>>
41 return initVector<std::vector<T>>(dim1,
42 [dim2](
auto &row){ row.resize(dim2); });
50 for (
const auto& stage : stages)
53 const auto pInstance = stage.factory();
55 blockSize =
std::min(blockSize, pInstance->SetBlockSize(blockSize));
57 stage.mpFirstInstance = move(pInstance);
64 const std::optional<Mixer::Stages>&
masterEffects,
size_t bufferSize)
66 size_t blockSize = bufferSize;
67 for (
const auto &input : inputs) {
68 const auto sequence = input.pSequence.get();
69 const auto nInChannels = sequence->NChannels();
85 const WarpOptions& warpOptions,
const double startTime,
86 const double stopTime,
const unsigned numOutChannels,
87 const size_t outBufferSize,
const bool outInterleaved,
double outRate,
90 : mNumChannels { numOutChannels }
91 , mInputs { move(inputs) }
93 , mBufferSize {
FindBufferSize(mInputs, mMasterEffects, outBufferSize) }
94 , mApplyGain { applyGain }
95 , mHighQuality { highQuality }
96 , mFormat { outFormat }
97 , mInterleaved { outInterleaved }
99 startTime, stopTime, warpOptions.initialSpeed, startTime }) }
107 , mFloatBuffers { 3, mBufferSize, 1, 1 }
110 , mTemp { mNumChannels, mBufferSize, 1, 1 }
112 mInterleaved ? 1 : mNumChannels,
114 size = mBufferSize * (mInterleaved ? mNumChannels : 1)](
115 auto& buffer) { buffer.Allocate(
size,
format); }) }
119 const auto nChannelsIn =
120 std::accumulate(mInputs.begin(), mInputs.end(),
size_t{},
121 [](
auto sum,
const auto &input){
122 return sum + input.pSequence->NChannels(); });
126 bool needsDither = std::any_of(mInputs.begin(), mInputs.end(),
127 [](
const Input &input){
128 return std::any_of(input.stages.begin(), input.stages.end(),
129 [](const MixerOptions::StageSpecification &spec){
130 return spec.mpFirstInstance &&
131 spec.mpFirstInstance->NeedsDither(); } ); } );
133 needsDither |= std::any_of(
134 mMasterEffects->begin(), mMasterEffects->end(),
136 return spec.mpFirstInstance && spec.mpFirstInstance->NeedsDither();
139 auto pMixerSpec = ( mixerSpec &&
140 mixerSpec->GetNumChannels() == mNumChannels &&
141 mixerSpec->GetNumTracks() == nChannelsIn
142 ) ? mixerSpec :
nullptr;
143 mHasMixerSpec = pMixerSpec !=
nullptr;
146 mSources.reserve(nChannelsIn);
148 const auto nMasterStages = mMasterEffects ? mMasterEffects->size() : 0;
151 mInputs.begin(), mInputs.end(), 0,
152 [](
auto sum,
const auto& input) {
153 return sum + input.stages.size() * input.pSequence->NChannels();
156 mSettings.reserve(nStages);
157 mStageBuffers.reserve(nStages);
160 for (
auto &input : mInputs) {
161 const auto &sequence = input.pSequence;
166 auto increment =
finally([&]{ i += sequence->NChannels(); });
168 auto &source = mSources.emplace_back(sequence,
BufferSize(), outRate,
169 warpOptions, highQuality, mayThrow, mTimesAndSpeed,
170 (pMixerSpec ? &pMixerSpec->mMap[i] :
nullptr));
172 for (
const auto &stage : input.stages)
174 auto& pNewDownstream =
175 RegisterEffectStage(*pDownstream, stage, outRate))
177 pDownstream = pNewDownstream.get();
179 mDecoratedSources.emplace_back(Source{ source, *pDownstream });
185 for (
const auto& stage : *mMasterEffects)
187 auto& pNewDownstream =
188 RegisterEffectStage(*pDownstream, stage, outRate))
190 mMasterStages.emplace_back(pDownstream = pNewDownstream.get());
195 std::tie(mNeedsDither, mEffectiveFormat) = NeedsDither(needsDither, outRate);
200std::pair<bool, sampleFormat>
215 for (
const auto &input :
mSources) {
216 auto &sequence = input.GetSequence();
218 if (sequence.GetRate() != rate)
229 for (
auto c : {0, 1}) {
230 const auto gain = sequence.GetChannelGain(c);
231 if (!(gain == 0.0 || gain == 1.0))
240 if (!sequence.HasTrivialEnvelope())
243 auto effectiveFormat = sequence.WidestEffectiveFormat();
248 widestEffectiveFormat =
249 std::max(widestEffectiveFormat, effectiveFormat);
257 assert(widestEffectiveFormat <=
mFormat);
258 return {
false, widestEffectiveFormat };
269 const unsigned char *channelFlags,
const float *gains,
272 const auto pSrc = &src;
273 for (
unsigned int c = 0; c < numChannels; c++) {
274 if (!channelFlags[c])
277 for (
int j = 0; j < len; ++j)
278 dest[j] += pSrc[j] * gains[c];
282#define stackAllocate(T, count) static_cast<T*>(alloca(count * sizeof(T)))
294 auto oldTime = mTime;
296 const auto backwards = (mT0 > mT1);
300 std::optional<size_t> maxOut;
306 maxOut = stage->Acquire(
mTemp, maxToProcess);
313 mTime = std::clamp(mTime, mT1, oldTime);
315 mTime = std::clamp(mTime, oldTime, mT1);
333 assert(*maxOut <= maxToProcess);
362 const bool backwards = (mT1 < mT0);
364 mTime = std::clamp(mTime, mT1, mT0);
366 mTime = std::clamp(mTime, mT0, mT1);
369 source.Reposition(mTime, bSkipping);
374 wxASSERT(std::isfinite(speed));
378 mSpeed = fabs(speed);
384 wxASSERT(std::isfinite(speed));
388 if ((speed > 0.0 && mT1 < mT0) || (speed < 0.0 && mT1 > mT0)) {
392 if (speed > 0.0 && mT1 < mT0) {
394 mT1 = std::numeric_limits<double>::max();
397 mT0 = std::numeric_limits<double>::max();
404 mSpeed = fabs(speed);
420 return std::accumulate(
423 return std::max(sum, source.downstream.Remaining());
442 auto findChannelFlags = [&channelFlags, numChannels =
mNumChannels]
444 const auto end = channelFlags + numChannels;
445 std::fill(channelFlags,
end, 0);
448 std::copy(map, map + numChannels, channelFlags);
449 else if (
IsMono(sequence))
450 std::fill(channelFlags,
end, 1);
454 if (numChannels >= 2)
463 for (
auto c = 0;c < data.
Channels(); ++c)
468 auto oResult = downstream.Acquire(
mFloatBuffers, maxToProcess);
474 const auto result = *oResult;
475 maxOut = std::max(maxOut, result);
479 const auto limit = std::min<size_t>(upstream.Channels(), maxChannels);
480 for (
size_t j = 0; j < limit; ++j)
483 auto& sequence = upstream.GetSequence();
489 gains[c] = sequence.GetChannelGain(c);
491 gains[c] = sequence.GetChannelGain(j);
496 gains[0] /=
static_cast<float>(limit);
500 findChannelFlags(upstream.MixerSpec(j), sequence, j);
504 downstream.Release();
512 assert(maxOut <= maxToProcess);
527 const auto&
factory = [&stage] {
542 return pNewDownstream;
static void MixBuffers(unsigned numChannels, const unsigned char *channelFlags, const float *gains, const float &src, AudioGraph::Buffers &dests, int len)
#define stackAllocate(T, count)
static const AttachedProjectObjects::RegisteredFactory masterEffects
static Settings & settings()
Accumulates (non-interleaved) data during effect processing.
float & GetWritePosition(unsigned iChannel)
Get writable position for one channel.
void Advance(size_t count)
Move the positions.
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.
Upstream producer of sample streams, taking Buffers as external context.
static std::unique_ptr< EffectStage > Create(int channel, int nInputChannels, Source &upstream, Buffers &inBuffers, const Factory &factory, EffectSettings &settings, double sampleRate, std::optional< sampleCount > genLength)
Satisfies postcondition of constructor or returns null.
AudioGraph::Buffers mFloatBuffers
bool AcceptsBuffers(const Buffers &buffers) const override
bool Release() override
Caller is done examining last Acquire()d positions.
const ApplyGain mApplyGain
bool AcceptsBlockSize(size_t blockSize) const override
std::vector< EffectSettings > mSettings
const std::vector< SampleBuffer > mBuffer
std::vector< AudioGraph::Source * > mMasterStages
std::vector< Input > Inputs
std::vector< std::unique_ptr< EffectStage > > mStages
void SetSpeedForKeyboardScrubbing(double speed, double startTime)
std::vector< Source > mDecoratedSources
sampleFormat EffectiveFormat() const
Deduce the effective width of the output, which may be narrower than the stored format.
const sampleFormat mFormat
std::optional< size_t > Acquire(Buffers &data, size_t bound) override
Occupy vacant space in Buffers with some data.
AudioGraph::Buffers mTemp
std::pair< bool, sampleFormat > NeedsDither(bool needsDither, double rate) const
const unsigned mNumChannels
sampleFormat mEffectiveFormat
constSamplePtr GetBuffer()
Retrieve the main buffer or the interleaved buffer.
std::vector< MixerOptions::StageSpecification > Stages
std::vector< AudioGraph::Buffers > mStageBuffers
double MixGetCurrentTime()
Current time in seconds (unwarped, i.e. always between startTime and stopTime)
sampleCount Remaining() const override
Result includes any amount Acquired and not yet Released.
std::vector< MixerSource > mSources
Mixer(Inputs inputs, std::optional< Stages > masterEffects, bool mayThrow, const WarpOptions &warpOptions, double startTime, double stopTime, unsigned numOutChannels, size_t outBufferSize, bool outInterleaved, double outRate, sampleFormat outFormat, bool highQuality=true, MixerSpec *mixerSpec=nullptr, ApplyGain applyGain=ApplyGain::MapChannels)
size_t BufferSize() const
void Reposition(double t, bool bSkipping=false)
Reposition processing to absolute time next time Process() is called.
std::unique_ptr< EffectStage > & RegisterEffectStage(AudioGraph::Source &upstream, const MixerOptions::StageSpecification &stage, double outRate)
void SetTimesAndSpeed(double t0, double t1, double speed, bool bSkipping=false)
Used in scrubbing and other nonuniform playback policies.
const std::shared_ptr< TimesAndSpeed > mTimesAndSpeed
A matrix of booleans, one row per input channel, column per output.
bool VariableRates() const
Positions or offsets within audio files need a wide type.
bool IsMono(const Channel &channel)
Whether the channel is mono.
void ConsiderStages(const Mixer::Stages &stages, size_t &blockSize)
size_t FindBufferSize(const Mixer::Inputs &inputs, const std::optional< Mixer::Stages > &masterEffects, size_t bufferSize)
std::vector< std::vector< T > > initVector(size_t dim1, size_t dim2)
const char * end(const char *str) noexcept
void copy(const T *src, T *dst, int32_t n)
std::shared_ptr< EffectInstance > mpFirstInstance
Immutable structure is an argument to Mixer's constructor.