Audacity 3.2.0
Classes | Public Types | Public Member Functions | Private Member Functions | Private Attributes | List of all members
Mixer Class Reference

Functions for doing the mixdown of the tracks. More...

#include <Mix.h>

Inheritance diagram for Mixer:
[legend]
Collaboration diagram for Mixer:
[legend]

Classes

struct  Input
 
struct  Source
 

Public Types

enum class  ApplyGain { Discard , MapChannels , Mixdown }
 
using WarpOptions = MixerOptions::Warp
 
using MixerSpec = MixerOptions::Downmix
 
using ResampleParameters = MixerOptions::ResampleParameters
 
using TimesAndSpeed = MixerOptions::TimesAndSpeed
 
using Stages = std::vector< MixerOptions::StageSpecification >
 
using Inputs = std::vector< Input >
 
- Public Types inherited from AudioGraph::Source
using Buffers = AudioGraph::Buffers
 

Public Member Functions

 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)
 
 Mixer (const Mixer &)=delete
 
Mixeroperator= (const Mixer &)=delete
 
virtual ~Mixer ()
 
size_t BufferSize () const
 
size_t Process (size_t maxSamples)
 
size_t Process ()
 
void Reposition (double t, bool bSkipping=false)
 Reposition processing to absolute time next time Process() is called. More...
 
void SetTimesAndSpeed (double t0, double t1, double speed, bool bSkipping=false)
 Used in scrubbing and other nonuniform playback policies. More...
 
void SetSpeedForKeyboardScrubbing (double speed, double startTime)
 
double MixGetCurrentTime ()
 Current time in seconds (unwarped, i.e. always between startTime and stopTime) More...
 
constSamplePtr GetBuffer ()
 Retrieve the main buffer or the interleaved buffer. More...
 
constSamplePtr GetBuffer (int channel)
 Retrieve one of the non-interleaved buffers. More...
 
sampleFormat EffectiveFormat () const
 Deduce the effective width of the output, which may be narrower than the stored format. More...
 
- Public Member Functions inherited from AudioGraph::Source
virtual ~Source ()
 
virtual bool AcceptsBuffers (const Buffers &buffers) const =0
 
virtual bool AcceptsBlockSize (size_t blockSize) const =0
 
virtual std::optional< size_t > Acquire (Buffers &data, size_t bound)=0
 Occupy vacant space in Buffers with some data. More...
 
virtual sampleCount Remaining () const =0
 Result includes any amount Acquired and not yet Released. More...
 
virtual bool Release ()=0
 Caller is done examining last Acquire()d positions. More...
 
virtual bool Terminates () const
 Needed only to make some postconditions assertable; defaults true. More...
 

Private Member Functions

void Clear ()
 
bool AcceptsBuffers (const Buffers &buffers) const override
 
bool AcceptsBlockSize (size_t blockSize) const override
 
std::optional< size_t > Acquire (Buffers &data, size_t bound) override
 Occupy vacant space in Buffers with some data. More...
 
sampleCount Remaining () const override
 Result includes any amount Acquired and not yet Released. More...
 
bool Release () override
 Caller is done examining last Acquire()d positions. More...
 
std::unique_ptr< EffectStage > & RegisterEffectStage (AudioGraph::Source &upstream, const MixerOptions::StageSpecification &stage, double outRate)
 
std::pair< bool, sampleFormatNeedsDither (bool needsDither, double rate) const
 

Private Attributes

const unsigned mNumChannels
 
Inputs mInputs
 
const std::optional< StagesmMasterEffects
 
const size_t mBufferSize
 
const ApplyGain mApplyGain
 
const bool mHighQuality
 
const sampleFormat mFormat
 
const bool mInterleaved
 
sampleFormat mEffectiveFormat
 
bool mNeedsDither
 
bool mHasMixerSpec {false}
 
const std::shared_ptr< TimesAndSpeedmTimesAndSpeed
 
AudioGraph::Buffers mFloatBuffers
 
AudioGraph::Buffers mTemp
 
const std::vector< SampleBuffermBuffer
 
std::vector< MixerSourcemSources
 
std::vector< EffectSettingsmSettings
 
std::vector< AudioGraph::BuffersmStageBuffers
 
std::vector< std::unique_ptr< EffectStage > > mStages
 
std::vector< AudioGraph::Source * > mMasterStages
 
std::vector< SourcemDecoratedSources
 

Detailed Description

Functions for doing the mixdown of the tracks.

Definition at line 28 of file Mix.h.

Member Typedef Documentation

