31template<
typename T,
typename F> std::vector<T>
34 std::vector<T> result( dim1 );
35 for (
auto &row : result)
40template<
typename T> std::vector<std::vector<T>>
43 return initVector<std::vector<T>>(dim1,
44 [dim2](
auto &row){ row.resize(dim2); });
54 for (
const auto& stage : stages)
57 const auto pInstance = stage.factory();
59 blockSize =
std::min(blockSize, pInstance->SetBlockSize(blockSize));
61 stage.mpFirstInstance = move(pInstance);
68 const std::optional<Mixer::Stages>&
masterEffects,
size_t bufferSize)
70 size_t blockSize = bufferSize;
71 for (
const auto &input : inputs) {
72 const auto sequence = input.pSequence.get();
73 const auto nInChannels = sequence->NChannels();
94 const WarpOptions& warpOptions,
const double startTime,
95 const double stopTime,
const unsigned numOutChannels,
96 const size_t outBufferSize,
const bool outInterleaved,
double outRate,
99 : mNumChannels { numOutChannels }
100 , mInputs { move(inputs) }
102 , mBufferSize {
FindBufferSize(mInputs, mMasterEffects, outBufferSize) }
103 , mApplyVolume { applyVolume }
104 , mHighQuality { highQuality }
105 , mFormat { outFormat }
106 , mInterleaved { outInterleaved }
108 startTime, stopTime, warpOptions.initialSpeed, startTime }) }
111 , mTemp { mNumChannels, mBufferSize, 1, 1 }
113 mInterleaved ? 1 : mNumChannels,
115 size = mBufferSize * (mInterleaved ? mNumChannels : 1)](
116 auto& buffer) { buffer.Allocate(
size,
format); }) }
120 const auto nChannelsIn =
121 std::accumulate(mInputs.begin(), mInputs.end(),
size_t{},
122 [](
auto sum,
const auto &input){
123 return sum + input.pSequence->NChannels(); });
127 bool needsDither = std::any_of(mInputs.begin(), mInputs.end(),
128 [](
const Input &input){
129 return std::any_of(input.stages.begin(), input.stages.end(), NeedsDitherPred); }
132 needsDither |= std::any_of(
135 auto pMixerSpec = ( mixerSpec &&
136 mixerSpec->GetNumChannels() == mNumChannels &&
137 mixerSpec->GetNumTracks() == nChannelsIn
138 ) ? mixerSpec :
nullptr;
139 mHasMixerSpec = pMixerSpec !=
nullptr;
142 mSources.reserve(nChannelsIn);
144 const auto nMasterStages = mMasterEffects ? mMasterEffects->size() : 0;
147 mInputs.begin(), mInputs.end(), 0,
148 [](
auto sum,
const auto& input) {
149 return sum + input.stages.size();
152 mSettings.reserve(nStages);
153 mStageBuffers.reserve(nStages);
156 std::vector<std::unique_ptr<DownmixSource>> downmixSources;
157 for (
auto &input : mInputs) {
158 const auto &sequence = input.pSequence;
164 auto &source = mSources.emplace_back(sequence,
BufferSize(), outRate,
165 warpOptions, highQuality, mayThrow, mTimesAndSpeed);
167 for (
const auto &stage : input.stages)
169 auto& pNewDownstream =
170 RegisterEffectStage(*pDownstream, sequence->NChannels(), stage, outRate))
172 pDownstream = pNewDownstream.get();
174 downmixSources.emplace_back(
175 std::make_unique<SequenceDownmixSource>(
178 pMixerSpec ? &pMixerSpec->mMap[i] :
nullptr
182 i += sequence->NChannels();
185 if (mMasterEffects && !mMasterEffects->empty())
187 mDownmixStage = std::make_unique<DownmixStage>(
188 std::move(downmixSources), mNumChannels, mBufferSize, ApplyVolume::MapChannels
192 for (
const auto& stage : *mMasterEffects)
195 auto& pNewDownstream =
196 RegisterEffectStage(*pDownstream, mNumChannels, stage, outRate))
198 pDownstream = pNewDownstream.get();
204 std::vector<std::unique_ptr<DownmixSource>> masterDownmixSources;
205 masterDownmixSources.push_back(std::make_unique<SimpleDonwmixSource>(*pDownstream, mNumChannels));
206 mMasterDownmixStage = std::make_unique<DownmixStage>(
207 std::move(masterDownmixSources), mNumChannels, mBufferSize, ApplyVolume::Mixdown);
208 mDownstream = mMasterDownmixStage.get();
212 mDownmixStage = std::make_unique<DownmixStage>(
213 std::move(downmixSources),
218 mDownstream = mDownmixStage.get();
222 std::tie(mNeedsDither, mEffectiveFormat) = NeedsDither(needsDither, outRate);
227std::pair<bool, sampleFormat>
242 for (
const auto &input :
mSources) {
243 auto &sequence = input.GetSequence();
245 if (sequence.GetRate() != rate)
256 for (
auto c : {0, 1}) {
257 const auto volume = sequence.GetChannelVolume(c);
258 if (!(volume == 0.0 || volume == 1.0))
267 if (!sequence.HasTrivialEnvelope())
270 auto effectiveFormat = sequence.WidestEffectiveFormat();
275 widestEffectiveFormat =
276 std::max(widestEffectiveFormat, effectiveFormat);
284 assert(widestEffectiveFormat <=
mFormat);
285 return {
false, widestEffectiveFormat };
305 auto oldTime = mTime;
307 const auto backwards = (mT0 > mT1);
311 std::optional<size_t> maxOut;
320 mTime = std::clamp(mTime, mT1, oldTime);
322 mTime = std::clamp(mTime, oldTime, mT1);
340 assert(*maxOut <= maxToProcess);
369 const bool backwards = (mT1 < mT0);
371 mTime = std::clamp(mTime, mT1, mT0);
373 mTime = std::clamp(mTime, mT0, mT1);
376 source.Reposition(mTime, bSkipping);
381 wxASSERT(std::isfinite(speed));
385 mSpeed = fabs(speed);
391 wxASSERT(std::isfinite(speed));
395 if ((speed > 0.0 && mT1 < mT0) || (speed < 0.0 && mT1 > mT0)) {
399 if (speed > 0.0 && mT1 < mT0) {
401 mT1 = std::numeric_limits<double>::max();
404 mT0 = std::numeric_limits<double>::max();
411 mSpeed = fabs(speed);
426 const auto&
factory = [&stage] {
441 return pNewDownstream;
static const AttachedProjectObjects::RegisteredFactory masterEffects
static Settings & settings()
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.
virtual std::optional< size_t > Acquire(Buffers &data, size_t bound)=0
Occupy vacant space in Buffers with some data.
virtual bool Release()=0
Caller is done examining last Acquire()d positions.
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.
std::unique_ptr< EffectStage > & RegisterEffectStage(AudioGraph::Source &upstream, size_t numChannels, const MixerOptions::StageSpecification &stage, double outRate)
AudioGraph::Source * mDownstream
std::vector< EffectSettings > mSettings
const std::vector< SampleBuffer > mBuffer
std::vector< Input > Inputs
std::vector< std::unique_ptr< EffectStage > > mStages
void SetSpeedForKeyboardScrubbing(double speed, double startTime)
sampleFormat EffectiveFormat() const
Deduce the effective width of the output, which may be narrower than the stored format.
const sampleFormat mFormat
AudioGraph::Buffers mTemp
const ApplyVolume mApplyVolume
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
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, ApplyVolume applyVolume=ApplyVolume::MapChannels)
std::vector< AudioGraph::Buffers > mStageBuffers
double MixGetCurrentTime()
Current time in seconds (unwarped, i.e. always between startTime and stopTime)
std::vector< MixerSource > mSources
size_t BufferSize() const
void Reposition(double t, bool bSkipping=false)
Reposition processing to absolute time next time Process() is called.
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
void ConsiderStages(const Mixer::Stages &stages, size_t &blockSize)
auto NeedsDitherPred(const MixerOptions::StageSpecification &spec)
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)
std::shared_ptr< EffectInstance > mpFirstInstance
Immutable structure is an argument to Mixer's constructor.