30template<
typename T,
typename F> std::vector<T>
33 std::vector<T> result( dim1 );
34 for (
auto &row : result)
39template<
typename T> std::vector<std::vector<T>>
42 return initVector<std::vector<T>>(dim1,
43 [dim2](
auto &row){ row.resize(dim2); });
51 size_t blockSize = bufferSize;
52 const auto nTracks = inputs.size();
53 for (
size_t i = 0; i < nTracks;) {
54 const auto &input = inputs[i];
55 const auto leader = input.pTrack.get();
57 if (!leader || i + nInChannels > nTracks) {
61 auto increment =
finally([&]{ i += nInChannels; });
62 for (
const auto &stage : input.stages) {
64 const auto pInstance = stage.factory();
66 blockSize =
std::min(blockSize, pInstance->SetBlockSize(blockSize));
68 stage.mpFirstInstance = move(pInstance);
78 const double startTime,
const double stopTime,
79 const unsigned numOutChannels,
80 const size_t outBufferSize,
const bool outInterleaved,
82 const bool highQuality,
MixerSpec *
const mixerSpec,
83 const bool applyTrackGains
84) : mNumChannels{ numOutChannels }
85 , mInputs{ move(inputs) }
87 , mApplyTrackGains{ applyTrackGains }
88 , mHighQuality{ highQuality }
89 , mFormat{ outFormat }
90 , mInterleaved{ outInterleaved }
93 startTime, stopTime, warpOptions.initialSpeed, startTime
102 , mFloatBuffers{ 3, mBufferSize, 1, 1 }
105 , mTemp{
initVector<float>(mNumChannels, mBufferSize) }
108 size = mBufferSize * (mInterleaved ? mNumChannels : 1)
109 ](auto &buffer){ buffer.Allocate(
size,
format); }
114 const auto nTracks = mInputs.size();
118 bool needsDither = std::any_of(mInputs.begin(), mInputs.end(),
119 [](
const Input &input){
120 return std::any_of(input.stages.begin(), input.stages.end(),
121 [](const MixerOptions::StageSpecification &spec){
122 return spec.mpFirstInstance &&
123 spec.mpFirstInstance->NeedsDither(); } ); } );
125 auto pMixerSpec = ( mixerSpec &&
126 mixerSpec->GetNumChannels() == mNumChannels &&
127 mixerSpec->GetNumTracks() == nTracks
128 ) ? mixerSpec :
nullptr;
131 mSources.reserve(nTracks);
132 auto nStages = std::accumulate(mInputs.begin(), mInputs.end(), 0,
133 [](
auto sum,
auto &input){ return sum + input.stages.size(); });
134 mSettings.reserve(nStages);
135 mStageBuffers.reserve(nStages);
137 for (
size_t i = 0; i < nTracks;) {
138 const auto &input = mInputs[i];
139 const auto leader = input.pTrack.get();
141 if (!leader || i + nInChannels > nTracks) {
145 auto increment =
finally([&]{ i += nInChannels; });
147 auto &source = mSources.emplace_back( *leader,
BufferSize(), outRate,
148 warpOptions, highQuality, mayThrow, mTimesAndSpeed,
149 (pMixerSpec ? &pMixerSpec->mMap[i] :
nullptr));
151 for (
const auto &stage : input.stages) {
153 auto &
settings = mSettings.emplace_back(stage.settings);
158 auto &stageInput = mStageBuffers.emplace_back(3, mBufferSize, 1);
159 const auto &
factory = [&stage]{
161 return stage.mpFirstInstance
162 ? move(stage.mpFirstInstance)
165 auto &pNewDownstream =
167 *pDownstream, stageInput,
171 pDownstream = pNewDownstream.get();
175 mStageBuffers.pop_back();
176 mSettings.pop_back();
179 mDecoratedSources.emplace_back(Source{ source, *pDownstream });
183 std::tie(mNeedsDither, mEffectiveFormat) = NeedsDither(needsDither, outRate);
190std::pair<bool, sampleFormat>
205 for (
const auto &input :
mInputs) {
206 auto &pTrack = input.pTrack;
209 auto &track = *pTrack;
210 if (track.GetRate() != rate)
215 for (
auto c : {0, 1}) {
216 const auto gain = track.GetChannelGain(c);
217 if (!(gain == 0.0 || gain == 1.0))
227 if (!track.HasTrivialEnvelope())
230 auto effectiveFormat = track.WidestEffectiveFormat();
235 widestEffectiveFormat =
236 std::max(widestEffectiveFormat, effectiveFormat);
244 assert(widestEffectiveFormat <=
mFormat);
245 return {
false, widestEffectiveFormat };
251 for (
auto &buffer:
mTemp)
252 std::fill(buffer.begin(), buffer.end(), 0);
256 const unsigned char *channelFlags,
const float *gains,
257 const float &src, std::vector<std::vector<float>> &dests,
int len)
259 const auto pSrc = &src;
260 for (
unsigned int c = 0; c < numChannels; c++) {
261 if (!channelFlags[c])
263 float *dest = dests[c].data();
264 float gain = gains[c];
265 for (
int j = 0; j < len; ++j)
266 *dest++ += pSrc[j] * gain;
270#define stackAllocate(T, count) static_cast<T*>(alloca(count * sizeof(T)))
288 auto findChannelFlags = [&channelFlags, numChannels =
mNumChannels]
290 const auto end = channelFlags + numChannels;
291 std::fill(channelFlags,
end, 0);
294 std::copy(map, map + numChannels, channelFlags);
295 else switch(channel) {
298 std::fill(channelFlags,
end, 1);
304 if (numChannels >= 2)
314 auto oldTime = mTime;
316 const auto backwards = (mT0 > mT1);
323 auto oResult = downstream.Acquire(
mFloatBuffers, maxToProcess);
329 auto result = *oResult;
330 maxOut = std::max(maxOut, result);
334 const auto limit = std::min<size_t>(upstream.Channels(), maxChannels);
335 for (
size_t j = 0; j < limit; ++j) {
337 const auto track = upstream.GetChannel(j);
340 gains[c] = track->GetChannelGain(c);
342 findChannelFlags(upstream.MixerSpec(j), track->GetChannel());
346 downstream.Release();
352 mTime = std::clamp(mTime, mT1, oldTime);
354 mTime = std::clamp(mTime, oldTime, mT1);
372 assert(maxOut <= maxToProcess);
403 for(
size_t i=0; i<mNumInputTracks; i++)
404 mSamplePos[i] = mInputTrack[i].GetTrack()->TimeToLongSamples(mT0);
406 for(
size_t i=0; i<mNumInputTracks; i++) {
422 const bool backwards = (mT1 < mT0);
424 mTime = std::clamp(mTime, mT1, mT0);
426 mTime = std::clamp(mTime, mT0, mT1);
429 source.Reposition(mTime, bSkipping);
434 wxASSERT(std::isfinite(speed));
438 mSpeed = fabs(speed);
444 wxASSERT(std::isfinite(speed));
448 if ((speed > 0.0 && mT1 < mT0) || (speed < 0.0 && mT1 > mT0)) {
452 if (speed > 0.0 && mT1 < mT0) {
454 mT1 = std::numeric_limits<double>::max();
457 mT0 = std::numeric_limits<double>::max();
464 mSpeed = fabs(speed);
static void MixBuffers(unsigned numChannels, const unsigned char *channelFlags, const float *gains, const float &src, std::vector< std::vector< float > > &dests, int len)
#define stackAllocate(T, count)
static Settings & settings()
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
constSamplePtr GetReadPosition(unsigned iChannel) const
Get accumulated data for one channel.
static std::unique_ptr< EffectStage > Create(bool multi, Source &upstream, Buffers &inBuffers, const Factory &factory, EffectSettings &settings, double sampleRate, std::optional< sampleCount > genLength, const Track &track)
Satisfies postcondition of constructor or returns null.
Upstream producer of sample streams, taking Buffers as external context.
AudioGraph::Buffers mFloatBuffers
const std::vector< SampleBuffer > mBuffer
std::vector< Input > Inputs
void SetSpeedForKeyboardScrubbing(double speed, double startTime)
std::vector< Source > mDecoratedSources
const bool mApplyTrackGains
sampleFormat EffectiveFormat() const
Deduce the effective width of the output, which may be narrower than the stored format.
const sampleFormat mFormat
std::vector< std::vector< float > > mTemp
std::pair< bool, sampleFormat > NeedsDither(bool needsDither, double rate) const
void Restart()
Restart processing at beginning of buffer next time Process() is called.
const unsigned mNumChannels
sampleFormat mEffectiveFormat
constSamplePtr GetBuffer()
Retrieve the main buffer or the interleaved buffer.
Mixer(Inputs inputs, 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, bool applytTrackGains=true)
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
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
size_t FindBufferSize(const Mixer::Inputs &inputs, size_t bufferSize)
std::vector< std::vector< T > > initVector(size_t dim1, size_t dim2)
static RegisteredToolbarFactory factory
Immutable structure is an argument to Mixer's constructor.