◆ Inputs

using Mixer::Inputs = std::vector<Input>

Definition at line 47 of file Mix.h.

◆ MixerSpec

Definition at line 32 of file Mix.h.

◆ ResampleParameters

Definition at line 33 of file Mix.h.

◆ Stages

Definition at line 35 of file Mix.h.

◆ TimesAndSpeed

Definition at line 34 of file Mix.h.

◆ WarpOptions

Definition at line 31 of file Mix.h.

Member Enumeration Documentation

◆ ApplyGain

enum class Mixer::ApplyGain
strong
Enumerator
Discard 
MapChannels 
Mixdown 

Definition at line 49 of file Mix.h.

50 {
51 Discard,//< No source gain is applied
52 MapChannels, //< Apply gains per source's channel
53 Mixdown, //< Average gains from all channels in the source, numOutChannels should be 1
54 };

Constructor & Destructor Documentation

◆ Mixer() [1/2]

Mixer::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 
)
Precondition
all sequences in inputs are non-null
any left channels in inputs are immediately followed by their partners
Postcondition
BufferSize() <= outBufferSize (equality when no inputs have stages)
Parameters
mixerSpecNull or else must have a lifetime enclosing this object's

Definition at line 83 of file Mix.cpp.

90 : mNumChannels { numOutChannels }
91 , mInputs { move(inputs) }
94 , mApplyGain { applyGain }
95 , mHighQuality { highQuality }
96 , mFormat { outFormat }
97 , mInterleaved { outInterleaved }
98 , mTimesAndSpeed { std::make_shared<TimesAndSpeed>(TimesAndSpeed {
99 startTime, stopTime, warpOptions.initialSpeed, startTime }) }
100
101 // PRL: Bug2536: see other comments below for the last, padding argument
102 // TODO: more-than-two-channels
103 // Issue 3565 workaround: allocate one extra buffer when applying a
104 // GVerb effect stage. It is simply discarded
105 // See also issue 3854, when the number of out channels expected by the
106 // plug-in is yet larger
107 , mFloatBuffers { 3, mBufferSize, 1, 1 }
108
109 // non-interleaved
110 , mTemp { mNumChannels, mBufferSize, 1, 1 }
111 , mBuffer { initVector<SampleBuffer>(
113 [format = mFormat,
115 auto& buffer) { buffer.Allocate(size, format); }) }
117{
118 assert(BufferSize() <= outBufferSize);
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(); });
123
124 // Examine the temporary instances that were made in FindBufferSize
125 // This finds a sufficient, but not necessary, condition to do dithering
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(); } ); } );
132 if (mMasterEffects)
133 needsDither |= std::any_of(
134 mMasterEffects->begin(), mMasterEffects->end(),
135 [](const MixerOptions::StageSpecification& spec) {
136 return spec.mpFirstInstance && spec.mpFirstInstance->NeedsDither();
137 });
138
139 auto pMixerSpec = ( mixerSpec &&
140 mixerSpec->GetNumChannels() == mNumChannels &&
141 mixerSpec->GetNumTracks() == nChannelsIn
142 ) ? mixerSpec : nullptr;
143 mHasMixerSpec = pMixerSpec != nullptr;
144
145 // Reserve vectors first so we can take safe references to pushed elements
146 mSources.reserve(nChannelsIn);
147 // One stereo-capable stage per effect.
148 const auto nMasterStages = mMasterEffects ? mMasterEffects->size() : 0;
149 const auto nStages =
150 std::accumulate(
151 mInputs.begin(), mInputs.end(), 0,
152 [](auto sum, const auto& input) {
153 return sum + input.stages.size() * input.pSequence->NChannels();
154 }) +
155 nMasterStages;
156 mSettings.reserve(nStages);
157 mStageBuffers.reserve(nStages);
158
159 size_t i = 0;
160 for (auto &input : mInputs) {
161 const auto &sequence = input.pSequence;
162 if (!sequence) {
163 assert(false);
164 break;
165 }
166 auto increment = finally([&]{ i += sequence->NChannels(); });
167
168 auto &source = mSources.emplace_back(sequence, BufferSize(), outRate,
169 warpOptions, highQuality, mayThrow, mTimesAndSpeed,
170 (pMixerSpec ? &pMixerSpec->mMap[i] : nullptr));
171 AudioGraph::Source *pDownstream = &source;
172 for (const auto &stage : input.stages)
173 if (
174 auto& pNewDownstream =
175 RegisterEffectStage(*pDownstream, stage, outRate))
176 {
177 pDownstream = pNewDownstream.get();
178 }
179 mDecoratedSources.emplace_back(Source{ source, *pDownstream });
180 }
181
182 if (mMasterEffects)
183 {
184 AudioGraph::Source* pDownstream = this;
185 for (const auto& stage : *mMasterEffects)
186 if (
187 auto& pNewDownstream =
188 RegisterEffectStage(*pDownstream, stage, outRate))
189 {
190 mMasterStages.emplace_back(pDownstream = pNewDownstream.get());
191 }
192 }
193
194 // Decide once at construction time
195 std::tie(mNeedsDither, mEffectiveFormat) = NeedsDither(needsDither, outRate);
196}
static const AttachedProjectObjects::RegisteredFactory masterEffects
Upstream producer of sample streams, taking Buffers as external context.
AudioGraph::Buffers mFloatBuffers
Definition: Mix.h:168
const ApplyGain mApplyGain
Definition: Mix.h:153
std::vector< EffectSettings > mSettings
Definition: Mix.h:179
const std::vector< SampleBuffer > mBuffer
Definition: Mix.h:176
std::vector< AudioGraph::Source * > mMasterStages
Definition: Mix.h:182
std::vector< Source > mDecoratedSources
Definition: Mix.h:185
const sampleFormat mFormat
Definition: Mix.h:155
Inputs mInputs
Definition: Mix.h:141
MixerOptions::TimesAndSpeed TimesAndSpeed
Definition: Mix.h:34
AudioGraph::Buffers mTemp
Definition: Mix.h:173
std::pair< bool, sampleFormat > NeedsDither(bool needsDither, double rate) const
Definition: Mix.cpp:201
const unsigned mNumChannels
Definition: Mix.h:140
sampleFormat mEffectiveFormat
Definition: Mix.h:159
const std::optional< Stages > mMasterEffects
Definition: Mix.h:142
const bool mInterleaved
Definition: Mix.h:156
const size_t mBufferSize
Definition: Mix.h:145
bool mNeedsDither
Definition: Mix.h:160
std::vector< AudioGraph::Buffers > mStageBuffers
Definition: Mix.h:180
const bool mHighQuality
Definition: Mix.h:154
std::vector< MixerSource > mSources
Definition: Mix.h:178
size_t BufferSize() const
Definition: Mix.h:80
std::unique_ptr< EffectStage > & RegisterEffectStage(AudioGraph::Source &upstream, const MixerOptions::StageSpecification &stage, double outRate)
Definition: Mix.cpp:516
const std::shared_ptr< TimesAndSpeed > mTimesAndSpeed
Definition: Mix.h:163
bool mHasMixerSpec
Definition: Mix.h:161
unsigned GetNumTracks() const
Definition: MixerOptions.h:50
unsigned GetNumChannels() const
Definition: MixerOptions.h:47
size_t FindBufferSize(const Mixer::Inputs &inputs, const std::optional< Mixer::Stages > &masterEffects, size_t bufferSize)
Definition: Mix.cpp:62

