11namespace tracktion {
inline namespace engine
15 float maxAbsValue,
float minAbsThreshold)
22 for (
int i = numSamps; --i >= 0;)
26 if (n >= minAbsThreshold)
31 else if (n <= -minAbsThreshold)
46void resetFP() noexcept
52 #if JUCE_MAC && JUCE_INTEL
57static unsigned short getFPStatus() noexcept
59 unsigned short sw = 0;
64 _asm fstsw WORD PTR sw
66 asm (
"fstsw %%ax" :
"=a" (sw));
74inline void clearFP() noexcept
80 #if JUCE_MAC && JUCE_INTEL
81 __asm __volatile (
"fclex");
85bool hasFloatingPointDenormaliseOccurred() noexcept
87 if ((getFPStatus() & 0x02) != 0)
101 if (hasFloatingPointDenormaliseOccurred())
115 juce::FloatVectorOperations::fill (buffer.
getWritePointer (i, start), 0.000000045f, numSamples);
120 juce::FloatVectorOperations::add (buffer.
getWritePointer (i, start), 0.000000045f, numSamples);
126float dbToGain (
float db)
noexcept
128 return std::pow (10.0f, db * (1.0f / 20.0f));
131float gainToDb (
float gain)
noexcept
133 return (gain > 0.0f) ? 20.0f *
std::log10 (gain) : -100.0f;
136static const float volScaleFactor = 20.0f;
138float decibelsToVolumeFaderPosition (
float db)
noexcept
140 return (db > -100.0f) ?
std::exp ((db - 6.0f) * (1.0f / volScaleFactor)) : 0.0f;
143float volumeFaderPositionToDB (
float pos)
noexcept
145 return (pos > 0.0f) ? (volScaleFactor *
std::log (pos)) + 6.0f : -100.0f;
148float volumeFaderPositionToGain (
float pos)
noexcept
150 return (pos > 0.0f) ?
std::pow (10.0f, ((volScaleFactor * logf (pos)) + 6.0f) * (1.0f / 20.0f)) : 0.0f;
153float gainToVolumeFaderPosition (
float gain)
noexcept
155 return (gain > 0.0f) ?
std::exp (((20.0f *
std::log10 (gain)) - 6.0f) * (1.0f / volScaleFactor)) : 0.0f;
158juce::String gainToDbString (
float gain,
float infLevel,
int decPlaces)
176 return dbToGain (dbStringToDb (dbStr));
181 if (std::abs (pan) < 0.001f)
182 return TRANS(
"Centre");
187 return s +
" " +
TRANS(
"Left");
189 return "+" + s +
" " +
TRANS(
"Right");
199 if (std::abs (semitones - (
int) semitones) < 0.01)
200 t << (
int) semitones;
204 if (std::abs (semitones) != 1)
205 return TRANS(
"33 semitones").replace (
"33", t);
207 return TRANS(
"1 semitone").replace (
"1", t);
210static bool isNotSilent (
float v)
noexcept
212 const float zeroThresh = 1.0f / 8000.0f;
213 return v < -zeroThresh || v > zeroThresh;
216bool isAudioDataAlmostSilent (
const float* data,
int num)
218 return ! (isNotSilent (data[0])
219 || isNotSilent (data[num / 2])
220 || isNotSilent (getAudioDataMagnitude (data, num)));
223float getAudioDataMagnitude (
const float* data,
int num)
225 auto range = juce::FloatVectorOperations::findMinAndMax (data, num);
227 return std::max (std::abs (range.getStart()),
228 std::abs (range.getEnd()));
232void getGainsFromVolumeFaderPositionAndPan (
float volSliderPos,
float pan,
const PanLaw panLaw,
233 float& leftGain,
float& rightGain)
noexcept
235 const float gain = volumeFaderPositionToGain (volSliderPos);
237 if (panLaw == PanLawLinear)
239 const float pv = pan * gain;
241 leftGain = gain - pv;
242 rightGain = gain + pv;
248 pan = (pan + 1.0f) * 0.5f;
250 leftGain =
std::sin ((1.0f - pan) * halfPi);
251 rightGain =
std::sin (pan * halfPi);
257 case PanLaw3dBCenter: ratio = 1.0f;
break;
258 case PanLaw2point5dBCenter: ratio = 2.5f / 3.0f;
break;
259 case PanLaw4point5dBCenter: ratio = 1.5f;
break;
260 case PanLaw6dBCenter: ratio = 2.0f;
break;
272 leftGain =
std::pow (leftGain, ratio) * gain;
273 rightGain =
std::pow (rightGain, ratio) * gain;
277static PanLaw defaultPanLaw = PanLawLinear;
279PanLaw getDefaultPanLaw() noexcept
281 return defaultPanLaw;
284void setDefaultPanLaw (
const PanLaw panLaw)
286 defaultPanLaw = panLaw;
294 s.
add (
"(" +
TRANS(
"Use Default") +
")");
311 juce::FloatVectorOperations::convertFixedToFloat (d, (
const int*) d, 1.0f / (
double) 0x7fffffff, buffer.
getNumSamples());
323 const double samp = *(
const float*) d;
337 inline void apply (
float value)
noexcept
339 *channel0++ *= value;
348 inline void apply (
float value)
noexcept
350 *channel0++ *= value;
351 *channel1++ *= value;
356 int channel,
int startSample,
int numSamples,
370 float startAlpha,
float endAlpha)
372 jassert (startSample >= 0 && startSample + numSamples <= buffer.
getNumSamples() && numSamples > 0);
386 applyCrossfadeSection (buffer, i, startSample, numSamples, type, startAlpha, endAlpha);
396 inline void apply (
float value)
noexcept
398 *dest++ += *src++ * value;
404 int destChannel,
int destStartIndex,
405 int sourceChannel,
int sourceStartIndex,
406 const int numSamples,
408 const float startAlpha,
409 const float endAlpha)
411 if (! src.hasBeenCleared())
413 if (startAlpha == endAlpha)
415 dest.
addFrom (destChannel, destStartIndex, src, sourceChannel, sourceStartIndex, numSamples, endAlpha);
419 AddingFadeApplier d = { dest.
getWritePointer (destChannel, destStartIndex),
420 src.getReadPointer (sourceChannel, sourceStartIndex) };
430 const float fadeLineThickness = 1.5f;
434 if (fadeType == AudioFadeCurve::linear)
441 float left = (clip.getX() & ~3) - 3.0f;
442 float right = clip.getRight() + 5.0f;
449 for (
float x = left; x <
right; x += 3.0f)
452 s.
lineTo (right, x1 > x2 ? bottom : top);
475 for (
int i = 8; --i >= 0;)
476 buffers.add (
new Buffer());
481 clearSingletonInstance();
491 for (
auto b : buffers)
496 auto newBuffer =
new Buffer();
497 newBuffer->isFree =
false;
500 buffers.add (newBuffer);
513 : allocatedBuffer (
BufferList::getInstance()->get()),
514 buffer (allocatedBuffer->buffer)
516 buffer.setSize (numChans, numSamples,
false,
false,
true);
520 : allocatedBuffer (
BufferList::getInstance()->get()),
521 buffer (allocatedBuffer->buffer)
528 for (
int i = 0; i < chans; ++i)
534 allocatedBuffer->isFree =
true;
539 BufferList::getInstance();
545#if TRACKTION_UNIT_TESTS && ENGINE_UNIT_TESTS_PAN_LAW
550 PanLawTests() :
juce::UnitTest (
"PanLaw",
"tracktion_engine") {}
553 void runTest()
override
558 beginTest (
"Linear");
560 testPanLaw (PanLawLinear, 0.0f, 0.0f, 0.0f, 0.0f);
561 testPanLaw (PanLawLinear, 1.0f, 0.0f, 1.0f, 1.0f);
562 testPanLaw (PanLawLinear, 1.0f, -1.0f, 2.0f, 0.0f);
563 testPanLaw (PanLawLinear, 1.0f, 1.0f, 0.0f, 2.0f);
565 testPanLaw (PanLawLinear, 0.5f, 0.0f, 0.5f, 0.5f);
566 testPanLaw (PanLawLinear, 0.5f, -1.0f, 1.0f, 0.0f);
567 testPanLaw (PanLawLinear, 0.5f, 1.0f, 0.0f, 1.0f);
569 testPanLaw (PanLawLinear, 1.0f, -0.5f, 1.5f, 0.5f);
570 testPanLaw (PanLawLinear, 1.0f, 0.5f, 0.5f, 1.5f);
573 beginTest (
"-2.5dB");
576 testPanLaw (PanLaw2point5dBCenter, 0.0f, 0.0f, 0.0f, 0.0f);
577 testPanLaw (PanLaw2point5dBCenter, 1.0f, 0.0f, centreGain, centreGain);
578 testPanLaw (PanLaw2point5dBCenter, 1.0f, -1.0f, 1.0f, 0.0f);
579 testPanLaw (PanLaw2point5dBCenter, 1.0f, 1.0f, 0.0f, 1.0f);
585 testPanLaw (PanLaw3dBCenter, 0.0f, 0.0f, 0.0f, 0.0f);
586 testPanLaw (PanLaw3dBCenter, 1.0f, 0.0f, centreGain, centreGain);
587 testPanLaw (PanLaw3dBCenter, 1.0f, -1.0f, 1.0f, 0.0f);
588 testPanLaw (PanLaw3dBCenter, 1.0f, 1.0f, 0.0f, 1.0f);
591 beginTest (
"-4.5dB");
594 testPanLaw (PanLaw4point5dBCenter, 0.0f, 0.0f, 0.0f, 0.0f);
595 testPanLaw (PanLaw4point5dBCenter, 1.0f, 0.0f, centreGain, centreGain);
596 testPanLaw (PanLaw4point5dBCenter, 1.0f, -1.0f, 1.0f, 0.0f);
597 testPanLaw (PanLaw4point5dBCenter, 1.0f, 1.0f, 0.0f, 1.0f);
603 testPanLaw (PanLaw6dBCenter, 0.0f, 0.0f, 0.0f, 0.0f);
604 testPanLaw (PanLaw6dBCenter, 1.0f, 0.0f, centreGain, centreGain);
605 testPanLaw (PanLaw6dBCenter, 1.0f, -1.0f, 1.0f, 0.0f);
606 testPanLaw (PanLaw6dBCenter, 1.0f, 1.0f, 0.0f, 1.0f);
611 void testPanLaw (PanLaw pl,
float gain,
float pan,
612 float expectedLeftGain,
float expectedRightGain)
614 expectGreaterOrEqual (gain, 0.0f);
615 expectGreaterOrEqual (pan, -1.0f);
616 expectLessOrEqual (pan, 1.0f);
618 float leftGain = 0.0;
619 float rightGain = 0.0;
620 getGainsFromVolumeFaderPositionAndPan (gainToVolumeFaderPosition (gain), pan, pl,
621 leftGain, rightGain);
622 expectWithinAbsoluteError (leftGain, expectedLeftGain, 0.01f);
623 expectWithinAbsoluteError (rightGain, expectedRightGain, 0.01f);
627static PanLawTests panLawTests;
void setSize(int newNumChannels, int newNumSamples, bool keepExistingContent=false, bool clearExtraSpace=false, bool avoidReallocating=false)
Type * getWritePointer(int channelNumber) noexcept
int getNumChannels() const noexcept
int getNumSamples() const noexcept
void copyFrom(int destChannel, int destStartSample, const AudioBuffer &source, int sourceChannel, int sourceStartSample, int numSamples) noexcept
void addFrom(int destChannel, int destStartSample, const AudioBuffer &source, int sourceChannel, int sourceStartSample, int numSamples, Type gainToApplyToSource=Type(1)) noexcept
bool hasBeenCleared() const noexcept
const Type * getReadPointer(int channelNumber) const noexcept
static Type decibelsToGain(Type decibels, Type minusInfinityDb=Type(defaultMinusInfinitydB))
static String toString(Type decibels, int decimalPlaces=2, Type minusInfinityDb=Type(defaultMinusInfinitydB), bool shouldIncludeSuffix=true, StringRef customMinusInfinityString={})
void setOpacity(float newOpacity)
void fillPath(const Path &path) const
void strokePath(const Path &path, const PathStrokeType &strokeType, const AffineTransform &transform={}) const
void startNewSubPath(float startX, float startY)
void lineTo(float endX, float endY)
void add(String stringToAdd)
float getFloatValue() const noexcept
String retainCharacters(StringRef charactersToRetain) const
bool contains(StringRef text) const noexcept
An audio scratch buffer that has pooled storage.
juce::AudioBuffer< float > & buffer
The buffer to use.
~AudioScratchBuffer() noexcept
Destructor.
AudioScratchBuffer(int numChans, int numSamples)
Creates a buffer for a given number of channels and samples.
static void initialise()
Initialises the internal buffer list.
#define TRANS(stringLiteral)
#define JUCE_IMPLEMENT_SINGLETON(Classname)
#define JUCE_DECLARE_SINGLETON(Classname, doNotRecreateAfterDeletion)
void ignoreUnused(Types &&...) noexcept
int roundToInt(const FloatType value) noexcept
PanLaw
All laws have been designed to be equal-power, excluding linear respectively.
Type
A enumeration of the curve classes available.
static void renderBlockForType(DestSamplePointer &dest, int numSamples, float startAlpha, float endAlpha, Type type) noexcept
Multiplies a block of samples by the curve shape between two alpha-positions.
static float alphaToGainForType(Type type, float alpha) noexcept
Converts an alpha position along the curve (0 to 1.0) into the gain at that point.