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 size_t blockSize = bufferSize;
51 const auto nTracks = inputs.size();
52 for (
size_t i = 0; i < nTracks;) {
53 const auto &input = inputs[i];
54 const auto leader = input.pTrack.get();
56 if (!leader || i + nInChannels > nTracks) {
60 auto increment =
finally([&]{ i += nInChannels; });
61 for (
const auto &stage : input.stages)
62 blockSize =
std::min(blockSize, stage.mpInstance->SetBlockSize(blockSize));
71 const double startTime,
const double stopTime,
72 const unsigned numOutChannels,
73 const size_t outBufferSize,
const bool outInterleaved,
75 const bool highQuality,
MixerSpec *
const mixerSpec,
76 const bool applyTrackGains
77) : mNumChannels{ numOutChannels }
78 , mInputs{ move(inputs) }
80 , mApplyTrackGains{ applyTrackGains }
81 , mHighQuality{ highQuality }
82 , mFormat{ outFormat }
83 , mInterleaved{ outInterleaved }
86 startTime, stopTime, warpOptions.initialSpeed, startTime
91 , mFloatBuffers{ 2, mBufferSize, 1, 1 }
94 , mTemp{
initVector<float>(mNumChannels, mBufferSize) }
97 size = mBufferSize * (mInterleaved ? mNumChannels : 1)
98 ](auto &buffer){ buffer.Allocate(
size,
format); }
102 const auto nTracks = mInputs.size();
104 auto pMixerSpec = ( mixerSpec &&
105 mixerSpec->GetNumChannels() == mNumChannels &&
106 mixerSpec->GetNumTracks() == nTracks
107 ) ? mixerSpec :
nullptr;
110 mSources.reserve(nTracks);
111 auto nStages = std::accumulate(mInputs.begin(), mInputs.end(), 0,
112 [](
auto sum,
auto &input){ return sum + input.stages.size(); });
113 mSettings.reserve(nStages);
114 mStageBuffers.reserve(nStages);
116 for (
size_t i = 0; i < nTracks;) {
117 const auto &input = mInputs[i];
118 const auto leader = input.pTrack.get();
120 if (!leader || i + nInChannels > nTracks) {
124 auto increment =
finally([&]{ i += nInChannels; });
126 auto &source = mSources.emplace_back( *leader,
BufferSize(), outRate,
127 warpOptions, highQuality, mayThrow, mTimesAndSpeed,
128 (pMixerSpec ? &pMixerSpec->mMap[i] :
nullptr));
130 for (
const auto &stage : input.stages) {
132 auto &
settings = mSettings.emplace_back(stage.settings);
135 auto &stageInput = mStageBuffers.emplace_back(2, mBufferSize, 1);
137 mStages.emplace_back(std::make_unique<AudioGraph::EffectStage>(
138 *pDownstream, stageInput,
139 *stage.mpInstance,
settings, outRate, std::nullopt,
143 mDecoratedSources.emplace_back(Source{ source, *pDownstream });
153 for (
auto &buffer:
mTemp)
154 std::fill(buffer.begin(), buffer.end(), 0);
158 const unsigned char *channelFlags,
const float *gains,
159 const float &src, std::vector<std::vector<float>> &dests,
int len)
161 const auto pSrc = &src;
162 for (
unsigned int c = 0; c < numChannels; c++) {
163 if (!channelFlags[c])
165 float *dest = dests[c].data();
166 float gain = gains[c];
167 for (
int j = 0; j < len; ++j)
168 *dest++ += pSrc[j] * gain;
172#define stackAllocate(T, count) static_cast<T*>(alloca(count * sizeof(T)))
190 auto findChannelFlags = [&channelFlags, numChannels =
mNumChannels]
192 const auto end = channelFlags + numChannels;
193 std::fill(channelFlags,
end, 0);
196 std::copy(map, map + numChannels, channelFlags);
197 else switch(channel) {
200 std::fill(channelFlags,
end, 1);
206 if (numChannels >= 2)
216 auto oldTime = mTime;
218 const auto backwards = (mT0 > mT1);
225 auto oResult = downstream.Acquire(
mFloatBuffers, maxToProcess);
228 auto result = *oResult;
229 maxOut = std::max(maxOut, result);
233 const auto limit = std::min<size_t>(upstream.Channels(), maxChannels);
234 for (
size_t j = 0; j < limit; ++j) {
236 const auto track = upstream.GetChannel(j);
239 gains[c] = track->GetChannelGain(c);
241 findChannelFlags(upstream.MixerSpec(j), track->GetChannel());
245 downstream.Release();
251 mTime = std::clamp(mTime, mT1, oldTime);
253 mTime = std::clamp(mTime, oldTime, mT1);
269 assert(maxOut <= maxToProcess);
295 for(
size_t i=0; i<mNumInputTracks; i++)
296 mSamplePos[i] = mInputTrack[i].GetTrack()->TimeToLongSamples(mT0);
298 for(
size_t i=0; i<mNumInputTracks; i++) {
314 const bool backwards = (mT1 < mT0);
316 mTime = std::clamp(mTime, mT1, mT0);
318 mTime = std::clamp(mTime, mT0, mT1);
321 source.Reposition(mTime, bSkipping);
326 wxASSERT(std::isfinite(speed));
330 mSpeed = fabs(speed);
336 wxASSERT(std::isfinite(speed));
340 if ((speed > 0.0 && mT1 < mT0) || (speed < 0.0 && mT1 > mT0)) {
344 if (speed > 0.0 && mT1 < mT0) {
346 mT1 = std::numeric_limits<double>::max();
349 mT0 = std::numeric_limits<double>::max();
356 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.
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
const sampleFormat mFormat
std::vector< std::vector< float > > mTemp
const unsigned mNumChannels
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()
std::vector< MixerSource > mSources
size_t BufferSize() const
void Reposition(double t, bool bSkipping=false)
void SetTimesAndSpeed(double t0, double t1, double speed, bool bSkipping=false)
const std::shared_ptr< TimesAndSpeed > mTimesAndSpeed
A matrix of booleans, one row per input channel, column per output.
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)
Immutable structure is an argument to Mixer's constructor.