References anonymous_namespace{ExportPCM.cpp}::format, and size.

◆ Mixer() [2/2]

Mixer::Mixer ( const Mixer )
delete

◆ ~Mixer()

Mixer::~Mixer ( )
virtualdefault

Member Function Documentation

◆ AcceptsBlockSize()

bool Mixer::AcceptsBlockSize ( size_t  blockSize) const
overrideprivatevirtual

Implements AudioGraph::Source.

Definition at line 413 of file Mix.cpp.

414{
415 return blockSize <= BufferSize();
416}

References BufferSize().

Referenced by AcceptsBuffers().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ AcceptsBuffers()

bool Mixer::AcceptsBuffers ( const Buffers buffers) const
overrideprivatevirtual

Implements AudioGraph::Source.

Definition at line 407 of file Mix.cpp.

408{
409 return buffers.Channels() == mNumChannels &&
410 AcceptsBlockSize(buffers.BlockSize());
411}
bool AcceptsBlockSize(size_t blockSize) const override
Definition: Mix.cpp:413

References AcceptsBlockSize(), AudioGraph::Buffers::BlockSize(), AudioGraph::Buffers::Channels(), and mNumChannels.

Here is the call graph for this function:

◆ Acquire()

std::optional< size_t > Mixer::Acquire ( Buffers data,
size_t  bound 
)
overrideprivatevirtual

Occupy vacant space in Buffers with some data.

