@@ -39,10 +39,9 @@ AudioSampleBuffer::AudioSampleBuffer (const AudioSampleBuffer& other) noexcept | |||||
size (other.size) | size (other.size) | ||||
{ | { | ||||
allocateData(); | allocateData(); | ||||
const size_t numBytes = sizeof (float) * (size_t) size; | |||||
for (int i = 0; i < numChannels; ++i) | for (int i = 0; i < numChannels; ++i) | ||||
memcpy (channels[i], other.channels[i], numBytes); | |||||
FloatVectorOperations::copy (channels[i], other.channels[i], size); | |||||
} | } | ||||
void AudioSampleBuffer::allocateData() | void AudioSampleBuffer::allocateData() | ||||
@@ -130,10 +129,8 @@ AudioSampleBuffer& AudioSampleBuffer::operator= (const AudioSampleBuffer& other) | |||||
{ | { | ||||
setSize (other.getNumChannels(), other.getNumSamples(), false, false, false); | setSize (other.getNumChannels(), other.getNumSamples(), false, false, false); | ||||
const size_t numBytes = sizeof (float) * (size_t) size; | |||||
for (int i = 0; i < numChannels; ++i) | for (int i = 0; i < numChannels; ++i) | ||||
memcpy (channels[i], other.channels[i], numBytes); | |||||
FloatVectorOperations::copy (channels[i], other.channels[i], size); | |||||
} | } | ||||
return *this; | return *this; | ||||
@@ -154,15 +151,17 @@ void AudioSampleBuffer::setSize (const int newNumChannels, | |||||
if (newNumSamples != size || newNumChannels != numChannels) | if (newNumSamples != size || newNumChannels != numChannels) | ||||
{ | { | ||||
const size_t channelListSize = sizeof (float*) * (size_t) (newNumChannels + 1); | |||||
const size_t newTotalBytes = ((size_t) newNumChannels * (size_t) newNumSamples * sizeof (float)) + channelListSize + 32; | |||||
const size_t allocatedSamplesPerChannel = (newNumSamples + 3) & ~3; | |||||
const size_t channelListSize = ((sizeof (float*) * (size_t) (newNumChannels + 1)) + 15) & ~15; | |||||
const size_t newTotalBytes = ((size_t) newNumChannels * (size_t) allocatedSamplesPerChannel * sizeof (float)) | |||||
+ channelListSize + 32; | |||||
if (keepExistingContent) | if (keepExistingContent) | ||||
{ | { | ||||
HeapBlock <char, true> newData; | HeapBlock <char, true> newData; | ||||
newData.allocate (newTotalBytes, clearExtraSpace); | newData.allocate (newTotalBytes, clearExtraSpace); | ||||
const size_t numBytesToCopy = sizeof (float) * (size_t) jmin (newNumSamples, size); | |||||
const size_t numSamplesToCopy = jmin (newNumSamples, size); | |||||
float** const newChannels = reinterpret_cast <float**> (newData.getData()); | float** const newChannels = reinterpret_cast <float**> (newData.getData()); | ||||
float* newChan = reinterpret_cast <float*> (newData + channelListSize); | float* newChan = reinterpret_cast <float*> (newData + channelListSize); | ||||
@@ -170,12 +169,12 @@ void AudioSampleBuffer::setSize (const int newNumChannels, | |||||
for (int j = 0; j < newNumChannels; ++j) | for (int j = 0; j < newNumChannels; ++j) | ||||
{ | { | ||||
newChannels[j] = newChan; | newChannels[j] = newChan; | ||||
newChan += newNumSamples; | |||||
newChan += allocatedSamplesPerChannel; | |||||
} | } | ||||
const int numChansToCopy = jmin (numChannels, newNumChannels); | const int numChansToCopy = jmin (numChannels, newNumChannels); | ||||
for (int i = 0; i < numChansToCopy; ++i) | for (int i = 0; i < numChansToCopy; ++i) | ||||
memcpy (newChannels[i], channels[i], numBytesToCopy); | |||||
FloatVectorOperations::copy (newChannels[i], channels[i], numSamplesToCopy); | |||||
allocatedData.swapWith (newData); | allocatedData.swapWith (newData); | ||||
allocatedBytes = newTotalBytes; | allocatedBytes = newTotalBytes; | ||||
@@ -199,7 +198,7 @@ void AudioSampleBuffer::setSize (const int newNumChannels, | |||||
for (int i = 0; i < newNumChannels; ++i) | for (int i = 0; i < newNumChannels; ++i) | ||||
{ | { | ||||
channels[i] = chan; | channels[i] = chan; | ||||
chan += newNumSamples; | |||||
chan += allocatedSamplesPerChannel; | |||||
} | } | ||||
} | } | ||||
@@ -212,7 +211,7 @@ void AudioSampleBuffer::setSize (const int newNumChannels, | |||||
void AudioSampleBuffer::clear() noexcept | void AudioSampleBuffer::clear() noexcept | ||||
{ | { | ||||
for (int i = 0; i < numChannels; ++i) | for (int i = 0; i < numChannels; ++i) | ||||
zeromem (channels[i], sizeof (float) * (size_t) size); | |||||
FloatVectorOperations::clear (channels[i], size); | |||||
} | } | ||||
void AudioSampleBuffer::clear (const int startSample, | void AudioSampleBuffer::clear (const int startSample, | ||||
@@ -221,7 +220,7 @@ void AudioSampleBuffer::clear (const int startSample, | |||||
jassert (startSample >= 0 && startSample + numSamples <= size); | jassert (startSample >= 0 && startSample + numSamples <= size); | ||||
for (int i = 0; i < numChannels; ++i) | for (int i = 0; i < numChannels; ++i) | ||||
zeromem (channels [i] + startSample, sizeof (float) * (size_t) numSamples); | |||||
FloatVectorOperations::clear (channels[i] + startSample, numSamples); | |||||
} | } | ||||
void AudioSampleBuffer::clear (const int channel, | void AudioSampleBuffer::clear (const int channel, | ||||
@@ -231,7 +230,7 @@ void AudioSampleBuffer::clear (const int channel, | |||||
jassert (isPositiveAndBelow (channel, numChannels)); | jassert (isPositiveAndBelow (channel, numChannels)); | ||||
jassert (startSample >= 0 && startSample + numSamples <= size); | jassert (startSample >= 0 && startSample + numSamples <= size); | ||||
zeromem (channels [channel] + startSample, sizeof (float) * (size_t) numSamples); | |||||
FloatVectorOperations::clear (channels [channel] + startSample, numSamples); | |||||
} | } | ||||
void AudioSampleBuffer::applyGain (const int channel, | void AudioSampleBuffer::applyGain (const int channel, | ||||
@@ -244,17 +243,12 @@ void AudioSampleBuffer::applyGain (const int channel, | |||||
if (gain != 1.0f) | if (gain != 1.0f) | ||||
{ | { | ||||
float* d = channels [channel] + startSample; | |||||
float* const d = channels [channel] + startSample; | |||||
if (gain == 0.0f) | if (gain == 0.0f) | ||||
{ | |||||
zeromem (d, sizeof (float) * (size_t) numSamples); | |||||
} | |||||
FloatVectorOperations::clear (d, numSamples); | |||||
else | else | ||||
{ | |||||
while (--numSamples >= 0) | |||||
*d++ *= gain; | |||||
} | |||||
FloatVectorOperations::multiply (d, gain, numSamples); | |||||
} | } | ||||
} | } | ||||
@@ -322,19 +316,13 @@ void AudioSampleBuffer::addFrom (const int destChannel, | |||||
if (gain != 0.0f && numSamples > 0) | if (gain != 0.0f && numSamples > 0) | ||||
{ | { | ||||
float* d = channels [destChannel] + destStartSample; | |||||
const float* s = source.channels [sourceChannel] + sourceStartSample; | |||||
float* const d = channels [destChannel] + destStartSample; | |||||
const float* const s = source.channels [sourceChannel] + sourceStartSample; | |||||
if (gain != 1.0f) | if (gain != 1.0f) | ||||
{ | |||||
while (--numSamples >= 0) | |||||
*d++ += gain * *s++; | |||||
} | |||||
FloatVectorOperations::addWithMultiply (d, s, gain, numSamples); | |||||
else | else | ||||
{ | |||||
while (--numSamples >= 0) | |||||
*d++ += *s++; | |||||
} | |||||
FloatVectorOperations::add (d, s, numSamples); | |||||
} | } | ||||
} | } | ||||
@@ -350,18 +338,12 @@ void AudioSampleBuffer::addFrom (const int destChannel, | |||||
if (gain != 0.0f && numSamples > 0) | if (gain != 0.0f && numSamples > 0) | ||||
{ | { | ||||
float* d = channels [destChannel] + destStartSample; | |||||
float* const d = channels [destChannel] + destStartSample; | |||||
if (gain != 1.0f) | if (gain != 1.0f) | ||||
{ | |||||
while (--numSamples >= 0) | |||||
*d++ += gain * *source++; | |||||
} | |||||
FloatVectorOperations::addWithMultiply (d, source, gain, numSamples); | |||||
else | else | ||||
{ | |||||
while (--numSamples >= 0) | |||||
*d++ += *source++; | |||||
} | |||||
FloatVectorOperations::add (d, source, numSamples); | |||||
} | } | ||||
} | } | ||||
@@ -378,11 +360,7 @@ void AudioSampleBuffer::addFromWithRamp (const int destChannel, | |||||
if (startGain == endGain) | if (startGain == endGain) | ||||
{ | { | ||||
addFrom (destChannel, | |||||
destStartSample, | |||||
source, | |||||
numSamples, | |||||
startGain); | |||||
addFrom (destChannel, destStartSample, source, numSamples, startGain); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -415,9 +393,9 @@ void AudioSampleBuffer::copyFrom (const int destChannel, | |||||
if (numSamples > 0) | if (numSamples > 0) | ||||
{ | { | ||||
memcpy (channels [destChannel] + destStartSample, | |||||
source.channels [sourceChannel] + sourceStartSample, | |||||
sizeof (float) * (size_t) numSamples); | |||||
FloatVectorOperations::copy (channels [destChannel] + destStartSample, | |||||
source.channels [sourceChannel] + sourceStartSample, | |||||
numSamples); | |||||
} | } | ||||
} | } | ||||
@@ -432,9 +410,9 @@ void AudioSampleBuffer::copyFrom (const int destChannel, | |||||
if (numSamples > 0) | if (numSamples > 0) | ||||
{ | { | ||||
memcpy (channels [destChannel] + destStartSample, | |||||
source, | |||||
sizeof (float) * (size_t) numSamples); | |||||
FloatVectorOperations::copy (channels [destChannel] + destStartSample, | |||||
source, | |||||
numSamples); | |||||
} | } | ||||
} | } | ||||
@@ -455,18 +433,13 @@ void AudioSampleBuffer::copyFrom (const int destChannel, | |||||
if (gain != 1.0f) | if (gain != 1.0f) | ||||
{ | { | ||||
if (gain == 0) | if (gain == 0) | ||||
{ | |||||
zeromem (d, sizeof (float) * (size_t) numSamples); | |||||
} | |||||
FloatVectorOperations::clear (d, numSamples); | |||||
else | else | ||||
{ | |||||
while (--numSamples >= 0) | |||||
*d++ = gain * *source++; | |||||
} | |||||
FloatVectorOperations::copyWithMultiply (d, source, gain, numSamples); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
memcpy (d, source, sizeof (float) * (size_t) numSamples); | |||||
FloatVectorOperations::copy (d, source, numSamples); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -484,11 +457,7 @@ void AudioSampleBuffer::copyFromWithRamp (const int destChannel, | |||||
if (startGain == endGain) | if (startGain == endGain) | ||||
{ | { | ||||
copyFrom (destChannel, | |||||
destStartSample, | |||||
source, | |||||
numSamples, | |||||
startGain); | |||||
copyFrom (destChannel, destStartSample, source, numSamples, startGain); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -515,7 +484,8 @@ void AudioSampleBuffer::findMinMax (const int channel, | |||||
jassert (isPositiveAndBelow (channel, numChannels)); | jassert (isPositiveAndBelow (channel, numChannels)); | ||||
jassert (startSample >= 0 && startSample + numSamples <= size); | jassert (startSample >= 0 && startSample + numSamples <= size); | ||||
findMinAndMax (channels [channel] + startSample, numSamples, minVal, maxVal); | |||||
FloatVectorOperations::findMinAndMax (channels [channel] + startSample, | |||||
numSamples, minVal, maxVal); | |||||
} | } | ||||
float AudioSampleBuffer::getMagnitude (const int channel, | float AudioSampleBuffer::getMagnitude (const int channel, | ||||
@@ -0,0 +1,234 @@ | |||||
/* | |||||
============================================================================== | |||||
This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
Copyright 2004-11 by Raw Material Software Ltd. | |||||
------------------------------------------------------------------------------ | |||||
JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
Public License (Version 2), as published by the Free Software Foundation. | |||||
A copy of the license is included in the JUCE distribution, or can be found | |||||
online at www.gnu.org/licenses. | |||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
------------------------------------------------------------------------------ | |||||
To release a closed-source product which uses JUCE, commercial licenses are | |||||
available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
============================================================================== | |||||
*/ | |||||
#if JUCE_USE_SSE_INTRINSICS | |||||
namespace FloatVectorHelpers | |||||
{ | |||||
static bool sse2Present = false; | |||||
static bool isSSE2Available() | |||||
{ | |||||
if (sse2Present) | |||||
return true; | |||||
sse2Present = SystemStats::hasSSE2(); | |||||
return sse2Present; | |||||
} | |||||
inline static bool isAligned (const void* p) | |||||
{ | |||||
return (((pointer_sized_int) p) & 15) == 0; | |||||
} | |||||
} | |||||
#define JUCE_BEGIN_SSE_OP \ | |||||
if (FloatVectorHelpers::isSSE2Available()) \ | |||||
{ \ | |||||
const int numLongOps = num / 4; | |||||
#define JUCE_FINISH_SSE_OP(normalOp) \ | |||||
_mm_empty(); \ | |||||
num &= 3; \ | |||||
if (num == 0) return; \ | |||||
} \ | |||||
for (int i = 0; i < num; ++i) normalOp; | |||||
#define JUCE_SSE_LOOP(sseOp, srcLoad, dstLoad, dstStore, locals, increment) \ | |||||
for (int i = 0; i < numLongOps; ++i) \ | |||||
{ \ | |||||
locals (srcLoad, dstLoad); \ | |||||
dstStore (dest, sseOp); \ | |||||
increment; \ | |||||
} | |||||
#define JUCE_INCREMENT_SRC_DEST dest += 4; src += 4; | |||||
#define JUCE_INCREMENT_DEST dest += 4; | |||||
#define JUCE_LOAD_NONE(srcLoad, dstLoad) | |||||
#define JUCE_LOAD_DEST(srcLoad, dstLoad) const __m128 d = dstLoad (dest); | |||||
#define JUCE_LOAD_SRC(srcLoad, dstLoad) const __m128 s = srcLoad (src); | |||||
#define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const __m128 d = dstLoad (dest); const __m128 s = srcLoad (src); | |||||
#define JUCE_PERFORM_SSE_OP_DEST(normalOp, sseOp) \ | |||||
JUCE_BEGIN_SSE_OP \ | |||||
if (FloatVectorHelpers::isAligned (dest)) JUCE_SSE_LOOP (sseOp, dummy, _mm_load_ps, _mm_store_ps, JUCE_LOAD_DEST, JUCE_INCREMENT_DEST) \ | |||||
else JUCE_SSE_LOOP (sseOp, dummy, _mm_loadu_ps, _mm_storeu_ps, JUCE_LOAD_DEST, JUCE_INCREMENT_DEST) \ | |||||
JUCE_FINISH_SSE_OP (normalOp) | |||||
#define JUCE_PERFORM_SSE_OP_SRC_DEST(normalOp, sseOp, locals, increment) \ | |||||
JUCE_BEGIN_SSE_OP \ | |||||
if (FloatVectorHelpers::isAligned (dest)) \ | |||||
{ \ | |||||
if (FloatVectorHelpers::isAligned (src)) JUCE_SSE_LOOP (sseOp, _mm_load_ps, _mm_load_ps, _mm_store_ps, locals, increment) \ | |||||
else JUCE_SSE_LOOP (sseOp, _mm_loadu_ps, _mm_load_ps, _mm_store_ps, locals, increment) \ | |||||
}\ | |||||
else \ | |||||
{ \ | |||||
if (FloatVectorHelpers::isAligned (src)) JUCE_SSE_LOOP (sseOp, _mm_load_ps, _mm_loadu_ps, _mm_storeu_ps, locals, increment) \ | |||||
else JUCE_SSE_LOOP (sseOp, _mm_loadu_ps, _mm_loadu_ps, _mm_storeu_ps, locals, increment) \ | |||||
} \ | |||||
JUCE_FINISH_SSE_OP (normalOp) | |||||
#else | |||||
#define JUCE_PERFORM_SSE_OP_DEST(normalOp, unused1) for (int i = 0; i < num; ++i) normalOp; | |||||
#define JUCE_PERFORM_SSE_OP_SRC_DEST(normalOp, sseOp, locals, increment) for (int i = 0; i < num; ++i) normalOp; | |||||
#endif | |||||
void FloatVectorOperations::clear (float* dest, const int num) noexcept | |||||
{ | |||||
zeromem (dest, num * sizeof (float)); | |||||
} | |||||
void FloatVectorOperations::copy (float* dest, const float* src, const int num) noexcept | |||||
{ | |||||
memcpy (dest, src, num * sizeof (float)); | |||||
} | |||||
void FloatVectorOperations::copyWithMultiply (float* dest, const float* src, float multiplier, int num) noexcept | |||||
{ | |||||
#if JUCE_USE_SSE_INTRINSICS | |||||
const __m128 mult = _mm_load1_ps (&multiplier); | |||||
#endif | |||||
JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] = src[i] * multiplier, | |||||
_mm_mul_ps (mult, s), | |||||
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST) | |||||
} | |||||
void FloatVectorOperations::add (float* dest, const float* src, int num) noexcept | |||||
{ | |||||
JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] += src[i], | |||||
_mm_add_ps (d, s), | |||||
JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST) | |||||
} | |||||
void FloatVectorOperations::add (float* dest, float amount, int num) noexcept | |||||
{ | |||||
#if JUCE_USE_SSE_INTRINSICS | |||||
const __m128 amountToAdd = _mm_load1_ps (&amount); | |||||
#endif | |||||
JUCE_PERFORM_SSE_OP_DEST (dest[i] += amount, | |||||
_mm_add_ps (d, amountToAdd)) | |||||
} | |||||
void FloatVectorOperations::addWithMultiply (float* dest, const float* src, float multiplier, int num) noexcept | |||||
{ | |||||
#if JUCE_USE_SSE_INTRINSICS | |||||
const __m128 mult = _mm_load1_ps (&multiplier); | |||||
#endif | |||||
JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] += src[i] * multiplier, | |||||
_mm_add_ps (d, _mm_mul_ps (mult, s)), | |||||
JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST) | |||||
} | |||||
void FloatVectorOperations::multiply (float* dest, const float* src, int num) noexcept | |||||
{ | |||||
JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] *= src[i], | |||||
_mm_mul_ps (d, s), | |||||
JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST) | |||||
} | |||||
void FloatVectorOperations::multiply (float* dest, float multiplier, int num) noexcept | |||||
{ | |||||
#if JUCE_USE_SSE_INTRINSICS | |||||
const __m128 mult = _mm_load1_ps (&multiplier); | |||||
#endif | |||||
JUCE_PERFORM_SSE_OP_DEST (dest[i] *= multiplier, | |||||
_mm_mul_ps (d, mult)) | |||||
} | |||||
void FloatVectorOperations::convertFixedToFloat (float* dest, const int* src, float multiplier, int num) noexcept | |||||
{ | |||||
#if JUCE_USE_SSE_INTRINSICS | |||||
const __m128 mult = _mm_load1_ps (&multiplier); | |||||
#endif | |||||
JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] = src[i] * multiplier, | |||||
_mm_mul_ps (mult, _mm_movelh_ps (_mm_cvt_pi2ps (_mm_setzero_ps(), ((const __m64*) src)[0]), | |||||
_mm_cvt_pi2ps (_mm_setzero_ps(), ((const __m64*) src)[1]))), | |||||
JUCE_LOAD_NONE, JUCE_INCREMENT_SRC_DEST) | |||||
} | |||||
void FloatVectorOperations::findMinAndMax (const float* src, int num, float& minResult, float& maxResult) noexcept | |||||
{ | |||||
#if JUCE_USE_SSE_INTRINSICS | |||||
const int numLongOps = num / 4; | |||||
if (numLongOps > 1 && FloatVectorHelpers::isSSE2Available()) | |||||
{ | |||||
__m128 mn, mx; | |||||
#define JUCE_MINMAX_SSE_LOOP(loadOp) \ | |||||
mn = loadOp (src); \ | |||||
mx = mn; \ | |||||
src += 4; \ | |||||
for (int i = 1; i < numLongOps; ++i) \ | |||||
{ \ | |||||
const __m128 s = loadOp (src); \ | |||||
mn = _mm_min_ps (mn, s); \ | |||||
mx = _mm_max_ps (mx, s); \ | |||||
src += 4; \ | |||||
} | |||||
if (FloatVectorHelpers::isAligned (src)) { JUCE_MINMAX_SSE_LOOP (_mm_load_ps) } | |||||
else { JUCE_MINMAX_SSE_LOOP (_mm_loadu_ps) } | |||||
float localMin, localMax; | |||||
{ | |||||
float mns[4], mxs[4]; | |||||
_mm_storeu_ps (mns, mn); | |||||
_mm_storeu_ps (mxs, mx); | |||||
_mm_empty(); | |||||
localMin = jmin (mns[0], mns[1], mns[2], mns[3]); | |||||
localMax = jmax (mxs[0], mxs[1], mxs[2], mxs[3]); | |||||
} | |||||
num &= 3; | |||||
if (num != 0) | |||||
{ | |||||
for (int i = 0; i < num; ++i) | |||||
{ | |||||
const float s = src[i]; | |||||
localMin = jmin (localMin, s); | |||||
localMax = jmax (localMax, s); | |||||
} | |||||
} | |||||
minResult = localMin; | |||||
maxResult = localMax; | |||||
return; | |||||
} | |||||
#endif | |||||
juce::findMinAndMax (src, num, minResult, maxResult); | |||||
} |
@@ -0,0 +1,69 @@ | |||||
/* | |||||
============================================================================== | |||||
This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
Copyright 2004-11 by Raw Material Software Ltd. | |||||
------------------------------------------------------------------------------ | |||||
JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
Public License (Version 2), as published by the Free Software Foundation. | |||||
A copy of the license is included in the JUCE distribution, or can be found | |||||
online at www.gnu.org/licenses. | |||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
------------------------------------------------------------------------------ | |||||
To release a closed-source product which uses JUCE, commercial licenses are | |||||
available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
============================================================================== | |||||
*/ | |||||
#ifndef __JUCE_FLOATVECTOROPERATIONS_JUCEHEADER__ | |||||
#define __JUCE_FLOATVECTOROPERATIONS_JUCEHEADER__ | |||||
//============================================================================== | |||||
/** | |||||
*/ | |||||
class JUCE_API FloatVectorOperations | |||||
{ | |||||
public: | |||||
//============================================================================== | |||||
/** Clears a vector of floats. */ | |||||
static void clear (float* dest, int numValues) noexcept; | |||||
/** Copies a vector of floats. */ | |||||
static void copy (float* dest, const float* src, int numValues) noexcept; | |||||
/** Copies a vector of floats, multiplying each value by a given multiplier */ | |||||
static void copyWithMultiply (float* dest, const float* src, float multiplier, int numValues) noexcept; | |||||
/** Adds the source values to the destination values. */ | |||||
static void add (float* dest, const float* src, int numValues) noexcept; | |||||
/** Adds a fixed value to the destination values. */ | |||||
static void add (float* dest, float amount, int numValues) noexcept; | |||||
/** Multiplies each source value by the given multiplier, then adds it to the destination value. */ | |||||
static void addWithMultiply (float* dest, const float* src, float multiplier, int numValues) noexcept; | |||||
/** Multiplies the destination values by the source values. */ | |||||
static void multiply (float* dest, const float* src, int numValues) noexcept; | |||||
/** Multiplies each of the destination values by a fixed multiplier. */ | |||||
static void multiply (float* dest, float multiplier, int numValues) noexcept; | |||||
/** Converts a stream of integers to floats, multiplying each one by the given multiplier. */ | |||||
static void convertFixedToFloat (float* dest, const int* src, float multiplier, int numValues) noexcept; | |||||
/** Finds the miniumum and maximum values in the given array. */ | |||||
static void findMinAndMax (const float* src, int numValues, float& minResult, float& maxResult) noexcept; | |||||
}; | |||||
#endif // __JUCE_FLOATVECTOROPERATIONS_JUCEHEADER__ |
@@ -38,7 +38,7 @@ IIRFilter::IIRFilter() | |||||
IIRFilter::IIRFilter (const IIRFilter& other) | IIRFilter::IIRFilter (const IIRFilter& other) | ||||
: active (other.active), v1 (0), v2 (0) | : active (other.active), v1 (0), v2 (0) | ||||
{ | { | ||||
const ScopedLock sl (other.processLock); | |||||
const SpinLock::ScopedLockType sl (other.processLock); | |||||
memcpy (coefficients, other.coefficients, sizeof (coefficients)); | memcpy (coefficients, other.coefficients, sizeof (coefficients)); | ||||
} | } | ||||
@@ -49,7 +49,7 @@ IIRFilter::~IIRFilter() | |||||
//============================================================================== | //============================================================================== | ||||
void IIRFilter::reset() noexcept | void IIRFilter::reset() noexcept | ||||
{ | { | ||||
const ScopedLock sl (processLock); | |||||
const SpinLock::ScopedLockType sl (processLock); | |||||
v1 = v2 = 0; | v1 = v2 = 0; | ||||
} | } | ||||
@@ -59,8 +59,8 @@ float IIRFilter::processSingleSampleRaw (const float in) noexcept | |||||
JUCE_SNAP_TO_ZERO (out); | JUCE_SNAP_TO_ZERO (out); | ||||
v1 = coefficients[1] * in - coefficients[4] * out + v2; | |||||
v2 = coefficients[2] * in - coefficients[5] * out; | |||||
v1 = coefficients[1] * in - coefficients[3] * out + v2; | |||||
v2 = coefficients[2] * in - coefficients[4] * out; | |||||
return out; | return out; | ||||
} | } | ||||
@@ -68,23 +68,29 @@ float IIRFilter::processSingleSampleRaw (const float in) noexcept | |||||
void IIRFilter::processSamples (float* const samples, | void IIRFilter::processSamples (float* const samples, | ||||
const int numSamples) noexcept | const int numSamples) noexcept | ||||
{ | { | ||||
const ScopedLock sl (processLock); | |||||
const SpinLock::ScopedLockType sl (processLock); | |||||
if (active) | if (active) | ||||
{ | { | ||||
const float c0 = coefficients[0]; | |||||
const float c1 = coefficients[1]; | |||||
const float c2 = coefficients[2]; | |||||
const float c3 = coefficients[3]; | |||||
const float c4 = coefficients[4]; | |||||
float lv1 = v1, lv2 = v2; | |||||
for (int i = 0; i < numSamples; ++i) | for (int i = 0; i < numSamples; ++i) | ||||
{ | { | ||||
const float in = samples[i]; | const float in = samples[i]; | ||||
float out = coefficients[0] * in + v1; | |||||
JUCE_SNAP_TO_ZERO (out); | |||||
v1 = coefficients[1] * in - coefficients[4] * out + v2; | |||||
v2 = coefficients[2] * in - coefficients[5] * out; | |||||
const float out = c0 * in + lv1; | |||||
samples[i] = out; | samples[i] = out; | ||||
lv1 = c1 * in - c3 * out + lv2; | |||||
lv2 = c2 * in - c4 * out; | |||||
} | } | ||||
JUCE_SNAP_TO_ZERO (lv1); v1 = lv1; | |||||
JUCE_SNAP_TO_ZERO (lv2); v2 = lv2; | |||||
} | } | ||||
} | } | ||||
@@ -194,14 +200,14 @@ void IIRFilter::makeBandPass (const double sampleRate, | |||||
void IIRFilter::makeInactive() noexcept | void IIRFilter::makeInactive() noexcept | ||||
{ | { | ||||
const ScopedLock sl (processLock); | |||||
const SpinLock::ScopedLockType sl (processLock); | |||||
active = false; | active = false; | ||||
} | } | ||||
//============================================================================== | //============================================================================== | ||||
void IIRFilter::copyCoefficientsFrom (const IIRFilter& other) noexcept | void IIRFilter::copyCoefficientsFrom (const IIRFilter& other) noexcept | ||||
{ | { | ||||
const ScopedLock sl (processLock); | |||||
const SpinLock::ScopedLockType sl (processLock); | |||||
memcpy (coefficients, other.coefficients, sizeof (coefficients)); | memcpy (coefficients, other.coefficients, sizeof (coefficients)); | ||||
active = other.active; | active = other.active; | ||||
@@ -219,14 +225,13 @@ void IIRFilter::setCoefficients (double c1, double c2, double c3, | |||||
c5 *= a; | c5 *= a; | ||||
c6 *= a; | c6 *= a; | ||||
const ScopedLock sl (processLock); | |||||
const SpinLock::ScopedLockType sl (processLock); | |||||
coefficients[0] = (float) c1; | coefficients[0] = (float) c1; | ||||
coefficients[1] = (float) c2; | coefficients[1] = (float) c2; | ||||
coefficients[2] = (float) c3; | coefficients[2] = (float) c3; | ||||
coefficients[3] = (float) c4; | |||||
coefficients[4] = (float) c5; | |||||
coefficients[5] = (float) c6; | |||||
coefficients[3] = (float) c5; | |||||
coefficients[4] = (float) c6; | |||||
active = true; | active = true; | ||||
} | } | ||||
@@ -131,13 +131,13 @@ public: | |||||
protected: | protected: | ||||
//============================================================================== | //============================================================================== | ||||
CriticalSection processLock; | |||||
SpinLock processLock; | |||||
void setCoefficients (double c1, double c2, double c3, | void setCoefficients (double c1, double c2, double c3, | ||||
double c4, double c5, double c6) noexcept; | double c4, double c5, double c6) noexcept; | ||||
bool active; | bool active; | ||||
float coefficients[6]; | |||||
float coefficients[5]; | |||||
float v1, v2; | float v1, v2; | ||||
// (use the copyCoefficientsFrom() method instead of this operator) | // (use the copyCoefficientsFrom() method instead of this operator) | ||||
@@ -35,15 +35,27 @@ | |||||
// Your project must contain an AppConfig.h file with your project-specific settings in it, | // Your project must contain an AppConfig.h file with your project-specific settings in it, | ||||
// and your header search path must make it accessible to the module's files. | // and your header search path must make it accessible to the module's files. | ||||
#include "AppConfig.h" | #include "AppConfig.h" | ||||
#include "juce_audio_basics.h" | #include "juce_audio_basics.h" | ||||
#ifndef JUCE_USE_SSE_INTRINSICS | |||||
#define JUCE_USE_SSE_INTRINSICS 1 | |||||
#endif | |||||
#if ! JUCE_INTEL | |||||
#define JUCE_USE_SSE_INTRINSICS 0 | |||||
#endif | |||||
#if JUCE_USE_SSE_INTRINSICS | |||||
#include <emmintrin.h> | |||||
#endif | |||||
namespace juce | namespace juce | ||||
{ | { | ||||
// START_AUTOINCLUDE buffers/*.cpp, effects/*.cpp, midi/*.cpp, sources/*.cpp, synthesisers/*.cpp | // START_AUTOINCLUDE buffers/*.cpp, effects/*.cpp, midi/*.cpp, sources/*.cpp, synthesisers/*.cpp | ||||
#include "buffers/juce_AudioDataConverters.cpp" | #include "buffers/juce_AudioDataConverters.cpp" | ||||
#include "buffers/juce_AudioSampleBuffer.cpp" | #include "buffers/juce_AudioSampleBuffer.cpp" | ||||
#include "buffers/juce_FloatVectorOperations.cpp" | |||||
#include "effects/juce_IIRFilter.cpp" | #include "effects/juce_IIRFilter.cpp" | ||||
#include "effects/juce_LagrangeInterpolator.cpp" | #include "effects/juce_LagrangeInterpolator.cpp" | ||||
#include "midi/juce_MidiBuffer.cpp" | #include "midi/juce_MidiBuffer.cpp" | ||||
@@ -39,6 +39,9 @@ namespace juce | |||||
#ifndef __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ | #ifndef __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ | ||||
#include "buffers/juce_AudioSampleBuffer.h" | #include "buffers/juce_AudioSampleBuffer.h" | ||||
#endif | #endif | ||||
#ifndef __JUCE_FLOATVECTOROPERATIONS_JUCEHEADER__ | |||||
#include "buffers/juce_FloatVectorOperations.h" | |||||
#endif | |||||
#ifndef __JUCE_DECIBELS_JUCEHEADER__ | #ifndef __JUCE_DECIBELS_JUCEHEADER__ | ||||
#include "effects/juce_Decibels.h" | #include "effects/juce_Decibels.h" | ||||
#endif | #endif | ||||
@@ -160,18 +160,29 @@ void AudioFormatReader::read (AudioSampleBuffer* buffer, | |||||
} | } | ||||
} | } | ||||
template <typename SampleType> | |||||
static inline void getChannelMinAndMax (SampleType* channel, const int numSamples, SampleType& mn, SampleType& mx) | |||||
{ | |||||
findMinAndMax (channel, numSamples, mn, mx); | |||||
} | |||||
static inline void getChannelMinAndMax (float* channel, const int numSamples, float& mn, float& mx) | |||||
{ | |||||
FloatVectorOperations::findMinAndMax (channel, numSamples, mn, mx); | |||||
} | |||||
template <typename SampleType> | template <typename SampleType> | ||||
static void getStereoMinAndMax (SampleType* const* channels, const int numChannels, const int numSamples, | static void getStereoMinAndMax (SampleType* const* channels, const int numChannels, const int numSamples, | ||||
SampleType& lmin, SampleType& lmax, SampleType& rmin, SampleType& rmax) | SampleType& lmin, SampleType& lmax, SampleType& rmin, SampleType& rmax) | ||||
{ | { | ||||
SampleType bufMin, bufMax; | SampleType bufMin, bufMax; | ||||
findMinAndMax (channels[0], numSamples, bufMin, bufMax); | |||||
getChannelMinAndMax (channels[0], numSamples, bufMin, bufMax); | |||||
lmax = jmax (lmax, bufMax); | lmax = jmax (lmax, bufMax); | ||||
lmin = jmin (lmin, bufMin); | lmin = jmin (lmin, bufMin); | ||||
if (numChannels > 1) | if (numChannels > 1) | ||||
{ | { | ||||
findMinAndMax (channels[1], numSamples, bufMin, bufMax); | |||||
getChannelMinAndMax (channels[1], numSamples, bufMin, bufMax); | |||||
rmax = jmax (rmax, bufMax); | rmax = jmax (rmax, bufMax); | ||||
rmin = jmin (rmin, bufMin); | rmin = jmin (rmin, bufMin); | ||||
} | } | ||||
@@ -562,7 +562,7 @@ protected: | |||||
if (juceFilter->isSuspended()) | if (juceFilter->isSuspended()) | ||||
{ | { | ||||
for (int i = 0; i < numOut; ++i) | for (int i = 0; i < numOut; ++i) | ||||
zeromem (outputs [i], sizeof (float) * numSamples); | |||||
FloatVectorOperations::clear (outputs [i], numSamples); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -573,7 +573,7 @@ protected: | |||||
channels[i] = outputs [i]; | channels[i] = outputs [i]; | ||||
if (i < numIn && inputs != outputs) | if (i < numIn && inputs != outputs) | ||||
memcpy (outputs [i], inputs[i], sizeof (float) * numSamples); | |||||
FloatVectorOperations::copy (outputs [i], inputs[i], numSamples); | |||||
} | } | ||||
for (; i < numIn; ++i) | for (; i < numIn; ++i) | ||||
@@ -813,9 +813,9 @@ private: | |||||
for (int i = fNumOutputs; --i >= 0;) | for (int i = fNumOutputs; --i >= 0;) | ||||
{ | { | ||||
if (i < fNumInputs) | if (i < fNumInputs) | ||||
memcpy (outputs[i], inputs[i], numSamples * sizeof (float)); | |||||
FloatVectorOperations::copy (outputs[i], inputs[i], numSamples); | |||||
else | else | ||||
zeromem (outputs[i], numSamples * sizeof (float)); | |||||
FloatVectorOperations::clear (outputs[i], numSamples); | |||||
} | } | ||||
} | } | ||||
@@ -526,7 +526,7 @@ public: | |||||
if (filter->isSuspended()) | if (filter->isSuspended()) | ||||
{ | { | ||||
for (int i = 0; i < numOut; ++i) | for (int i = 0; i < numOut; ++i) | ||||
zeromem (outputs[i], sizeof (float) * (size_t) numSamples); | |||||
FloatVectorOperations::clear (outputs[i], numSamples); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -700,7 +700,7 @@ void AudioThumbnail::addBlock (const int64 startSample, const AudioSampleBuffer& | |||||
{ | { | ||||
float low, high; | float low, high; | ||||
const int start = i * samplesPerThumbSample; | const int start = i * samplesPerThumbSample; | ||||
findMinAndMax (sourceData + start, jmin (samplesPerThumbSample, numSamples - start), low, high); | |||||
FloatVectorOperations::findMinAndMax (sourceData + start, jmin (samplesPerThumbSample, numSamples - start), low, high); | |||||
dest[i].setFloat (low, high); | dest[i].setFloat (low, high); | ||||
} | } | ||||
} | } | ||||