May exceeed a single block of production Can assume same buffer is passed each time, while the caller advances it over the previous production, or discards it, or rotates the buffer. May rewind or rotate the buffer.

Returns
number of positions available to read from data or nullopt to fail
Precondition
AcceptsBuffers(data)
AcceptsBlockSize(data.BlockSize())
bound <= data.BlockSize()
data.BlockSize() <= data.Remaining()
Postcondition
result: !result || *result <= bound
result: !result || *result <= data.Remaining()
result: !result || *result <= Remaining()
data.Remaining() > 0
result: !result || bound == 0 || Remaining() == 0 || *result > 0 (progress guarantee)
!Terminates() or Remaining() was not previously defined, or is unchanged

Implements AudioGraph::Source.

Definition at line 432 of file Mix.cpp.

433{
434 // TODO: more-than-two-channels
435 auto maxChannels = std::max(2u, mFloatBuffers.Channels());
436 const auto channelFlags = stackAllocate(unsigned char, mNumChannels);
437 const auto gains = stackAllocate(float, mNumChannels);
439 std::fill(gains, gains + mNumChannels, 1.0f);
440
441 // Decides which output buffers an input channel accumulates into
442 auto findChannelFlags = [&channelFlags, numChannels = mNumChannels]
443 (const bool *map, const WideSampleSequence &sequence, size_t iChannel){
444 const auto end = channelFlags + numChannels;
445 std::fill(channelFlags, end, 0);
446 if (map)
447 // ignore left and right when downmixing is customized
448 std::copy(map, map + numChannels, channelFlags);
449 else if (IsMono(sequence))
450 std::fill(channelFlags, end, 1);
451 else if (iChannel == 0)
452 channelFlags[0] = 1;
453 else if (iChannel == 1) {
454 if (numChannels >= 2)
455 channelFlags[1] = 1;
456 else
457 channelFlags[0] = 1;
458 }
459 return channelFlags;
460 };
461
462 size_t maxOut = 0;
463 for (auto c = 0;c < data.Channels(); ++c)
464 data.ClearBuffer(c, maxToProcess);
465
466 for (auto& [upstream, downstream] : mDecoratedSources)
467 {
468 auto oResult = downstream.Acquire(mFloatBuffers, maxToProcess);
469 // One of MixVariableRates or MixSameRate assigns into mTemp[*][*]
470 // which are the sources for the CopySamples calls, and they copy into
471 // mBuffer[*][*]
472 if (!oResult)
473 return 0;
474 const auto result = *oResult;
475 maxOut = std::max(maxOut, result);
476
477 // Insert effect stages here! Passing them all channels of the track
478
479 const auto limit = std::min<size_t>(upstream.Channels(), maxChannels);
480 for (size_t j = 0; j < limit; ++j)
481 {
482 const auto pFloat = (const float*)mFloatBuffers.GetReadPosition(j);
483 auto& sequence = upstream.GetSequence();
485 {
486 for (size_t c = 0; c < mNumChannels; ++c)
487 {
488 if (mNumChannels > 1)
489 gains[c] = sequence.GetChannelGain(c);
490 else
491 gains[c] = sequence.GetChannelGain(j);
492 }
493 if (
495 mNumChannels == 1)
496 gains[0] /= static_cast<float>(limit);
497 }
498
499 const auto flags =
500 findChannelFlags(upstream.MixerSpec(j), sequence, j);
501 MixBuffers(mNumChannels, flags, gains, *pFloat, data, result);
502 }
503
504 downstream.Release();
505 mFloatBuffers.Advance(result);
507 }
508
509 // MB: this doesn't take warping into account, replaced with code based on mSamplePos
510 //mT += (maxOut / mRate);
511
512 assert(maxOut <= maxToProcess);
513 return maxOut;
514}
static void MixBuffers(unsigned numChannels, const unsigned char *channelFlags, const float *gains, const float &src, AudioGraph::Buffers &dests, int len)
Definition: Mix.cpp:268
#define stackAllocate(T, count)
Definition: Mix.cpp:282
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.
bool IsMono(const Channel &channel)
Whether the channel is mono.
const char * end(const char *str) noexcept
Definition: StringUtils.h:106
void copy(const T *src, T *dst, int32_t n)
Definition: VectorOps.h:40

References AudioGraph::Buffers::Advance(), AudioGraph::Buffers::Channels(), AudioGraph::Buffers::ClearBuffer(), staffpad::vo::copy(), Discard, details::end(), AudioGraph::Buffers::GetReadPosition(), anonymous_namespace{StretchingSequenceIntegrationTest.cpp}::iChannel, AudioGraph::IsMono(), mApplyGain, mDecoratedSources, mFloatBuffers, mHasMixerSpec, MixBuffers(), Mixdown, mNumChannels, AudioGraph::Buffers::Rotate(), and stackAllocate.

Referenced by Process().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ BufferSize()

size_t Mixer::BufferSize ( ) const
inline

Definition at line 80 of file Mix.h.

80{ return mBufferSize; }

Referenced by AcceptsBlockSize(), and Process().

Here is the caller graph for this function:

◆ Clear()

void Mixer::Clear ( )
private

Definition at line 262 of file Mix.cpp.

263{
264 for (auto c = 0; c < mTemp.Channels(); ++c)
266}
void ClearBuffer(unsigned iChannel, size_t n)

References AudioGraph::Buffers::Channels(), AudioGraph::Buffers::ClearBuffer(), mBufferSize, and mTemp.

Referenced by Process().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ EffectiveFormat()

sampleFormat Mixer::EffectiveFormat ( ) const

Deduce the effective width of the output, which may be narrower than the stored format.

Definition at line 347 of file Mix.cpp.

348{
349 return mEffectiveFormat;
350}

References mEffectiveFormat.

Referenced by MixAndRender().

Here is the caller graph for this function:

◆ GetBuffer() [1/2]

constSamplePtr Mixer::GetBuffer ( )

Retrieve the main buffer or the interleaved buffer.

Definition at line 337 of file Mix.cpp.

338{
339 return mBuffer[0].ptr();
340}

References mBuffer.

Referenced by MixAndRender().

Here is the caller graph for this function:

◆ GetBuffer() [2/2]

constSamplePtr Mixer::GetBuffer ( int  channel)

Retrieve one of the non-interleaved buffers.

Definition at line 342 of file Mix.cpp.

343{
344 return mBuffer[channel].ptr();
345}

References mBuffer.

◆ MixGetCurrentTime()

double Mixer::MixGetCurrentTime ( )

Current time in seconds (unwarped, i.e. always between startTime and stopTime)

This value is not accurate, it's useful for progress bars and indicators, but nothing else.

Definition at line 352 of file Mix.cpp.

353{
354 return mTimesAndSpeed->mTime;
355}

References mTimesAndSpeed.

Referenced by anonymous_namespace{ExportPluginHelpers.cpp}::EvalExportProgress(), and MixAndRender().

Here is the caller graph for this function:

◆ NeedsDither()

std::pair< bool, sampleFormat > Mixer::NeedsDither ( bool  needsDither,
double  rate 
) const
private

TODO: more-than-two-channels

Definition at line 201 of file Mix.cpp.

202{
203 // This will accumulate the widest effective format of any input
204 // clip
205 auto widestEffectiveFormat = narrowestSampleFormat;
206
207 // needsDither may already be given as true.
208 // There are many other possible disqualifiers for the avoidance of dither.
209 if (std::any_of(mSources.begin(), mSources.end(),
210 std::mem_fn(&MixerSource::VariableRates))
211 )
212 // We will call MixVariableRates(), so we need nontrivial resampling
213 needsDither = true;
214
215 for (const auto &input : mSources) {
216 auto &sequence = input.GetSequence();
217
218 if (sequence.GetRate() != rate)
219 // Also leads to MixVariableRates(), needs nontrivial resampling
220 needsDither = true;
221 else if (mApplyGain == ApplyGain::Mixdown &&
222 !mHasMixerSpec &&
223 sequence.NChannels() > 1 && mNumChannels == 1)
224 {
225 needsDither = true;
226 }
227 else if (mApplyGain != ApplyGain::Discard) {
229 for (auto c : {0, 1}) {
230 const auto gain = sequence.GetChannelGain(c);
231 if (!(gain == 0.0 || gain == 1.0))
232 // Fractional gain may be applied even in MixSameRate
233 needsDither = true;
234 }
235 }
236 // Examine all tracks. (This ignores the time bounds for the mixer.
237 // If it did not, we might avoid dither in more cases. But if we fix
238 // that, remember that some mixers change their time bounds after
239 // construction, as when scrubbing.)
240 if (!sequence.HasTrivialEnvelope())
241 // Varying or non-unit gain may be applied even in MixSameRate
242 needsDither = true;
243 auto effectiveFormat = sequence.WidestEffectiveFormat();
244 if (effectiveFormat > mFormat)
245 // Real, not just nominal, precision loss would happen in at
246 // least one clip
247 needsDither = true;
248 widestEffectiveFormat =
249 std::max(widestEffectiveFormat, effectiveFormat);
250 }
251
252 if (needsDither)
253 // Results will be dithered to width mFormat
254 return { true, mFormat };
255 else {
256 // Results will not be dithered
257 assert(widestEffectiveFormat <= mFormat);
258 return { false, widestEffectiveFormat };
259 }
260}
@ narrowestSampleFormat
Two synonyms for previous values that might change if more values were added.
bool VariableRates() const
Definition: MixerSource.h:65

References Discard, mApplyGain, mFormat, mHasMixerSpec, Mixdown, mNumChannels, mSources, narrowestSampleFormat, and MixerSource::VariableRates().

Here is the call graph for this function:

◆ operator=()

Mixer & Mixer::operator= ( const Mixer )
delete

◆ Process() [1/2]

size_t Mixer::Process ( )
inline
Postcondition
result: result <= BufferSize()

Definition at line 99 of file Mix.h.

99{ return Process(BufferSize()); }
size_t Process()
Definition: Mix.h:99

References BufferSize, and Process().

Referenced by Process().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Process() [2/2]

size_t Mixer::Process ( size_t  maxSamples)

Process a maximum of 'maxSamples' samples and put them into the buffer, at GetBuffer().

Precondition
maxSamples <= BufferSize()
Postcondition
result: result <= maxSamples
Returns
number of output samples, or 0, if there are no more samples that must be processed.

Definition at line 284 of file Mix.cpp.

285{
286 assert(maxToProcess <= BufferSize());
287
288 // MB: this is wrong! mT represented warped time, and mTime is too inaccurate to use
289 // it here. It's also unnecessary I think.
290 //if (mT >= mT1)
291 // return 0;
292
293 auto &[mT0, mT1, _, mTime] = *mTimesAndSpeed;
294 auto oldTime = mTime;
295 // backwards (as possibly in scrubbing)
296 const auto backwards = (mT0 > mT1);
297
298 Clear();
299
300 std::optional<size_t> maxOut;
301 if (mMasterStages.empty())
302 maxOut = Acquire(mTemp, maxToProcess);
303 else
304 {
305 const auto stage = mMasterStages.back();
306 maxOut = stage->Acquire(mTemp, maxToProcess);
307 stage->Release();
308 }
309 if (!maxOut)
310 return 0;
311
312 if (backwards)
313 mTime = std::clamp(mTime, mT1, oldTime);
314 else
315 mTime = std::clamp(mTime, oldTime, mT1);
316
317 const auto dstStride = (mInterleaved ? mNumChannels : 1);
318 auto ditherType = mNeedsDither
321 for (size_t c = 0; c < mNumChannels; ++c)
324 ? mBuffer[0].ptr() + (c * SAMPLE_SIZE(mFormat))
325 : mBuffer[c].ptr()
326 ),
327 mFormat, *maxOut, ditherType,
328 1, dstStride);
329
330 // MB: this doesn't take warping into account, replaced with code based on mSamplePos
331 //mT += (maxOut / mRate);
332
333 assert(*maxOut <= maxToProcess);
334 return *maxOut;
335}
@ none
Definition: Dither.h:20
#define _(s)
Definition: Internat.h:73
DitherType gLowQualityDither
These global variables are assigned at application startup or after change of preferences.
DitherType gHighQualityDither
void CopySamples(constSamplePtr src, sampleFormat srcFormat, samplePtr dst, sampleFormat dstFormat, size_t len, DitherType ditherType, unsigned int srcStride, unsigned int dstStride)
Copy samples from any format to any other format; apply dithering only if narrowing the format.
#define SAMPLE_SIZE(SampleFormat)
Definition: SampleFormat.h:52
std::optional< size_t > Acquire(Buffers &data, size_t bound) override
Occupy vacant space in Buffers with some data.
Definition: Mix.cpp:432
void Clear()
Definition: Mix.cpp:262

References _, Acquire(), BufferSize(), Clear(), CopySamples(), floatSample, AudioGraph::Buffers::GetReadPosition(), gHighQualityDither, gLowQualityDither, mBuffer, mFormat, mHighQuality, mInterleaved, mMasterStages, mNeedsDither, mNumChannels, mTemp, mTimesAndSpeed, none, and SAMPLE_SIZE.

Referenced by MixAndRender().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ RegisterEffectStage()

std::unique_ptr< EffectStage > & Mixer::RegisterEffectStage ( AudioGraph::Source upstream,
const MixerOptions::StageSpecification stage,
double  outRate 
)
private

Definition at line 516 of file Mix.cpp.

519{
520 // Make a mutable copy of stage.settings
521 auto& settings = mSettings.emplace_back(stage.settings);
522 // TODO: more-than-two-channels
523 // Like mFloatBuffers but padding not needed for soxr
524 // Allocate one extra buffer to hold dummy zero inputs
525 // (Issue 3854)
526 auto& stageInput = mStageBuffers.emplace_back(3, mBufferSize, 1);
527 const auto& factory = [&stage] {
528 // Avoid unnecessary repeated calls to the factory
529 return stage.mpFirstInstance ? move(stage.mpFirstInstance) :
530 stage.factory();
531 };
532 auto& pNewDownstream = mStages.emplace_back(EffectStage::Create(
533 -1, mNumChannels, upstream, stageInput, factory, settings, outRate,
534 std::nullopt));
535 if (!pNewDownstream)
536 {
537 // Just omit the failed stage from rendering
538 // TODO propagate the error?
539 mStageBuffers.pop_back();
540 mSettings.pop_back();
541 }
542 return pNewDownstream;
543}
static RegisteredToolbarFactory factory
static Settings & settings()
Definition: TrackInfo.cpp:51
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.
Definition: EffectStage.cpp:79
std::vector< std::unique_ptr< EffectStage > > mStages
Definition: Mix.h:181
std::shared_ptr< EffectInstance > mpFirstInstance
Definition: MixerOptions.h:110

References EffectStage::Create(), MixerOptions::StageSpecification::factory, factory, mBufferSize, mNumChannels, MixerOptions::StageSpecification::mpFirstInstance, mSettings, mStageBuffers, mStages, MixerOptions::StageSpecification::settings, and settings().

Here is the call graph for this function:

◆ Release()

bool Mixer::Release ( )
overrideprivatevirtual

Caller is done examining last Acquire()d positions.

May be called only after at least one successful call to Acquire()

Returns
success
Postcondition
!Terminates() or Remaining() reduced by what was last returned by Acquire()

Implements AudioGraph::Source.

Definition at line 427 of file Mix.cpp.

428{
429 return true;
430}

◆ Remaining()

sampleCount Mixer::Remaining ( ) const
overrideprivatevirtual

Result includes any amount Acquired and not yet Released.

May be undefined before the first successful call to Acquire()

Postcondition
result: result >= 0

Implements AudioGraph::Source.

Definition at line 418 of file Mix.cpp.

419{
420 return std::accumulate(
421 mDecoratedSources.begin(), mDecoratedSources.end(), sampleCount { 0 },
422 [](sampleCount sum, const Source& source) {
423 return std::max(sum, source.downstream.Remaining());
424 });
425}
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:19

References mDecoratedSources.

◆ Reposition()

void Mixer::Reposition ( double  t,
bool  bSkipping = false 
)

Reposition processing to absolute time next time Process() is called.

Definition at line 357 of file Mix.cpp.

358{
359 const auto &[mT0, mT1, _, __] = *mTimesAndSpeed;
360 auto &mTime = mTimesAndSpeed->mTime;
361 mTime = t;
362 const bool backwards = (mT1 < mT0);
363 if (backwards)
364 mTime = std::clamp(mTime, mT1, mT0);
365 else
366 mTime = std::clamp(mTime, mT0, mT1);
367
368 for (auto &source : mSources)
369 source.Reposition(mTime, bSkipping);
370}

References _, mSources, and mTimesAndSpeed.

Referenced by SetSpeedForKeyboardScrubbing(), and SetTimesAndSpeed().

Here is the caller graph for this function:

◆ SetSpeedForKeyboardScrubbing()

void Mixer::SetSpeedForKeyboardScrubbing ( double  speed,
double  startTime 
)

Definition at line 382 of file Mix.cpp.

383{
384 wxASSERT(std::isfinite(speed));
385 auto &[mT0, mT1, mSpeed, _] = *mTimesAndSpeed;
386
387 // Check if the direction has changed
388 if ((speed > 0.0 && mT1 < mT0) || (speed < 0.0 && mT1 > mT0)) {
389 // It's safe to use 0 and std::numeric_limits<double>::max(),
390 // because Mixer::MixVariableRates() doesn't sample past the start
391 // or end of the audio in a track.
392 if (speed > 0.0 && mT1 < mT0) {
393 mT0 = 0;
394 mT1 = std::numeric_limits<double>::max();
395 }
396 else {
397 mT0 = std::numeric_limits<double>::max();
398 mT1 = 0;
399 }
400
401 Reposition(startTime, true);
402 }
403
404 mSpeed = fabs(speed);
405}
void Reposition(double t, bool bSkipping=false)
Reposition processing to absolute time next time Process() is called.
Definition: Mix.cpp:357

References _, mTimesAndSpeed, and Reposition().

Here is the call graph for this function:

◆ SetTimesAndSpeed()

void Mixer::SetTimesAndSpeed ( double  t0,
double  t1,
double  speed,
bool  bSkipping = false 
)

Used in scrubbing and other nonuniform playback policies.

Definition at line 372 of file Mix.cpp.

373{
374 wxASSERT(std::isfinite(speed));
375 auto &[mT0, mT1, mSpeed, _] = *mTimesAndSpeed;
376 mT0 = t0;
377 mT1 = t1;
378 mSpeed = fabs(speed);
379 Reposition(t0, bSkipping);
380}

References _, mTimesAndSpeed, and Reposition().

Here is the call graph for this function:

Member Data Documentation

◆ mApplyGain

const ApplyGain Mixer::mApplyGain
private

Definition at line 153 of file Mix.h.

Referenced by Acquire(), and NeedsDither().

◆ mBuffer

const std::vector<SampleBuffer> Mixer::mBuffer
private

Definition at line 176 of file Mix.h.

Referenced by GetBuffer(), and Process().

◆ mBufferSize

const size_t Mixer::mBufferSize
private

Definition at line 145 of file Mix.h.

Referenced by Clear(), and RegisterEffectStage().

◆ mDecoratedSources

std::vector<Source> Mixer::mDecoratedSources
private

Definition at line 185 of file Mix.h.

Referenced by Acquire(), and Remaining().

◆ mEffectiveFormat

sampleFormat Mixer::mEffectiveFormat
private

Definition at line 159 of file Mix.h.

Referenced by EffectiveFormat().

◆ mFloatBuffers

AudioGraph::Buffers Mixer::mFloatBuffers
private

Definition at line 168 of file Mix.h.

Referenced by Acquire().

◆ mFormat

const sampleFormat Mixer::mFormat
private

Definition at line 155 of file Mix.h.

Referenced by NeedsDither(), and Process().

◆ mHasMixerSpec

bool Mixer::mHasMixerSpec {false}
private

Definition at line 161 of file Mix.h.

Referenced by Acquire(), and NeedsDither().

◆ mHighQuality

const bool Mixer::mHighQuality
private

Definition at line 154 of file Mix.h.

Referenced by Process().

◆ mInputs

Inputs Mixer::mInputs
private

Definition at line 141 of file Mix.h.

◆ mInterleaved

const bool Mixer::mInterleaved
private

Definition at line 156 of file Mix.h.

Referenced by Process().

◆ mMasterEffects

const std::optional<Stages> Mixer::mMasterEffects
private

Definition at line 142 of file Mix.h.

◆ mMasterStages

std::vector<AudioGraph::Source*> Mixer::mMasterStages
private

Definition at line 182 of file Mix.h.

Referenced by Process().

◆ mNeedsDither

bool Mixer::mNeedsDither
private

Definition at line 160 of file Mix.h.

Referenced by Process().

◆ mNumChannels

const unsigned Mixer::mNumChannels
private

Definition at line 140 of file Mix.h.

Referenced by AcceptsBuffers(), Acquire(), NeedsDither(), Process(), and RegisterEffectStage().

◆ mSettings

std::vector<EffectSettings> Mixer::mSettings
private

Definition at line 179 of file Mix.h.

Referenced by RegisterEffectStage().

◆ mSources

std::vector<MixerSource> Mixer::mSources
private

Definition at line 178 of file Mix.h.

Referenced by NeedsDither(), and Reposition().

◆ mStageBuffers

std::vector<AudioGraph::Buffers> Mixer::mStageBuffers
private

Definition at line 180 of file Mix.h.

Referenced by RegisterEffectStage().

◆ mStages

std::vector<std::unique_ptr<EffectStage> > Mixer::mStages
private

Definition at line 181 of file Mix.h.

Referenced by RegisterEffectStage().

◆ mTemp

AudioGraph::Buffers Mixer::mTemp
private

Definition at line 173 of file Mix.h.

Referenced by Clear(), and Process().

◆ mTimesAndSpeed

const std::shared_ptr<TimesAndSpeed> Mixer::mTimesAndSpeed
private

The documentation for this class was generated from the following files: