| @@ -487,13 +487,10 @@ public: | |||
| } | |||
| /** Scans a block of data, returning the lowest and highest levels as floats */ | |||
| void findMinAndMax (size_t numSamples, float& minValue, float& maxValue) const noexcept | |||
| Range<float> findMinAndMax (size_t numSamples) const noexcept | |||
| { | |||
| if (numSamples == 0) | |||
| { | |||
| minValue = maxValue = 0; | |||
| return; | |||
| } | |||
| return Range<float>(); | |||
| Pointer dest (*this); | |||
| @@ -512,27 +509,32 @@ public: | |||
| if (v < mn) mn = v; | |||
| } | |||
| minValue = mn; | |||
| maxValue = mx; | |||
| return Range<float> (mn, mx); | |||
| } | |||
| else | |||
| int32 mn = dest.getAsInt32(); | |||
| dest.advance(); | |||
| int32 mx = mn; | |||
| while (--numSamples > 0) | |||
| { | |||
| int32 mn = dest.getAsInt32(); | |||
| const int v = dest.getAsInt32(); | |||
| dest.advance(); | |||
| int32 mx = mn; | |||
| while (--numSamples > 0) | |||
| { | |||
| const int v = dest.getAsInt32(); | |||
| dest.advance(); | |||
| if (mx < v) mx = v; | |||
| if (v < mn) mn = v; | |||
| } | |||
| if (mx < v) mx = v; | |||
| if (v < mn) mn = v; | |||
| } | |||
| return Range<float> (mn * (float) (1.0 / (1.0 + Int32::maxValue)), | |||
| mx * (float) (1.0 / (1.0 + Int32::maxValue))); | |||
| } | |||
| minValue = mn * (float) (1.0 / (1.0 + Int32::maxValue)); | |||
| maxValue = mx * (float) (1.0 / (1.0 + Int32::maxValue)); | |||
| } | |||
| /** Scans a block of data, returning the lowest and highest levels as floats */ | |||
| void findMinAndMax (size_t numSamples, float& minValue, float& maxValue) const noexcept | |||
| { | |||
| Range<float> r (findMinAndMax (numSamples)); | |||
| minValue = r.getStart(); | |||
| maxValue = r.getEnd(); | |||
| } | |||
| /** Returns true if the pointer is using a floating-point format. */ | |||
| @@ -134,6 +134,19 @@ namespace FloatVectorHelpers | |||
| } \ | |||
| JUCE_FINISH_VEC_OP (normalOp) | |||
| #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST(normalOp, vecOp, locals, increment, setupOp) \ | |||
| JUCE_BEGIN_VEC_OP \ | |||
| setupOp \ | |||
| { \ | |||
| Mode::ParallelType (&loadSrc1) (const Mode::Type* v) = FloatVectorHelpers::isAligned (src1) ? Mode::loadA : Mode::loadU; \ | |||
| Mode::ParallelType (&loadSrc2) (const Mode::Type* v) = FloatVectorHelpers::isAligned (src2) ? Mode::loadA : Mode::loadU; \ | |||
| Mode::ParallelType (&loadDst) (const Mode::Type* v) = FloatVectorHelpers::isAligned (dest) ? Mode::loadA : Mode::loadU; \ | |||
| void (&storeDst) (Mode::Type* dest, Mode::ParallelType a) = FloatVectorHelpers::isAligned (dest) ? Mode::storeA : Mode::storeU; \ | |||
| JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, loadSrc1, loadSrc2, loadDst, storeDst, locals, increment); \ | |||
| } \ | |||
| JUCE_FINISH_VEC_OP (normalOp) | |||
| //============================================================================== | |||
| #elif JUCE_USE_ARM_NEON | |||
| @@ -211,6 +224,13 @@ namespace FloatVectorHelpers | |||
| JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \ | |||
| JUCE_FINISH_VEC_OP (normalOp) | |||
| #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST(normalOp, vecOp, locals, increment, setupOp) \ | |||
| JUCE_BEGIN_VEC_OP \ | |||
| setupOp \ | |||
| JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \ | |||
| JUCE_FINISH_VEC_OP (normalOp) | |||
| //============================================================================== | |||
| #else | |||
| #define JUCE_PERFORM_VEC_OP_DEST(normalOp, vecOp, locals, setupOp) \ | |||
| @@ -221,6 +241,10 @@ namespace FloatVectorHelpers | |||
| #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \ | |||
| for (int i = 0; i < num; ++i) normalOp; | |||
| #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST(normalOp, vecOp, locals, increment, setupOp) \ | |||
| for (int i = 0; i < num; ++i) normalOp; | |||
| #endif | |||
| //============================================================================== | |||
| @@ -240,11 +264,20 @@ namespace FloatVectorHelpers | |||
| increment; \ | |||
| } | |||
| #define JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD(vecOp, src1Load, src2Load, dstLoad, dstStore, locals, increment) \ | |||
| for (int i = 0; i < numLongOps; ++i) \ | |||
| { \ | |||
| locals (src1Load, src2Load, dstLoad); \ | |||
| dstStore (dest, vecOp); \ | |||
| increment; \ | |||
| } | |||
| #define JUCE_LOAD_NONE(srcLoad, dstLoad) | |||
| #define JUCE_LOAD_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest); | |||
| #define JUCE_LOAD_SRC(srcLoad, dstLoad) const Mode::ParallelType s = srcLoad (src); | |||
| #define JUCE_LOAD_SRC1_SRC2(src1Load, src2Load) const Mode::ParallelType s1 = src1Load (src1), s2 = src2Load (src2); | |||
| #define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest), s = srcLoad (src); | |||
| #define JUCE_LOAD_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest); | |||
| #define JUCE_LOAD_SRC(srcLoad, dstLoad) const Mode::ParallelType s = srcLoad (src); | |||
| #define JUCE_LOAD_SRC1_SRC2(src1Load, src2Load) const Mode::ParallelType s1 = src1Load (src1), s2 = src2Load (src2); | |||
| #define JUCE_LOAD_SRC1_SRC2_DEST(src1Load, src2Load, dstLoad) const Mode::ParallelType d = dstLoad (dest), s1 = src1Load (src1), s2 = src2Load (src2); | |||
| #define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest), s = srcLoad (src); | |||
| #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON | |||
| template<int typeSize> struct ModeType { typedef BasicOps32 Mode; }; | |||
| @@ -580,6 +613,28 @@ void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (double* dest, const d | |||
| const Mode::ParallelType mult = Mode::load1 (multiplier);) | |||
| } | |||
| void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (float* dest, const float* src1, const float* src2, int num) noexcept | |||
| { | |||
| #if JUCE_USE_VDSP_FRAMEWORK | |||
| vDSP_vma ((float*) src1, 1, (float*) src2, 1, dest, 1, dest, 1, (vDSP_Length) num); | |||
| #else | |||
| JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] += src1[i] * src2[i], Mode::add (d, Mode::mul (s1, s2)), | |||
| JUCE_LOAD_SRC1_SRC2_DEST, | |||
| JUCE_INCREMENT_SRC1_SRC2_DEST, ) | |||
| #endif | |||
| } | |||
| void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (double* dest, const double* src1, const double* src2, int num) noexcept | |||
| { | |||
| #if JUCE_USE_VDSP_FRAMEWORK | |||
| vDSP_vmaD ((double*) src1, 1, (double*) src2, 1, dest, 1, dest, 1, (vDSP_Length) num); | |||
| #else | |||
| JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] += src1[i] * src2[i], Mode::add (d, Mode::mul (s1, s2)), | |||
| JUCE_LOAD_SRC1_SRC2_DEST, | |||
| JUCE_INCREMENT_SRC1_SRC2_DEST, ) | |||
| #endif | |||
| } | |||
| void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* src, int num) noexcept | |||
| { | |||
| #if JUCE_USE_VDSP_FRAMEWORK | |||
| @@ -682,6 +737,96 @@ void JUCE_CALLTYPE FloatVectorOperations::convertFixedToFloat (float* dest, cons | |||
| #endif | |||
| } | |||
| void JUCE_CALLTYPE FloatVectorOperations::min (float* dest, const float* src, float comp, int num) noexcept | |||
| { | |||
| JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmin (src[i], comp), Mode::min (s, cmp), | |||
| JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, | |||
| const Mode::ParallelType cmp = Mode::load1 (comp);) | |||
| } | |||
| void JUCE_CALLTYPE FloatVectorOperations::min (double* dest, const double* src, double comp, int num) noexcept | |||
| { | |||
| JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmin (src[i], comp), Mode::min (s, cmp), | |||
| JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, | |||
| const Mode::ParallelType cmp = Mode::load1 (comp);) | |||
| } | |||
| void JUCE_CALLTYPE FloatVectorOperations::min (float* dest, const float* src1, const float* src2, int num) noexcept | |||
| { | |||
| #if JUCE_USE_VDSP_FRAMEWORK | |||
| vDSP_vmin ((float*) src1, 1, (float*) src2, 1, dest, 1, (vDSP_Length) num); | |||
| #else | |||
| JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmin (src1[i], src2[i]), Mode::min (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, ) | |||
| #endif | |||
| } | |||
| void JUCE_CALLTYPE FloatVectorOperations::min (double* dest, const double* src1, const double* src2, int num) noexcept | |||
| { | |||
| #if JUCE_USE_VDSP_FRAMEWORK | |||
| vDSP_vminD ((double*) src1, 1, (double*) src2, 1, dest, 1, (vDSP_Length) num); | |||
| #else | |||
| JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmin (src1[i], src2[i]), Mode::min (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, ) | |||
| #endif | |||
| } | |||
| void JUCE_CALLTYPE FloatVectorOperations::max (float* dest, const float* src, float comp, int num) noexcept | |||
| { | |||
| JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (src[i], comp), Mode::max (s, cmp), | |||
| JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, | |||
| const Mode::ParallelType cmp = Mode::load1 (comp);) | |||
| } | |||
| void JUCE_CALLTYPE FloatVectorOperations::max (double* dest, const double* src, double comp, int num) noexcept | |||
| { | |||
| JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (src[i], comp), Mode::max (s, cmp), | |||
| JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, | |||
| const Mode::ParallelType cmp = Mode::load1 (comp);) | |||
| } | |||
| void JUCE_CALLTYPE FloatVectorOperations::max (float* dest, const float* src1, const float* src2, int num) noexcept | |||
| { | |||
| #if JUCE_USE_VDSP_FRAMEWORK | |||
| vDSP_vmax ((float*) src1, 1, (float*) src2, 1, dest, 1, (vDSP_Length) num); | |||
| #else | |||
| JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmax (src1[i], src2[i]), Mode::max (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, ) | |||
| #endif | |||
| } | |||
| void JUCE_CALLTYPE FloatVectorOperations::max (double* dest, const double* src1, const double* src2, int num) noexcept | |||
| { | |||
| #if JUCE_USE_VDSP_FRAMEWORK | |||
| vDSP_vmaxD ((double*) src1, 1, (double*) src2, 1, dest, 1, (vDSP_Length) num); | |||
| #else | |||
| JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmax (src1[i], src2[i]), Mode::max (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, ) | |||
| #endif | |||
| } | |||
| void JUCE_CALLTYPE FloatVectorOperations::clip (float* dest, const float* src, float low, float high, int num) noexcept | |||
| { | |||
| jassert(high >= low); | |||
| #if JUCE_USE_VDSP_FRAMEWORK | |||
| vDSP_vclip ((float*) src, 1, &low, &high, dest, 1, (vDSP_Length) num); | |||
| #else | |||
| JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (jmin (src[i], high), low), Mode::max (Mode::min (s, hi), lo), | |||
| JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, | |||
| const Mode::ParallelType lo = Mode::load1 (low); const Mode::ParallelType hi = Mode::load1 (high);) | |||
| #endif | |||
| } | |||
| void JUCE_CALLTYPE FloatVectorOperations::clip (double* dest, const double* src, double low, double high, int num) noexcept | |||
| { | |||
| jassert(high >= low); | |||
| #if JUCE_USE_VDSP_FRAMEWORK | |||
| vDSP_vclipD ((double*) src, 1, &low, &high, dest, 1, (vDSP_Length) num); | |||
| #else | |||
| JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (jmin (src[i], high), low), Mode::max (Mode::min (s, hi), lo), | |||
| JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, | |||
| const Mode::ParallelType lo = Mode::load1 (low); const Mode::ParallelType hi = Mode::load1 (high);) | |||
| #endif | |||
| } | |||
| Range<float> JUCE_CALLTYPE FloatVectorOperations::findMinAndMax (const float* src, int num) noexcept | |||
| { | |||
| #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON | |||
| @@ -823,6 +968,11 @@ public: | |||
| fillRandomly (random, int1, num); | |||
| doConversionTest (u, data1, data2, int1, num); | |||
| FloatVectorOperations::fill (data1, (ValueType) 2, num); | |||
| FloatVectorOperations::fill (data2, (ValueType) 3, num); | |||
| FloatVectorOperations::addWithMultiply (data1, data1, data2, num); | |||
| u.expect (areAllValuesEqual (data1, num, (ValueType) 8)); | |||
| } | |||
| static void doConversionTest (UnitTest& u, float* data1, float* data2, int* const int1, int num) | |||
| @@ -101,6 +101,12 @@ public: | |||
| /** Multiplies each source value by the given multiplier, then adds it to the destination value. */ | |||
| static void JUCE_CALLTYPE addWithMultiply (double* dest, const double* src, double multiplier, int numValues) noexcept; | |||
| /** Multiplies each source1 value by the corresponding source2 value, then adds it to the destination value. */ | |||
| static void JUCE_CALLTYPE addWithMultiply (float* dest, const float* src1, const float* src2, int num) noexcept; | |||
| /** Multiplies each source1 value by the corresponding source2 value, then adds it to the destination value. */ | |||
| static void JUCE_CALLTYPE addWithMultiply (double* dest, const double* src1, const double* src2, int num) noexcept; | |||
| /** Multiplies the destination values by the source values. */ | |||
| static void JUCE_CALLTYPE multiply (float* dest, const float* src, int numValues) noexcept; | |||
| @@ -134,6 +140,36 @@ public: | |||
| /** Converts a stream of integers to floats, multiplying each one by the given multiplier. */ | |||
| static void JUCE_CALLTYPE convertFixedToFloat (float* dest, const int* src, float multiplier, int numValues) noexcept; | |||
| /** Each element of dest will be the minimum of the corresponding element of the source array and the given comp value. */ | |||
| static void JUCE_CALLTYPE min (float* dest, const float* src, float comp, int num) noexcept; | |||
| /** Each element of dest will be the minimum of the corresponding element of the source array and the given comp value. */ | |||
| static void JUCE_CALLTYPE min (double* dest, const double* src, double comp, int num) noexcept; | |||
| /** Each element of dest will be the minimum of the corresponding source1 and source2 values. */ | |||
| static void JUCE_CALLTYPE min (float* dest, const float* src1, const float* src2, int num) noexcept; | |||
| /** Each element of dest will be the minimum of the corresponding source1 and source2 values. */ | |||
| static void JUCE_CALLTYPE min (double* dest, const double* src1, const double* src2, int num) noexcept; | |||
| /** Each element of dest will be the maximum of the corresponding element of the source array and the given comp value. */ | |||
| static void JUCE_CALLTYPE max (float* dest, const float* src, float comp, int num) noexcept; | |||
| /** Each element of dest will be the maximum of the corresponding element of the source array and the given comp value. */ | |||
| static void JUCE_CALLTYPE max (double* dest, const double* src, double comp, int num) noexcept; | |||
| /** Each element of dest will be the maximum of the corresponding source1 and source2 values. */ | |||
| static void JUCE_CALLTYPE max (float* dest, const float* src1, const float* src2, int num) noexcept; | |||
| /** Each element of dest will be the maximum of the corresponding source1 and source2 values. */ | |||
| static void JUCE_CALLTYPE max (double* dest, const double* src1, const double* src2, int num) noexcept; | |||
| /** Each element of dest is calculated by hard clipping the corresponding src element so that it is in the range specified by the arguments low and high. */ | |||
| static void JUCE_CALLTYPE clip (float* dest, const float* src, float low, float high, int num) noexcept; | |||
| /** Each element of dest is calculated by hard clipping the corresponding src element so that it is in the range specified by the arguments low and high. */ | |||
| static void JUCE_CALLTYPE clip (double* dest, const double* src, double low, double high, int num) noexcept; | |||
| /** Finds the miniumum and maximum values in the given array. */ | |||
| static Range<float> JUCE_CALLTYPE findMinAndMax (const float* src, int numValues) noexcept; | |||
| @@ -0,0 +1,277 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2013 - Raw Material Software Ltd. | |||
| Permission is granted to use this software under the terms of either: | |||
| a) the GPL v2 (or any later version) | |||
| b) the Affero GPL v3 | |||
| Details of these licenses can be found 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.juce.com for more information. | |||
| ============================================================================== | |||
| */ | |||
| // (For the moment, we'll implement a few local operators for this complex class - one | |||
| // day we'll probably either have a juce complex class, or use the C++11 one) | |||
| static FFT::Complex operator+ (FFT::Complex a, FFT::Complex b) noexcept { FFT::Complex c = { a.r + b.r, a.i + b.i }; return c; } | |||
| static FFT::Complex operator- (FFT::Complex a, FFT::Complex b) noexcept { FFT::Complex c = { a.r - b.r, a.i - b.i }; return c; } | |||
| static FFT::Complex operator* (FFT::Complex a, FFT::Complex b) noexcept { FFT::Complex c = { a.r * b.r - a.i * b.i, a.r * b.i + a.i * b.r }; return c; } | |||
| static FFT::Complex& operator+= (FFT::Complex& a, FFT::Complex b) noexcept { a.r += b.r; a.i += b.i; return a; } | |||
| //============================================================================== | |||
| struct FFT::FFTConfig | |||
| { | |||
| FFTConfig (int sizeOfFFT, bool isInverse) | |||
| : fftSize (sizeOfFFT), inverse (isInverse), twiddleTable ((size_t) sizeOfFFT) | |||
| { | |||
| for (int i = 0; i < fftSize; ++i) | |||
| { | |||
| const double phase = (isInverse ? 2.0 : -2.0) * double_Pi * i / fftSize; | |||
| twiddleTable[i].r = (float) cos (phase); | |||
| twiddleTable[i].i = (float) sin (phase); | |||
| } | |||
| const int root = (int) std::sqrt ((double) fftSize); | |||
| int divisor = 4, n = fftSize; | |||
| for (int i = 0; i < numElementsInArray (factors); ++i) | |||
| { | |||
| while ((n % divisor) != 0) | |||
| { | |||
| if (divisor == 2) divisor = 3; | |||
| else if (divisor == 4) divisor = 2; | |||
| else divisor += 2; | |||
| if (divisor > root) | |||
| divisor = n; | |||
| } | |||
| n /= divisor; | |||
| jassert (divisor == 1 || divisor == 2 || divisor == 4); | |||
| factors[i].radix = divisor; | |||
| factors[i].length = n; | |||
| } | |||
| } | |||
| void perform (const Complex* input, Complex* output) const noexcept | |||
| { | |||
| perform (input, output, 1, 1, factors); | |||
| } | |||
| const int fftSize; | |||
| const bool inverse; | |||
| struct Factor { int radix, length; }; | |||
| Factor factors[32]; | |||
| HeapBlock<Complex> twiddleTable; | |||
| void perform (const Complex* input, Complex* output, const int stride, const int strideIn, const Factor* facs) const noexcept | |||
| { | |||
| const Factor factor (*facs++); | |||
| Complex* const originalOutput = output; | |||
| const Complex* const outputEnd = output + factor.radix * factor.length; | |||
| if (stride == 1 && factor.radix <= 5) | |||
| { | |||
| for (int i = 0; i < factor.radix; ++i) | |||
| perform (input + stride * strideIn * i, output + i * factor.length, stride * factor.radix, strideIn, facs); | |||
| butterfly (factor, output, stride); | |||
| return; | |||
| } | |||
| if (factor.length == 1) | |||
| { | |||
| do | |||
| { | |||
| *output++ = *input; | |||
| input += stride * strideIn; | |||
| } | |||
| while (output < outputEnd); | |||
| } | |||
| else | |||
| { | |||
| do | |||
| { | |||
| perform (input, output, stride * factor.radix, strideIn, facs); | |||
| input += stride * strideIn; | |||
| output += factor.length; | |||
| } | |||
| while (output < outputEnd); | |||
| } | |||
| butterfly (factor, originalOutput, stride); | |||
| } | |||
| void butterfly (const Factor factor, Complex* data, const int stride) const noexcept | |||
| { | |||
| switch (factor.radix) | |||
| { | |||
| case 1: break; | |||
| case 2: butterfly2 (data, stride, factor.length); return; | |||
| case 4: butterfly4 (data, stride, factor.length); return; | |||
| default: jassertfalse; break; | |||
| } | |||
| Complex* scratch = static_cast<Complex*> (alloca (sizeof (Complex) * (size_t) factor.radix)); | |||
| for (int i = 0; i < factor.length; ++i) | |||
| { | |||
| for (int k = i, q1 = 0; q1 < factor.radix; ++q1) | |||
| { | |||
| scratch[q1] = data[k]; | |||
| k += factor.length; | |||
| } | |||
| for (int k = i, q1 = 0; q1 < factor.radix; ++q1) | |||
| { | |||
| int twiddleIndex = 0; | |||
| data[k] = scratch[0]; | |||
| for (int q = 1; q < factor.radix; ++q) | |||
| { | |||
| twiddleIndex += stride * k; | |||
| if (twiddleIndex >= fftSize) | |||
| twiddleIndex -= fftSize; | |||
| data[k] += scratch[q] * twiddleTable[twiddleIndex]; | |||
| } | |||
| k += factor.length; | |||
| } | |||
| } | |||
| } | |||
| void butterfly2 (Complex* data, const int stride, const int length) const noexcept | |||
| { | |||
| Complex* dataEnd = data + length; | |||
| const Complex* tw = twiddleTable; | |||
| for (int i = length; --i >= 0;) | |||
| { | |||
| const Complex s (*dataEnd * *tw); | |||
| tw += stride; | |||
| *dataEnd++ = *data - s; | |||
| *data++ += s; | |||
| } | |||
| } | |||
| void butterfly4 (Complex* data, const int stride, const int length) const noexcept | |||
| { | |||
| const int lengthX2 = length * 2; | |||
| const int lengthX3 = length * 3; | |||
| const Complex* twiddle1 = twiddleTable; | |||
| const Complex* twiddle2 = twiddle1; | |||
| const Complex* twiddle3 = twiddle1; | |||
| for (int i = length; --i >= 0;) | |||
| { | |||
| const Complex s0 = data[length] * *twiddle1; | |||
| const Complex s1 = data[lengthX2] * *twiddle2; | |||
| const Complex s2 = data[lengthX3] * *twiddle3; | |||
| const Complex s3 = s0 + s2; | |||
| const Complex s4 = s0 - s2; | |||
| const Complex s5 = *data - s1; | |||
| *data += s1; | |||
| data[lengthX2] = *data - s3; | |||
| twiddle1 += stride; | |||
| twiddle2 += stride * 2; | |||
| twiddle3 += stride * 3; | |||
| *data += s3; | |||
| if (inverse) | |||
| { | |||
| data[length].r = s5.r - s4.i; | |||
| data[length].i = s5.i + s4.r; | |||
| data[lengthX3].r = s5.r + s4.i; | |||
| data[lengthX3].i = s5.i - s4.r; | |||
| } | |||
| else | |||
| { | |||
| data[length].r = s5.r + s4.i; | |||
| data[length].i = s5.i - s4.r; | |||
| data[lengthX3].r = s5.r - s4.i; | |||
| data[lengthX3].i = s5.i + s4.r; | |||
| } | |||
| ++data; | |||
| } | |||
| } | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FFTConfig) | |||
| }; | |||
| //============================================================================== | |||
| FFT::FFT (int order, bool inverse) : config (new FFTConfig (1 << order, inverse)), size (1 << order) {} | |||
| FFT::~FFT() {} | |||
| void FFT::perform (const Complex* const input, Complex* const output) const noexcept | |||
| { | |||
| config->perform (input, output); | |||
| } | |||
| void FFT::performRealOnlyForwardTransform (float* d) const noexcept | |||
| { | |||
| // This can only be called on an FFT object that was created to do forward transforms. | |||
| jassert (! config->inverse); | |||
| Complex* const scratch = static_cast<Complex*> (alloca (16 + sizeof (Complex) * (size_t) size)); | |||
| for (int i = 0; i < size; ++i) | |||
| { | |||
| scratch[i].r = d[i]; | |||
| scratch[i].i = 0; | |||
| } | |||
| perform (scratch, reinterpret_cast<Complex*> (d)); | |||
| } | |||
| void FFT::performRealOnlyInverseTransform (float* d) const noexcept | |||
| { | |||
| // This can only be called on an FFT object that was created to do inverse transforms. | |||
| jassert (config->inverse); | |||
| Complex* const scratch = static_cast<Complex*> (alloca (16 + sizeof (Complex) * (size_t) size)); | |||
| perform (reinterpret_cast<const Complex*> (d), scratch); | |||
| const float scaleFactor = 1.0f / size; | |||
| for (int i = 0; i < size; ++i) | |||
| { | |||
| d[i] = scratch[i].r * scaleFactor; | |||
| d[i + size] = scratch[i].i * scaleFactor; | |||
| } | |||
| } | |||
| void FFT::performFrequencyOnlyForwardTransform (float* d) const noexcept | |||
| { | |||
| performRealOnlyForwardTransform (d); | |||
| const int twiceSize = size * 2; | |||
| for (int i = 0; i < twiceSize; i += 2) | |||
| { | |||
| d[i / 2] = juce_hypot (d[i], d[i + 1]); | |||
| if (i >= size) | |||
| { | |||
| d[i] = 0; | |||
| d[i + 1] = 0; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,92 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2013 - Raw Material Software Ltd. | |||
| Permission is granted to use this software under the terms of either: | |||
| a) the GPL v2 (or any later version) | |||
| b) the Affero GPL v3 | |||
| Details of these licenses can be found 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.juce.com for more information. | |||
| ============================================================================== | |||
| */ | |||
| /** | |||
| A very minimal FFT class. | |||
| This is only a simple low-footprint implementation and isn't tuned for speed - it may | |||
| be useful for simple applications where one of the more complex FFT libraries would be | |||
| overkill. (But in the future it may end up becoming optimised of course...) | |||
| The FFT class itself contains lookup tables, so there's some overhead in creating | |||
| one, you should create and cache an FFT object for each size/direction of transform | |||
| that you need, and re-use them to perform the actual operation. | |||
| */ | |||
| class JUCE_API FFT | |||
| { | |||
| public: | |||
| /** Initialises an object for performing either a forward or inverse FFT with the given size. | |||
| The the number of points the FFT will operate on will be 2 ^ order. | |||
| */ | |||
| FFT (int order, bool isInverse); | |||
| /** Destructor. */ | |||
| ~FFT(); | |||
| /** A complex number, for the purposes of the FFT class. */ | |||
| struct Complex | |||
| { | |||
| float r; /**< Real part. */ | |||
| float i; /**< Imaginary part. */ | |||
| }; | |||
| /** Performs an out-of-place FFT, either forward or inverse depending on the mode | |||
| that was passed to this object's constructor. | |||
| The arrays must contain at least getSize() elements. | |||
| */ | |||
| void perform (const Complex* input, Complex* output) const noexcept; | |||
| /** Performs an in-place forward transform on a block of real data. | |||
| The size of the array passed in must be 2 * getSize(), and the first half | |||
| should contain your raw input sample data. On return, the array will contain | |||
| complex frequency + phase data, and can be passed to performRealOnlyInverseTransform() | |||
| in order to convert it back to reals. | |||
| */ | |||
| void performRealOnlyForwardTransform (float* inputOutputData) const noexcept; | |||
| /** Performs a reverse operation to data created in performRealOnlyForwardTransform(). | |||
| The size of the array passed in must be 2 * getSize(), containing complex | |||
| frequency and phase data. On return, the first half of the array will contain | |||
| the reconstituted samples. | |||
| */ | |||
| void performRealOnlyInverseTransform (float* inputOutputData) const noexcept; | |||
| /** Takes an array and simply transforms it to the frequency spectrum. | |||
| This may be handy for things like frequency displays or analysis. | |||
| */ | |||
| void performFrequencyOnlyForwardTransform (float* inputOutputData) const noexcept; | |||
| /** Returns the number of data points that this FFT was created to work with. */ | |||
| int getSize() const noexcept { return size; } | |||
| private: | |||
| struct FFTConfig; | |||
| ScopedPointer<FFTConfig> config; | |||
| const int size; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FFT) | |||
| }; | |||
| @@ -23,7 +23,7 @@ | |||
| */ | |||
| #if JUCE_INTEL | |||
| #define JUCE_SNAP_TO_ZERO(n) if (! (n < -1.0e-8 || n > 1.0e-8)) n = 0; | |||
| #define JUCE_SNAP_TO_ZERO(n) if (! (n < -1.0e-8f || n > 1.0e-8f)) n = 0; | |||
| #else | |||
| #define JUCE_SNAP_TO_ZERO(n) | |||
| #endif | |||
| @@ -64,7 +64,7 @@ IIRCoefficients IIRCoefficients::makeLowPass (const double sampleRate, | |||
| { | |||
| jassert (sampleRate > 0); | |||
| const double n = 1.0 / tan (double_Pi * frequency / sampleRate); | |||
| const double n = 1.0 / std::tan (double_Pi * frequency / sampleRate); | |||
| const double nSquared = n * n; | |||
| const double c1 = 1.0 / (1.0 + std::sqrt (2.0) * n + nSquared); | |||
| @@ -79,7 +79,7 @@ IIRCoefficients IIRCoefficients::makeLowPass (const double sampleRate, | |||
| IIRCoefficients IIRCoefficients::makeHighPass (const double sampleRate, | |||
| const double frequency) noexcept | |||
| { | |||
| const double n = tan (double_Pi * frequency / sampleRate); | |||
| const double n = std::tan (double_Pi * frequency / sampleRate); | |||
| const double nSquared = n * n; | |||
| const double c1 = 1.0 / (1.0 + std::sqrt (2.0) * n + nSquared); | |||
| @@ -87,7 +87,10 @@ int LagrangeInterpolator::process (const double actualRatio, const float* in, | |||
| if (numOut >= 4) | |||
| { | |||
| memcpy (lastInputSamples, in + (numOut - 4), 4 * sizeof (float)); | |||
| const float* end = in + numOut; | |||
| for (int i = 0; i < 4; ++i) | |||
| lastInputSamples[i] = *--end; | |||
| } | |||
| else | |||
| { | |||
| @@ -152,7 +155,10 @@ int LagrangeInterpolator::processAdding (const double actualRatio, const float* | |||
| if (numOut >= 4) | |||
| { | |||
| memcpy (lastInputSamples, in + (numOut - 4), 4 * sizeof (float)); | |||
| const float* end = in + numOut; | |||
| for (int i = 0; i < 4; ++i) | |||
| lastInputSamples[i] = *--end; | |||
| } | |||
| else | |||
| { | |||
| @@ -82,12 +82,13 @@ public: | |||
| const float dryScaleFactor = 2.0f; | |||
| const float wet = newParams.wetLevel * wetScaleFactor; | |||
| wet1 = wet * (newParams.width * 0.5f + 0.5f); | |||
| wet2 = wet * (1.0f - newParams.width) * 0.5f; | |||
| dry = newParams.dryLevel * dryScaleFactor; | |||
| dryGain.setValue (newParams.dryLevel * dryScaleFactor); | |||
| wetGain1.setValue (0.5f * wet * (1.0f + newParams.width)); | |||
| wetGain2.setValue (0.5f * wet * (1.0f - newParams.width)); | |||
| gain = isFrozen (newParams.freezeMode) ? 0.0f : 0.015f; | |||
| parameters = newParams; | |||
| shouldUpdateDamping = true; | |||
| updateDamping(); | |||
| } | |||
| //============================================================================== | |||
| @@ -115,7 +116,12 @@ public: | |||
| allPass[1][i].setSize ((intSampleRate * (allPassTunings[i] + stereoSpread)) / 44100); | |||
| } | |||
| shouldUpdateDamping = true; | |||
| const double smoothTime = 0.01; | |||
| damping .reset (sampleRate, smoothTime); | |||
| feedback.reset (sampleRate, smoothTime); | |||
| dryGain .reset (sampleRate, smoothTime); | |||
| wetGain1.reset (sampleRate, smoothTime); | |||
| wetGain2.reset (sampleRate, smoothTime); | |||
| } | |||
| /** Clears the reverb's buffers. */ | |||
| @@ -137,18 +143,18 @@ public: | |||
| { | |||
| jassert (left != nullptr && right != nullptr); | |||
| if (shouldUpdateDamping) | |||
| updateDamping(); | |||
| for (int i = 0; i < numSamples; ++i) | |||
| { | |||
| const float input = (left[i] + right[i]) * gain; | |||
| float outL = 0, outR = 0; | |||
| const float damp = damping.getNextValue(); | |||
| const float feedbck = feedback.getNextValue(); | |||
| for (int j = 0; j < numCombs; ++j) // accumulate the comb filters in parallel | |||
| { | |||
| outL += comb[0][j].process (input); | |||
| outR += comb[1][j].process (input); | |||
| outL += comb[0][j].process (input, damp, feedbck); | |||
| outR += comb[1][j].process (input, damp, feedbck); | |||
| } | |||
| for (int j = 0; j < numAllPasses; ++j) // run the allpass filters in series | |||
| @@ -157,6 +163,10 @@ public: | |||
| outR = allPass[1][j].process (outR); | |||
| } | |||
| const float dry = dryGain.getNextValue(); | |||
| const float wet1 = wetGain1.getNextValue(); | |||
| const float wet2 = wetGain2.getNextValue(); | |||
| left[i] = outL * wet1 + outR * wet2 + left[i] * dry; | |||
| right[i] = outR * wet1 + outL * wet2 + right[i] * dry; | |||
| } | |||
| @@ -167,32 +177,30 @@ public: | |||
| { | |||
| jassert (samples != nullptr); | |||
| if (shouldUpdateDamping) | |||
| updateDamping(); | |||
| for (int i = 0; i < numSamples; ++i) | |||
| { | |||
| const float input = samples[i] * gain; | |||
| float output = 0; | |||
| const float damp = damping.getNextValue(); | |||
| const float feedbck = feedback.getNextValue(); | |||
| for (int j = 0; j < numCombs; ++j) // accumulate the comb filters in parallel | |||
| output += comb[0][j].process (input); | |||
| output += comb[0][j].process (input, damp, feedbck); | |||
| for (int j = 0; j < numAllPasses; ++j) // run the allpass filters in series | |||
| output = allPass[0][j].process (output); | |||
| const float dry = dryGain.getNextValue(); | |||
| const float wet1 = wetGain1.getNextValue(); | |||
| samples[i] = output * wet1 + samples[i] * dry; | |||
| } | |||
| } | |||
| private: | |||
| //============================================================================== | |||
| Parameters parameters; | |||
| volatile bool shouldUpdateDamping; | |||
| float gain, wet1, wet2, dry; | |||
| inline static bool isFrozen (const float freezeMode) noexcept { return freezeMode >= 0.5f; } | |||
| static bool isFrozen (const float freezeMode) noexcept { return freezeMode >= 0.5f; } | |||
| void updateDamping() noexcept | |||
| { | |||
| @@ -200,8 +208,6 @@ private: | |||
| const float roomOffset = 0.7f; | |||
| const float dampScaleFactor = 0.4f; | |||
| shouldUpdateDamping = false; | |||
| if (isFrozen (parameters.freezeMode)) | |||
| setDamping (0.0f, 1.0f); | |||
| else | |||
| @@ -211,19 +217,15 @@ private: | |||
| void setDamping (const float dampingToUse, const float roomSizeToUse) noexcept | |||
| { | |||
| for (int j = 0; j < numChannels; ++j) | |||
| for (int i = numCombs; --i >= 0;) | |||
| comb[j][i].setFeedbackAndDamp (roomSizeToUse, dampingToUse); | |||
| damping.setValue (dampingToUse); | |||
| feedback.setValue (roomSizeToUse); | |||
| } | |||
| //============================================================================== | |||
| class CombFilter | |||
| { | |||
| public: | |||
| CombFilter() noexcept | |||
| : bufferSize (0), bufferIndex (0), | |||
| feedback (0), last (0), damp1 (0), damp2 (0) | |||
| {} | |||
| CombFilter() noexcept : bufferSize (0), bufferIndex (0), last (0) {} | |||
| void setSize (const int size) | |||
| { | |||
| @@ -243,22 +245,15 @@ private: | |||
| buffer.clear ((size_t) bufferSize); | |||
| } | |||
| void setFeedbackAndDamp (const float f, const float d) noexcept | |||
| { | |||
| damp1 = d; | |||
| damp2 = 1.0f - d; | |||
| feedback = f; | |||
| } | |||
| inline float process (const float input) noexcept | |||
| float process (const float input, const float damp, const float feedbackLevel) noexcept | |||
| { | |||
| const float output = buffer [bufferIndex]; | |||
| last = (output * damp2) + (last * damp1); | |||
| const float output = buffer[bufferIndex]; | |||
| last = (output * (1.0f - damp)) + (last * damp); | |||
| JUCE_UNDENORMALISE (last); | |||
| float temp = input + (last * feedback); | |||
| float temp = input + (last * feedbackLevel); | |||
| JUCE_UNDENORMALISE (temp); | |||
| buffer [bufferIndex] = temp; | |||
| buffer[bufferIndex] = temp; | |||
| bufferIndex = (bufferIndex + 1) % bufferSize; | |||
| return output; | |||
| } | |||
| @@ -266,7 +261,7 @@ private: | |||
| private: | |||
| HeapBlock<float> buffer; | |||
| int bufferSize, bufferIndex; | |||
| float feedback, last, damp1, damp2; | |||
| float last; | |||
| JUCE_DECLARE_NON_COPYABLE (CombFilter) | |||
| }; | |||
| @@ -294,7 +289,7 @@ private: | |||
| buffer.clear ((size_t) bufferSize); | |||
| } | |||
| inline float process (const float input) noexcept | |||
| float process (const float input) noexcept | |||
| { | |||
| const float bufferedValue = buffer [bufferIndex]; | |||
| float temp = input + (bufferedValue * 0.5f); | |||
| @@ -311,11 +306,65 @@ private: | |||
| JUCE_DECLARE_NON_COPYABLE (AllPassFilter) | |||
| }; | |||
| //============================================================================== | |||
| class LinearSmoothedValue | |||
| { | |||
| public: | |||
| LinearSmoothedValue() noexcept | |||
| : currentValue (0), target (0), step (0), countdown (0), stepsToTarget (0) | |||
| { | |||
| } | |||
| void reset (double sampleRate, double fadeLengthSeconds) noexcept | |||
| { | |||
| jassert (sampleRate > 0 && fadeLengthSeconds >= 0); | |||
| stepsToTarget = (int) std::floor (fadeLengthSeconds * sampleRate); | |||
| currentValue = target; | |||
| countdown = 0; | |||
| } | |||
| void setValue (float newValue) noexcept | |||
| { | |||
| if (target != newValue) | |||
| { | |||
| target = newValue; | |||
| countdown = stepsToTarget; | |||
| if (countdown <= 0) | |||
| currentValue = target; | |||
| else | |||
| step = (target - currentValue) / countdown; | |||
| } | |||
| } | |||
| float getNextValue() noexcept | |||
| { | |||
| if (countdown <= 0) | |||
| return target; | |||
| --countdown; | |||
| currentValue += step; | |||
| return currentValue; | |||
| } | |||
| private: | |||
| float currentValue, target, step; | |||
| int countdown, stepsToTarget; | |||
| JUCE_DECLARE_NON_COPYABLE (LinearSmoothedValue) | |||
| }; | |||
| //============================================================================== | |||
| enum { numCombs = 8, numAllPasses = 4, numChannels = 2 }; | |||
| Parameters parameters; | |||
| float gain; | |||
| CombFilter comb [numChannels][numCombs]; | |||
| AllPassFilter allPass [numChannels][numAllPasses]; | |||
| LinearSmoothedValue damping, feedback, dryGain, wetGain1, wetGain2; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Reverb) | |||
| }; | |||
| @@ -78,6 +78,7 @@ namespace juce | |||
| #include "effects/juce_IIRFilter.cpp" | |||
| #include "effects/juce_IIRFilterOld.cpp" | |||
| #include "effects/juce_LagrangeInterpolator.cpp" | |||
| #include "effects/juce_FFT.cpp" | |||
| #include "midi/juce_MidiBuffer.cpp" | |||
| #include "midi/juce_MidiFile.cpp" | |||
| #include "midi/juce_MidiKeyboardState.cpp" | |||
| @@ -31,6 +31,9 @@ | |||
| namespace juce | |||
| { | |||
| #undef Complex // apparently some C libraries actually define these symbols (!) | |||
| #undef Factor | |||
| #include "buffers/juce_AudioDataConverters.h" | |||
| #include "buffers/juce_AudioSampleBuffer.h" | |||
| #include "buffers/juce_FloatVectorOperations.h" | |||
| @@ -38,6 +41,7 @@ namespace juce | |||
| #include "effects/juce_IIRFilter.h" | |||
| #include "effects/juce_IIRFilterOld.h" | |||
| #include "effects/juce_LagrangeInterpolator.h" | |||
| #include "effects/juce_FFT.h" | |||
| #include "effects/juce_Reverb.h" | |||
| #include "midi/juce_MidiMessage.h" | |||
| #include "midi/juce_MidiBuffer.h" | |||
| @@ -276,14 +276,11 @@ void MidiMessageSequence::deleteSysExMessages() | |||
| } | |||
| //============================================================================== | |||
| void MidiMessageSequence::createControllerUpdatesForTime (const int channelNumber, | |||
| const double time, | |||
| OwnedArray<MidiMessage>& dest) | |||
| void MidiMessageSequence::createControllerUpdatesForTime (const int channelNumber, const double time, Array<MidiMessage>& dest) | |||
| { | |||
| bool doneProg = false; | |||
| bool donePitchWheel = false; | |||
| Array<int> doneControllers; | |||
| doneControllers.ensureStorageAllocated (32); | |||
| bool doneControllers[128] = { 0 }; | |||
| for (int i = list.size(); --i >= 0;) | |||
| { | |||
| @@ -291,28 +288,25 @@ void MidiMessageSequence::createControllerUpdatesForTime (const int channelNumbe | |||
| if (mm.isForChannel (channelNumber) && mm.getTimeStamp() <= time) | |||
| { | |||
| if (mm.isProgramChange()) | |||
| if (mm.isProgramChange() && ! doneProg) | |||
| { | |||
| if (! doneProg) | |||
| { | |||
| dest.add (new MidiMessage (mm, 0.0)); | |||
| doneProg = true; | |||
| } | |||
| doneProg = true; | |||
| dest.add (MidiMessage (mm, 0.0)); | |||
| } | |||
| else if (mm.isController()) | |||
| else if (mm.isPitchWheel() && ! donePitchWheel) | |||
| { | |||
| if (! doneControllers.contains (mm.getControllerNumber())) | |||
| { | |||
| dest.add (new MidiMessage (mm, 0.0)); | |||
| doneControllers.add (mm.getControllerNumber()); | |||
| } | |||
| donePitchWheel = true; | |||
| dest.add (MidiMessage (mm, 0.0)); | |||
| } | |||
| else if (mm.isPitchWheel()) | |||
| else if (mm.isController()) | |||
| { | |||
| if (! donePitchWheel) | |||
| const int controllerNumber = mm.getControllerNumber(); | |||
| jassert (isPositiveAndBelow (controllerNumber, 128)); | |||
| if (! doneControllers[controllerNumber]) | |||
| { | |||
| dest.add (new MidiMessage (mm, 0.0)); | |||
| donePitchWheel = true; | |||
| doneControllers[controllerNumber] = true; | |||
| dest.add (MidiMessage (mm, 0.0)); | |||
| } | |||
| } | |||
| } | |||
| @@ -247,7 +247,7 @@ public: | |||
| state at the required time. | |||
| */ | |||
| void createControllerUpdatesForTime (int channelNumber, double time, | |||
| OwnedArray<MidiMessage>& resultMessages); | |||
| Array<MidiMessage>& resultMessages); | |||
| //============================================================================== | |||
| /** Swaps this sequence with another one. */ | |||
| @@ -24,14 +24,14 @@ | |||
| ResamplingAudioSource::ResamplingAudioSource (AudioSource* const inputSource, | |||
| const bool deleteInputWhenDeleted, | |||
| const int numChannels_) | |||
| const int channels) | |||
| : input (inputSource, deleteInputWhenDeleted), | |||
| ratio (1.0), | |||
| lastRatio (1.0), | |||
| bufferPos (0), | |||
| sampsInBuffer (0), | |||
| subSampleOffset (0), | |||
| numChannels (numChannels_) | |||
| numChannels (channels) | |||
| { | |||
| jassert (input != nullptr); | |||
| zeromem (coefficients, sizeof (coefficients)); | |||
| @@ -51,9 +51,10 @@ void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected, double s | |||
| { | |||
| const SpinLock::ScopedLockType sl (ratioLock); | |||
| input->prepareToPlay (samplesPerBlockExpected, sampleRate); | |||
| const int scaledBlockSize = roundToInt (samplesPerBlockExpected * ratio); | |||
| input->prepareToPlay (scaledBlockSize, sampleRate * ratio); | |||
| buffer.setSize (numChannels, roundToInt (samplesPerBlockExpected * ratio) + 32); | |||
| buffer.setSize (numChannels, scaledBlockSize + 32); | |||
| filterStates.calloc ((size_t) numChannels); | |||
| srcBuffers.calloc ((size_t) numChannels); | |||
| @@ -93,7 +94,7 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf | |||
| lastRatio = localRatio; | |||
| } | |||
| const int sampsNeeded = roundToInt (info.numSamples * localRatio) + 2; | |||
| const int sampsNeeded = roundToInt (info.numSamples * localRatio) + 3; | |||
| int bufferSize = buffer.getNumSamples(); | |||
| @@ -138,8 +139,11 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf | |||
| } | |||
| int nextPos = (bufferPos + 1) % bufferSize; | |||
| for (int m = info.numSamples; --m >= 0;) | |||
| { | |||
| jassert (sampsInBuffer > 0 && nextPos != endOfBufferPos); | |||
| const float alpha = (float) subSampleOffset; | |||
| for (int channel = 0; channel < channelsToProcess; ++channel) | |||
| @@ -148,8 +152,6 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf | |||
| subSampleOffset += localRatio; | |||
| jassert (sampsInBuffer > 0); | |||
| while (subSampleOffset >= 1.0) | |||
| { | |||
| if (++bufferPos >= bufferSize) | |||
| @@ -29,6 +29,7 @@ SynthesiserSound::~SynthesiserSound() {} | |||
| SynthesiserVoice::SynthesiserVoice() | |||
| : currentSampleRate (44100.0), | |||
| currentlyPlayingNote (-1), | |||
| currentPlayingMidiChannel (0), | |||
| noteOnTime (0), | |||
| keyIsDown (false), | |||
| sostenutoPedalDown (false) | |||
| @@ -41,8 +42,7 @@ SynthesiserVoice::~SynthesiserVoice() | |||
| bool SynthesiserVoice::isPlayingChannel (const int midiChannel) const | |||
| { | |||
| return currentlyPlayingSound != nullptr | |||
| && currentlyPlayingSound->appliesToChannel (midiChannel); | |||
| return currentPlayingMidiChannel == midiChannel; | |||
| } | |||
| void SynthesiserVoice::setCurrentPlaybackSampleRate (const double newRate) | |||
| @@ -50,10 +50,16 @@ void SynthesiserVoice::setCurrentPlaybackSampleRate (const double newRate) | |||
| currentSampleRate = newRate; | |||
| } | |||
| bool SynthesiserVoice::isVoiceActive() const | |||
| { | |||
| return getCurrentlyPlayingNote() >= 0; | |||
| } | |||
| void SynthesiserVoice::clearCurrentNote() | |||
| { | |||
| currentlyPlayingNote = -1; | |||
| currentlyPlayingSound = nullptr; | |||
| currentPlayingMidiChannel = 0; | |||
| } | |||
| void SynthesiserVoice::aftertouchChanged (int) {} | |||
| @@ -253,14 +259,15 @@ void Synthesiser::startVoice (SynthesiserVoice* const voice, | |||
| if (voice->currentlyPlayingSound != nullptr) | |||
| voice->stopNote (0.0f, false); | |||
| voice->startNote (midiNoteNumber, velocity, sound, | |||
| lastPitchWheelValues [midiChannel - 1]); | |||
| voice->currentlyPlayingNote = midiNoteNumber; | |||
| voice->currentPlayingMidiChannel = midiChannel; | |||
| voice->noteOnTime = ++lastNoteOnCounter; | |||
| voice->currentlyPlayingSound = sound; | |||
| voice->keyIsDown = true; | |||
| voice->sostenutoPedalDown = false; | |||
| voice->startNote (midiNoteNumber, velocity, sound, | |||
| lastPitchWheelValues [midiChannel - 1]); | |||
| } | |||
| } | |||
| @@ -285,7 +292,8 @@ void Synthesiser::noteOff (const int midiChannel, | |||
| { | |||
| SynthesiserVoice* const voice = voices.getUnchecked (i); | |||
| if (voice->getCurrentlyPlayingNote() == midiNoteNumber) | |||
| if (voice->getCurrentlyPlayingNote() == midiNoteNumber | |||
| && voice->isPlayingChannel (midiChannel)) | |||
| { | |||
| if (SynthesiserSound* const sound = voice->getCurrentlyPlayingSound()) | |||
| { | |||
| @@ -426,7 +434,7 @@ SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay, | |||
| { | |||
| SynthesiserVoice* const voice = voices.getUnchecked (i); | |||
| if (voice->getCurrentlyPlayingNote() < 0 && voice->canPlaySound (soundToPlay)) | |||
| if ((! voice->isVoiceActive()) && voice->canPlaySound (soundToPlay)) | |||
| return voice; | |||
| } | |||
| @@ -440,7 +448,7 @@ struct VoiceAgeSorter | |||
| { | |||
| static int compareElements (SynthesiserVoice* v1, SynthesiserVoice* v2) noexcept | |||
| { | |||
| return v1->wasStartedBefore (*v2) ? 1 : (v2->wasStartedBefore (*v1) ? -1 : 0); | |||
| return v1->wasStartedBefore (*v2) ? -1 : (v2->wasStartedBefore (*v1) ? 1 : 0); | |||
| } | |||
| }; | |||
| @@ -473,10 +481,10 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay, | |||
| } | |||
| } | |||
| jassert (bottom != nullptr && top != nullptr); | |||
| const int stealableVoiceRange = usableVoices.size() - 6; | |||
| // The oldest note that's playing with the target pitch playing is ideal.. | |||
| for (int i = 0; i < usableVoices.size(); ++i) | |||
| for (int i = 0; i < stealableVoiceRange; ++i) | |||
| { | |||
| SynthesiserVoice* const voice = usableVoices.getUnchecked (i); | |||
| @@ -485,7 +493,7 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay, | |||
| } | |||
| // ..otherwise, look for the oldest note that isn't the top or bottom note.. | |||
| for (int i = 0; i < usableVoices.size(); ++i) | |||
| for (int i = 0; i < stealableVoiceRange; ++i) | |||
| { | |||
| SynthesiserVoice* const voice = usableVoices.getUnchecked (i); | |||
| @@ -493,6 +501,6 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay, | |||
| return voice; | |||
| } | |||
| // ..otherwise, there's only one or two voices to choose from - we'll return the top one.. | |||
| return top; | |||
| // ..otherwise, there's only one or two voices to choose from - we'll return the oldest one.. | |||
| return usableVoices.getFirst(); | |||
| } | |||
| @@ -140,6 +140,12 @@ public: | |||
| */ | |||
| virtual void stopNote (float velocity, bool allowTailOff) = 0; | |||
| /** Returns true if this voice is currently busy playing a sound. | |||
| By default this just checks the getCurrentlyPlayingNote() value, but can | |||
| be overridden for more advanced checking. | |||
| */ | |||
| virtual bool isVoiceActive() const; | |||
| /** Called to let the voice know that the pitch wheel has been moved. | |||
| This will be called during the rendering callback, so must be fast and thread-safe. | |||
| */ | |||
| @@ -185,17 +191,17 @@ public: | |||
| */ | |||
| virtual void setCurrentPlaybackSampleRate (double newRate); | |||
| /** Returns the current target sample rate at which rendering is being done. | |||
| Subclasses may need to know this so that they can pitch things correctly. | |||
| */ | |||
| double getSampleRate() const noexcept { return currentSampleRate; } | |||
| /** Returns true if the voice is currently playing a sound which is mapped to the given | |||
| midi channel. | |||
| If it's not currently playing, this will return false. | |||
| */ | |||
| bool isPlayingChannel (int midiChannel) const; | |||
| virtual bool isPlayingChannel (int midiChannel) const; | |||
| /** Returns the current target sample rate at which rendering is being done. | |||
| Subclasses may need to know this so that they can pitch things correctly. | |||
| */ | |||
| double getSampleRate() const noexcept { return currentSampleRate; } | |||
| /** Returns true if the key that triggered this voice is still held down. | |||
| Note that the voice may still be playing after the key was released (e.g because the | |||
| @@ -230,7 +236,7 @@ private: | |||
| friend class Synthesiser; | |||
| double currentSampleRate; | |||
| int currentlyPlayingNote; | |||
| int currentlyPlayingNote, currentPlayingMidiChannel; | |||
| uint32 noteOnTime; | |||
| SynthesiserSound::Ptr currentlyPlayingSound; | |||
| bool keyIsDown, sostenutoPedalDown; | |||
| @@ -92,7 +92,6 @@ AudioDeviceManager::AudioDeviceManager() | |||
| : numInputChansNeeded (0), | |||
| numOutputChansNeeded (2), | |||
| listNeedsScanning (true), | |||
| useInputNames (false), | |||
| inputLevel (0), | |||
| testSoundPosition (0), | |||
| cpuUsageMs (0), | |||
| @@ -154,7 +153,8 @@ static void addIfNotNull (OwnedArray<AudioIODeviceType>& list, AudioIODeviceType | |||
| void AudioDeviceManager::createAudioDeviceTypes (OwnedArray<AudioIODeviceType>& list) | |||
| { | |||
| addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI()); | |||
| addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (false)); | |||
| addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (true)); | |||
| addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_DirectSound()); | |||
| addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ASIO()); | |||
| addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_CoreAudio()); | |||
| @@ -177,6 +177,17 @@ void AudioDeviceManager::addAudioDeviceType (AudioIODeviceType* newDeviceType) | |||
| } | |||
| } | |||
| static bool deviceListContains (AudioIODeviceType* type, bool isInput, const String& name) | |||
| { | |||
| StringArray devices (type->getDeviceNames (isInput)); | |||
| for (int i = devices.size(); --i >= 0;) | |||
| if (devices[i].trim().equalsIgnoreCase (name.trim())) | |||
| return true; | |||
| return false; | |||
| } | |||
| //============================================================================== | |||
| String AudioDeviceManager::initialise (const int numInputChannelsNeeded, | |||
| const int numOutputChannelsNeeded, | |||
| @@ -363,8 +374,8 @@ AudioIODeviceType* AudioDeviceManager::findType (const String& inputName, const | |||
| { | |||
| AudioIODeviceType* const type = availableDeviceTypes.getUnchecked(i); | |||
| if ((inputName.isNotEmpty() && type->getDeviceNames (true).contains (inputName, true)) | |||
| || (outputName.isNotEmpty() && type->getDeviceNames (false).contains (outputName, true))) | |||
| if ((inputName.isNotEmpty() && deviceListContains (type, true, inputName)) | |||
| || (outputName.isNotEmpty() && deviceListContains (type, false, outputName))) | |||
| { | |||
| return type; | |||
| } | |||
| @@ -458,17 +469,11 @@ String AudioDeviceManager::setAudioDeviceSetup (const AudioDeviceSetup& newSetup | |||
| deleteCurrentDevice(); | |||
| scanDevicesIfNeeded(); | |||
| if (newOutputDeviceName.isNotEmpty() | |||
| && ! type->getDeviceNames (false).contains (newOutputDeviceName)) | |||
| { | |||
| if (newOutputDeviceName.isNotEmpty() && ! deviceListContains (type, false, newOutputDeviceName)) | |||
| return "No such device: " + newOutputDeviceName; | |||
| } | |||
| if (newInputDeviceName.isNotEmpty() | |||
| && ! type->getDeviceNames (true).contains (newInputDeviceName)) | |||
| { | |||
| if (newInputDeviceName.isNotEmpty() && ! deviceListContains (type, true, newInputDeviceName)) | |||
| return "No such device: " + newInputDeviceName; | |||
| } | |||
| currentAudioDevice = type->createDevice (newOutputDeviceName, newInputDeviceName); | |||
| @@ -450,7 +450,6 @@ private: | |||
| BigInteger inputChannels, outputChannels; | |||
| ScopedPointer<XmlElement> lastExplicitSettings; | |||
| mutable bool listNeedsScanning; | |||
| bool useInputNames; | |||
| Atomic<int> inputLevelMeasurementEnabledCount; | |||
| double inputLevel; | |||
| ScopedPointer<AudioSampleBuffer> testSound; | |||
| @@ -50,7 +50,7 @@ AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_iOSAudio() | |||
| #endif | |||
| #if ! (JUCE_WINDOWS && JUCE_WASAPI) | |||
| AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_WASAPI() { return nullptr; } | |||
| AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_WASAPI (bool) { return nullptr; } | |||
| #endif | |||
| #if ! (JUCE_WINDOWS && JUCE_DIRECTSOUND) | |||
| @@ -151,7 +151,7 @@ public: | |||
| /** Creates an iOS device type if it's available on this platform, or returns null. */ | |||
| static AudioIODeviceType* createAudioIODeviceType_iOSAudio(); | |||
| /** Creates a WASAPI device type if it's available on this platform, or returns null. */ | |||
| static AudioIODeviceType* createAudioIODeviceType_WASAPI(); | |||
| static AudioIODeviceType* createAudioIODeviceType_WASAPI (bool exclusiveMode); | |||
| /** Creates a DirectSound device type if it's available on this platform, or returns null. */ | |||
| static AudioIODeviceType* createAudioIODeviceType_DirectSound(); | |||
| /** Creates an ASIO device type if it's available on this platform, or returns null. */ | |||
| @@ -72,7 +72,7 @@ | |||
| This means that anyone who wants to use JUCE's ASIO abilities will have to: | |||
| 1) Agree to Steinberg's licensing terms and download the ASIO SDK | |||
| (see www.steinberg.net/Steinberg/Developers.asp). | |||
| (see http://www.steinberg.net/en/company/developers.html). | |||
| 2) Enable this code with a global definition #define JUCE_ASIO 1. | |||
| @@ -43,12 +43,21 @@ | |||
| #endif | |||
| /** Config: JUCE_WASAPI | |||
| Enables WASAPI audio devices (Windows Vista and above). | |||
| Enables WASAPI audio devices (Windows Vista and above). See also the | |||
| JUCE_WASAPI_EXCLUSIVE flag. | |||
| */ | |||
| #ifndef JUCE_WASAPI | |||
| #define JUCE_WASAPI 1 | |||
| #endif | |||
| /** Config: JUCE_WASAPI_EXCLUSIVE | |||
| Enables WASAPI audio devices in exclusive mode (Windows Vista and above). | |||
| */ | |||
| #ifndef JUCE_WASAPI_EXCLUSIVE | |||
| #define JUCE_WASAPI_EXCLUSIVE 0 | |||
| #endif | |||
| /** Config: JUCE_DIRECTSOUND | |||
| Enables DirectSound audio (MS Windows only). | |||
| */ | |||
| @@ -139,7 +139,7 @@ public: | |||
| //============================================================================== | |||
| /** Destructor. */ | |||
| virtual ~MidiInput(); | |||
| ~MidiInput(); | |||
| /** Returns the name of this device. */ | |||
| const String& getName() const noexcept { return name; } | |||
| @@ -158,23 +158,21 @@ public: | |||
| @see stop | |||
| */ | |||
| virtual void start(); | |||
| void start(); | |||
| /** Stops the device running. | |||
| @see start | |||
| */ | |||
| virtual void stop(); | |||
| void stop(); | |||
| protected: | |||
| private: | |||
| //============================================================================== | |||
| String name; | |||
| void* internal; | |||
| explicit MidiInput (const String& name); | |||
| // The input objects are created with the openDevice() method. | |||
| explicit MidiInput (const String&); | |||
| private: | |||
| //============================================================================== | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiInput) | |||
| }; | |||
| @@ -82,13 +82,12 @@ public: | |||
| //============================================================================== | |||
| /** Destructor. */ | |||
| virtual ~MidiOutput(); | |||
| ~MidiOutput(); | |||
| /** Makes this device output a midi message. | |||
| @see MidiMessage | |||
| */ | |||
| virtual void sendMessageNow (const MidiMessage& message); | |||
| void sendMessageNow (const MidiMessage& message); | |||
| //============================================================================== | |||
| /** This lets you supply a block of messages that will be sent out at some point | |||
| @@ -100,7 +99,7 @@ public: | |||
| This will only work if you've already started the thread with startBackgroundThread(). | |||
| A time is supplied, at which the block of messages should be sent. This time uses | |||
| A time is specified, at which the block of messages should be sent. This time uses | |||
| the same time base as Time::getMillisecondCounter(), and must be in the future. | |||
| The samplesPerSecondForBuffer parameter indicates the number of samples per second | |||
| @@ -108,38 +107,34 @@ public: | |||
| samplesPerSecondForBuffer value is needed to convert this sample position to a | |||
| real time. | |||
| */ | |||
| virtual void sendBlockOfMessages (const MidiBuffer& buffer, | |||
| double millisecondCounterToStartAt, | |||
| double samplesPerSecondForBuffer); | |||
| void sendBlockOfMessages (const MidiBuffer& buffer, | |||
| double millisecondCounterToStartAt, | |||
| double samplesPerSecondForBuffer); | |||
| /** Gets rid of any midi messages that had been added by sendBlockOfMessages(). | |||
| */ | |||
| virtual void clearAllPendingMessages(); | |||
| /** Gets rid of any midi messages that had been added by sendBlockOfMessages(). */ | |||
| void clearAllPendingMessages(); | |||
| /** Starts up a background thread so that the device can send blocks of data. | |||
| Call this to get the device ready, before using sendBlockOfMessages(). | |||
| */ | |||
| virtual void startBackgroundThread(); | |||
| void startBackgroundThread(); | |||
| /** Stops the background thread, and clears any pending midi events. | |||
| @see startBackgroundThread | |||
| */ | |||
| virtual void stopBackgroundThread(); | |||
| void stopBackgroundThread(); | |||
| protected: | |||
| private: | |||
| //============================================================================== | |||
| void* internal; | |||
| CriticalSection lock; | |||
| struct PendingMessage; | |||
| PendingMessage* firstMessage; | |||
| MidiOutput(); | |||
| MidiOutput(); // These objects are created with the openDevice() method. | |||
| void run() override; | |||
| private: | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiOutput) | |||
| }; | |||
| @@ -47,13 +47,13 @@ public: | |||
| // this is a total guess about how to calculate the latency, but seems to vaguely agree | |||
| // with the devices I've tested.. YMMV | |||
| inputLatency = ((javaDevice.minBufferSizeIn * 2) / 3); | |||
| outputLatency = ((javaDevice.minBufferSizeOut * 2) / 3); | |||
| inputLatency = (javaDevice.minBufferSizeIn * 2) / 3; | |||
| outputLatency = (javaDevice.minBufferSizeOut * 2) / 3; | |||
| const int longestLatency = jmax (inputLatency, outputLatency); | |||
| const int totalLatency = inputLatency + outputLatency; | |||
| inputLatency = ((longestLatency * inputLatency) / totalLatency) & ~15; | |||
| outputLatency = ((longestLatency * outputLatency) / totalLatency) & ~15; | |||
| const int64 longestLatency = jmax (inputLatency, outputLatency); | |||
| const int64 totalLatency = inputLatency + outputLatency; | |||
| inputLatency = (int) ((longestLatency * inputLatency) / totalLatency) & ~15; | |||
| outputLatency = (int) ((longestLatency * outputLatency) / totalLatency) & ~15; | |||
| } | |||
| ~OpenSLAudioIODevice() | |||
| @@ -30,7 +30,7 @@ namespace | |||
| #endif | |||
| #if JUCE_ALSA_LOGGING | |||
| #define JUCE_ALSA_LOG(dbgtext) { juce::String tempDbgBuf ("ALSA: "); tempDbgBuf << dbgtext; Logger::writeToLog (tempDbgBuf); DBG (tempDbgBuf) } | |||
| #define JUCE_ALSA_LOG(dbgtext) { juce::String tempDbgBuf ("ALSA: "); tempDbgBuf << dbgtext; Logger::writeToLog (tempDbgBuf); DBG (tempDbgBuf); } | |||
| #define JUCE_CHECKED_RESULT(x) (logErrorMessage (x, __LINE__)) | |||
| static int logErrorMessage (int err, int lineNum) | |||
| @@ -149,7 +149,7 @@ class ALSADevice | |||
| { | |||
| public: | |||
| ALSADevice (const String& devID, bool forInput) | |||
| : handle (0), | |||
| : handle (nullptr), | |||
| bitDepth (16), | |||
| numChannelsRunning (0), | |||
| latency (0), | |||
| @@ -183,16 +183,16 @@ public: | |||
| void closeNow() | |||
| { | |||
| if (handle != 0) | |||
| if (handle != nullptr) | |||
| { | |||
| snd_pcm_close (handle); | |||
| handle = 0; | |||
| handle = nullptr; | |||
| } | |||
| } | |||
| bool setParameters (unsigned int sampleRate, int numChannels, int bufferSize) | |||
| { | |||
| if (handle == 0) | |||
| if (handle == nullptr) | |||
| return false; | |||
| JUCE_ALSA_LOG ("ALSADevice::setParameters(" << deviceID << ", " | |||
| @@ -644,8 +644,21 @@ public: | |||
| { | |||
| while (! threadShouldExit()) | |||
| { | |||
| if (inputDevice != nullptr && inputDevice->handle) | |||
| if (inputDevice != nullptr && inputDevice->handle != nullptr) | |||
| { | |||
| if (outputDevice == nullptr || outputDevice->handle == nullptr) | |||
| { | |||
| JUCE_ALSA_FAILED (snd_pcm_wait (inputDevice->handle, 2000)); | |||
| if (threadShouldExit()) | |||
| break; | |||
| snd_pcm_sframes_t avail = snd_pcm_avail_update (inputDevice->handle); | |||
| if (avail < 0) | |||
| JUCE_ALSA_FAILED (snd_pcm_recover (inputDevice->handle, avail, 0)); | |||
| } | |||
| audioIoInProgress = true; | |||
| if (! inputDevice->readFromInputDevice (inputChannelBuffer, bufferSize)) | |||
| @@ -679,7 +692,7 @@ public: | |||
| } | |||
| } | |||
| if (outputDevice != nullptr && outputDevice->handle) | |||
| if (outputDevice != nullptr && outputDevice->handle != nullptr) | |||
| { | |||
| JUCE_ALSA_FAILED (snd_pcm_wait (outputDevice->handle, 2000)); | |||
| @@ -702,6 +715,7 @@ public: | |||
| audioIoInProgress = false; | |||
| } | |||
| } | |||
| audioIoInProgress = false; | |||
| } | |||
| @@ -419,7 +419,7 @@ public: | |||
| port.deletePort(); | |||
| } | |||
| void sendMessageNow (const MidiMessage& message) | |||
| bool sendMessageNow (const MidiMessage& message) | |||
| { | |||
| if (message.getRawDataSize() > maxEventSize) | |||
| { | |||
| @@ -435,12 +435,17 @@ public: | |||
| const uint8* data = message.getRawData(); | |||
| snd_seq_t* seqHandle = port.client->get(); | |||
| bool success = true; | |||
| while (numBytes > 0) | |||
| { | |||
| const long numSent = snd_midi_event_encode (midiParser, data, numBytes, &event); | |||
| if (numSent <= 0) | |||
| { | |||
| success = numSent == 0; | |||
| break; | |||
| } | |||
| numBytes -= numSent; | |||
| data += numSent; | |||
| @@ -449,11 +454,15 @@ public: | |||
| snd_seq_ev_set_subs (&event); | |||
| snd_seq_ev_set_direct (&event); | |||
| snd_seq_event_output (seqHandle, &event); | |||
| if (snd_seq_event_output_direct (seqHandle, &event) < 0) | |||
| { | |||
| success = false; | |||
| break; | |||
| } | |||
| } | |||
| snd_seq_drain_output (seqHandle); | |||
| snd_midi_event_reset_encode (midiParser); | |||
| return success; | |||
| } | |||
| private: | |||
| @@ -543,7 +543,7 @@ public: | |||
| // set sample rate | |||
| AudioObjectPropertyAddress pa; | |||
| pa.mSelector = kAudioDevicePropertyNominalSampleRate; | |||
| pa.mScope = kAudioObjectPropertyScopeWildcard; | |||
| pa.mScope = kAudioObjectPropertyScopeGlobal; | |||
| pa.mElement = kAudioObjectPropertyElementMaster; | |||
| Float64 sr = newSampleRate; | |||
| @@ -123,9 +123,9 @@ struct ASIOSampleFormat | |||
| { | |||
| switch (bitDepth) | |||
| { | |||
| case 16: convertInt16ToFloat (static_cast <const char*> (src), dst, byteStride, samps, littleEndian); break; | |||
| case 24: convertInt24ToFloat (static_cast <const char*> (src), dst, byteStride, samps, littleEndian); break; | |||
| case 32: convertInt32ToFloat (static_cast <const char*> (src), dst, byteStride, samps, littleEndian); break; | |||
| case 16: convertInt16ToFloat (static_cast<const char*> (src), dst, byteStride, samps, littleEndian); break; | |||
| case 24: convertInt24ToFloat (static_cast<const char*> (src), dst, byteStride, samps, littleEndian); break; | |||
| case 32: convertInt32ToFloat (static_cast<const char*> (src), dst, byteStride, samps, littleEndian); break; | |||
| default: jassertfalse; break; | |||
| } | |||
| } | |||
| @@ -141,9 +141,9 @@ struct ASIOSampleFormat | |||
| { | |||
| switch (bitDepth) | |||
| { | |||
| case 16: convertFloatToInt16 (src, static_cast <char*> (dst), byteStride, samps, littleEndian); break; | |||
| case 24: convertFloatToInt24 (src, static_cast <char*> (dst), byteStride, samps, littleEndian); break; | |||
| case 32: convertFloatToInt32 (src, static_cast <char*> (dst), byteStride, samps, littleEndian); break; | |||
| case 16: convertFloatToInt16 (src, static_cast<char*> (dst), byteStride, samps, littleEndian); break; | |||
| case 24: convertFloatToInt24 (src, static_cast<char*> (dst), byteStride, samps, littleEndian); break; | |||
| case 32: convertFloatToInt32 (src, static_cast<char*> (dst), byteStride, samps, littleEndian); break; | |||
| default: jassertfalse; break; | |||
| } | |||
| } | |||
| @@ -300,7 +300,7 @@ private: | |||
| //============================================================================== | |||
| class ASIOAudioIODevice; | |||
| static ASIOAudioIODevice* volatile currentASIODev[3] = { 0 }; | |||
| static ASIOAudioIODevice* volatile currentASIODev[16] = { 0 }; | |||
| extern HWND juce_messageWindowHandle; | |||
| @@ -438,8 +438,6 @@ public: | |||
| currentBlockSizeSamples = bufferSizeSamples; | |||
| currentChansOut.clear(); | |||
| currentChansIn.clear(); | |||
| inBuffers.clear (totalNumInputChans + 1); | |||
| outBuffers.clear (totalNumOutputChans + 1); | |||
| updateSampleRates(); | |||
| @@ -458,6 +456,13 @@ public: | |||
| setSampleRate (sampleRate); | |||
| // (need to get this again in case a sample rate change affected the channel count) | |||
| err = asioObject->getChannels (&totalNumInputChans, &totalNumOutputChans); | |||
| jassert (err == ASE_OK); | |||
| inBuffers.calloc (totalNumInputChans + 8); | |||
| outBuffers.calloc (totalNumOutputChans + 8); | |||
| if (needToReset) | |||
| { | |||
| JUCE_ASIO_LOG (" Resetting"); | |||
| @@ -1320,7 +1325,7 @@ private: | |||
| inputFormat[i].convertToFloat (infos[i].buffers[bi], inBuffers[i], samps); | |||
| } | |||
| currentCallback->audioDeviceIOCallback (const_cast <const float**> (inBuffers.getData()), numActiveInputChans, | |||
| currentCallback->audioDeviceIOCallback (const_cast<const float**> (inBuffers.getData()), numActiveInputChans, | |||
| outBuffers, numActiveOutputChans, samps); | |||
| for (int i = 0; i < numActiveOutputChans; ++i) | |||
| @@ -1340,6 +1345,29 @@ private: | |||
| asioObject->outputReady(); | |||
| } | |||
| long asioMessagesCallback (long selector, long value) | |||
| { | |||
| switch (selector) | |||
| { | |||
| case kAsioSelectorSupported: | |||
| if (value == kAsioResetRequest || value == kAsioEngineVersion || value == kAsioResyncRequest | |||
| || value == kAsioLatenciesChanged || value == kAsioSupportsInputMonitor) | |||
| return 1; | |||
| break; | |||
| case kAsioBufferSizeChange: JUCE_ASIO_LOG ("kAsioBufferSizeChange"); resetRequest(); return 1; | |||
| case kAsioResetRequest: JUCE_ASIO_LOG ("kAsioResetRequest"); resetRequest(); return 1; | |||
| case kAsioResyncRequest: JUCE_ASIO_LOG ("kAsioResyncRequest"); resetRequest(); return 1; | |||
| case kAsioLatenciesChanged: JUCE_ASIO_LOG ("kAsioLatenciesChanged"); return 1; | |||
| case kAsioEngineVersion: return 2; | |||
| case kAsioSupportsTimeInfo: | |||
| case kAsioSupportsTimeCode: return 0; | |||
| } | |||
| return 0; | |||
| } | |||
| //============================================================================== | |||
| template <int deviceIndex> | |||
| struct ASIOCallbackFunctions | |||
| @@ -1360,56 +1388,43 @@ private: | |||
| static long JUCE_ASIOCALLBACK asioMessagesCallback (long selector, long value, void*, double*) | |||
| { | |||
| switch (selector) | |||
| { | |||
| case kAsioSelectorSupported: | |||
| if (value == kAsioResetRequest || value == kAsioEngineVersion || value == kAsioResyncRequest | |||
| || value == kAsioLatenciesChanged || value == kAsioSupportsInputMonitor) | |||
| return 1; | |||
| break; | |||
| case kAsioBufferSizeChange: JUCE_ASIO_LOG ("kAsioBufferSizeChange"); return sendResetRequest (deviceIndex); | |||
| case kAsioResetRequest: JUCE_ASIO_LOG ("kAsioResetRequest"); return sendResetRequest (deviceIndex); | |||
| case kAsioResyncRequest: JUCE_ASIO_LOG ("kAsioResyncRequest"); return sendResetRequest (deviceIndex); | |||
| case kAsioLatenciesChanged: JUCE_ASIO_LOG ("kAsioLatenciesChanged"); return 1; | |||
| case kAsioEngineVersion: return 2; | |||
| case kAsioSupportsTimeInfo: | |||
| case kAsioSupportsTimeCode: | |||
| return 0; | |||
| } | |||
| return 0; | |||
| return currentASIODev[deviceIndex] != nullptr | |||
| ? currentASIODev[deviceIndex]->asioMessagesCallback (selector, value) | |||
| : 0; | |||
| } | |||
| static void JUCE_ASIOCALLBACK sampleRateChangedCallback (ASIOSampleRate) | |||
| { | |||
| sendResetRequest (deviceIndex); | |||
| if (currentASIODev[deviceIndex] != nullptr) | |||
| currentASIODev[deviceIndex]->resetRequest(); | |||
| } | |||
| static long sendResetRequest (int index) | |||
| static void setCallbacks (ASIOCallbacks& callbacks) noexcept | |||
| { | |||
| if (currentASIODev[index] != nullptr) | |||
| currentASIODev[index]->resetRequest(); | |||
| return 1; | |||
| callbacks.bufferSwitch = &bufferSwitchCallback; | |||
| callbacks.asioMessage = &asioMessagesCallback; | |||
| callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback; | |||
| callbacks.sampleRateDidChange = &sampleRateChangedCallback; | |||
| } | |||
| static void setCallbacks (ASIOCallbacks& callbacks) | |||
| static void setCallbacksForDevice (ASIOCallbacks& callbacks, ASIOAudioIODevice* device) noexcept | |||
| { | |||
| callbacks.bufferSwitch = &bufferSwitchCallback; | |||
| callbacks.asioMessage = &asioMessagesCallback; | |||
| callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback; | |||
| callbacks.sampleRateDidChange = &sampleRateChangedCallback; | |||
| if (currentASIODev[deviceIndex] == device) | |||
| setCallbacks (callbacks); | |||
| else | |||
| ASIOCallbackFunctions<deviceIndex + 1>::setCallbacksForDevice (callbacks, device); | |||
| } | |||
| }; | |||
| void setCallbackFunctions() | |||
| template <> | |||
| struct ASIOCallbackFunctions <sizeof(currentASIODev) / sizeof(currentASIODev[0])> | |||
| { | |||
| static void setCallbacksForDevice (ASIOCallbacks&, ASIOAudioIODevice*) noexcept {} | |||
| }; | |||
| void setCallbackFunctions() noexcept | |||
| { | |||
| if (currentASIODev[0] == this) ASIOCallbackFunctions<0>::setCallbacks (callbacks); | |||
| else if (currentASIODev[1] == this) ASIOCallbackFunctions<1>::setCallbacks (callbacks); | |||
| else if (currentASIODev[2] == this) ASIOCallbackFunctions<2>::setCallbacks (callbacks); | |||
| else jassertfalse; | |||
| ASIOCallbackFunctions<0>::setCallbacksForDevice (callbacks, this); | |||
| } | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ASIOAudioIODevice) | |||
| @@ -1503,15 +1518,16 @@ public: | |||
| jassert (inputDeviceName == outputDeviceName || outputDeviceName.isEmpty() || inputDeviceName.isEmpty()); | |||
| jassert (hasScanned); // need to call scanForDevices() before doing this | |||
| const int index = deviceNames.indexOf (outputDeviceName.isNotEmpty() ? outputDeviceName | |||
| : inputDeviceName); | |||
| const String deviceName (outputDeviceName.isNotEmpty() ? outputDeviceName | |||
| : inputDeviceName); | |||
| const int index = deviceNames.indexOf (deviceName); | |||
| if (index >= 0) | |||
| { | |||
| const int freeSlot = findFreeSlot(); | |||
| if (freeSlot >= 0) | |||
| return new ASIOAudioIODevice (this, outputDeviceName, | |||
| return new ASIOAudioIODevice (this, deviceName, | |||
| classIds.getReference (index), freeSlot); | |||
| } | |||
| @@ -1255,7 +1255,7 @@ private: | |||
| DSoundDeviceList deviceList; | |||
| bool hasScanned; | |||
| void systemDeviceChanged() | |||
| void systemDeviceChanged() override | |||
| { | |||
| DSoundDeviceList newList; | |||
| newList.scan(); | |||
| @@ -45,6 +45,7 @@ void logFailure (HRESULT hr) | |||
| { | |||
| case E_POINTER: m = "E_POINTER"; break; | |||
| case E_INVALIDARG: m = "E_INVALIDARG"; break; | |||
| case E_NOINTERFACE: m = "E_NOINTERFACE"; break; | |||
| #define JUCE_WASAPI_ERR(desc, n) \ | |||
| case MAKE_HRESULT(1, 0x889, n): m = #desc; break; | |||
| @@ -126,7 +127,11 @@ enum EDataFlow | |||
| eAll = (eCapture + 1) | |||
| }; | |||
| enum { DEVICE_STATE_ACTIVE = 1 }; | |||
| enum | |||
| { | |||
| DEVICE_STATE_ACTIVE = 1, | |||
| AUDCLNT_BUFFERFLAGS_SILENT = 2 | |||
| }; | |||
| JUCE_IUNKNOWNCLASS (IPropertyStore, "886d8eeb-8cf2-4446-8d02-cdba1dbdcf99") | |||
| { | |||
| @@ -328,6 +333,11 @@ int refTimeToSamples (const REFERENCE_TIME& t, const double sampleRate) noexcept | |||
| return roundToInt (sampleRate * ((double) t) * 0.0000001); | |||
| } | |||
| REFERENCE_TIME samplesToRefTime (const int numSamples, const double sampleRate) noexcept | |||
| { | |||
| return (REFERENCE_TIME) ((numSamples * 10000.0 * 1000.0 / sampleRate) + 0.5); | |||
| } | |||
| void copyWavFormat (WAVEFORMATEXTENSIBLE& dest, const WAVEFORMATEX* const src) noexcept | |||
| { | |||
| memcpy (&dest, src, src->wFormatTag == WAVE_FORMAT_EXTENSIBLE ? sizeof (WAVEFORMATEXTENSIBLE) | |||
| @@ -348,9 +358,12 @@ public: | |||
| defaultBufferSize (0), | |||
| latencySamples (0), | |||
| useExclusiveMode (exclusiveMode), | |||
| actualBufferSize (0), | |||
| bytesPerSample (0), | |||
| bytesPerFrame (0), | |||
| sampleRateHasChanged (false) | |||
| { | |||
| clientEvent = CreateEvent (0, false, false, _T("JuceWASAPI")); | |||
| clientEvent = CreateEvent (nullptr, false, false, nullptr); | |||
| ComSmartPtr<IAudioClient> tempClient (createClient()); | |||
| if (tempClient == nullptr) | |||
| @@ -376,16 +389,24 @@ public: | |||
| rates.addUsingDefaultSort (defaultSampleRate); | |||
| static const int ratesToTest[] = { 44100, 48000, 88200, 96000, 176400, 192000 }; | |||
| if (useExclusiveMode | |||
| && findSupportedFormat (tempClient, defaultSampleRate, format.dwChannelMask, format)) | |||
| { | |||
| // Got a format that is supported by the device so we can ask what sample rates are supported (in whatever format) | |||
| } | |||
| static const int ratesToTest[] = { 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000 }; | |||
| for (int i = 0; i < numElementsInArray (ratesToTest); ++i) | |||
| { | |||
| if (ratesToTest[i] == defaultSampleRate) | |||
| if (rates.contains (ratesToTest[i])) | |||
| continue; | |||
| format.Format.nSamplesPerSec = (DWORD) ratesToTest[i]; | |||
| format.Format.nSamplesPerSec = (DWORD) ratesToTest[i]; | |||
| format.Format.nAvgBytesPerSec = (DWORD) (format.Format.nSamplesPerSec * format.Format.nChannels * format.Format.wBitsPerSample / 8); | |||
| if (SUCCEEDED (tempClient->IsFormatSupported (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED, | |||
| if (SUCCEEDED (tempClient->IsFormatSupported (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE | |||
| : AUDCLNT_SHAREMODE_SHARED, | |||
| (WAVEFORMATEX*) &format, 0))) | |||
| if (! rates.contains (ratesToTest[i])) | |||
| rates.addUsingDefaultSort (ratesToTest[i]); | |||
| @@ -400,7 +421,7 @@ public: | |||
| bool isOk() const noexcept { return defaultBufferSize > 0 && defaultSampleRate > 0; } | |||
| bool openClient (const double newSampleRate, const BigInteger& newChannels) | |||
| bool openClient (const double newSampleRate, const BigInteger& newChannels, const int bufferSizeSamples) | |||
| { | |||
| sampleRate = newSampleRate; | |||
| channels = newChannels; | |||
| @@ -413,8 +434,7 @@ public: | |||
| client = createClient(); | |||
| if (client != nullptr | |||
| && (tryInitialisingWithFormat (true, 4) || tryInitialisingWithFormat (false, 4) | |||
| || tryInitialisingWithFormat (false, 3) || tryInitialisingWithFormat (false, 2))) | |||
| && tryInitialisingWithBufferSize (bufferSizeSamples)) | |||
| { | |||
| sampleRateHasChanged = false; | |||
| @@ -465,7 +485,7 @@ public: | |||
| BigInteger channels; | |||
| Array<int> channelMaps; | |||
| UINT32 actualBufferSize; | |||
| int bytesPerSample; | |||
| int bytesPerSample, bytesPerFrame; | |||
| bool sampleRateHasChanged; | |||
| virtual void updateFormat (bool isFloat) = 0; | |||
| @@ -536,12 +556,19 @@ private: | |||
| return client; | |||
| } | |||
| bool tryInitialisingWithFormat (const bool useFloat, const int bytesPerSampleToTry) | |||
| struct AudioSampleFormat | |||
| { | |||
| bool useFloat; | |||
| int bitsPerSampleToTry; | |||
| int bytesPerSampleContainer; | |||
| }; | |||
| bool tryFormat (const AudioSampleFormat sampleFormat, IAudioClient* clientToUse, double sampleRate, | |||
| DWORD mixFormatChannelMask, WAVEFORMATEXTENSIBLE& format) const | |||
| { | |||
| WAVEFORMATEXTENSIBLE format; | |||
| zerostruct (format); | |||
| if (numChannels <= 2 && bytesPerSampleToTry <= 2) | |||
| if (numChannels <= 2 && sampleFormat.bitsPerSampleToTry <= 16) | |||
| { | |||
| format.Format.wFormatTag = WAVE_FORMAT_PCM; | |||
| } | |||
| @@ -553,45 +580,97 @@ private: | |||
| format.Format.nSamplesPerSec = (DWORD) sampleRate; | |||
| format.Format.nChannels = (WORD) numChannels; | |||
| format.Format.wBitsPerSample = (WORD) (8 * bytesPerSampleToTry); | |||
| format.Format.nAvgBytesPerSec = (DWORD) (format.Format.nSamplesPerSec * numChannels * bytesPerSampleToTry); | |||
| format.Format.nBlockAlign = (WORD) (numChannels * bytesPerSampleToTry); | |||
| format.SubFormat = useFloat ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : KSDATAFORMAT_SUBTYPE_PCM; | |||
| format.Samples.wValidBitsPerSample = format.Format.wBitsPerSample; | |||
| format.Format.wBitsPerSample = (WORD) (8 * sampleFormat.bytesPerSampleContainer); | |||
| format.Samples.wValidBitsPerSample = (WORD) (sampleFormat.bitsPerSampleToTry); | |||
| format.Format.nBlockAlign = (WORD) (format.Format.nChannels * format.Format.wBitsPerSample / 8); | |||
| format.Format.nAvgBytesPerSec = (DWORD) (format.Format.nSamplesPerSec * format.Format.nBlockAlign); | |||
| format.SubFormat = sampleFormat.useFloat ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : KSDATAFORMAT_SUBTYPE_PCM; | |||
| format.dwChannelMask = mixFormatChannelMask; | |||
| WAVEFORMATEXTENSIBLE* nearestFormat = nullptr; | |||
| HRESULT hr = client->IsFormatSupported (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE | |||
| : AUDCLNT_SHAREMODE_SHARED, | |||
| (WAVEFORMATEX*) &format, | |||
| useExclusiveMode ? nullptr : (WAVEFORMATEX**) &nearestFormat); | |||
| HRESULT hr = clientToUse->IsFormatSupported (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE | |||
| : AUDCLNT_SHAREMODE_SHARED, | |||
| (WAVEFORMATEX*) &format, | |||
| useExclusiveMode ? nullptr : (WAVEFORMATEX**) &nearestFormat); | |||
| logFailure (hr); | |||
| if (hr == S_FALSE && format.Format.nSamplesPerSec == nearestFormat->Format.nSamplesPerSec) | |||
| { | |||
| copyWavFormat (format, (WAVEFORMATEX*) nearestFormat); | |||
| copyWavFormat (format, (const WAVEFORMATEX*) nearestFormat); | |||
| hr = S_OK; | |||
| } | |||
| CoTaskMemFree (nearestFormat); | |||
| return check (hr); | |||
| } | |||
| REFERENCE_TIME defaultPeriod = 0, minPeriod = 0; | |||
| if (useExclusiveMode) | |||
| check (client->GetDevicePeriod (&defaultPeriod, &minPeriod)); | |||
| bool findSupportedFormat (IAudioClient* clientToUse, double sampleRate, | |||
| DWORD mixFormatChannelMask, WAVEFORMATEXTENSIBLE& format) const | |||
| { | |||
| static const AudioSampleFormat formats[] = | |||
| { | |||
| { true, 32, 4 }, | |||
| { false, 32, 4 }, | |||
| { false, 24, 4 }, | |||
| { false, 24, 3 }, | |||
| { false, 20, 4 }, | |||
| { false, 20, 3 }, | |||
| { false, 16, 2 } | |||
| }; | |||
| for (int i = 0; i < numElementsInArray (formats); ++i) | |||
| if (tryFormat (formats[i], clientToUse, sampleRate, mixFormatChannelMask, format)) | |||
| return true; | |||
| return false; | |||
| } | |||
| GUID session; | |||
| if (hr == S_OK | |||
| && check (client->Initialize (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED, | |||
| 0x40000 /*AUDCLNT_STREAMFLAGS_EVENTCALLBACK*/, | |||
| defaultPeriod, defaultPeriod, (WAVEFORMATEX*) &format, &session))) | |||
| bool tryInitialisingWithBufferSize (const int bufferSizeSamples) | |||
| { | |||
| WAVEFORMATEXTENSIBLE format; | |||
| if (findSupportedFormat (client, sampleRate, mixFormatChannelMask, format)) | |||
| { | |||
| actualNumChannels = format.Format.nChannels; | |||
| const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; | |||
| bytesPerSample = format.Format.wBitsPerSample / 8; | |||
| REFERENCE_TIME defaultPeriod = 0, minPeriod = 0; | |||
| updateFormat (isFloat); | |||
| return true; | |||
| check (client->GetDevicePeriod (&defaultPeriod, &minPeriod)); | |||
| if (useExclusiveMode && bufferSizeSamples > 0) | |||
| defaultPeriod = jmax (minPeriod, samplesToRefTime (bufferSizeSamples, format.Format.nSamplesPerSec)); | |||
| for (;;) | |||
| { | |||
| GUID session; | |||
| HRESULT hr = client->Initialize (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED, | |||
| 0x40000 /*AUDCLNT_STREAMFLAGS_EVENTCALLBACK*/, | |||
| defaultPeriod, useExclusiveMode ? defaultPeriod : 0, (WAVEFORMATEX*) &format, &session); | |||
| if (check (hr)) | |||
| { | |||
| actualNumChannels = format.Format.nChannels; | |||
| const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; | |||
| bytesPerSample = format.Format.wBitsPerSample / 8; | |||
| bytesPerFrame = format.Format.nBlockAlign; | |||
| updateFormat (isFloat); | |||
| return true; | |||
| } | |||
| // Handle the "alignment dance" : http://msdn.microsoft.com/en-us/library/windows/desktop/dd370875(v=vs.85).aspx (see Remarks) | |||
| if (hr != MAKE_HRESULT (1, 0x889, 0x19)) // AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED | |||
| break; | |||
| UINT32 numFrames = 0; | |||
| if (! check (client->GetBufferSize (&numFrames))) | |||
| break; | |||
| // Recreate client | |||
| client = nullptr; | |||
| client = createClient(); | |||
| defaultPeriod = samplesToRefTime (numFrames, format.Format.nSamplesPerSec); | |||
| } | |||
| } | |||
| return false; | |||
| @@ -615,12 +694,9 @@ public: | |||
| close(); | |||
| } | |||
| bool open (const double newSampleRate, const BigInteger& newChannels) | |||
| bool open (const double newSampleRate, const BigInteger& newChannels, int bufferSizeSamples) | |||
| { | |||
| reservoirSize = 0; | |||
| reservoirCapacity = 16384; | |||
| reservoir.setSize (actualNumChannels * reservoirCapacity * sizeof (float)); | |||
| return openClient (newSampleRate, newChannels) | |||
| return openClient (newSampleRate, newChannels, bufferSizeSamples) | |||
| && (numChannels == 0 || check (client->GetService (__uuidof (IAudioCaptureClient), | |||
| (void**) captureClient.resetAndGetPointerAddress()))); | |||
| } | |||
| @@ -630,88 +706,129 @@ public: | |||
| closeClient(); | |||
| captureClient = nullptr; | |||
| reservoir.reset(); | |||
| reservoirReadPos = reservoirWritePos = 0; | |||
| } | |||
| template<class SourceType> | |||
| void updateFormatWithType (SourceType*) | |||
| void updateFormatWithType (SourceType*) noexcept | |||
| { | |||
| typedef AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> NativeType; | |||
| converter = new AudioData::ConverterInstance<AudioData::Pointer<SourceType, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1); | |||
| } | |||
| void updateFormat (bool isFloat) | |||
| void updateFormat (bool isFloat) override | |||
| { | |||
| if (isFloat) updateFormatWithType ((AudioData::Float32*) nullptr); | |||
| else if (bytesPerSample == 4) updateFormatWithType ((AudioData::Int32*) nullptr); | |||
| else if (bytesPerSample == 3) updateFormatWithType ((AudioData::Int24*) nullptr); | |||
| else updateFormatWithType ((AudioData::Int16*) nullptr); | |||
| } | |||
| bool start (const int userBufferSize) | |||
| { | |||
| reservoirSize = actualBufferSize + userBufferSize; | |||
| reservoirMask = nextPowerOfTwo (reservoirSize) - 1; | |||
| reservoir.setSize ((reservoirMask + 1) * bytesPerFrame, true); | |||
| reservoirReadPos = reservoirWritePos = 0; | |||
| if (! check (client->Start())) | |||
| return false; | |||
| purgeInputBuffers(); | |||
| return true; | |||
| } | |||
| void purgeInputBuffers() | |||
| { | |||
| if (isFloat) updateFormatWithType ((AudioData::Float32*) 0); | |||
| else if (bytesPerSample == 4) updateFormatWithType ((AudioData::Int32*) 0); | |||
| else if (bytesPerSample == 3) updateFormatWithType ((AudioData::Int24*) 0); | |||
| else updateFormatWithType ((AudioData::Int16*) 0); | |||
| uint8* inputData; | |||
| UINT32 numSamplesAvailable; | |||
| DWORD flags; | |||
| while (captureClient->GetBuffer (&inputData, &numSamplesAvailable, &flags, nullptr, nullptr) | |||
| != MAKE_HRESULT (0, 0x889, 0x1) /* AUDCLNT_S_BUFFER_EMPTY */) | |||
| captureClient->ReleaseBuffer (numSamplesAvailable); | |||
| } | |||
| void copyBuffers (float** destBuffers, int numDestBuffers, int bufferSize, Thread& thread) | |||
| int getNumSamplesInReservoir() const noexcept { return reservoirWritePos - reservoirReadPos; } | |||
| void handleDeviceBuffer() | |||
| { | |||
| if (numChannels <= 0) | |||
| return; | |||
| int offset = 0; | |||
| uint8* inputData; | |||
| UINT32 numSamplesAvailable; | |||
| DWORD flags; | |||
| while (bufferSize > 0) | |||
| while (check (captureClient->GetBuffer (&inputData, &numSamplesAvailable, &flags, nullptr, nullptr)) && numSamplesAvailable > 0) | |||
| { | |||
| if (reservoirSize > 0) // There's stuff in the reservoir, so use that... | |||
| int samplesLeft = (int) numSamplesAvailable; | |||
| while (samplesLeft > 0) | |||
| { | |||
| const int samplesToDo = jmin (bufferSize, (int) reservoirSize); | |||
| const int localWrite = reservoirWritePos & reservoirMask; | |||
| const int samplesToDo = jmin (samplesLeft, reservoirMask + 1 - localWrite); | |||
| const int samplesToDoBytes = samplesToDo * bytesPerFrame; | |||
| for (int i = 0; i < numDestBuffers; ++i) | |||
| converter->convertSamples (destBuffers[i] + offset, 0, reservoir.getData(), channelMaps.getUnchecked(i), samplesToDo); | |||
| void* reservoirPtr = addBytesToPointer (reservoir.getData(), localWrite * bytesPerFrame); | |||
| bufferSize -= samplesToDo; | |||
| offset += samplesToDo; | |||
| reservoirSize = 0; | |||
| if ((flags & AUDCLNT_BUFFERFLAGS_SILENT) != 0) | |||
| zeromem (reservoirPtr, samplesToDoBytes); | |||
| else | |||
| memcpy (reservoirPtr, inputData, samplesToDoBytes); | |||
| reservoirWritePos += samplesToDo; | |||
| inputData += samplesToDoBytes; | |||
| samplesLeft -= samplesToDo; | |||
| } | |||
| else | |||
| { | |||
| UINT32 packetLength = 0; | |||
| if (! check (captureClient->GetNextPacketSize (&packetLength))) | |||
| break; | |||
| if (packetLength == 0) | |||
| { | |||
| if (thread.threadShouldExit() | |||
| || WaitForSingleObject (clientEvent, 1000) == WAIT_TIMEOUT) | |||
| break; | |||
| if (getNumSamplesInReservoir() > reservoirSize) | |||
| reservoirReadPos = reservoirWritePos - reservoirSize; | |||
| continue; | |||
| } | |||
| captureClient->ReleaseBuffer (numSamplesAvailable); | |||
| } | |||
| } | |||
| uint8* inputData; | |||
| UINT32 numSamplesAvailable; | |||
| DWORD flags; | |||
| void copyBuffersFromReservoir (float** destBuffers, int numDestBuffers, int bufferSize) | |||
| { | |||
| if ((numChannels <= 0 && bufferSize == 0) || reservoir.getSize() == 0) | |||
| return; | |||
| if (check (captureClient->GetBuffer (&inputData, &numSamplesAvailable, &flags, 0, 0))) | |||
| { | |||
| const int samplesToDo = jmin (bufferSize, (int) numSamplesAvailable); | |||
| int offset = jmax (0, bufferSize - getNumSamplesInReservoir()); | |||
| for (int i = 0; i < numDestBuffers; ++i) | |||
| converter->convertSamples (destBuffers[i] + offset, 0, inputData, channelMaps.getUnchecked(i), samplesToDo); | |||
| if (offset > 0) | |||
| { | |||
| for (int i = 0; i < numDestBuffers; ++i) | |||
| zeromem (destBuffers[i], offset * sizeof (float)); | |||
| bufferSize -= samplesToDo; | |||
| offset += samplesToDo; | |||
| bufferSize -= offset; | |||
| reservoirReadPos -= offset / 2; | |||
| } | |||
| if (samplesToDo < (int) numSamplesAvailable) | |||
| { | |||
| reservoirSize = jmin ((int) (numSamplesAvailable - samplesToDo), reservoirCapacity); | |||
| memcpy ((uint8*) reservoir.getData(), inputData + bytesPerSample * actualNumChannels * samplesToDo, | |||
| (size_t) (bytesPerSample * actualNumChannels * reservoirSize)); | |||
| } | |||
| while (bufferSize > 0) | |||
| { | |||
| const int localRead = reservoirReadPos & reservoirMask; | |||
| captureClient->ReleaseBuffer (numSamplesAvailable); | |||
| } | |||
| } | |||
| const int samplesToDo = jmin (bufferSize, getNumSamplesInReservoir(), reservoirMask + 1 - localRead); | |||
| if (samplesToDo <= 0) | |||
| break; | |||
| const int reservoirOffset = localRead * bytesPerFrame; | |||
| for (int i = 0; i < numDestBuffers; ++i) | |||
| converter->convertSamples (destBuffers[i] + offset, 0, addBytesToPointer (reservoir.getData(), reservoirOffset), channelMaps.getUnchecked(i), samplesToDo); | |||
| bufferSize -= samplesToDo; | |||
| offset += samplesToDo; | |||
| reservoirReadPos += samplesToDo; | |||
| } | |||
| } | |||
| ComSmartPtr<IAudioCaptureClient> captureClient; | |||
| MemoryBlock reservoir; | |||
| int reservoirSize, reservoirCapacity; | |||
| int reservoirSize, reservoirMask; | |||
| volatile int reservoirReadPos, reservoirWritePos; | |||
| ScopedPointer<AudioData::Converter> converter; | |||
| private: | |||
| @@ -732,10 +849,11 @@ public: | |||
| close(); | |||
| } | |||
| bool open (const double newSampleRate, const BigInteger& newChannels) | |||
| bool open (const double newSampleRate, const BigInteger& newChannels, int bufferSizeSamples) | |||
| { | |||
| return openClient (newSampleRate, newChannels) | |||
| && (numChannels == 0 || check (client->GetService (__uuidof (IAudioRenderClient), (void**) renderClient.resetAndGetPointerAddress()))); | |||
| return openClient (newSampleRate, newChannels, bufferSizeSamples) | |||
| && (numChannels == 0 || check (client->GetService (__uuidof (IAudioRenderClient), | |||
| (void**) renderClient.resetAndGetPointerAddress()))); | |||
| } | |||
| void close() | |||
| @@ -751,15 +869,42 @@ public: | |||
| converter = new AudioData::ConverterInstance<NativeType, AudioData::Pointer<DestType, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, actualNumChannels); | |||
| } | |||
| void updateFormat (bool isFloat) | |||
| void updateFormat (bool isFloat) override | |||
| { | |||
| if (isFloat) updateFormatWithType ((AudioData::Float32*) nullptr); | |||
| else if (bytesPerSample == 4) updateFormatWithType ((AudioData::Int32*) nullptr); | |||
| else if (bytesPerSample == 3) updateFormatWithType ((AudioData::Int24*) nullptr); | |||
| else updateFormatWithType ((AudioData::Int16*) nullptr); | |||
| } | |||
| bool start() | |||
| { | |||
| if (isFloat) updateFormatWithType ((AudioData::Float32*) 0); | |||
| else if (bytesPerSample == 4) updateFormatWithType ((AudioData::Int32*) 0); | |||
| else if (bytesPerSample == 3) updateFormatWithType ((AudioData::Int24*) 0); | |||
| else updateFormatWithType ((AudioData::Int16*) 0); | |||
| int samplesToDo = getNumSamplesAvailableToCopy(); | |||
| uint8* outputData; | |||
| if (check (renderClient->GetBuffer (samplesToDo, &outputData))) | |||
| renderClient->ReleaseBuffer (samplesToDo, AUDCLNT_BUFFERFLAGS_SILENT); | |||
| return check (client->Start()); | |||
| } | |||
| int getNumSamplesAvailableToCopy() const | |||
| { | |||
| if (numChannels <= 0) | |||
| return 0; | |||
| if (! useExclusiveMode) | |||
| { | |||
| UINT32 padding = 0; | |||
| if (check (client->GetCurrentPadding (&padding))) | |||
| return actualBufferSize - (int) padding; | |||
| } | |||
| return actualBufferSize; | |||
| } | |||
| void copyBuffers (const float** const srcBuffers, const int numSrcBuffers, int bufferSize, Thread& thread) | |||
| void copyBuffers (const float** const srcBuffers, const int numSrcBuffers, int bufferSize, | |||
| WASAPIInputDevice* inputDevice, Thread& thread) | |||
| { | |||
| if (numChannels <= 0) | |||
| return; | |||
| @@ -768,22 +913,25 @@ public: | |||
| while (bufferSize > 0) | |||
| { | |||
| UINT32 padding = 0; | |||
| if (! check (client->GetCurrentPadding (&padding))) | |||
| return; | |||
| // This is needed in order not to drop any input data if the output device endpoint buffer was full | |||
| if ((! useExclusiveMode) && inputDevice != nullptr | |||
| && WaitForSingleObject (inputDevice->clientEvent, 0) == WAIT_OBJECT_0) | |||
| inputDevice->handleDeviceBuffer(); | |||
| int samplesToDo = useExclusiveMode ? bufferSize | |||
| : jmin ((int) (actualBufferSize - padding), bufferSize); | |||
| int samplesToDo = jmin (getNumSamplesAvailableToCopy(), bufferSize); | |||
| if (samplesToDo <= 0) | |||
| if (samplesToDo == 0) | |||
| { | |||
| if (thread.threadShouldExit() | |||
| || WaitForSingleObject (clientEvent, 1000) == WAIT_TIMEOUT) | |||
| break; | |||
| // This can ONLY occur in non-exclusive mode | |||
| if (! thread.threadShouldExit() && WaitForSingleObject (clientEvent, 1000) == WAIT_OBJECT_0) | |||
| continue; | |||
| continue; | |||
| break; | |||
| } | |||
| if (useExclusiveMode && WaitForSingleObject (clientEvent, 1000) == WAIT_TIMEOUT) | |||
| break; | |||
| uint8* outputData = nullptr; | |||
| if (check (renderClient->GetBuffer ((UINT32) samplesToDo, &outputData))) | |||
| { | |||
| @@ -791,10 +939,10 @@ public: | |||
| converter->convertSamples (outputData, channelMaps.getUnchecked(i), srcBuffers[i] + offset, 0, samplesToDo); | |||
| renderClient->ReleaseBuffer ((UINT32) samplesToDo, 0); | |||
| offset += samplesToDo; | |||
| bufferSize -= samplesToDo; | |||
| } | |||
| bufferSize -= samplesToDo; | |||
| offset += samplesToDo; | |||
| } | |||
| } | |||
| @@ -812,13 +960,14 @@ class WASAPIAudioIODevice : public AudioIODevice, | |||
| { | |||
| public: | |||
| WASAPIAudioIODevice (const String& deviceName, | |||
| const String& outputDeviceId_, | |||
| const String& inputDeviceId_, | |||
| const String& typeName, | |||
| const String& outputDeviceID, | |||
| const String& inputDeviceID, | |||
| const bool exclusiveMode) | |||
| : AudioIODevice (deviceName, "Windows Audio"), | |||
| : AudioIODevice (deviceName, typeName), | |||
| Thread ("Juce WASAPI"), | |||
| outputDeviceId (outputDeviceId_), | |||
| inputDeviceId (inputDeviceId_), | |||
| outputDeviceId (outputDeviceID), | |||
| inputDeviceId (inputDeviceID), | |||
| useExclusiveMode (exclusiveMode), | |||
| isOpen_ (false), | |||
| isStarted (false), | |||
| @@ -932,19 +1081,33 @@ public: | |||
| lastKnownInputChannels = inputChannels; | |||
| lastKnownOutputChannels = outputChannels; | |||
| if (inputDevice != nullptr && ! inputDevice->open (currentSampleRate, inputChannels)) | |||
| if (inputDevice != nullptr && ! inputDevice->open (currentSampleRate, inputChannels, bufferSizeSamples)) | |||
| { | |||
| lastError = TRANS("Couldn't open the input device!"); | |||
| return lastError; | |||
| } | |||
| if (outputDevice != nullptr && ! outputDevice->open (currentSampleRate, outputChannels)) | |||
| if (outputDevice != nullptr && ! outputDevice->open (currentSampleRate, outputChannels, bufferSizeSamples)) | |||
| { | |||
| close(); | |||
| lastError = TRANS("Couldn't open the output device!"); | |||
| return lastError; | |||
| } | |||
| if (useExclusiveMode) | |||
| { | |||
| // This is to make sure that the callback uses actualBufferSize in case of exclusive mode | |||
| if (inputDevice != nullptr && outputDevice != nullptr && inputDevice->actualBufferSize != outputDevice->actualBufferSize) | |||
| { | |||
| close(); | |||
| lastError = TRANS("Couldn't open the output device (buffer size mismatch)"); | |||
| return lastError; | |||
| } | |||
| currentBufferSizeSamples = outputDevice != nullptr ? outputDevice->actualBufferSize | |||
| : inputDevice->actualBufferSize; | |||
| } | |||
| if (inputDevice != nullptr) ResetEvent (inputDevice->clientEvent); | |||
| if (outputDevice != nullptr) ResetEvent (outputDevice->clientEvent); | |||
| @@ -955,7 +1118,7 @@ public: | |||
| { | |||
| latencyIn = (int) (inputDevice->latencySamples + currentBufferSizeSamples); | |||
| if (! check (inputDevice->client->Start())) | |||
| if (! inputDevice->start (currentBufferSizeSamples)) | |||
| { | |||
| close(); | |||
| lastError = TRANS("Couldn't start the input device!"); | |||
| @@ -967,7 +1130,7 @@ public: | |||
| { | |||
| latencyOut = (int) (outputDevice->latencySamples + currentBufferSizeSamples); | |||
| if (! check (outputDevice->client->Start())) | |||
| if (! outputDevice->start()) | |||
| { | |||
| close(); | |||
| lastError = TRANS("Couldn't start the output device!"); | |||
| @@ -1056,34 +1219,48 @@ public: | |||
| const int bufferSize = currentBufferSizeSamples; | |||
| const int numInputBuffers = getActiveInputChannels().countNumberOfSetBits(); | |||
| const int numOutputBuffers = getActiveOutputChannels().countNumberOfSetBits(); | |||
| bool sampleRateChanged = false; | |||
| bool sampleRateHasChanged = false; | |||
| AudioSampleBuffer ins (jmax (1, numInputBuffers), bufferSize + 32); | |||
| AudioSampleBuffer outs (jmax (1, numOutputBuffers), bufferSize + 32); | |||
| float** const inputBuffers = ins.getArrayOfWritePointers(); | |||
| float** const outputBuffers = outs.getArrayOfWritePointers(); | |||
| ins.clear(); | |||
| outs.clear(); | |||
| while (! threadShouldExit()) | |||
| { | |||
| if (inputDevice != nullptr) | |||
| { | |||
| inputDevice->copyBuffers (inputBuffers, numInputBuffers, bufferSize, *this); | |||
| if (outputDevice == nullptr) | |||
| { | |||
| if (WaitForSingleObject (inputDevice->clientEvent, 1000) == WAIT_TIMEOUT) | |||
| break; | |||
| if (threadShouldExit()) | |||
| break; | |||
| inputDevice->handleDeviceBuffer(); | |||
| if (inputDevice->getNumSamplesInReservoir() < bufferSize) | |||
| continue; | |||
| } | |||
| else | |||
| { | |||
| if (useExclusiveMode && WaitForSingleObject (inputDevice->clientEvent, 0) == WAIT_OBJECT_0) | |||
| inputDevice->handleDeviceBuffer(); | |||
| } | |||
| inputDevice->copyBuffersFromReservoir (inputBuffers, numInputBuffers, bufferSize); | |||
| if (inputDevice->sampleRateHasChanged) | |||
| { | |||
| sampleRateChanged = true; | |||
| sampleRateHasChanged = true; | |||
| sampleRateChangedByOutput = false; | |||
| } | |||
| } | |||
| { | |||
| const ScopedLock sl (startStopLock); | |||
| const ScopedTryLock sl (startStopLock); | |||
| if (isStarted) | |||
| if (sl.isLocked() && isStarted) | |||
| callback->audioDeviceIOCallback (const_cast<const float**> (inputBuffers), numInputBuffers, | |||
| outputBuffers, numOutputBuffers, bufferSize); | |||
| else | |||
| @@ -1092,16 +1269,18 @@ public: | |||
| if (outputDevice != nullptr) | |||
| { | |||
| outputDevice->copyBuffers (const_cast<const float**> (outputBuffers), numOutputBuffers, bufferSize, *this); | |||
| // Note that this function is handed the input device so it can check for the event and make sure | |||
| // the input reservoir is filled up correctly even when bufferSize > device actualBufferSize | |||
| outputDevice->copyBuffers (const_cast<const float**> (outputBuffers), numOutputBuffers, bufferSize, inputDevice, *this); | |||
| if (outputDevice->sampleRateHasChanged) | |||
| { | |||
| sampleRateChanged = true; | |||
| sampleRateHasChanged = true; | |||
| sampleRateChangedByOutput = true; | |||
| } | |||
| } | |||
| if (sampleRateChanged) | |||
| if (sampleRateHasChanged) | |||
| { | |||
| triggerAsyncUpdate(); | |||
| break; // Quit the thread... will restart it later! | |||
| @@ -1208,9 +1387,10 @@ class WASAPIAudioIODeviceType : public AudioIODeviceType, | |||
| private DeviceChangeDetector | |||
| { | |||
| public: | |||
| WASAPIAudioIODeviceType() | |||
| : AudioIODeviceType ("Windows Audio"), | |||
| WASAPIAudioIODeviceType (bool exclusive) | |||
| : AudioIODeviceType (exclusive ? "Windows Audio (Exclusive Mode)" : "Windows Audio"), | |||
| DeviceChangeDetector (L"Windows Audio"), | |||
| exclusiveMode (exclusive), | |||
| hasScanned (false) | |||
| { | |||
| } | |||
| @@ -1267,7 +1447,6 @@ public: | |||
| { | |||
| jassert (hasScanned); // need to call scanForDevices() before doing this | |||
| const bool useExclusiveMode = false; | |||
| ScopedPointer<WASAPIAudioIODevice> device; | |||
| const int outputIndex = outputDeviceNames.indexOf (outputDeviceName); | |||
| @@ -1277,9 +1456,10 @@ public: | |||
| { | |||
| device = new WASAPIAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName | |||
| : inputDeviceName, | |||
| getTypeName(), | |||
| outputDeviceIds [outputIndex], | |||
| inputDeviceIds [inputIndex], | |||
| useExclusiveMode); | |||
| exclusiveMode); | |||
| if (! device->initialise()) | |||
| device = nullptr; | |||
| @@ -1293,7 +1473,7 @@ public: | |||
| StringArray inputDeviceNames, inputDeviceIds; | |||
| private: | |||
| bool hasScanned; | |||
| bool exclusiveMode, hasScanned; | |||
| ComSmartPtr<IMMDeviceEnumerator> enumerator; | |||
| //============================================================================== | |||
| @@ -1418,7 +1598,7 @@ private: | |||
| } | |||
| //============================================================================== | |||
| void systemDeviceChanged() | |||
| void systemDeviceChanged() override | |||
| { | |||
| StringArray newOutNames, newInNames, newOutIds, newInIds; | |||
| scan (newOutNames, newInNames, newOutIds, newInIds); | |||
| @@ -1493,12 +1673,16 @@ struct MMDeviceMasterVolume | |||
| } | |||
| //============================================================================== | |||
| AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_WASAPI() | |||
| AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_WASAPI (bool exclusiveMode) | |||
| { | |||
| if (SystemStats::getOperatingSystemType() >= SystemStats::WinVista) | |||
| return new WasapiClasses::WASAPIAudioIODeviceType(); | |||
| #if ! JUCE_WASAPI_EXCLUSIVE | |||
| if (exclusiveMode) | |||
| return nullptr; | |||
| #endif | |||
| return nullptr; | |||
| return SystemStats::getOperatingSystemType() >= SystemStats::WinVista | |||
| ? new WasapiClasses::WASAPIAudioIODeviceType (exclusiveMode) | |||
| : nullptr; | |||
| } | |||
| //============================================================================== | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -1,6 +1,6 @@ | |||
| /* alloc - Convenience routines for safely allocating memory | |||
| * Copyright (C) 2007-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -33,7 +33,7 @@ | |||
| #ifndef FLAC__SHARE__ALLOC_H | |||
| #define FLAC__SHARE__ALLOC_H | |||
| #if HAVE_CONFIG_H | |||
| #ifdef HAVE_CONFIG_H | |||
| # include <config.h> | |||
| #endif | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2001-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2004-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -1,5 +1,5 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2012 Xiph.org Foundation | |||
| * Copyright (C) 2012-2014 Xiph.org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -73,23 +73,25 @@ | |||
| #endif | |||
| #if defined(_MSC_VER) | |||
| #if _MSC_VER < 1500 | |||
| /* Visual Studio 2008 has restrict. */ | |||
| #define restrict __restrict | |||
| #endif | |||
| #define inline __inline | |||
| #endif | |||
| /* adjust for compilers that can't understand using LLU suffix for uint64_t literals */ | |||
| #ifdef _MSC_VER | |||
| #define FLAC__U64L(x) x | |||
| #if defined __INTEL_COMPILER || (defined _MSC_VER && defined _WIN64) | |||
| /* MSVS generates VERY slow 32-bit code with __restrict */ | |||
| #define flac_restrict __restrict | |||
| #elif defined __GNUC__ | |||
| #define flac_restrict __restrict__ | |||
| #else | |||
| #define FLAC__U64L(x) x##LLU | |||
| #define flac_restrict | |||
| #endif | |||
| #define FLAC__U64L(x) x##ULL | |||
| #if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ | |||
| #define FLAC__STRCASECMP stricmp | |||
| #define FLAC__STRNCASECMP strnicmp | |||
| #else | |||
| #define FLAC__STRCASECMP strcasecmp | |||
| #define FLAC__STRNCASECMP strncasecmp | |||
| #endif | |||
| @@ -139,6 +141,7 @@ | |||
| #ifdef _WIN32 | |||
| /* All char* strings are in UTF-8 format. Added to support Unicode files on Windows */ | |||
| #include "win_utf8_io.h" | |||
| #define flac_printf printf_utf8 | |||
| #define flac_fprintf fprintf_utf8 | |||
| @@ -160,12 +163,7 @@ | |||
| #define flac_utime utime | |||
| #define flac_unlink unlink | |||
| #define flac_rename rename | |||
| #ifdef _WIN32 | |||
| #define flac_stat _stat64 | |||
| #else | |||
| #define flac_stat stat | |||
| #endif | |||
| #endif | |||
| @@ -177,8 +175,14 @@ | |||
| #define flac_fstat fstat | |||
| #endif | |||
| #ifndef M_LN2 | |||
| #define M_LN2 0.69314718055994530942 | |||
| #endif | |||
| #ifndef M_PI | |||
| #define M_PI 3.14159265358979323846 | |||
| #endif | |||
| /* FLAC needs to compile and work correctly on systems with a norrmal ISO C99 | |||
| /* FLAC needs to compile and work correctly on systems with a normal ISO C99 | |||
| * snprintf as well as Microsoft Visual Studio which has an non-standards | |||
| * conformant snprint_s function. | |||
| * | |||
| @@ -188,6 +192,7 @@ | |||
| extern "C" { | |||
| #endif | |||
| int flac_snprintf(char *str, size_t size, const char *fmt, ...); | |||
| int flac_vsnprintf(char *str, size_t size, const char *fmt, va_list va); | |||
| #ifdef __cplusplus | |||
| }; | |||
| #endif | |||
| @@ -1,5 +1,5 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2012 Xiph.org Foundation | |||
| * Copyright (C) 2012-2014 Xiph.org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -33,20 +33,46 @@ | |||
| #if HAVE_BSWAP32 /* GCC and Clang */ | |||
| /* GCC prior to 4.8 didn't provide bswap16 on x86_64 */ | |||
| #if ! HAVE_BSWAP16 | |||
| static inline unsigned short __builtin_bswap16(unsigned short a) | |||
| { | |||
| return (a<<8)|(a>>8); | |||
| } | |||
| #endif | |||
| #define ENDSWAP_16(x) (__builtin_bswap16 (x)) | |||
| #define ENDSWAP_32(x) (__builtin_bswap32 (x)) | |||
| #elif defined _MSC_VER /* Windows. Apparently in <stdlib.h>. */ | |||
| #define ENDSWAP_16(x) (_byteswap_ushort (x)) | |||
| #define ENDSWAP_32(x) (_byteswap_ulong (x)) | |||
| #elif defined HAVE_BYTESWAP_H /* Linux */ | |||
| #include <byteswap.h> | |||
| #define ENDSWAP_16(x) (bswap_16 (x)) | |||
| #define ENDSWAP_32(x) (bswap_32 (x)) | |||
| #else | |||
| #define ENDSWAP_32(x) ((((x) >> 24) & 0xFF) + (((x) >> 8) & 0xFF00) + (((x) & 0xFF00) << 8) + (((x) & 0xFF) << 24)) | |||
| #define ENDSWAP_16(x) ((((x) >> 8) & 0xFF) | (((x) & 0xFF) << 8)) | |||
| #define ENDSWAP_32(x) ((((x) >> 24) & 0xFF) | (((x) >> 8) & 0xFF00) | (((x) & 0xFF00) << 8) | (((x) & 0xFF) << 24)) | |||
| #endif | |||
| /* Host to little-endian byte swapping. */ | |||
| #if CPU_IS_BIG_ENDIAN | |||
| #define H2LE_16(x) ENDSWAP_16 (x) | |||
| #define H2LE_32(x) ENDSWAP_32 (x) | |||
| #else | |||
| #define H2LE_16(x) (x) | |||
| #define H2LE_32(x) (x) | |||
| #endif | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -61,9 +61,9 @@ | |||
| #elif defined(_MSC_VER) | |||
| #ifdef FLAC_API_EXPORTS | |||
| #define FLAC_API _declspec(dllexport) | |||
| #define FLAC_API __declspec(dllexport) | |||
| #else | |||
| #define FLAC_API _declspec(dllimport) | |||
| #define FLAC_API __declspec(dllimport) | |||
| #endif | |||
| #elif defined(FLAC__USE_VISIBILITY_ATTR) | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -509,9 +509,11 @@ typedef enum { | |||
| FLAC__METADATA_TYPE_PICTURE = 6, | |||
| /**< <A HREF="../format.html#metadata_block_picture">PICTURE</A> block */ | |||
| FLAC__METADATA_TYPE_UNDEFINED = 7 | |||
| FLAC__METADATA_TYPE_UNDEFINED = 7, | |||
| /**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */ | |||
| FLAC__MAX_METADATA_TYPE = FLAC__MAX_METADATA_TYPE_CODE, | |||
| /**< No type will ever be greater than this. There is not enough room in the protocol block. */ | |||
| } FLAC__MetadataType; | |||
| /** Maps a FLAC__MetadataType to a C string. | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2001-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -30,12 +30,11 @@ | |||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #if HAVE_CONFIG_H | |||
| #ifdef HAVE_CONFIG_H | |||
| # include <config.h> | |||
| #endif | |||
| #include "include/private/bitmath.h" | |||
| #include "../assert.h" | |||
| /* An example of what FLAC__bitmath_silog2() computes: | |||
| * | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -30,7 +30,7 @@ | |||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #if HAVE_CONFIG_H | |||
| #ifdef HAVE_CONFIG_H | |||
| # include <config.h> | |||
| #endif | |||
| @@ -73,7 +73,6 @@ | |||
| */ | |||
| static const unsigned FLAC__BITREADER_DEFAULT_CAPACITY = 65536u / FLAC__BITS_PER_WORD; /* in words */ | |||
| /* WATCHOUT: assembly routines rely on the order in which these fields are declared */ | |||
| struct FLAC__BitReader { | |||
| /* any partially-consumed word at the head will stay right-justified as bits are consumed from the left */ | |||
| /* any incomplete word at the tail will be left-justified, and bytes from the read callback are added on the right */ | |||
| @@ -87,7 +86,6 @@ struct FLAC__BitReader { | |||
| unsigned crc16_align; /* the number of bits in the current consumed word that should not be CRC'd */ | |||
| FLAC__BitReaderReadCallback read_callback; | |||
| void *client_data; | |||
| FLAC__CPUInfo cpu_info; | |||
| }; | |||
| static inline void crc16_update_word_(FLAC__BitReader *br, uint32_t word) | |||
| @@ -119,8 +117,7 @@ static inline void crc16_update_word_(FLAC__BitReader *br, uint32_t word) | |||
| br->crc16_align = 0; | |||
| } | |||
| /* would be static except it needs to be called by asm routines */ | |||
| FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br) | |||
| static FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br) | |||
| { | |||
| unsigned start, end; | |||
| size_t bytes; | |||
| @@ -231,7 +228,7 @@ void FLAC__bitreader_delete(FLAC__BitReader *br) | |||
| * | |||
| ***********************************************************************/ | |||
| FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__CPUInfo cpu, FLAC__BitReaderReadCallback rcb, void *cd) | |||
| FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__BitReaderReadCallback rcb, void *cd) | |||
| { | |||
| FLAC__ASSERT(0 != br); | |||
| @@ -243,7 +240,6 @@ FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__CPUInfo cpu, FLAC__Bi | |||
| return false; | |||
| br->read_callback = rcb; | |||
| br->client_data = cd; | |||
| br->cpu_info = cpu; | |||
| return true; | |||
| } | |||
| @@ -1048,9 +1044,9 @@ FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *v | |||
| return true; | |||
| } | |||
| /* These functions a declared inline in this file but are also callable as | |||
| /* These functions are declared inline in this file but are also callable as | |||
| * externs from elsewhere. | |||
| * According to the C99 sepc, section 6.7.4, simply providing a function | |||
| * According to the C99 spec, section 6.7.4, simply providing a function | |||
| * prototype in a header file without 'inline' and making the function inline | |||
| * in this file should be sufficient. | |||
| * Unfortunately, the Microsoft VS compiler doesn't pick them up externally. To | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -30,7 +30,7 @@ | |||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #if HAVE_CONFIG_H | |||
| #ifdef HAVE_CONFIG_H | |||
| # include <config.h> | |||
| #endif | |||
| @@ -47,8 +47,7 @@ | |||
| /* WATCHOUT: if you change this you must also change the following #defines down to SWAP_BE_WORD_TO_HOST below to match */ | |||
| /* WATCHOUT: there are a few places where the code will not work unless uint32_t is >= 32 bits wide */ | |||
| #define FLAC__BYTES_PER_WORD 4 | |||
| #undef FLAC__BITS_PER_WORD | |||
| #define FLAC__BITS_PER_WORD 32 | |||
| #define FLAC__BITS_PER_WORD (8 * FLAC__BYTES_PER_WORD) | |||
| #define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff) | |||
| /* SWAP_BE_WORD_TO_HOST swaps bytes in a uint32_t (which is always big-endian) if necessary to match host byte order */ | |||
| #if WORDS_BIGENDIAN | |||
| @@ -524,28 +523,6 @@ FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FL | |||
| msbits = uval >> parameter; | |||
| #if 0 /* OPT: can remove this special case if it doesn't make up for the extra compare (doesn't make a statistically significant difference with msvc or gcc/x86) */ | |||
| if(bw->bits && bw->bits + msbits + lsbits <= FLAC__BITS_PER_WORD) { /* i.e. if the whole thing fits in the current uint32_t */ | |||
| /* ^^^ if bw->bits is 0 then we may have filled the buffer and have no free uint32_t to work in */ | |||
| bw->bits = bw->bits + msbits + lsbits; | |||
| uval |= mask1; /* set stop bit */ | |||
| uval &= mask2; /* mask off unused top bits */ | |||
| /* NOT: bw->accum <<= msbits + lsbits because msbits+lsbits could be 32, then the shift would be a NOP */ | |||
| bw->accum <<= msbits; | |||
| bw->accum <<= lsbits; | |||
| bw->accum |= uval; | |||
| if(bw->bits == FLAC__BITS_PER_WORD) { | |||
| bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); | |||
| bw->bits = 0; | |||
| /* burying the capacity check down here means we have to grow the buffer a little if there are more vals to do */ | |||
| if(bw->capacity <= bw->words && nvals > 1 && !bitwriter_grow_(bw, 1)) { | |||
| FLAC__ASSERT(bw->capacity == bw->words); | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| else { | |||
| #elif 1 /*@@@@@@ OPT: try this version with MSVC6 to see if better, not much difference for gcc-4 */ | |||
| if(bw->bits && bw->bits + msbits + lsbits < FLAC__BITS_PER_WORD) { /* i.e. if the whole thing fits in the current uint32_t */ | |||
| /* ^^^ if bw->bits is 0 then we may have filled the buffer and have no free uint32_t to work in */ | |||
| bw->bits = bw->bits + msbits + lsbits; | |||
| @@ -555,7 +532,6 @@ FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FL | |||
| bw->accum |= uval; | |||
| } | |||
| else { | |||
| #endif | |||
| /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+msbits+lsbits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */ | |||
| /* OPT: pessimism may cause flurry of false calls to grow_ which eat up all savings before it */ | |||
| if(bw->capacity <= bw->words + bw->bits + msbits + 1/*lsbits always fit in 1 uint32_t*/ && !bitwriter_grow_(bw, msbits+lsbits)) | |||
| @@ -610,9 +586,7 @@ break1: | |||
| bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); | |||
| bw->accum = uval; | |||
| } | |||
| #if 1 | |||
| } | |||
| #endif | |||
| vals++; | |||
| nvals--; | |||
| } | |||
| @@ -853,9 +827,9 @@ FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw) | |||
| return true; | |||
| } | |||
| /* These functions a declared inline in this file but are also callable as | |||
| /* These functions are declared inline in this file but are also callable as | |||
| * externs from elsewhere. | |||
| * According to the C99 sepc, section 6.7.4, simply providing a function | |||
| * According to the C99 spec, section 6.7.4, simply providing a function | |||
| * prototype in a header file without 'inline' and making the function inline | |||
| * in this file should be sufficient. | |||
| * Unfortunately, the Microsoft VS compiler doesn't pick them up externally. To | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2001-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -30,47 +30,47 @@ | |||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #if HAVE_CONFIG_H | |||
| #ifdef HAVE_CONFIG_H | |||
| # include <config.h> | |||
| #endif | |||
| #include "include/private/cpu.h" | |||
| #include <stdlib.h> | |||
| #include <stdio.h> | |||
| #if 0 | |||
| #include <stdlib.h> | |||
| #include <memory.h> | |||
| #include <stdio.h> | |||
| #endif | |||
| #if defined FLAC__CPU_IA32 | |||
| # include <signal.h> | |||
| #elif defined FLAC__CPU_PPC | |||
| # if !defined FLAC__NO_ASM | |||
| # if defined FLAC__SYS_DARWIN | |||
| # include <sys/sysctl.h> | |||
| # include <mach/mach.h> | |||
| # include <mach/mach_host.h> | |||
| # include <mach/host_info.h> | |||
| # include <mach/machine.h> | |||
| # ifndef CPU_SUBTYPE_POWERPC_970 | |||
| # define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100) | |||
| # endif | |||
| # else /* FLAC__SYS_DARWIN */ | |||
| # include <signal.h> | |||
| # include <setjmp.h> | |||
| static sigjmp_buf jmpbuf; | |||
| static volatile sig_atomic_t canjump = 0; | |||
| static void sigill_handler (int sig) | |||
| static void disable_sse(FLAC__CPUInfo *info) | |||
| { | |||
| if (!canjump) { | |||
| signal (sig, SIG_DFL); | |||
| raise (sig); | |||
| } | |||
| canjump = 0; | |||
| siglongjmp (jmpbuf, 1); | |||
| info->ia32.sse = false; | |||
| info->ia32.sse2 = false; | |||
| info->ia32.sse3 = false; | |||
| info->ia32.ssse3 = false; | |||
| info->ia32.sse41 = false; | |||
| info->ia32.sse42 = false; | |||
| } | |||
| static void disable_avx(FLAC__CPUInfo *info) | |||
| { | |||
| info->ia32.avx = false; | |||
| info->ia32.avx2 = false; | |||
| info->ia32.fma = false; | |||
| } | |||
| # endif /* FLAC__SYS_DARWIN */ | |||
| # endif /* FLAC__NO_ASM */ | |||
| #endif /* FLAC__CPU_PPC */ | |||
| #elif defined FLAC__CPU_X86_64 | |||
| static void disable_avx(FLAC__CPUInfo *info) | |||
| { | |||
| info->x86.avx = false; | |||
| info->x86.avx2 = false; | |||
| info->x86.fma = false; | |||
| } | |||
| #endif | |||
| #if defined (__NetBSD__) || defined(__OpenBSD__) | |||
| #include <sys/param.h> | |||
| @@ -87,25 +87,34 @@ static void sigill_handler (int sig) | |||
| /* how to get sysctlbyname()? */ | |||
| #endif | |||
| #ifdef FLAC__CPU_IA32 | |||
| /* these are flags in EDX of CPUID AX=00000001 */ | |||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_CMOV = 0x00008000; | |||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_MMX = 0x00800000; | |||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_FXSR = 0x01000000; | |||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE = 0x02000000; | |||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2 = 0x04000000; | |||
| #endif | |||
| /* these are flags in ECX of CPUID AX=00000001 */ | |||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE3 = 0x00000001; | |||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_SSSE3 = 0x00000200; | |||
| /* these are flags in EDX of CPUID AX=80000001 */ | |||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW = 0x80000000; | |||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW = 0x40000000; | |||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX = 0x00400000; | |||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE41 = 0x00080000; | |||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE42 = 0x00100000; | |||
| #if defined FLAC__AVX_SUPPORTED | |||
| /* these are flags in ECX of CPUID AX=00000001 */ | |||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_OSXSAVE = 0x08000000; | |||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_AVX = 0x10000000; | |||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_FMA = 0x00001000; | |||
| /* these are flags in EBX of CPUID AX=00000007 */ | |||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_AVX2 = 0x00000020; | |||
| #endif | |||
| /* | |||
| * Extra stuff needed for detection of OS support for SSE on IA-32 | |||
| */ | |||
| #if defined(FLAC__CPU_IA32) && !defined FLAC__NO_ASM && defined FLAC__HAS_NASM && !defined FLAC__NO_SSE_OS && !defined FLAC__SSE_OS | |||
| #if defined(FLAC__CPU_IA32) && !defined FLAC__NO_ASM && (defined FLAC__HAS_NASM || defined FLAC__HAS_X86INTRIN) && !defined FLAC__NO_SSE_OS && !defined FLAC__SSE_OS | |||
| # if defined(__linux__) | |||
| /* | |||
| * If the OS doesn't support SSE, we will get here with a SIGILL. We | |||
| @@ -120,35 +129,14 @@ static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX = 0x00400000; | |||
| * 6 bytes extra in case our estimate is wrong | |||
| * 12 bytes puts us in the NOP "landing zone" | |||
| */ | |||
| # undef USE_OBSOLETE_SIGCONTEXT_FLAVOR /* #define this to use the older signal handler method */ | |||
| # ifdef USE_OBSOLETE_SIGCONTEXT_FLAVOR | |||
| static void sigill_handler_sse_os(int signal, struct sigcontext sc) | |||
| { | |||
| (void)signal; | |||
| sc.eip += 3 + 3 + 6; | |||
| } | |||
| # else | |||
| # include <sys/ucontext.h> | |||
| static void sigill_handler_sse_os(int signal, siginfo_t *si, void *uc) | |||
| { | |||
| (void)signal, (void)si; | |||
| ((ucontext_t*)uc)->uc_mcontext.gregs[14/*REG_EIP*/] += 3 + 3 + 6; | |||
| } | |||
| # endif | |||
| # elif defined(_MSC_VER) | |||
| # include <windows.h> | |||
| # define USE_TRY_CATCH_FLAVOR /* sigill_handler flavor resulted in several crash reports on win32 */ | |||
| # ifdef USE_TRY_CATCH_FLAVOR | |||
| # else | |||
| LONG CALLBACK sigill_handler_sse_os(EXCEPTION_POINTERS *ep) | |||
| { | |||
| if(ep->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) { | |||
| ep->ContextRecord->Eip += 3 + 3 + 6; | |||
| return EXCEPTION_CONTINUE_EXECUTION; | |||
| } | |||
| return EXCEPTION_CONTINUE_SEARCH; | |||
| } | |||
| # endif | |||
| # endif | |||
| #endif | |||
| @@ -159,261 +147,344 @@ void FLAC__cpu_info(FLAC__CPUInfo *info) | |||
| * IA32-specific | |||
| */ | |||
| #ifdef FLAC__CPU_IA32 | |||
| FLAC__bool ia32_fxsr = false; | |||
| FLAC__bool ia32_osxsave = false; | |||
| (void) ia32_fxsr; (void) ia32_osxsave; /* to avoid warnings about unused variables */ | |||
| memset(info, 0, sizeof(*info)); | |||
| info->type = FLAC__CPUINFO_TYPE_IA32; | |||
| #if !defined FLAC__NO_ASM && defined FLAC__HAS_NASM | |||
| #if !defined FLAC__NO_ASM && (defined FLAC__HAS_NASM || defined FLAC__HAS_X86INTRIN) | |||
| info->use_asm = true; /* we assume a minimum of 80386 with FLAC__CPU_IA32 */ | |||
| info->data.ia32.cpuid = FLAC__cpu_have_cpuid_asm_ia32()? true : false; | |||
| info->data.ia32.bswap = info->data.ia32.cpuid; /* CPUID => BSWAP since it came after */ | |||
| info->data.ia32.cmov = false; | |||
| info->data.ia32.mmx = false; | |||
| info->data.ia32.fxsr = false; | |||
| info->data.ia32.sse = false; | |||
| info->data.ia32.sse2 = false; | |||
| info->data.ia32.sse3 = false; | |||
| info->data.ia32.ssse3 = false; | |||
| info->data.ia32._3dnow = false; | |||
| info->data.ia32.ext3dnow = false; | |||
| info->data.ia32.extmmx = false; | |||
| if(info->data.ia32.cpuid) { | |||
| /* http://www.sandpile.org/ia32/cpuid.htm */ | |||
| FLAC__uint32 flags_edx, flags_ecx; | |||
| FLAC__cpu_info_asm_ia32(&flags_edx, &flags_ecx); | |||
| info->data.ia32.cmov = (flags_edx & FLAC__CPUINFO_IA32_CPUID_CMOV )? true : false; | |||
| info->data.ia32.mmx = (flags_edx & FLAC__CPUINFO_IA32_CPUID_MMX )? true : false; | |||
| info->data.ia32.fxsr = (flags_edx & FLAC__CPUINFO_IA32_CPUID_FXSR )? true : false; | |||
| info->data.ia32.sse = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE )? true : false; | |||
| info->data.ia32.sse2 = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE2 )? true : false; | |||
| info->data.ia32.sse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 )? true : false; | |||
| info->data.ia32.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3)? true : false; | |||
| #ifdef FLAC__USE_3DNOW | |||
| flags_edx = FLAC__cpu_info_extended_amd_asm_ia32(); | |||
| info->data.ia32._3dnow = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW )? true : false; | |||
| info->data.ia32.ext3dnow = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW)? true : false; | |||
| info->data.ia32.extmmx = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX )? true : false; | |||
| #ifdef FLAC__HAS_X86INTRIN | |||
| if(!FLAC__cpu_have_cpuid_x86()) | |||
| return; | |||
| #else | |||
| if(!FLAC__cpu_have_cpuid_asm_ia32()) | |||
| return; | |||
| #endif | |||
| { | |||
| /* http://www.sandpile.org/x86/cpuid.htm */ | |||
| #ifdef FLAC__HAS_X86INTRIN | |||
| FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx; | |||
| FLAC__cpu_info_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx); | |||
| #else | |||
| info->data.ia32._3dnow = info->data.ia32.ext3dnow = info->data.ia32.extmmx = false; | |||
| FLAC__uint32 flags_ecx, flags_edx; | |||
| FLAC__cpu_info_asm_ia32(&flags_edx, &flags_ecx); | |||
| #endif | |||
| info->ia32.cmov = (flags_edx & FLAC__CPUINFO_IA32_CPUID_CMOV )? true : false; | |||
| info->ia32.mmx = (flags_edx & FLAC__CPUINFO_IA32_CPUID_MMX )? true : false; | |||
| ia32_fxsr = (flags_edx & FLAC__CPUINFO_IA32_CPUID_FXSR )? true : false; | |||
| info->ia32.sse = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE )? true : false; | |||
| info->ia32.sse2 = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE2 )? true : false; | |||
| info->ia32.sse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 )? true : false; | |||
| info->ia32.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3)? true : false; | |||
| info->ia32.sse41 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE41)? true : false; | |||
| info->ia32.sse42 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE42)? true : false; | |||
| #if defined FLAC__HAS_X86INTRIN && defined FLAC__AVX_SUPPORTED | |||
| ia32_osxsave = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_OSXSAVE)? true : false; | |||
| info->ia32.avx = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_AVX )? true : false; | |||
| info->ia32.fma = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_FMA )? true : false; | |||
| FLAC__cpu_info_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx); | |||
| info->ia32.avx2 = (flags_ebx & FLAC__CPUINFO_IA32_CPUID_AVX2 )? true : false; | |||
| #endif | |||
| } | |||
| #ifdef DEBUG | |||
| fprintf(stderr, "CPU info (IA-32):\n"); | |||
| fprintf(stderr, " CPUID ...... %c\n", info->data.ia32.cpuid ? 'Y' : 'n'); | |||
| fprintf(stderr, " BSWAP ...... %c\n", info->data.ia32.bswap ? 'Y' : 'n'); | |||
| fprintf(stderr, " CMOV ....... %c\n", info->data.ia32.cmov ? 'Y' : 'n'); | |||
| fprintf(stderr, " MMX ........ %c\n", info->data.ia32.mmx ? 'Y' : 'n'); | |||
| fprintf(stderr, " FXSR ....... %c\n", info->data.ia32.fxsr ? 'Y' : 'n'); | |||
| fprintf(stderr, " SSE ........ %c\n", info->data.ia32.sse ? 'Y' : 'n'); | |||
| fprintf(stderr, " SSE2 ....... %c\n", info->data.ia32.sse2 ? 'Y' : 'n'); | |||
| fprintf(stderr, " SSE3 ....... %c\n", info->data.ia32.sse3 ? 'Y' : 'n'); | |||
| fprintf(stderr, " SSSE3 ...... %c\n", info->data.ia32.ssse3 ? 'Y' : 'n'); | |||
| fprintf(stderr, " 3DNow! ..... %c\n", info->data.ia32._3dnow ? 'Y' : 'n'); | |||
| fprintf(stderr, " 3DNow!-ext . %c\n", info->data.ia32.ext3dnow? 'Y' : 'n'); | |||
| fprintf(stderr, " 3DNow!-MMX . %c\n", info->data.ia32.extmmx ? 'Y' : 'n'); | |||
| fprintf(stderr, "CPU info (IA-32):\n"); | |||
| fprintf(stderr, " CMOV ....... %c\n", info->ia32.cmov ? 'Y' : 'n'); | |||
| fprintf(stderr, " MMX ........ %c\n", info->ia32.mmx ? 'Y' : 'n'); | |||
| fprintf(stderr, " SSE ........ %c\n", info->ia32.sse ? 'Y' : 'n'); | |||
| fprintf(stderr, " SSE2 ....... %c\n", info->ia32.sse2 ? 'Y' : 'n'); | |||
| fprintf(stderr, " SSE3 ....... %c\n", info->ia32.sse3 ? 'Y' : 'n'); | |||
| fprintf(stderr, " SSSE3 ...... %c\n", info->ia32.ssse3 ? 'Y' : 'n'); | |||
| fprintf(stderr, " SSE41 ...... %c\n", info->ia32.sse41 ? 'Y' : 'n'); | |||
| fprintf(stderr, " SSE42 ...... %c\n", info->ia32.sse42 ? 'Y' : 'n'); | |||
| # if defined FLAC__HAS_X86INTRIN && defined FLAC__AVX_SUPPORTED | |||
| fprintf(stderr, " AVX ........ %c\n", info->ia32.avx ? 'Y' : 'n'); | |||
| fprintf(stderr, " FMA ........ %c\n", info->ia32.fma ? 'Y' : 'n'); | |||
| fprintf(stderr, " AVX2 ....... %c\n", info->ia32.avx2 ? 'Y' : 'n'); | |||
| # endif | |||
| #endif | |||
| /* | |||
| * now have to check for OS support of SSE/SSE2 | |||
| */ | |||
| if(info->data.ia32.fxsr || info->data.ia32.sse || info->data.ia32.sse2) { | |||
| /* | |||
| * now have to check for OS support of SSE instructions | |||
| */ | |||
| if(info->ia32.sse) { | |||
| #if defined FLAC__NO_SSE_OS | |||
| /* assume user knows better than us; turn it off */ | |||
| info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||
| /* assume user knows better than us; turn it off */ | |||
| disable_sse(info); | |||
| #elif defined FLAC__SSE_OS | |||
| /* assume user knows better than us; leave as detected above */ | |||
| /* assume user knows better than us; leave as detected above */ | |||
| #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__APPLE__) | |||
| int sse = 0; | |||
| size_t len; | |||
| /* at least one of these must work: */ | |||
| len = sizeof(sse); sse = sse || (sysctlbyname("hw.instruction_sse", &sse, &len, NULL, 0) == 0 && sse); | |||
| len = sizeof(sse); sse = sse || (sysctlbyname("hw.optional.sse" , &sse, &len, NULL, 0) == 0 && sse); /* __APPLE__ ? */ | |||
| if(!sse) | |||
| info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||
| int sse = 0; | |||
| size_t len; | |||
| /* at least one of these must work: */ | |||
| len = sizeof(sse); sse = sse || (sysctlbyname("hw.instruction_sse", &sse, &len, NULL, 0) == 0 && sse); | |||
| len = sizeof(sse); sse = sse || (sysctlbyname("hw.optional.sse" , &sse, &len, NULL, 0) == 0 && sse); /* __APPLE__ ? */ | |||
| if(!sse) | |||
| disable_sse(info); | |||
| #elif defined(__NetBSD__) || defined (__OpenBSD__) | |||
| # if __NetBSD_Version__ >= 105250000 || (defined __OpenBSD__) | |||
| int val = 0, mib[2] = { CTL_MACHDEP, CPU_SSE }; | |||
| size_t len = sizeof(val); | |||
| if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val) | |||
| info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||
| else { /* double-check SSE2 */ | |||
| mib[1] = CPU_SSE2; | |||
| len = sizeof(val); | |||
| if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val) | |||
| info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||
| int val = 0, mib[2] = { CTL_MACHDEP, CPU_SSE }; | |||
| size_t len = sizeof(val); | |||
| if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val) | |||
| disable_sse(info); | |||
| else { /* double-check SSE2 */ | |||
| mib[1] = CPU_SSE2; | |||
| len = sizeof(val); | |||
| if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val) { | |||
| disable_sse(info); | |||
| info->ia32.sse = true; | |||
| } | |||
| } | |||
| # else | |||
| info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||
| disable_sse(info); | |||
| # endif | |||
| #elif defined(__linux__) | |||
| int sse = 0; | |||
| struct sigaction sigill_save; | |||
| #ifdef USE_OBSOLETE_SIGCONTEXT_FLAVOR | |||
| if(0 == sigaction(SIGILL, NULL, &sigill_save) && signal(SIGILL, (void (*)(int))sigill_handler_sse_os) != SIG_ERR) | |||
| #else | |||
| struct sigaction sigill_sse; | |||
| sigill_sse.sa_sigaction = sigill_handler_sse_os; | |||
| __sigemptyset(&sigill_sse.sa_mask); | |||
| sigill_sse.sa_flags = SA_SIGINFO | SA_RESETHAND; /* SA_RESETHAND just in case our SIGILL return jump breaks, so we don't get stuck in a loop */ | |||
| if(0 == sigaction(SIGILL, &sigill_sse, &sigill_save)) | |||
| #endif | |||
| { | |||
| /* http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html */ | |||
| /* see sigill_handler_sse_os() for an explanation of the following: */ | |||
| asm volatile ( | |||
| "xorl %0,%0\n\t" /* for some reason, still need to do this to clear 'sse' var */ | |||
| "xorps %%xmm0,%%xmm0\n\t" /* will cause SIGILL if unsupported by OS */ | |||
| "incl %0\n\t" /* SIGILL handler will jump over this */ | |||
| /* landing zone */ | |||
| "nop\n\t" /* SIGILL jump lands here if "inc" is 9 bytes */ | |||
| "nop\n\t" | |||
| "nop\n\t" | |||
| "nop\n\t" | |||
| "nop\n\t" | |||
| "nop\n\t" | |||
| "nop\n\t" /* SIGILL jump lands here if "inc" is 3 bytes (expected) */ | |||
| "nop\n\t" | |||
| "nop" /* SIGILL jump lands here if "inc" is 1 byte */ | |||
| : "=r"(sse) | |||
| : "r"(sse) | |||
| ); | |||
| sigaction(SIGILL, &sigill_save, NULL); | |||
| } | |||
| int sse = 0; | |||
| struct sigaction sigill_save; | |||
| struct sigaction sigill_sse; | |||
| sigill_sse.sa_sigaction = sigill_handler_sse_os; | |||
| __sigemptyset(&sigill_sse.sa_mask); | |||
| sigill_sse.sa_flags = SA_SIGINFO | SA_RESETHAND; /* SA_RESETHAND just in case our SIGILL return jump breaks, so we don't get stuck in a loop */ | |||
| if(0 == sigaction(SIGILL, &sigill_sse, &sigill_save)) | |||
| { | |||
| /* http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html */ | |||
| /* see sigill_handler_sse_os() for an explanation of the following: */ | |||
| asm volatile ( | |||
| "xorps %%xmm0,%%xmm0\n\t" /* will cause SIGILL if unsupported by OS */ | |||
| "incl %0\n\t" /* SIGILL handler will jump over this */ | |||
| /* landing zone */ | |||
| "nop\n\t" /* SIGILL jump lands here if "inc" is 9 bytes */ | |||
| "nop\n\t" | |||
| "nop\n\t" | |||
| "nop\n\t" | |||
| "nop\n\t" | |||
| "nop\n\t" | |||
| "nop\n\t" /* SIGILL jump lands here if "inc" is 3 bytes (expected) */ | |||
| "nop\n\t" | |||
| "nop" /* SIGILL jump lands here if "inc" is 1 byte */ | |||
| : "=r"(sse) | |||
| : "0"(sse) | |||
| ); | |||
| if(!sse) | |||
| info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||
| sigaction(SIGILL, &sigill_save, NULL); | |||
| } | |||
| if(!sse) | |||
| disable_sse(info); | |||
| #elif defined(_MSC_VER) | |||
| # ifdef USE_TRY_CATCH_FLAVOR | |||
| _try { | |||
| __asm { | |||
| # if _MSC_VER <= 1200 | |||
| /* VC6 assembler doesn't know SSE, have to emit bytecode instead */ | |||
| _emit 0x0F | |||
| _emit 0x57 | |||
| _emit 0xC0 | |||
| # else | |||
| xorps xmm0,xmm0 | |||
| # endif | |||
| } | |||
| } | |||
| _except(EXCEPTION_EXECUTE_HANDLER) { | |||
| if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION) | |||
| info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||
| } | |||
| # else | |||
| int sse = 0; | |||
| LPTOP_LEVEL_EXCEPTION_FILTER save = SetUnhandledExceptionFilter(sigill_handler_sse_os); | |||
| /* see GCC version above for explanation */ | |||
| /* http://msdn2.microsoft.com/en-us/library/4ks26t93.aspx */ | |||
| /* http://www.codeproject.com/cpp/gccasm.asp */ | |||
| /* http://www.hick.org/~mmiller/msvc_inline_asm.html */ | |||
| __try { | |||
| __asm { | |||
| # if _MSC_VER <= 1200 | |||
| /* VC6 assembler doesn't know SSE, have to emit bytecode instead */ | |||
| _emit 0x0F | |||
| _emit 0x57 | |||
| _emit 0xC0 | |||
| # else | |||
| xorps xmm0,xmm0 | |||
| # endif | |||
| inc sse | |||
| nop | |||
| nop | |||
| nop | |||
| nop | |||
| nop | |||
| nop | |||
| nop | |||
| nop | |||
| nop | |||
| } | |||
| SetUnhandledExceptionFilter(save); | |||
| if(!sse) | |||
| info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||
| # endif | |||
| } | |||
| __except(EXCEPTION_EXECUTE_HANDLER) { | |||
| if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION) | |||
| disable_sse(info); | |||
| } | |||
| #elif defined(__GNUC__) /* MinGW goes here */ | |||
| int sse = 0; | |||
| /* Based on the idea described in Agner Fog's manual "Optimizing subroutines in assembly language" */ | |||
| /* In theory, not guaranteed to detect lack of OS SSE support on some future Intel CPUs, but in practice works (see the aforementioned manual) */ | |||
| if (ia32_fxsr) { | |||
| struct { | |||
| FLAC__uint32 buff[128]; | |||
| } __attribute__((aligned(16))) fxsr; | |||
| FLAC__uint32 old_val, new_val; | |||
| asm volatile ("fxsave %0" : "=m" (fxsr) : "m" (fxsr)); | |||
| old_val = fxsr.buff[50]; | |||
| fxsr.buff[50] ^= 0x0013c0de; /* change value in the buffer */ | |||
| asm volatile ("fxrstor %0" : "=m" (fxsr) : "m" (fxsr)); /* try to change SSE register */ | |||
| fxsr.buff[50] = old_val; /* restore old value in the buffer */ | |||
| asm volatile ("fxsave %0 " : "=m" (fxsr) : "m" (fxsr)); /* old value will be overwritten if SSE register was changed */ | |||
| new_val = fxsr.buff[50]; /* == old_val if FXRSTOR didn't change SSE register and (old_val ^ 0x0013c0de) otherwise */ | |||
| fxsr.buff[50] = old_val; /* again restore old value in the buffer */ | |||
| asm volatile ("fxrstor %0" : "=m" (fxsr) : "m" (fxsr)); /* restore old values of registers */ | |||
| if ((old_val^new_val) == 0x0013c0de) | |||
| sse = 1; | |||
| } | |||
| if(!sse) | |||
| disable_sse(info); | |||
| #else | |||
| /* no way to test, disable to be safe */ | |||
| info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||
| /* no way to test, disable to be safe */ | |||
| disable_sse(info); | |||
| #endif | |||
| #ifdef DEBUG | |||
| fprintf(stderr, " SSE OS sup . %c\n", info->data.ia32.sse ? 'Y' : 'n'); | |||
| fprintf(stderr, " SSE OS sup . %c\n", info->ia32.sse ? 'Y' : 'n'); | |||
| #endif | |||
| } | |||
| else /* info->ia32.sse == false */ | |||
| disable_sse(info); | |||
| } | |||
| /* | |||
| * now have to check for OS support of AVX instructions | |||
| */ | |||
| if(info->ia32.avx && ia32_osxsave) { | |||
| FLAC__uint32 ecr = FLAC__cpu_xgetbv_x86(); | |||
| if ((ecr & 0x6) != 0x6) | |||
| disable_avx(info); | |||
| #ifdef DEBUG | |||
| fprintf(stderr, " AVX OS sup . %c\n", info->ia32.avx ? 'Y' : 'n'); | |||
| #endif | |||
| } | |||
| else /* no OS AVX support*/ | |||
| disable_avx(info); | |||
| #else | |||
| info->use_asm = false; | |||
| #endif | |||
| /* | |||
| * PPC-specific | |||
| * x86-64-specific | |||
| */ | |||
| #elif defined FLAC__CPU_PPC | |||
| info->type = FLAC__CPUINFO_TYPE_PPC; | |||
| # if !defined FLAC__NO_ASM | |||
| #elif defined FLAC__CPU_X86_64 | |||
| FLAC__bool x86_osxsave = false; | |||
| (void) x86_osxsave; /* to avoid warnings about unused variables */ | |||
| memset(info, 0, sizeof(*info)); | |||
| info->type = FLAC__CPUINFO_TYPE_X86_64; | |||
| #if !defined FLAC__NO_ASM && defined FLAC__HAS_X86INTRIN | |||
| info->use_asm = true; | |||
| # ifdef FLAC__USE_ALTIVEC | |||
| # if defined FLAC__SYS_DARWIN | |||
| { | |||
| int val = 0, mib[2] = { CTL_HW, HW_VECTORUNIT }; | |||
| size_t len = sizeof(val); | |||
| info->data.ppc.altivec = !(sysctl(mib, 2, &val, &len, NULL, 0) || !val); | |||
| /* http://www.sandpile.org/x86/cpuid.htm */ | |||
| FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx; | |||
| FLAC__cpu_info_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx); | |||
| info->x86.sse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 )? true : false; | |||
| info->x86.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3)? true : false; | |||
| info->x86.sse41 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE41)? true : false; | |||
| info->x86.sse42 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE42)? true : false; | |||
| #if defined FLAC__AVX_SUPPORTED | |||
| x86_osxsave = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_OSXSAVE)? true : false; | |||
| info->x86.avx = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_AVX )? true : false; | |||
| info->x86.fma = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_FMA )? true : false; | |||
| FLAC__cpu_info_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx); | |||
| info->x86.avx2 = (flags_ebx & FLAC__CPUINFO_IA32_CPUID_AVX2 )? true : false; | |||
| #endif | |||
| } | |||
| { | |||
| host_basic_info_data_t hostInfo; | |||
| mach_msg_type_number_t infoCount; | |||
| infoCount = HOST_BASIC_INFO_COUNT; | |||
| host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount); | |||
| #ifdef DEBUG | |||
| fprintf(stderr, "CPU info (x86-64):\n"); | |||
| fprintf(stderr, " SSE3 ....... %c\n", info->x86.sse3 ? 'Y' : 'n'); | |||
| fprintf(stderr, " SSSE3 ...... %c\n", info->x86.ssse3 ? 'Y' : 'n'); | |||
| fprintf(stderr, " SSE41 ...... %c\n", info->x86.sse41 ? 'Y' : 'n'); | |||
| fprintf(stderr, " SSE42 ...... %c\n", info->x86.sse42 ? 'Y' : 'n'); | |||
| # if defined FLAC__AVX_SUPPORTED | |||
| fprintf(stderr, " AVX ........ %c\n", info->x86.avx ? 'Y' : 'n'); | |||
| fprintf(stderr, " FMA ........ %c\n", info->x86.fma ? 'Y' : 'n'); | |||
| fprintf(stderr, " AVX2 ....... %c\n", info->x86.avx2 ? 'Y' : 'n'); | |||
| # endif | |||
| #endif | |||
| info->data.ppc.ppc64 = (hostInfo.cpu_type == CPU_TYPE_POWERPC) && (hostInfo.cpu_subtype == CPU_SUBTYPE_POWERPC_970); | |||
| /* | |||
| * now have to check for OS support of AVX instructions | |||
| */ | |||
| if(info->x86.avx && x86_osxsave) { | |||
| FLAC__uint32 ecr = FLAC__cpu_xgetbv_x86(); | |||
| if ((ecr & 0x6) != 0x6) | |||
| disable_avx(info); | |||
| #ifdef DEBUG | |||
| fprintf(stderr, " AVX OS sup . %c\n", info->x86.avx ? 'Y' : 'n'); | |||
| #endif | |||
| } | |||
| # else /* FLAC__USE_ALTIVEC && !FLAC__SYS_DARWIN */ | |||
| { | |||
| /* no Darwin, do it the brute-force way */ | |||
| /* @@@@@@ this is not thread-safe; replace with SSE OS method above or remove */ | |||
| info->data.ppc.altivec = 0; | |||
| info->data.ppc.ppc64 = 0; | |||
| else /* no OS AVX support*/ | |||
| disable_avx(info); | |||
| #else | |||
| info->use_asm = false; | |||
| #endif | |||
| signal (SIGILL, sigill_handler); | |||
| canjump = 0; | |||
| if (!sigsetjmp (jmpbuf, 1)) { | |||
| canjump = 1; | |||
| /* | |||
| * unknown CPU | |||
| */ | |||
| #else | |||
| info->type = FLAC__CPUINFO_TYPE_UNKNOWN; | |||
| info->use_asm = false; | |||
| #endif | |||
| } | |||
| asm volatile ( | |||
| "mtspr 256, %0\n\t" | |||
| "vand %%v0, %%v0, %%v0" | |||
| : | |||
| : "r" (-1) | |||
| ); | |||
| #if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN | |||
| info->data.ppc.altivec = 1; | |||
| } | |||
| canjump = 0; | |||
| if (!sigsetjmp (jmpbuf, 1)) { | |||
| int x = 0; | |||
| canjump = 1; | |||
| /* PPC64 hardware implements the cntlzd instruction */ | |||
| asm volatile ("cntlzd %0, %1" : "=r" (x) : "r" (x) ); | |||
| #if defined _MSC_VER | |||
| #include <intrin.h> /* for __cpuid() and _xgetbv() */ | |||
| #elif defined __GNUC__ && defined HAVE_CPUID_H | |||
| #include <cpuid.h> /* for __get_cpuid() and __get_cpuid_max() */ | |||
| #endif | |||
| info->data.ppc.ppc64 = 1; | |||
| } | |||
| signal (SIGILL, SIG_DFL); /*@@@@@@ should save and restore old signal */ | |||
| FLAC__uint32 FLAC__cpu_have_cpuid_x86(void) | |||
| { | |||
| #ifdef FLAC__CPU_X86_64 | |||
| return 1; | |||
| #else | |||
| # if defined _MSC_VER || defined __INTEL_COMPILER /* Do they support CPUs w/o CPUID support (or OSes that work on those CPUs)? */ | |||
| FLAC__uint32 flags1, flags2; | |||
| __asm { | |||
| pushfd | |||
| pushfd | |||
| pop eax | |||
| mov flags1, eax | |||
| xor eax, 0x200000 | |||
| push eax | |||
| popfd | |||
| pushfd | |||
| pop eax | |||
| mov flags2, eax | |||
| popfd | |||
| } | |||
| # endif | |||
| # else /* !FLAC__USE_ALTIVEC */ | |||
| info->data.ppc.altivec = 0; | |||
| info->data.ppc.ppc64 = 0; | |||
| # endif | |||
| if (((flags1^flags2) & 0x200000) != 0) | |||
| return 1; | |||
| else | |||
| return 0; | |||
| # elif defined __GNUC__ && defined HAVE_CPUID_H | |||
| if (__get_cpuid_max(0, 0) != 0) | |||
| return 1; | |||
| else | |||
| return 0; | |||
| # else | |||
| info->use_asm = false; | |||
| return 0; | |||
| # endif | |||
| #endif | |||
| } | |||
| /* | |||
| * unknown CPI | |||
| */ | |||
| void FLAC__cpu_info_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx) | |||
| { | |||
| (void) level; | |||
| #if defined _MSC_VER || defined __INTEL_COMPILER | |||
| int cpuinfo[4]; | |||
| int ext = level & 0x80000000; | |||
| __cpuid(cpuinfo, ext); | |||
| if((unsigned)cpuinfo[0] < level) { | |||
| *eax = *ebx = *ecx = *edx = 0; | |||
| return; | |||
| } | |||
| #if defined FLAC__AVX_SUPPORTED | |||
| __cpuidex(cpuinfo, level, 0); /* for AVX2 detection */ | |||
| #else | |||
| info->type = FLAC__CPUINFO_TYPE_UNKNOWN; | |||
| info->use_asm = false; | |||
| __cpuid(cpuinfo, level); /* some old compilers don't support __cpuidex */ | |||
| #endif | |||
| *eax = cpuinfo[0]; *ebx = cpuinfo[1]; *ecx = cpuinfo[2]; *edx = cpuinfo[3]; | |||
| #elif defined __GNUC__ && defined HAVE_CPUID_H | |||
| FLAC__uint32 ext = level & 0x80000000; | |||
| __cpuid(ext, *eax, *ebx, *ecx, *edx); | |||
| if (*eax < level) { | |||
| *eax = *ebx = *ecx = *edx = 0; | |||
| return; | |||
| } | |||
| __cpuid_count(level, 0, *eax, *ebx, *ecx, *edx); | |||
| #else | |||
| *eax = *ebx = *ecx = *edx = 0; | |||
| #endif | |||
| } | |||
| FLAC__uint32 FLAC__cpu_xgetbv_x86(void) | |||
| { | |||
| #if (defined _MSC_VER || defined __INTEL_COMPILER) && defined FLAC__AVX_SUPPORTED | |||
| return (FLAC__uint32)_xgetbv(0); | |||
| #elif defined __GNUC__ | |||
| FLAC__uint32 lo, hi; | |||
| asm volatile (".byte 0x0f, 0x01, 0xd0" : "=a"(lo), "=d"(hi) : "c" (0)); | |||
| return lo; | |||
| #else | |||
| return 0; | |||
| #endif | |||
| } | |||
| #endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */ | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -30,7 +30,7 @@ | |||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #if HAVE_CONFIG_H | |||
| #ifdef HAVE_CONFIG_H | |||
| # include <config.h> | |||
| #endif | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -30,21 +30,17 @@ | |||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #if HAVE_CONFIG_H | |||
| #ifdef HAVE_CONFIG_H | |||
| # include <config.h> | |||
| #endif | |||
| #include <math.h> | |||
| #include <string.h> | |||
| #include "../compat.h" | |||
| #include "include/private/bitmath.h" | |||
| #include "include/private/fixed.h" | |||
| #include "../assert.h" | |||
| #ifndef M_LN2 | |||
| /* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */ | |||
| #define M_LN2 0.69314718055994530942 | |||
| #endif | |||
| #ifdef local_abs | |||
| #undef local_abs | |||
| #endif | |||
| @@ -320,20 +316,11 @@ unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsig | |||
| FLAC__ASSERT(data_len > 0 || total_error_3 == 0); | |||
| FLAC__ASSERT(data_len > 0 || total_error_4 == 0); | |||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||
| #if defined _MSC_VER || defined __MINGW32__ | |||
| /* with MSVC you have to spoon feed it the casting */ | |||
| residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||
| residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||
| residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||
| residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||
| residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||
| #else | |||
| residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||
| residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||
| residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||
| residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||
| residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||
| #endif | |||
| #else | |||
| residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_wide_integerized(total_error_0, data_len) : 0; | |||
| residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_wide_integerized(total_error_1, data_len) : 0; | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2004-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -30,7 +30,7 @@ | |||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #if HAVE_CONFIG_H | |||
| #ifdef HAVE_CONFIG_H | |||
| # include <config.h> | |||
| #endif | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -30,7 +30,7 @@ | |||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #if HAVE_CONFIG_H | |||
| #ifdef HAVE_CONFIG_H | |||
| # include <config.h> | |||
| #endif | |||
| @@ -45,12 +45,7 @@ | |||
| /* VERSION should come from configure */ | |||
| FLAC_API const char *FLAC__VERSION_STRING = VERSION; | |||
| #if defined _MSC_VER || defined __BORLANDC__ || defined __MINW32__ | |||
| /* yet one more hack because of MSVC6: */ | |||
| FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC 1.3.0 20130526"; | |||
| #else | |||
| FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " VERSION " 20130526"; | |||
| #endif | |||
| FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " VERSION " 20141125"; | |||
| FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' }; | |||
| FLAC_API const unsigned FLAC__STREAM_SYNC = 0x664C6143; | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2001-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -34,6 +34,7 @@ | |||
| #define FLAC__PRIVATE__BITMATH_H | |||
| #include "../../../ordinals.h" | |||
| #include "../../../assert.h" | |||
| /* for CHAR_BIT */ | |||
| #include <limits.h> | |||
| @@ -74,16 +75,19 @@ static inline unsigned int FLAC__clz_soft_uint32(unsigned int word) | |||
| static inline unsigned int FLAC__clz_uint32(FLAC__uint32 v) | |||
| { | |||
| /* Never used with input 0 */ | |||
| FLAC__ASSERT(v > 0); | |||
| #if defined(__INTEL_COMPILER) | |||
| return _bit_scan_reverse(v) ^ 31U; | |||
| #elif defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) | |||
| /* This will translate either to (bsr ^ 31U), clz , ctlz, cntlz, lzcnt depending on | |||
| * -march= setting or to a software rutine in exotic machines. */ | |||
| * -march= setting or to a software routine in exotic machines. */ | |||
| return __builtin_clz(v); | |||
| #elif defined(_MSC_VER) && (_MSC_VER >= 1400) | |||
| FLAC__uint32 idx; | |||
| _BitScanReverse((DWORD*) &idx, v); | |||
| return idx ^ 31U; | |||
| { | |||
| unsigned long idx; | |||
| _BitScanReverse(&idx, v); | |||
| return idx ^ 31U; | |||
| } | |||
| #else | |||
| return FLAC__clz_soft_uint32(v); | |||
| #endif | |||
| @@ -99,7 +103,7 @@ static inline unsigned int FLAC__clz2_uint32(FLAC__uint32 v) | |||
| /* An example of what FLAC__bitmath_ilog2() computes: | |||
| * | |||
| * ilog2( 0) = undefined | |||
| * ilog2( 0) = assertion failure | |||
| * ilog2( 1) = 0 | |||
| * ilog2( 2) = 1 | |||
| * ilog2( 3) = 1 | |||
| @@ -122,45 +126,56 @@ static inline unsigned int FLAC__clz2_uint32(FLAC__uint32 v) | |||
| static inline unsigned FLAC__bitmath_ilog2(FLAC__uint32 v) | |||
| { | |||
| FLAC__ASSERT(v > 0); | |||
| #if defined(__INTEL_COMPILER) | |||
| return _bit_scan_reverse(v); | |||
| #elif defined(_MSC_VER) && (_MSC_VER >= 1400) | |||
| { | |||
| unsigned long idx; | |||
| _BitScanReverse(&idx, v); | |||
| return idx; | |||
| } | |||
| #else | |||
| return sizeof(FLAC__uint32) * CHAR_BIT - 1 - FLAC__clz_uint32(v); | |||
| #endif | |||
| } | |||
| #ifdef FLAC__INTEGER_ONLY_LIBRARY /*Unused otherwise */ | |||
| #ifdef FLAC__INTEGER_ONLY_LIBRARY /* Unused otherwise */ | |||
| static inline unsigned FLAC__bitmath_ilog2_wide(FLAC__uint64 v) | |||
| { | |||
| if (v == 0) | |||
| return 0; | |||
| FLAC__ASSERT(v > 0); | |||
| #if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) | |||
| return sizeof(FLAC__uint64) * CHAR_BIT - 1 - __builtin_clzll(v); | |||
| /* Sorry, only supported in win64/Itanium.. */ | |||
| #elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && (defined(_M_IA64) || defined(_WIN64)) | |||
| FLAC__uint64 idx; | |||
| _BitScanReverse64(&idx, v); | |||
| return idx ^ 63U; | |||
| /* Sorry, only supported in x64/Itanium.. and both have fast FPU which makes integer-only encoder pointless */ | |||
| #elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && (defined(_M_IA64) || defined(_M_X64)) | |||
| { | |||
| unsigned long idx; | |||
| _BitScanReverse64(&idx, v); | |||
| return idx; | |||
| } | |||
| #else | |||
| /* Brain-damaged compilers will use the fastest possible way that is, | |||
| /* Brain-damaged compilers will use the fastest possible way that is, | |||
| de Bruijn sequences (http://supertech.csail.mit.edu/papers/debruijn.pdf) | |||
| (C) Timothy B. Terriberry (tterribe@xiph.org) 2001-2009 LGPL (v2 or later). | |||
| (C) Timothy B. Terriberry (tterribe@xiph.org) 2001-2009 CC0 (Public domain). | |||
| */ | |||
| static const unsigned char DEBRUIJN_IDX64[64]={ | |||
| 0, 1, 2, 7, 3,13, 8,19, 4,25,14,28, 9,34,20,40, | |||
| 5,17,26,38,15,46,29,48,10,31,35,54,21,50,41,57, | |||
| 63, 6,12,18,24,27,33,39,16,37,45,47,30,53,49,56, | |||
| 62,11,23,32,36,44,52,55,61,22,43,51,60,42,59,58 | |||
| }; | |||
| int ret; | |||
| ret= v>0; | |||
| v|= v>>1; | |||
| v|= v>>2; | |||
| v|= v>>4; | |||
| v|= v>>8; | |||
| v|= v>>16; | |||
| v|= v>>32; | |||
| v= (v>>1)+1; | |||
| ret+=DEBRUIJN_IDX64[v*0x218A392CD3D5DBF>>58&0x3F]; | |||
| return ret; | |||
| { | |||
| static const unsigned char DEBRUIJN_IDX64[64]={ | |||
| 0, 1, 2, 7, 3,13, 8,19, 4,25,14,28, 9,34,20,40, | |||
| 5,17,26,38,15,46,29,48,10,31,35,54,21,50,41,57, | |||
| 63, 6,12,18,24,27,33,39,16,37,45,47,30,53,49,56, | |||
| 62,11,23,32,36,44,52,55,61,22,43,51,60,42,59,58 | |||
| }; | |||
| v|= v>>1; | |||
| v|= v>>2; | |||
| v|= v>>4; | |||
| v|= v>>8; | |||
| v|= v>>16; | |||
| v|= v>>32; | |||
| v= (v>>1)+1; | |||
| return DEBRUIJN_IDX64[v*0x218A392CD3D5DBF>>58&0x3F]; | |||
| } | |||
| #endif | |||
| } | |||
| #endif | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -50,7 +50,7 @@ typedef FLAC__bool (*FLAC__BitReaderReadCallback)(FLAC__byte buffer[], size_t *b | |||
| */ | |||
| FLAC__BitReader *FLAC__bitreader_new(void); | |||
| void FLAC__bitreader_delete(FLAC__BitReader *br); | |||
| FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__CPUInfo cpu, FLAC__BitReaderReadCallback rcb, void *cd); | |||
| FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__BitReaderReadCallback rcb, void *cd); | |||
| void FLAC__bitreader_free(FLAC__BitReader *br); /* does not 'free(br)' */ | |||
| FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br); | |||
| void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out); | |||
| @@ -82,19 +82,10 @@ FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, F | |||
| FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, unsigned *val); | |||
| FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, unsigned parameter); | |||
| FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter); | |||
| #ifndef FLAC__NO_ASM | |||
| # ifdef FLAC__CPU_IA32 | |||
| # ifdef FLAC__HAS_NASM | |||
| FLAC__bool FLAC__bitreader_read_rice_signed_block_asm_ia32_bswap(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter); | |||
| # endif | |||
| # endif | |||
| #endif | |||
| #if 0 /* UNUSED */ | |||
| FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, unsigned parameter); | |||
| FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, unsigned *val, unsigned parameter); | |||
| #endif | |||
| FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, unsigned *rawlen); | |||
| FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, unsigned *rawlen); | |||
| FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br); | |||
| #endif | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2001-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -41,49 +41,59 @@ | |||
| typedef enum { | |||
| FLAC__CPUINFO_TYPE_IA32, | |||
| FLAC__CPUINFO_TYPE_PPC, | |||
| FLAC__CPUINFO_TYPE_X86_64, | |||
| FLAC__CPUINFO_TYPE_UNKNOWN | |||
| } FLAC__CPUInfo_Type; | |||
| #if defined FLAC__CPU_IA32 | |||
| typedef struct { | |||
| FLAC__bool cpuid; | |||
| FLAC__bool bswap; | |||
| FLAC__bool cmov; | |||
| FLAC__bool mmx; | |||
| FLAC__bool fxsr; | |||
| FLAC__bool sse; | |||
| FLAC__bool sse2; | |||
| FLAC__bool sse3; | |||
| FLAC__bool ssse3; | |||
| FLAC__bool _3dnow; | |||
| FLAC__bool ext3dnow; | |||
| FLAC__bool extmmx; | |||
| FLAC__bool sse41; | |||
| FLAC__bool sse42; | |||
| FLAC__bool avx; | |||
| FLAC__bool avx2; | |||
| FLAC__bool fma; | |||
| } FLAC__CPUInfo_IA32; | |||
| #elif defined FLAC__CPU_X86_64 | |||
| typedef struct { | |||
| FLAC__bool altivec; | |||
| FLAC__bool ppc64; | |||
| } FLAC__CPUInfo_PPC; | |||
| FLAC__bool sse3; | |||
| FLAC__bool ssse3; | |||
| FLAC__bool sse41; | |||
| FLAC__bool sse42; | |||
| FLAC__bool avx; | |||
| FLAC__bool avx2; | |||
| FLAC__bool fma; | |||
| } FLAC__CPUInfo_x86; | |||
| #endif | |||
| typedef struct { | |||
| FLAC__bool use_asm; | |||
| FLAC__CPUInfo_Type type; | |||
| union { | |||
| FLAC__CPUInfo_IA32 ia32; | |||
| FLAC__CPUInfo_PPC ppc; | |||
| } data; | |||
| #if defined FLAC__CPU_IA32 | |||
| FLAC__CPUInfo_IA32 ia32; | |||
| #elif defined FLAC__CPU_X86_64 | |||
| FLAC__CPUInfo_x86 x86; | |||
| #endif | |||
| } FLAC__CPUInfo; | |||
| void FLAC__cpu_info(FLAC__CPUInfo *info); | |||
| #ifndef FLAC__NO_ASM | |||
| #ifdef FLAC__CPU_IA32 | |||
| #ifdef FLAC__HAS_NASM | |||
| # if defined FLAC__CPU_IA32 && defined FLAC__HAS_NASM | |||
| FLAC__uint32 FLAC__cpu_have_cpuid_asm_ia32(void); | |||
| void FLAC__cpu_info_asm_ia32(FLAC__uint32 *flags_edx, FLAC__uint32 *flags_ecx); | |||
| FLAC__uint32 FLAC__cpu_info_extended_amd_asm_ia32(void); | |||
| #endif | |||
| #endif | |||
| # endif | |||
| # if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN | |||
| FLAC__uint32 FLAC__cpu_have_cpuid_x86(void); | |||
| void FLAC__cpu_info_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx); | |||
| FLAC__uint32 FLAC__cpu_xgetbv_x86(void); | |||
| # endif | |||
| #endif | |||
| #endif | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -51,7 +51,7 @@ FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len); | |||
| */ | |||
| extern unsigned const FLAC__crc16_table[256]; | |||
| #define FLAC__CRC16_UPDATE(data, crc) (((((crc)<<8) & 0xffff) ^ FLAC__crc16_table[((crc)>>8) ^ (data)])) | |||
| #define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) & 0xffff) ^ FLAC__crc16_table[((crc)>>8) ^ (data)]) | |||
| /* this alternate may be faster on some systems/compilers */ | |||
| #if 0 | |||
| #define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) ^ FLAC__crc16_table[((crc)>>8) ^ (data)]) & 0xffff) | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -37,6 +37,7 @@ | |||
| #include <config.h> | |||
| #endif | |||
| #include "cpu.h" | |||
| #include "float.h" | |||
| #include "../../../format.h" | |||
| @@ -54,14 +55,22 @@ | |||
| */ | |||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||
| unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); | |||
| unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); | |||
| # ifndef FLAC__NO_ASM | |||
| # ifdef FLAC__CPU_IA32 | |||
| # ifdef FLAC__HAS_NASM | |||
| unsigned FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); | |||
| # if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN | |||
| # ifdef FLAC__SSE2_SUPPORTED | |||
| unsigned FLAC__fixed_compute_best_predictor_intrin_sse2(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]); | |||
| unsigned FLAC__fixed_compute_best_predictor_wide_intrin_sse2(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]); | |||
| # endif | |||
| # ifdef FLAC__SSSE3_SUPPORTED | |||
| unsigned FLAC__fixed_compute_best_predictor_intrin_ssse3(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); | |||
| unsigned FLAC__fixed_compute_best_predictor_wide_intrin_ssse3(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]); | |||
| # endif | |||
| # endif | |||
| # if defined FLAC__CPU_IA32 && defined FLAC__HAS_NASM | |||
| unsigned FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); | |||
| # endif | |||
| # endif | |||
| unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); | |||
| #else | |||
| unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); | |||
| unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2004-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -37,6 +37,7 @@ | |||
| #include <config.h> | |||
| #endif | |||
| #include "cpu.h" | |||
| #include "float.h" | |||
| #include "../../../format.h" | |||
| @@ -75,7 +76,15 @@ void FLAC__lpc_compute_autocorrelation_asm_ia32(const FLAC__real data[], unsigne | |||
| void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); | |||
| void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); | |||
| void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); | |||
| void FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); | |||
| void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_16(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); | |||
| # endif | |||
| # endif | |||
| # if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN | |||
| # ifdef FLAC__SSE_SUPPORTED | |||
| void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); | |||
| void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); | |||
| void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); | |||
| void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); | |||
| # endif | |||
| # endif | |||
| #endif | |||
| @@ -145,6 +154,22 @@ void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *da | |||
| # ifdef FLAC__HAS_NASM | |||
| void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); | |||
| void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); | |||
| void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_asm_ia32(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); | |||
| # endif | |||
| # endif | |||
| # if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN | |||
| # ifdef FLAC__SSE2_SUPPORTED | |||
| void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); | |||
| void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); | |||
| # endif | |||
| # ifdef FLAC__SSE4_1_SUPPORTED | |||
| void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); | |||
| void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); | |||
| # endif | |||
| # ifdef FLAC__AVX2_SUPPORTED | |||
| void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); | |||
| void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); | |||
| void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); | |||
| # endif | |||
| # endif | |||
| #endif | |||
| @@ -173,11 +198,17 @@ void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], unsigned data_l | |||
| # ifdef FLAC__HAS_NASM | |||
| void FLAC__lpc_restore_signal_asm_ia32(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); | |||
| void FLAC__lpc_restore_signal_asm_ia32_mmx(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); | |||
| void FLAC__lpc_restore_signal_wide_asm_ia32(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); | |||
| # endif /* FLAC__HAS_NASM */ | |||
| # elif defined FLAC__CPU_PPC | |||
| void FLAC__lpc_restore_signal_asm_ppc_altivec_16(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); | |||
| void FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); | |||
| # endif/* FLAC__CPU_IA32 || FLAC__CPU_PPC */ | |||
| # endif /* FLAC__CPU_IA32 */ | |||
| # if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN | |||
| # ifdef FLAC__SSE2_SUPPORTED | |||
| void FLAC__lpc_restore_signal_16_intrin_sse2(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); | |||
| # endif | |||
| # ifdef FLAC__SSE4_1_SUPPORTED | |||
| void FLAC__lpc_restore_signal_wide_intrin_sse41(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); | |||
| # endif | |||
| # endif | |||
| #endif /* FLAC__NO_ASM */ | |||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||
| @@ -28,11 +28,17 @@ | |||
| #include "../../../ordinals.h" | |||
| typedef union { | |||
| FLAC__byte *p8; | |||
| FLAC__int16 *p16; | |||
| FLAC__int32 *p32; | |||
| } FLAC__multibyte; | |||
| typedef struct { | |||
| FLAC__uint32 in[16]; | |||
| FLAC__uint32 buf[4]; | |||
| FLAC__uint32 bytes[2]; | |||
| FLAC__byte *internal_buf; | |||
| FLAC__multibyte internal_buf; | |||
| size_t capacity; | |||
| } FLAC__MD5Context; | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2001-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2002-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -0,0 +1,67 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| * are met: | |||
| * | |||
| * - Redistributions of source code must retain the above copyright | |||
| * notice, this list of conditions and the following disclaimer. | |||
| * | |||
| * - Redistributions in binary form must reproduce the above copyright | |||
| * notice, this list of conditions and the following disclaimer in the | |||
| * documentation and/or other materials provided with the distribution. | |||
| * | |||
| * - Neither the name of the Xiph.org Foundation nor the names of its | |||
| * contributors may be used to endorse or promote products derived from | |||
| * this software without specific prior written permission. | |||
| * | |||
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||
| * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |||
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR | |||
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |||
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |||
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |||
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |||
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |||
| * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #ifndef FLAC__PRIVATE__STREAM_ENCODER_H | |||
| #define FLAC__PRIVATE__STREAM_ENCODER_H | |||
| #ifdef HAVE_CONFIG_H | |||
| #include <config.h> | |||
| #endif | |||
| /* | |||
| * This is used to avoid overflow with unusual signals in 32-bit | |||
| * accumulator in the *precompute_partition_info_sums_* functions. | |||
| */ | |||
| #define FLAC__MAX_EXTRA_RESIDUAL_BPS 4 | |||
| #if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN | |||
| #include "cpu.h" | |||
| #include "../../../format.h" | |||
| #ifdef FLAC__SSE2_SUPPORTED | |||
| extern void FLAC__precompute_partition_info_sums_intrin_sse2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], | |||
| unsigned residual_samples, unsigned predictor_order, unsigned min_partition_order, unsigned max_partition_order, unsigned bps); | |||
| #endif | |||
| #ifdef FLAC__SSSE3_SUPPORTED | |||
| extern void FLAC__precompute_partition_info_sums_intrin_ssse3(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], | |||
| unsigned residual_samples, unsigned predictor_order, unsigned min_partition_order, unsigned max_partition_order, unsigned bps); | |||
| #endif | |||
| #ifdef FLAC__AVX2_SUPPORTED | |||
| extern void FLAC__precompute_partition_info_sums_intrin_avx2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], | |||
| unsigned residual_samples, unsigned predictor_order, unsigned min_partition_order, unsigned max_partition_order, unsigned bps); | |||
| #endif | |||
| #endif | |||
| #endif | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2006-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -65,6 +65,8 @@ void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L); | |||
| void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L); | |||
| void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L); | |||
| void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p); | |||
| void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end); | |||
| void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end); | |||
| void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L); | |||
| #endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2001-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -40,6 +40,7 @@ | |||
| typedef struct FLAC__StreamDecoderProtected { | |||
| FLAC__StreamDecoderState state; | |||
| FLAC__StreamDecoderInitStatus initstate; | |||
| unsigned channels; | |||
| FLAC__ChannelAssignment channel_assignment; | |||
| unsigned bits_per_sample; | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2001-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -59,6 +59,8 @@ typedef enum { | |||
| FLAC__APODIZATION_RECTANGLE, | |||
| FLAC__APODIZATION_TRIANGLE, | |||
| FLAC__APODIZATION_TUKEY, | |||
| FLAC__APODIZATION_PARTIAL_TUKEY, | |||
| FLAC__APODIZATION_PUNCHOUT_TUKEY, | |||
| FLAC__APODIZATION_WELCH | |||
| } FLAC__ApodizationFunction; | |||
| @@ -71,6 +73,11 @@ typedef struct { | |||
| struct { | |||
| FLAC__real p; | |||
| } tukey; | |||
| struct { | |||
| FLAC__real p; | |||
| FLAC__real start; | |||
| FLAC__real end; | |||
| } multiple_tukey; | |||
| } parameters; | |||
| } FLAC__ApodizationSpecification; | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -30,7 +30,7 @@ | |||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #if HAVE_CONFIG_H | |||
| #ifdef HAVE_CONFIG_H | |||
| # include <config.h> | |||
| #endif | |||
| @@ -50,11 +50,6 @@ | |||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||
| #ifndef M_LN2 | |||
| /* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */ | |||
| #define M_LN2 0.69314718055994530942 | |||
| #endif | |||
| #if !defined(HAVE_LROUND) | |||
| #if defined(_MSC_VER) | |||
| #include <float.h> | |||
| @@ -65,7 +60,7 @@ | |||
| static inline long int lround(double x) { | |||
| return (long)(x + copysign (0.5, x)); | |||
| } | |||
| //If this fails, we are in the precence of a mid 90's compiler..move along... | |||
| /* If this fails, we are in the presence of a mid 90's compiler, move along... */ | |||
| #endif | |||
| void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], unsigned data_len) | |||
| @@ -160,7 +155,7 @@ void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned *max_o | |||
| lp_coeff[i][j] = (FLAC__real)(-lpc[j]); /* negate FIR filter coeff to get predictor coeff */ | |||
| error[i] = err; | |||
| /* see SF bug #1601812 http://sourceforge.net/tracker/index.php?func=detail&aid=1601812&group_id=13478&atid=113478 */ | |||
| /* see SF bug https://sourceforge.net/p/flac/bugs/234/ */ | |||
| if(err == 0.0) { | |||
| *max_order = i+1; | |||
| return; | |||
| @@ -264,7 +259,12 @@ int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, | |||
| return 0; | |||
| } | |||
| void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]) | |||
| #if defined(_MSC_VER) | |||
| // silence MSVC warnings about __restrict modifier | |||
| #pragma warning ( disable : 4028 ) | |||
| #endif | |||
| void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 * flac_restrict data, unsigned data_len, const FLAC__int32 * flac_restrict qlp_coeff, unsigned order, int lp_quantization, FLAC__int32 * flac_restrict residual) | |||
| #if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) | |||
| { | |||
| FLAC__int64 sumo; | |||
| @@ -524,7 +524,7 @@ void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, u | |||
| } | |||
| #endif | |||
| void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]) | |||
| void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 * flac_restrict data, unsigned data_len, const FLAC__int32 * flac_restrict qlp_coeff, unsigned order, int lp_quantization, FLAC__int32 * flac_restrict residual) | |||
| #if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) | |||
| { | |||
| unsigned i, j; | |||
| @@ -780,7 +780,7 @@ void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *da | |||
| #endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ | |||
| void FLAC__lpc_restore_signal(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]) | |||
| void FLAC__lpc_restore_signal(const FLAC__int32 * flac_restrict residual, unsigned data_len, const FLAC__int32 * flac_restrict qlp_coeff, unsigned order, int lp_quantization, FLAC__int32 * flac_restrict data) | |||
| #if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) | |||
| { | |||
| FLAC__int64 sumo; | |||
| @@ -1041,7 +1041,7 @@ void FLAC__lpc_restore_signal(const FLAC__int32 residual[], unsigned data_len, c | |||
| } | |||
| #endif | |||
| void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]) | |||
| void FLAC__lpc_restore_signal_wide(const FLAC__int32 * flac_restrict residual, unsigned data_len, const FLAC__int32 * flac_restrict qlp_coeff, unsigned order, int lp_quantization, FLAC__int32 * flac_restrict data) | |||
| #if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) | |||
| { | |||
| unsigned i, j; | |||
| @@ -1295,6 +1295,10 @@ void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], unsigned data_l | |||
| } | |||
| #endif | |||
| #if defined(_MSC_VER) | |||
| #pragma warning ( default : 4028 ) | |||
| #endif | |||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||
| FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__double lpc_error, unsigned total_samples) | |||
| @@ -1,4 +1,4 @@ | |||
| #if HAVE_CONFIG_H | |||
| #ifdef HAVE_CONFIG_H | |||
| # include <config.h> | |||
| #endif | |||
| @@ -7,6 +7,7 @@ | |||
| #include "include/private/md5.h" | |||
| #include "../alloc.h" | |||
| #include "../endswap.h" | |||
| /* | |||
| * This code implements the MD5 message-digest algorithm. | |||
| @@ -223,7 +224,7 @@ void FLAC__MD5Init(FLAC__MD5Context *ctx) | |||
| ctx->bytes[0] = 0; | |||
| ctx->bytes[1] = 0; | |||
| ctx->internal_buf = 0; | |||
| ctx->internal_buf.p8= 0; | |||
| ctx->capacity = 0; | |||
| } | |||
| @@ -259,9 +260,9 @@ void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *ctx) | |||
| byteSwap(ctx->buf, 4); | |||
| memcpy(digest, ctx->buf, 16); | |||
| if(0 != ctx->internal_buf) { | |||
| free(ctx->internal_buf); | |||
| ctx->internal_buf = 0; | |||
| if (0 != ctx->internal_buf.p8) { | |||
| free(ctx->internal_buf.p8); | |||
| ctx->internal_buf.p8= 0; | |||
| ctx->capacity = 0; | |||
| } | |||
| memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ | |||
| @@ -270,58 +271,124 @@ void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *ctx) | |||
| /* | |||
| * Convert the incoming audio signal to a byte stream | |||
| */ | |||
| static void format_input_(FLAC__byte *buf, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample) | |||
| static void format_input_(FLAC__multibyte *mbuf, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample) | |||
| { | |||
| FLAC__byte *buf_ = mbuf->p8; | |||
| FLAC__int16 *buf16 = mbuf->p16; | |||
| FLAC__int32 *buf32 = mbuf->p32; | |||
| FLAC__int32 a_word; | |||
| unsigned channel, sample; | |||
| register FLAC__int32 a_word; | |||
| register FLAC__byte *buf_ = buf; | |||
| #if WORDS_BIGENDIAN | |||
| #else | |||
| if(channels == 2 && bytes_per_sample == 2) { | |||
| FLAC__int16 *buf1_ = ((FLAC__int16*)buf_) + 1; | |||
| memcpy(buf_, signal[0], sizeof(FLAC__int32) * samples); | |||
| for(sample = 0; sample < samples; sample++, buf1_+=2) | |||
| *buf1_ = (FLAC__int16)signal[1][sample]; | |||
| } | |||
| else if(channels == 1 && bytes_per_sample == 2) { | |||
| FLAC__int16 *buf1_ = (FLAC__int16*)buf_; | |||
| for(sample = 0; sample < samples; sample++) | |||
| *buf1_++ = (FLAC__int16)signal[0][sample]; | |||
| } | |||
| else | |||
| #endif | |||
| if(bytes_per_sample == 2) { | |||
| if(channels == 2) { | |||
| for(sample = 0; sample < samples; sample++) { | |||
| a_word = signal[0][sample]; | |||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||
| *buf_++ = (FLAC__byte)a_word; | |||
| a_word = signal[1][sample]; | |||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||
| *buf_++ = (FLAC__byte)a_word; | |||
| /* Storage in the output buffer, buf, is little endian. */ | |||
| #define BYTES_CHANNEL_SELECTOR(bytes, channels) (bytes * 100 + channels) | |||
| /* First do the most commonly used combinations. */ | |||
| switch (BYTES_CHANNEL_SELECTOR (bytes_per_sample, channels)) { | |||
| /* One byte per sample. */ | |||
| case (BYTES_CHANNEL_SELECTOR (1, 1)): | |||
| for (sample = 0; sample < samples; sample++) | |||
| *buf_++ = signal[0][sample]; | |||
| return; | |||
| case (BYTES_CHANNEL_SELECTOR (1, 2)): | |||
| for (sample = 0; sample < samples; sample++) { | |||
| *buf_++ = signal[0][sample]; | |||
| *buf_++ = signal[1][sample]; | |||
| } | |||
| } | |||
| else if(channels == 1) { | |||
| for(sample = 0; sample < samples; sample++) { | |||
| return; | |||
| case (BYTES_CHANNEL_SELECTOR (1, 4)): | |||
| for (sample = 0; sample < samples; sample++) { | |||
| *buf_++ = signal[0][sample]; | |||
| *buf_++ = signal[1][sample]; | |||
| *buf_++ = signal[2][sample]; | |||
| *buf_++ = signal[3][sample]; | |||
| } | |||
| return; | |||
| case (BYTES_CHANNEL_SELECTOR (1, 6)): | |||
| for (sample = 0; sample < samples; sample++) { | |||
| *buf_++ = signal[0][sample]; | |||
| *buf_++ = signal[1][sample]; | |||
| *buf_++ = signal[2][sample]; | |||
| *buf_++ = signal[3][sample]; | |||
| *buf_++ = signal[4][sample]; | |||
| *buf_++ = signal[5][sample]; | |||
| } | |||
| return; | |||
| case (BYTES_CHANNEL_SELECTOR (1, 8)): | |||
| for (sample = 0; sample < samples; sample++) { | |||
| *buf_++ = signal[0][sample]; | |||
| *buf_++ = signal[1][sample]; | |||
| *buf_++ = signal[2][sample]; | |||
| *buf_++ = signal[3][sample]; | |||
| *buf_++ = signal[4][sample]; | |||
| *buf_++ = signal[5][sample]; | |||
| *buf_++ = signal[6][sample]; | |||
| *buf_++ = signal[7][sample]; | |||
| } | |||
| return; | |||
| /* Two bytes per sample. */ | |||
| case (BYTES_CHANNEL_SELECTOR (2, 1)): | |||
| for (sample = 0; sample < samples; sample++) | |||
| *buf16++ = H2LE_16(signal[0][sample]); | |||
| return; | |||
| case (BYTES_CHANNEL_SELECTOR (2, 2)): | |||
| for (sample = 0; sample < samples; sample++) { | |||
| *buf16++ = H2LE_16(signal[0][sample]); | |||
| *buf16++ = H2LE_16(signal[1][sample]); | |||
| } | |||
| return; | |||
| case (BYTES_CHANNEL_SELECTOR (2, 4)): | |||
| for (sample = 0; sample < samples; sample++) { | |||
| *buf16++ = H2LE_16(signal[0][sample]); | |||
| *buf16++ = H2LE_16(signal[1][sample]); | |||
| *buf16++ = H2LE_16(signal[2][sample]); | |||
| *buf16++ = H2LE_16(signal[3][sample]); | |||
| } | |||
| return; | |||
| case (BYTES_CHANNEL_SELECTOR (2, 6)): | |||
| for (sample = 0; sample < samples; sample++) { | |||
| *buf16++ = H2LE_16(signal[0][sample]); | |||
| *buf16++ = H2LE_16(signal[1][sample]); | |||
| *buf16++ = H2LE_16(signal[2][sample]); | |||
| *buf16++ = H2LE_16(signal[3][sample]); | |||
| *buf16++ = H2LE_16(signal[4][sample]); | |||
| *buf16++ = H2LE_16(signal[5][sample]); | |||
| } | |||
| return; | |||
| case (BYTES_CHANNEL_SELECTOR (2, 8)): | |||
| for (sample = 0; sample < samples; sample++) { | |||
| *buf16++ = H2LE_16(signal[0][sample]); | |||
| *buf16++ = H2LE_16(signal[1][sample]); | |||
| *buf16++ = H2LE_16(signal[2][sample]); | |||
| *buf16++ = H2LE_16(signal[3][sample]); | |||
| *buf16++ = H2LE_16(signal[4][sample]); | |||
| *buf16++ = H2LE_16(signal[5][sample]); | |||
| *buf16++ = H2LE_16(signal[6][sample]); | |||
| *buf16++ = H2LE_16(signal[7][sample]); | |||
| } | |||
| return; | |||
| /* Three bytes per sample. */ | |||
| case (BYTES_CHANNEL_SELECTOR (3, 1)): | |||
| for (sample = 0; sample < samples; sample++) { | |||
| a_word = signal[0][sample]; | |||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||
| *buf_++ = (FLAC__byte)a_word; | |||
| } | |||
| } | |||
| else { | |||
| for(sample = 0; sample < samples; sample++) { | |||
| for(channel = 0; channel < channels; channel++) { | |||
| a_word = signal[channel][sample]; | |||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||
| *buf_++ = (FLAC__byte)a_word; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| else if(bytes_per_sample == 3) { | |||
| if(channels == 2) { | |||
| for(sample = 0; sample < samples; sample++) { | |||
| return; | |||
| case (BYTES_CHANNEL_SELECTOR (3, 2)): | |||
| for (sample = 0; sample < samples; sample++) { | |||
| a_word = signal[0][sample]; | |||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||
| @@ -331,60 +398,90 @@ static void format_input_(FLAC__byte *buf, const FLAC__int32 * const signal[], u | |||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||
| *buf_++ = (FLAC__byte)a_word; | |||
| } | |||
| } | |||
| else if(channels == 1) { | |||
| for(sample = 0; sample < samples; sample++) { | |||
| a_word = signal[0][sample]; | |||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||
| *buf_++ = (FLAC__byte)a_word; | |||
| return; | |||
| /* Four bytes per sample. */ | |||
| case (BYTES_CHANNEL_SELECTOR (4, 1)): | |||
| for (sample = 0; sample < samples; sample++) | |||
| *buf32++ = H2LE_32(signal[0][sample]); | |||
| return; | |||
| case (BYTES_CHANNEL_SELECTOR (4, 2)): | |||
| for (sample = 0; sample < samples; sample++) { | |||
| *buf32++ = H2LE_32(signal[0][sample]); | |||
| *buf32++ = H2LE_32(signal[1][sample]); | |||
| } | |||
| } | |||
| else { | |||
| for(sample = 0; sample < samples; sample++) { | |||
| for(channel = 0; channel < channels; channel++) { | |||
| a_word = signal[channel][sample]; | |||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||
| *buf_++ = (FLAC__byte)a_word; | |||
| } | |||
| return; | |||
| case (BYTES_CHANNEL_SELECTOR (4, 4)): | |||
| for (sample = 0; sample < samples; sample++) { | |||
| *buf32++ = H2LE_32(signal[0][sample]); | |||
| *buf32++ = H2LE_32(signal[1][sample]); | |||
| *buf32++ = H2LE_32(signal[2][sample]); | |||
| *buf32++ = H2LE_32(signal[3][sample]); | |||
| } | |||
| } | |||
| } | |||
| else if(bytes_per_sample == 1) { | |||
| if(channels == 2) { | |||
| for(sample = 0; sample < samples; sample++) { | |||
| a_word = signal[0][sample]; | |||
| *buf_++ = (FLAC__byte)a_word; | |||
| a_word = signal[1][sample]; | |||
| *buf_++ = (FLAC__byte)a_word; | |||
| return; | |||
| case (BYTES_CHANNEL_SELECTOR (4, 6)): | |||
| for (sample = 0; sample < samples; sample++) { | |||
| *buf32++ = H2LE_32(signal[0][sample]); | |||
| *buf32++ = H2LE_32(signal[1][sample]); | |||
| *buf32++ = H2LE_32(signal[2][sample]); | |||
| *buf32++ = H2LE_32(signal[3][sample]); | |||
| *buf32++ = H2LE_32(signal[4][sample]); | |||
| *buf32++ = H2LE_32(signal[5][sample]); | |||
| } | |||
| } | |||
| else if(channels == 1) { | |||
| for(sample = 0; sample < samples; sample++) { | |||
| a_word = signal[0][sample]; | |||
| *buf_++ = (FLAC__byte)a_word; | |||
| return; | |||
| case (BYTES_CHANNEL_SELECTOR (4, 8)): | |||
| for (sample = 0; sample < samples; sample++) { | |||
| *buf32++ = H2LE_32(signal[0][sample]); | |||
| *buf32++ = H2LE_32(signal[1][sample]); | |||
| *buf32++ = H2LE_32(signal[2][sample]); | |||
| *buf32++ = H2LE_32(signal[3][sample]); | |||
| *buf32++ = H2LE_32(signal[4][sample]); | |||
| *buf32++ = H2LE_32(signal[5][sample]); | |||
| *buf32++ = H2LE_32(signal[6][sample]); | |||
| *buf32++ = H2LE_32(signal[7][sample]); | |||
| } | |||
| } | |||
| else { | |||
| for(sample = 0; sample < samples; sample++) { | |||
| for(channel = 0; channel < channels; channel++) { | |||
| return; | |||
| default: | |||
| break; | |||
| } | |||
| /* General version. */ | |||
| switch (bytes_per_sample) { | |||
| case 1: | |||
| for (sample = 0; sample < samples; sample++) | |||
| for (channel = 0; channel < channels; channel++) | |||
| *buf_++ = signal[channel][sample]; | |||
| return; | |||
| case 2: | |||
| for (sample = 0; sample < samples; sample++) | |||
| for (channel = 0; channel < channels; channel++) | |||
| *buf16++ = H2LE_16(signal[channel][sample]); | |||
| return; | |||
| case 3: | |||
| for (sample = 0; sample < samples; sample++) | |||
| for (channel = 0; channel < channels; channel++) { | |||
| a_word = signal[channel][sample]; | |||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||
| *buf_++ = (FLAC__byte)a_word; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| else { /* bytes_per_sample == 4, maybe optimize more later */ | |||
| for(sample = 0; sample < samples; sample++) { | |||
| for(channel = 0; channel < channels; channel++) { | |||
| a_word = signal[channel][sample]; | |||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||
| *buf_++ = (FLAC__byte)a_word; | |||
| } | |||
| } | |||
| return; | |||
| case 4: | |||
| for (sample = 0; sample < samples; sample++) | |||
| for (channel = 0; channel < channels; channel++) | |||
| *buf32++ = H2LE_32(signal[channel][sample]); | |||
| return; | |||
| default: | |||
| break; | |||
| } | |||
| } | |||
| @@ -396,26 +493,26 @@ FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const | |||
| const size_t bytes_needed = (size_t)channels * (size_t)samples * (size_t)bytes_per_sample; | |||
| /* overflow check */ | |||
| if((size_t)channels > SIZE_MAX / (size_t)bytes_per_sample) | |||
| if ((size_t)channels > SIZE_MAX / (size_t)bytes_per_sample) | |||
| return false; | |||
| if((size_t)channels * (size_t)bytes_per_sample > SIZE_MAX / (size_t)samples) | |||
| if ((size_t)channels * (size_t)bytes_per_sample > SIZE_MAX / (size_t)samples) | |||
| return false; | |||
| if(ctx->capacity < bytes_needed) { | |||
| FLAC__byte *tmp = (FLAC__byte*) realloc(ctx->internal_buf, bytes_needed); | |||
| if(0 == tmp) { | |||
| free(ctx->internal_buf); | |||
| if(0 == (ctx->internal_buf = (FLAC__byte*) safe_malloc_(bytes_needed))) | |||
| if (ctx->capacity < bytes_needed) { | |||
| FLAC__byte *tmp = (FLAC__byte*) realloc(ctx->internal_buf.p8, bytes_needed); | |||
| if (0 == tmp) { | |||
| free(ctx->internal_buf.p8); | |||
| if (0 == (ctx->internal_buf.p8= (FLAC__byte*) safe_malloc_(bytes_needed))) | |||
| return false; | |||
| } | |||
| else | |||
| ctx->internal_buf = tmp; | |||
| ctx->internal_buf.p8= tmp; | |||
| ctx->capacity = bytes_needed; | |||
| } | |||
| format_input_(ctx->internal_buf, signal, channels, samples, bytes_per_sample); | |||
| format_input_(&ctx->internal_buf, signal, channels, samples, bytes_per_sample); | |||
| FLAC__MD5Update(ctx, ctx->internal_buf, bytes_needed); | |||
| FLAC__MD5Update(ctx, ctx->internal_buf.p8, bytes_needed); | |||
| return true; | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2001-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -30,10 +30,14 @@ | |||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #if HAVE_CONFIG_H | |||
| #ifdef HAVE_CONFIG_H | |||
| # include <config.h> | |||
| #endif | |||
| #ifdef HAVE_STDINT_H | |||
| #include <stdint.h> | |||
| #endif | |||
| #include "include/private/memory.h" | |||
| #include "../assert.h" | |||
| #include "../alloc.h" | |||
| @@ -46,25 +50,8 @@ void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address) | |||
| #ifdef FLAC__ALIGN_MALLOC_DATA | |||
| /* align on 32-byte (256-bit) boundary */ | |||
| x = safe_malloc_add_2op_(bytes, /*+*/31); | |||
| #ifdef SIZEOF_VOIDP | |||
| #if SIZEOF_VOIDP == 4 | |||
| /* could do *aligned_address = x + ((unsigned) (32 - (((unsigned)x) & 31))) & 31; */ | |||
| *aligned_address = (void*)(((unsigned)x + 31) & -32); | |||
| #elif SIZEOF_VOIDP == 8 | |||
| *aligned_address = (void*)(((FLAC__uint64)x + 31) & (FLAC__uint64)(-((FLAC__int64)32))); | |||
| #else | |||
| # error Unsupported sizeof(void*) | |||
| #endif | |||
| #else | |||
| /* there's got to be a better way to do this right for all archs */ | |||
| if(sizeof(void*) == sizeof(unsigned)) | |||
| *aligned_address = (void*)(((unsigned)x + 31) & -32); | |||
| else if(sizeof(void*) == sizeof(FLAC__uint64)) | |||
| *aligned_address = (void*)(((FLAC__uint64)x + 31) & (FLAC__uint64)(-((FLAC__int64)32))); | |||
| else | |||
| return 0; | |||
| #endif | |||
| x = safe_malloc_add_2op_(bytes, /*+*/31L); | |||
| *aligned_address = (void*)(((uintptr_t)x + 31L) & -32L); | |||
| #else | |||
| x = safe_malloc_(bytes); | |||
| *aligned_address = x; | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -30,7 +30,7 @@ | |||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #if HAVE_CONFIG_H | |||
| #ifdef HAVE_CONFIG_H | |||
| # include <config.h> | |||
| #endif | |||
| @@ -70,7 +70,7 @@ FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC = | |||
| * | |||
| ***********************************************************************/ | |||
| static FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' }; | |||
| static const FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' }; | |||
| /*********************************************************************** | |||
| * | |||
| @@ -86,7 +86,7 @@ static FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder); | |||
| static FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder); | |||
| static FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length); | |||
| static FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length); | |||
| static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj); | |||
| static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, unsigned length); | |||
| static FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj); | |||
| static FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj); | |||
| static FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder); | |||
| @@ -141,9 +141,6 @@ typedef struct FLAC__StreamDecoderPrivate { | |||
| void (*local_lpc_restore_signal_64bit)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); | |||
| /* for use when the signal is <= 16 bits-per-sample, or <= 15 bits-per-sample on a side channel (which requires 1 extra bit): */ | |||
| void (*local_lpc_restore_signal_16bit)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); | |||
| /* for use when the signal is <= 16 bits-per-sample, or <= 15 bits-per-sample on a side channel (which requires 1 extra bit), AND order <= 8: */ | |||
| void (*local_lpc_restore_signal_16bit_order8)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); | |||
| FLAC__bool (*local_bitreader_read_rice_signed_block)(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter); | |||
| void *client_data; | |||
| FILE *file; /* only used if FLAC__stream_decoder_init_file()/FLAC__stream_decoder_init_file() called, else NULL */ | |||
| FLAC__BitReader *input; | |||
| @@ -380,7 +377,7 @@ static FLAC__StreamDecoderInitStatus init_stream_internal_( | |||
| #if FLAC__HAS_OGG | |||
| decoder->private_->is_ogg = is_ogg; | |||
| if(is_ogg && !FLAC__ogg_decoder_aspect_init(&decoder->protected_->ogg_decoder_aspect)) | |||
| return decoder->protected_->state = FLAC__STREAM_DECODER_OGG_ERROR; | |||
| return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE; | |||
| #endif | |||
| /* | |||
| @@ -391,42 +388,44 @@ static FLAC__StreamDecoderInitStatus init_stream_internal_( | |||
| decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal; | |||
| decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide; | |||
| decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal; | |||
| decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal; | |||
| decoder->private_->local_bitreader_read_rice_signed_block = FLAC__bitreader_read_rice_signed_block; | |||
| /* now override with asm where appropriate */ | |||
| #ifndef FLAC__NO_ASM | |||
| if(decoder->private_->cpuinfo.use_asm) { | |||
| #ifdef FLAC__CPU_IA32 | |||
| FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32); | |||
| #ifdef FLAC__HAS_NASM | |||
| #if 1 /*@@@@@@ OPT: not clearly faster, needs more testing */ | |||
| if(decoder->private_->cpuinfo.data.ia32.bswap) | |||
| decoder->private_->local_bitreader_read_rice_signed_block = FLAC__bitreader_read_rice_signed_block_asm_ia32_bswap; | |||
| #endif | |||
| if(decoder->private_->cpuinfo.data.ia32.mmx) { | |||
| decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide_asm_ia32; /* OPT_IA32: was really necessary for GCC < 4.9 */ | |||
| if(decoder->private_->cpuinfo.ia32.mmx) { | |||
| decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_asm_ia32; | |||
| decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ia32_mmx; | |||
| decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ia32_mmx; | |||
| } | |||
| else { | |||
| decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_asm_ia32; | |||
| decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ia32; | |||
| decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ia32; | |||
| } | |||
| #endif | |||
| #elif defined FLAC__CPU_PPC | |||
| FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_PPC); | |||
| if(decoder->private_->cpuinfo.data.ppc.altivec) { | |||
| decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ppc_altivec_16; | |||
| decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8; | |||
| #ifdef FLAC__HAS_X86INTRIN | |||
| # if defined FLAC__SSE2_SUPPORTED && !defined FLAC__HAS_NASM /* OPT_SSE: not better than MMX asm */ | |||
| if(decoder->private_->cpuinfo.ia32.sse2) { | |||
| decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_16_intrin_sse2; | |||
| } | |||
| # endif | |||
| # if defined FLAC__SSE4_1_SUPPORTED | |||
| if(decoder->private_->cpuinfo.ia32.sse41) { | |||
| decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide_intrin_sse41; | |||
| } | |||
| # endif | |||
| #endif | |||
| #elif defined FLAC__CPU_X86_64 | |||
| FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_X86_64); | |||
| /* No useful SSE optimizations yet */ | |||
| #endif | |||
| } | |||
| #endif | |||
| /* from here on, errors are fatal */ | |||
| if(!FLAC__bitreader_init(decoder->private_->input, decoder->private_->cpuinfo, read_callback_, decoder)) { | |||
| if(!FLAC__bitreader_init(decoder->private_->input, read_callback_, decoder)) { | |||
| decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; | |||
| return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR; | |||
| } | |||
| @@ -528,10 +527,10 @@ static FLAC__StreamDecoderInitStatus init_FILE_internal_( | |||
| FLAC__ASSERT(0 != file); | |||
| if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) | |||
| return (FLAC__StreamDecoderInitStatus) (decoder->protected_->state = (FLAC__StreamDecoderState) FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED); | |||
| return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED; | |||
| if(0 == write_callback || 0 == error_callback) | |||
| return (FLAC__StreamDecoderInitStatus) (decoder->protected_->state = (FLAC__StreamDecoderState) FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS); | |||
| return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS; | |||
| /* | |||
| * To make sure that our file does not go unclosed after an error, we | |||
| @@ -602,10 +601,10 @@ static FLAC__StreamDecoderInitStatus init_file_internal_( | |||
| * in FLAC__stream_decoder_init_FILE() before the FILE* is assigned. | |||
| */ | |||
| if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) | |||
| return (FLAC__StreamDecoderInitStatus) (decoder->protected_->state = (FLAC__StreamDecoderState) FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED); | |||
| return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED; | |||
| if(0 == write_callback || 0 == error_callback) | |||
| return (FLAC__StreamDecoderInitStatus) (decoder->protected_->state = (FLAC__StreamDecoderState) FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS); | |||
| return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS; | |||
| file = filename? flac_fopen(filename, "rb") : stdin; | |||
| @@ -652,7 +651,7 @@ FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder) | |||
| if(decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED) | |||
| return true; | |||
| /* see the comment in FLAC__seekable_stream_decoder_reset() as to why we | |||
| /* see the comment in FLAC__stream_decoder_reset() as to why we | |||
| * always call FLAC__MD5Final() | |||
| */ | |||
| FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context); | |||
| @@ -1316,9 +1315,6 @@ FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigne | |||
| memset(tmp, 0, sizeof(FLAC__int32)*4); | |||
| decoder->private_->output[i] = tmp + 4; | |||
| /* WATCHOUT: | |||
| * minimum of quadword alignment for PPC vector optimizations is REQUIRED: | |||
| */ | |||
| if(!FLAC__memory_alloc_aligned_int32_array(size, &decoder->private_->residual_unaligned[i], &decoder->private_->residual[i])) { | |||
| decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; | |||
| return false; | |||
| @@ -1368,6 +1364,10 @@ FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder) | |||
| id_ = 0; | |||
| continue; | |||
| } | |||
| if(id_ >= 3) | |||
| return false; | |||
| if(x == ID3V2_TAG_[id_]) { | |||
| id_++; | |||
| i = 0; | |||
| @@ -1446,6 +1446,7 @@ FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder) | |||
| unsigned real_length = length; | |||
| FLAC__StreamMetadata block; | |||
| memset(&block, 0, sizeof(block)); | |||
| block.is_last = is_last; | |||
| block.type = (FLAC__MetadataType)type; | |||
| block.length = length; | |||
| @@ -1470,36 +1471,37 @@ FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder) | |||
| return false; /* read_callback_ sets the state for us */ | |||
| } | |||
| else { | |||
| FLAC__bool ok = true; | |||
| switch(type) { | |||
| case FLAC__METADATA_TYPE_PADDING: | |||
| /* skip the padding bytes */ | |||
| if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length)) | |||
| return false; /* read_callback_ sets the state for us */ | |||
| ok = false; /* read_callback_ sets the state for us */ | |||
| break; | |||
| case FLAC__METADATA_TYPE_APPLICATION: | |||
| /* remember, we read the ID already */ | |||
| if(real_length > 0) { | |||
| if(0 == (block.data.application.data = (FLAC__byte*) malloc(real_length))) { | |||
| decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; | |||
| return false; | |||
| ok = false; | |||
| } | |||
| if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.data, real_length)) | |||
| return false; /* read_callback_ sets the state for us */ | |||
| else if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.data, real_length)) | |||
| ok = false; /* read_callback_ sets the state for us */ | |||
| } | |||
| else | |||
| block.data.application.data = 0; | |||
| break; | |||
| case FLAC__METADATA_TYPE_VORBIS_COMMENT: | |||
| if(!read_metadata_vorbiscomment_(decoder, &block.data.vorbis_comment)) | |||
| return false; | |||
| if(!read_metadata_vorbiscomment_(decoder, &block.data.vorbis_comment, real_length)) | |||
| ok = false; | |||
| break; | |||
| case FLAC__METADATA_TYPE_CUESHEET: | |||
| if(!read_metadata_cuesheet_(decoder, &block.data.cue_sheet)) | |||
| return false; | |||
| ok = false; | |||
| break; | |||
| case FLAC__METADATA_TYPE_PICTURE: | |||
| if(!read_metadata_picture_(decoder, &block.data.picture)) | |||
| return false; | |||
| ok = false; | |||
| break; | |||
| case FLAC__METADATA_TYPE_STREAMINFO: | |||
| case FLAC__METADATA_TYPE_SEEKTABLE: | |||
| @@ -1509,16 +1511,16 @@ FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder) | |||
| if(real_length > 0) { | |||
| if(0 == (block.data.unknown.data = (FLAC__byte*) malloc(real_length))) { | |||
| decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; | |||
| return false; | |||
| ok = false; | |||
| } | |||
| if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.unknown.data, real_length)) | |||
| return false; /* read_callback_ sets the state for us */ | |||
| else if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.unknown.data, real_length)) | |||
| ok = false; /* read_callback_ sets the state for us */ | |||
| } | |||
| else | |||
| block.data.unknown.data = 0; | |||
| break; | |||
| } | |||
| if(!decoder->private_->is_seeking && decoder->private_->metadata_callback) | |||
| if(ok && !decoder->private_->is_seeking && decoder->private_->metadata_callback) | |||
| decoder->private_->metadata_callback(decoder, &block, decoder->private_->client_data); | |||
| /* now we have to free any malloc()ed data in the block */ | |||
| @@ -1563,6 +1565,9 @@ FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder) | |||
| free(block.data.unknown.data); | |||
| break; | |||
| } | |||
| if(!ok) /* anything that unsets "ok" should also make sure decoder->protected_->state is updated */ | |||
| return false; | |||
| } | |||
| } | |||
| @@ -1689,58 +1694,88 @@ FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_ | |||
| return true; | |||
| } | |||
| FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj) | |||
| FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, unsigned length) | |||
| { | |||
| FLAC__uint32 i; | |||
| FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); | |||
| /* read vendor string */ | |||
| FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32); | |||
| if(!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->vendor_string.length)) | |||
| return false; /* read_callback_ sets the state for us */ | |||
| if(obj->vendor_string.length > 0) { | |||
| if(0 == (obj->vendor_string.entry = (FLAC__byte*) safe_malloc_add_2op_(obj->vendor_string.length, /*+*/1))) { | |||
| decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; | |||
| return false; | |||
| } | |||
| if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->vendor_string.entry, obj->vendor_string.length)) | |||
| if (length >= 8) { | |||
| length -= 8; /* vendor string length + num comments entries alone take 8 bytes */ | |||
| FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32); | |||
| if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->vendor_string.length)) | |||
| return false; /* read_callback_ sets the state for us */ | |||
| obj->vendor_string.entry[obj->vendor_string.length] = '\0'; | |||
| } | |||
| else | |||
| obj->vendor_string.entry = 0; | |||
| if (obj->vendor_string.length > 0) { | |||
| if (length < obj->vendor_string.length) { | |||
| obj->vendor_string.length = 0; | |||
| obj->vendor_string.entry = 0; | |||
| goto skip; | |||
| } | |||
| else | |||
| length -= obj->vendor_string.length; | |||
| if (0 == (obj->vendor_string.entry = (FLAC__byte*) safe_malloc_add_2op_(obj->vendor_string.length, /*+*/1))) { | |||
| decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; | |||
| return false; | |||
| } | |||
| if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->vendor_string.entry, obj->vendor_string.length)) | |||
| return false; /* read_callback_ sets the state for us */ | |||
| obj->vendor_string.entry[obj->vendor_string.length] = '\0'; | |||
| } | |||
| else | |||
| obj->vendor_string.entry = 0; | |||
| /* read num comments */ | |||
| FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN == 32); | |||
| if(!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->num_comments)) | |||
| return false; /* read_callback_ sets the state for us */ | |||
| /* read num comments */ | |||
| FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN == 32); | |||
| if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->num_comments)) | |||
| return false; /* read_callback_ sets the state for us */ | |||
| /* read comments */ | |||
| if(obj->num_comments > 0) { | |||
| if(0 == (obj->comments = (FLAC__StreamMetadata_VorbisComment_Entry*) safe_malloc_mul_2op_p(obj->num_comments, /*times*/sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) { | |||
| decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; | |||
| return false; | |||
| } | |||
| for(i = 0; i < obj->num_comments; i++) { | |||
| FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32); | |||
| if(!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->comments[i].length)) | |||
| return false; /* read_callback_ sets the state for us */ | |||
| if(obj->comments[i].length > 0) { | |||
| if(0 == (obj->comments[i].entry = (FLAC__byte*) safe_malloc_add_2op_(obj->comments[i].length, /*+*/1))) { | |||
| decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; | |||
| return false; | |||
| /* read comments */ | |||
| if (obj->num_comments > 0) { | |||
| if (0 == (obj->comments = (FLAC__StreamMetadata_VorbisComment_Entry*) safe_malloc_mul_2op_p(obj->num_comments, /*times*/sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) { | |||
| decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; | |||
| return false; | |||
| } | |||
| for (i = 0; i < obj->num_comments; i++) { | |||
| FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32); | |||
| if (length < 4) { | |||
| obj->num_comments = i; | |||
| goto skip; | |||
| } | |||
| if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length)) | |||
| else | |||
| length -= 4; | |||
| if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->comments[i].length)) | |||
| return false; /* read_callback_ sets the state for us */ | |||
| obj->comments[i].entry[obj->comments[i].length] = '\0'; | |||
| if (obj->comments[i].length > 0) { | |||
| if (length < obj->comments[i].length) { | |||
| obj->comments[i].length = 0; | |||
| obj->comments[i].entry = 0; | |||
| obj->num_comments = i; | |||
| goto skip; | |||
| } | |||
| else | |||
| length -= obj->comments[i].length; | |||
| if (0 == (obj->comments[i].entry = (FLAC__byte*) safe_malloc_add_2op_(obj->comments[i].length, /*+*/1))) { | |||
| decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; | |||
| return false; | |||
| } | |||
| if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length)) | |||
| return false; /* read_callback_ sets the state for us */ | |||
| obj->comments[i].entry[obj->comments[i].length] = '\0'; | |||
| } | |||
| else | |||
| obj->comments[i].entry = 0; | |||
| } | |||
| else | |||
| obj->comments[i].entry = 0; | |||
| } | |||
| else | |||
| obj->comments = 0; | |||
| } | |||
| else { | |||
| obj->comments = 0; | |||
| skip: | |||
| if (length > 0) { | |||
| /* This will only happen on files with invalid data in comments */ | |||
| if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length)) | |||
| return false; /* read_callback_ sets the state for us */ | |||
| } | |||
| return true; | |||
| @@ -2655,12 +2690,8 @@ FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, un | |||
| if( (FLAC__uint64)order * ((((FLAC__uint64)1)<<bps)-1) * ((1<<subframe->qlp_coeff_precision)-1) < (((FLAC__uint64)-1) << 32) ) | |||
| */ | |||
| if(bps + subframe->qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32) | |||
| if(bps <= 16 && subframe->qlp_coeff_precision <= 16) { | |||
| if(order <= 8) | |||
| decoder->private_->local_lpc_restore_signal_16bit_order8(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order); | |||
| else | |||
| decoder->private_->local_lpc_restore_signal_16bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order); | |||
| } | |||
| if(bps <= 16 && subframe->qlp_coeff_precision <= 16) | |||
| decoder->private_->local_lpc_restore_signal_16bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order); | |||
| else | |||
| decoder->private_->local_lpc_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order); | |||
| else | |||
| @@ -2708,14 +2739,16 @@ FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigne | |||
| if(decoder->private_->frame.header.blocksize < predictor_order) { | |||
| send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); | |||
| decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; | |||
| return true; | |||
| /* We have received a potentially malicious bit stream. All we can do is error out to avoid a heap overflow. */ | |||
| return false; | |||
| } | |||
| } | |||
| else { | |||
| if(partition_samples < predictor_order) { | |||
| send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); | |||
| decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; | |||
| return true; | |||
| /* We have received a potentially malicious bit stream. All we can do is error out to avoid a heap overflow. */ | |||
| return false; | |||
| } | |||
| } | |||
| @@ -2732,7 +2765,7 @@ FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigne | |||
| if(rice_parameter < pesc) { | |||
| partitioned_rice_contents->raw_bits[partition] = 0; | |||
| u = (partition_order == 0 || partition > 0)? partition_samples : partition_samples - predictor_order; | |||
| if(!decoder->private_->local_bitreader_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter)) | |||
| if(!FLAC__bitreader_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter)) | |||
| return false; /* read_callback_ sets the state for us */ | |||
| sample += u; | |||
| } | |||
| @@ -3074,12 +3107,7 @@ FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 s | |||
| return false; | |||
| } | |||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||
| #if defined _MSC_VER || defined __MINGW32__ | |||
| /* with VC++ you have to spoon feed it the casting */ | |||
| pos = (FLAC__int64)lower_bound + (FLAC__int64)((FLAC__double)(FLAC__int64)(target_sample - lower_bound_sample) / (FLAC__double)(FLAC__int64)(upper_bound_sample - lower_bound_sample) * (FLAC__double)(FLAC__int64)(upper_bound - lower_bound)) - approx_bytes_per_frame; | |||
| #else | |||
| pos = (FLAC__int64)lower_bound + (FLAC__int64)((FLAC__double)(target_sample - lower_bound_sample) / (FLAC__double)(upper_bound_sample - lower_bound_sample) * (FLAC__double)(upper_bound - lower_bound)) - approx_bytes_per_frame; | |||
| #endif | |||
| #else | |||
| /* a little less accurate: */ | |||
| if(upper_bound - lower_bound < 0xffffffff) | |||
| @@ -3203,12 +3231,7 @@ FLAC__bool seek_to_absolute_sample_ogg_(FLAC__StreamDecoder *decoder, FLAC__uint | |||
| } | |||
| else { | |||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||
| #if defined _MSC_VER || defined __MINGW32__ | |||
| /* with MSVC you have to spoon feed it the casting */ | |||
| pos = (FLAC__uint64)((FLAC__double)(FLAC__int64)(target_sample - left_sample) / (FLAC__double)(FLAC__int64)(right_sample - left_sample) * (FLAC__double)(FLAC__int64)(right_pos - left_pos)); | |||
| #else | |||
| pos = (FLAC__uint64)((FLAC__double)(target_sample - left_sample) / (FLAC__double)(right_sample - left_sample) * (FLAC__double)(right_pos - left_pos)); | |||
| #endif | |||
| #else | |||
| /* a little less accurate: */ | |||
| if ((target_sample-left_sample <= 0xffffffff) && (right_pos-left_pos <= 0xffffffff)) | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -30,7 +30,7 @@ | |||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #if HAVE_CONFIG_H | |||
| #ifdef HAVE_CONFIG_H | |||
| # include <config.h> | |||
| #endif | |||
| @@ -55,10 +55,10 @@ | |||
| #include "include/private/ogg_helper.h" | |||
| #include "include/private/ogg_mapping.h" | |||
| #endif | |||
| #include "include/private/stream_encoder.h" | |||
| #include "include/private/stream_encoder_framing.h" | |||
| #include "include/private/window.h" | |||
| #include "../alloc.h" | |||
| #include "../compat.h" | |||
| /* Exact Rice codeword length calculation is off by default. The simple | |||
| @@ -103,16 +103,18 @@ static struct CompressionLevels { | |||
| unsigned min_residual_partition_order; | |||
| unsigned max_residual_partition_order; | |||
| unsigned rice_parameter_search_dist; | |||
| const char *apodization; | |||
| } compression_levels_[] = { | |||
| { false, false, 0, 0, false, false, false, 0, 3, 0 }, | |||
| { true , true , 0, 0, false, false, false, 0, 3, 0 }, | |||
| { true , false, 0, 0, false, false, false, 0, 3, 0 }, | |||
| { false, false, 6, 0, false, false, false, 0, 4, 0 }, | |||
| { true , true , 8, 0, false, false, false, 0, 4, 0 }, | |||
| { true , false, 8, 0, false, false, false, 0, 5, 0 }, | |||
| { true , false, 8, 0, false, false, false, 0, 6, 0 }, | |||
| { true , false, 8, 0, false, false, true , 0, 6, 0 }, | |||
| { true , false, 12, 0, false, false, true , 0, 6, 0 } | |||
| { false, false, 0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" }, | |||
| { true , true , 0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" }, | |||
| { true , false, 0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" }, | |||
| { false, false, 6, 0, false, false, false, 0, 4, 0, "tukey(5e-1)" }, | |||
| { true , true , 8, 0, false, false, false, 0, 4, 0, "tukey(5e-1)" }, | |||
| { true , false, 8, 0, false, false, false, 0, 5, 0, "tukey(5e-1)" }, | |||
| { true , false, 8, 0, false, false, false, 0, 6, 0, "tukey(5e-1);partial_tukey(2)" }, | |||
| { true , false, 12, 0, false, false, false, 0, 6, 0, "tukey(5e-1);partial_tukey(2)" }, | |||
| { true , false, 12, 0, false, false, false, 0, 6, 0, "tukey(5e-1);partial_tukey(2);punchout_tukey(3)" } | |||
| /* here we use locale-independent 5e-1 instead of 0.5 or 0,5 */ | |||
| }; | |||
| @@ -342,10 +344,13 @@ typedef struct FLAC__StreamEncoderPrivate { | |||
| unsigned current_frame_number; | |||
| FLAC__MD5Context md5context; | |||
| FLAC__CPUInfo cpuinfo; | |||
| void (*local_precompute_partition_info_sums)(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], unsigned residual_samples, unsigned predictor_order, unsigned min_partition_order, unsigned max_partition_order, unsigned bps); | |||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||
| unsigned (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); | |||
| unsigned (*local_fixed_compute_best_predictor_wide)(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); | |||
| #else | |||
| unsigned (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); | |||
| unsigned (*local_fixed_compute_best_predictor_wide)(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); | |||
| #endif | |||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||
| void (*local_lpc_compute_autocorrelation)(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); | |||
| @@ -873,7 +878,9 @@ static FLAC__StreamEncoderInitStatus init_stream_internal_( | |||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||
| encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation; | |||
| #endif | |||
| encoder->private_->local_precompute_partition_info_sums = precompute_partition_info_sums_; | |||
| encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor; | |||
| encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide; | |||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients; | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide; | |||
| @@ -886,21 +893,23 @@ static FLAC__StreamEncoderInitStatus init_stream_internal_( | |||
| # ifdef FLAC__CPU_IA32 | |||
| FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32); | |||
| # ifdef FLAC__HAS_NASM | |||
| if(encoder->private_->cpuinfo.data.ia32.sse) { | |||
| if(encoder->private_->cpuinfo.ia32.sse) { | |||
| if(encoder->protected_->max_lpc_order < 4) | |||
| encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4; | |||
| else if(encoder->protected_->max_lpc_order < 8) | |||
| encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8; | |||
| else if(encoder->protected_->max_lpc_order < 12) | |||
| encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12; | |||
| else if(encoder->protected_->max_lpc_order < 16) | |||
| encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_16; | |||
| else | |||
| encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32; | |||
| } | |||
| else if(encoder->private_->cpuinfo.data.ia32._3dnow) | |||
| encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow; | |||
| else | |||
| encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32; | |||
| if(encoder->private_->cpuinfo.data.ia32.mmx) { | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_asm_ia32; /* OPT_IA32: was really necessary for GCC < 4.9 */ | |||
| if(encoder->private_->cpuinfo.ia32.mmx) { | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32; | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx; | |||
| } | |||
| @@ -908,16 +917,137 @@ static FLAC__StreamEncoderInitStatus init_stream_internal_( | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32; | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32; | |||
| } | |||
| if(encoder->private_->cpuinfo.data.ia32.mmx && encoder->private_->cpuinfo.data.ia32.cmov) | |||
| if(encoder->private_->cpuinfo.ia32.mmx && encoder->private_->cpuinfo.ia32.cmov) | |||
| encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov; | |||
| # endif /* FLAC__HAS_NASM */ | |||
| # endif /* FLAC__CPU_IA32 */ | |||
| # ifdef FLAC__HAS_X86INTRIN | |||
| # if defined FLAC__SSE_SUPPORTED | |||
| if(encoder->private_->cpuinfo.ia32.sse) { | |||
| if(encoder->protected_->max_lpc_order < 4) | |||
| encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4; | |||
| else if(encoder->protected_->max_lpc_order < 8) | |||
| encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8; | |||
| else if(encoder->protected_->max_lpc_order < 12) | |||
| encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12; | |||
| else if(encoder->protected_->max_lpc_order < 16) | |||
| encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16; | |||
| else | |||
| encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation; | |||
| } | |||
| # endif | |||
| # ifdef FLAC__SSE2_SUPPORTED | |||
| if(encoder->private_->cpuinfo.ia32.sse2) { | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2; | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2; | |||
| } | |||
| # endif | |||
| # ifdef FLAC__SSE4_1_SUPPORTED | |||
| if(encoder->private_->cpuinfo.ia32.sse41) { | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41; | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41; | |||
| } | |||
| # endif | |||
| # ifdef FLAC__AVX2_SUPPORTED | |||
| if(encoder->private_->cpuinfo.ia32.avx2) { | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2; | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2; | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2; | |||
| } | |||
| # endif | |||
| # ifdef FLAC__SSE2_SUPPORTED | |||
| if (encoder->private_->cpuinfo.ia32.sse2) { | |||
| encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_sse2; | |||
| encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_sse2; | |||
| } | |||
| # endif | |||
| # ifdef FLAC__SSSE3_SUPPORTED | |||
| if (encoder->private_->cpuinfo.ia32.ssse3) { | |||
| encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_ssse3; | |||
| encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_ssse3; | |||
| } | |||
| # endif | |||
| # endif /* FLAC__HAS_X86INTRIN */ | |||
| # elif defined FLAC__CPU_X86_64 | |||
| FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_X86_64); | |||
| # ifdef FLAC__HAS_X86INTRIN | |||
| # ifdef FLAC__SSE_SUPPORTED | |||
| if(encoder->protected_->max_lpc_order < 4) | |||
| encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4; | |||
| else if(encoder->protected_->max_lpc_order < 8) | |||
| encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8; | |||
| else if(encoder->protected_->max_lpc_order < 12) | |||
| encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12; | |||
| else if(encoder->protected_->max_lpc_order < 16) | |||
| encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16; | |||
| # endif | |||
| # ifdef FLAC__SSE2_SUPPORTED | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2; | |||
| # endif | |||
| # ifdef FLAC__SSE4_1_SUPPORTED | |||
| if(encoder->private_->cpuinfo.x86.sse41) { | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41; | |||
| } | |||
| # endif | |||
| # ifdef FLAC__AVX2_SUPPORTED | |||
| if(encoder->private_->cpuinfo.x86.avx2) { | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2; | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2; | |||
| encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2; | |||
| } | |||
| # endif | |||
| # ifdef FLAC__SSE2_SUPPORTED | |||
| encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_sse2; | |||
| encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_sse2; | |||
| # endif | |||
| # ifdef FLAC__SSSE3_SUPPORTED | |||
| if (encoder->private_->cpuinfo.x86.ssse3) { | |||
| encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_ssse3; | |||
| encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_ssse3; | |||
| } | |||
| # endif | |||
| # endif /* FLAC__HAS_X86INTRIN */ | |||
| # endif /* FLAC__CPU_... */ | |||
| } | |||
| # endif /* !FLAC__NO_ASM */ | |||
| #endif /* !FLAC__INTEGER_ONLY_LIBRARY */ | |||
| #if !defined FLAC__NO_ASM && defined FLAC__HAS_X86INTRIN | |||
| if(encoder->private_->cpuinfo.use_asm) { | |||
| # if defined FLAC__CPU_IA32 | |||
| # ifdef FLAC__SSE2_SUPPORTED | |||
| if(encoder->private_->cpuinfo.ia32.sse2) | |||
| encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_sse2; | |||
| # endif | |||
| # ifdef FLAC__SSSE3_SUPPORTED | |||
| if(encoder->private_->cpuinfo.ia32.ssse3) | |||
| encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_ssse3; | |||
| # endif | |||
| # ifdef FLAC__AVX2_SUPPORTED | |||
| if(encoder->private_->cpuinfo.ia32.avx2) | |||
| encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_avx2; | |||
| # endif | |||
| # elif defined FLAC__CPU_X86_64 | |||
| # ifdef FLAC__SSE2_SUPPORTED | |||
| encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_sse2; | |||
| # endif | |||
| # ifdef FLAC__SSSE3_SUPPORTED | |||
| if(encoder->private_->cpuinfo.x86.ssse3) | |||
| encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_ssse3; | |||
| # endif | |||
| # ifdef FLAC__AVX2_SUPPORTED | |||
| if(encoder->private_->cpuinfo.x86.avx2) | |||
| encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_avx2; | |||
| # endif | |||
| # endif /* FLAC__CPU_... */ | |||
| } | |||
| #endif /* !FLAC__NO_ASM && FLAC__HAS_X86INTRIN */ | |||
| /* finally override based on wide-ness if necessary */ | |||
| if(encoder->private_->use_wide_by_block) { | |||
| encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_wide; | |||
| encoder->private_->local_fixed_compute_best_predictor = encoder->private_->local_fixed_compute_best_predictor_wide; | |||
| } | |||
| /* set state to OK; from here on, errors are fatal and we'll override the state then */ | |||
| @@ -1152,7 +1282,7 @@ static FLAC__StreamEncoderInitStatus init_FILE_internal_( | |||
| FLAC__StreamEncoder *encoder, | |||
| FILE *file, | |||
| FLAC__StreamEncoderProgressCallback progress_callback, | |||
| void * /*client_data*/, | |||
| void *client_data, | |||
| FLAC__bool is_ogg | |||
| ) | |||
| { | |||
| @@ -1178,6 +1308,13 @@ static FLAC__StreamEncoderInitStatus init_FILE_internal_( | |||
| if(file == stdout) | |||
| file = get_binary_stdout_(); /* just to be safe */ | |||
| #ifdef _WIN32 | |||
| /* | |||
| * Windows can suffer quite badly from disk fragmentation. This can be | |||
| * reduced significantly by setting the output buffer size to be 10MB. | |||
| */ | |||
| setvbuf(file, NULL, _IOFBF, 10*1024*1024); | |||
| #endif | |||
| encoder->private_->file = file; | |||
| encoder->private_->progress_callback = progress_callback; | |||
| @@ -1447,11 +1584,10 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncod | |||
| ok &= FLAC__stream_encoder_set_do_mid_side_stereo (encoder, compression_levels_[value].do_mid_side_stereo); | |||
| ok &= FLAC__stream_encoder_set_loose_mid_side_stereo (encoder, compression_levels_[value].loose_mid_side_stereo); | |||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||
| #if 0 | |||
| /* was: */ | |||
| #if 1 | |||
| ok &= FLAC__stream_encoder_set_apodization (encoder, compression_levels_[value].apodization); | |||
| /* but it's too hard to specify the string in a locale-specific way */ | |||
| #else | |||
| /* equivalent to -A tukey(0.5) */ | |||
| encoder->protected_->num_apodizations = 1; | |||
| encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY; | |||
| encoder->protected_->apodizations[0].parameters.tukey.p = 0.5; | |||
| @@ -1555,6 +1691,48 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *en | |||
| encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY; | |||
| } | |||
| } | |||
| else if(n>15 && 0 == strncmp("partial_tukey(" , specification, 14)) { | |||
| FLAC__int32 tukey_parts = (FLAC__int32)strtod(specification+14, 0); | |||
| const char *si_1 = strchr(specification, '/'); | |||
| FLAC__real overlap = si_1?flac_min((FLAC__real)strtod(si_1+1, 0),0.99f):0.1f; | |||
| FLAC__real overlap_units = 1.0f/(1.0f - overlap) - 1.0f; | |||
| const char *si_2 = strchr((si_1?(si_1+1):specification), '/'); | |||
| FLAC__real tukey_p = si_2?(FLAC__real)strtod(si_2+1, 0):0.2f; | |||
| if (tukey_parts <= 1) { | |||
| encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = tukey_p; | |||
| encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY; | |||
| }else if (encoder->protected_->num_apodizations + tukey_parts < 32){ | |||
| FLAC__int32 m; | |||
| for(m = 0; m < tukey_parts; m++){ | |||
| encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.p = tukey_p; | |||
| encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.start = m/(tukey_parts+overlap_units); | |||
| encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.end = (m+1+overlap_units)/(tukey_parts+overlap_units); | |||
| encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_PARTIAL_TUKEY; | |||
| } | |||
| } | |||
| } | |||
| else if(n>16 && 0 == strncmp("punchout_tukey(" , specification, 15)) { | |||
| FLAC__int32 tukey_parts = (FLAC__int32)strtod(specification+15, 0); | |||
| const char *si_1 = strchr(specification, '/'); | |||
| FLAC__real overlap = si_1?flac_min((FLAC__real)strtod(si_1+1, 0),0.99f):0.2f; | |||
| FLAC__real overlap_units = 1.0f/(1.0f - overlap) - 1.0f; | |||
| const char *si_2 = strchr((si_1?(si_1+1):specification), '/'); | |||
| FLAC__real tukey_p = si_2?(FLAC__real)strtod(si_2+1, 0):0.2f; | |||
| if (tukey_parts <= 1) { | |||
| encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = tukey_p; | |||
| encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY; | |||
| }else if (encoder->protected_->num_apodizations + tukey_parts < 32){ | |||
| FLAC__int32 m; | |||
| for(m = 0; m < tukey_parts; m++){ | |||
| encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.p = tukey_p; | |||
| encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.start = m/(tukey_parts+overlap_units); | |||
| encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.end = (m+1+overlap_units)/(tukey_parts+overlap_units); | |||
| encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_PUNCHOUT_TUKEY; | |||
| } | |||
| } | |||
| } | |||
| else if(n==5 && 0 == strncmp("welch" , specification, n)) | |||
| encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_WELCH; | |||
| if (encoder->protected_->num_apodizations == 32) | |||
| @@ -2236,8 +2414,8 @@ FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_blocksize) | |||
| ok = true; | |||
| /* WATCHOUT: FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx() | |||
| * requires that the input arrays (in our case the integer signals) | |||
| /* WATCHOUT: FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx() and ..._intrin_sse2() | |||
| * require that the input arrays (in our case the integer signals) | |||
| * have a buffer of up to 3 zeroes in front (at negative indices) for | |||
| * alignment purposes; we use 4 in front to keep the data well-aligned. | |||
| */ | |||
| @@ -2334,6 +2512,12 @@ FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_blocksize) | |||
| case FLAC__APODIZATION_TUKEY: | |||
| FLAC__window_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.tukey.p); | |||
| break; | |||
| case FLAC__APODIZATION_PARTIAL_TUKEY: | |||
| FLAC__window_partial_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.multiple_tukey.p, encoder->protected_->apodizations[i].parameters.multiple_tukey.start, encoder->protected_->apodizations[i].parameters.multiple_tukey.end); | |||
| break; | |||
| case FLAC__APODIZATION_PUNCHOUT_TUKEY: | |||
| FLAC__window_punchout_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.multiple_tukey.p, encoder->protected_->apodizations[i].parameters.multiple_tukey.start, encoder->protected_->apodizations[i].parameters.multiple_tukey.end); | |||
| break; | |||
| case FLAC__APODIZATION_WELCH: | |||
| FLAC__window_welch(encoder->private_->window[i], new_blocksize); | |||
| break; | |||
| @@ -3165,7 +3349,7 @@ FLAC__bool process_subframe_( | |||
| #endif | |||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||
| FLAC__double lpc_residual_bits_per_sample; | |||
| FLAC__real autoc[FLAC__MAX_LPC_ORDER+1]; /* WATCHOUT: the size is important even though encoder->protected_->max_lpc_order might be less; some asm routines need all the space */ | |||
| FLAC__real autoc[FLAC__MAX_LPC_ORDER+1]; /* WATCHOUT: the size is important even though encoder->protected_->max_lpc_order might be less; some asm and x86 intrinsic routines need all the space */ | |||
| FLAC__double lpc_error[FLAC__MAX_LPC_ORDER]; | |||
| unsigned min_lpc_order, max_lpc_order, lpc_order; | |||
| unsigned min_qlp_coeff_precision, max_qlp_coeff_precision, qlp_coeff_precision; | |||
| @@ -3318,9 +3502,9 @@ FLAC__bool process_subframe_( | |||
| } | |||
| if(encoder->protected_->do_qlp_coeff_prec_search) { | |||
| min_qlp_coeff_precision = FLAC__MIN_QLP_COEFF_PRECISION; | |||
| /* try to ensure a 32-bit datapath throughout for 16bps(+1bps for side channel) or less */ | |||
| if(subframe_bps <= 17) { | |||
| max_qlp_coeff_precision = flac_min(32 - subframe_bps - lpc_order, FLAC__MAX_QLP_COEFF_PRECISION); | |||
| /* try to keep qlp coeff precision such that only 32-bit math is required for decode of <=16bps streams */ | |||
| if(subframe_bps <= 16) { | |||
| max_qlp_coeff_precision = flac_min(32 - subframe_bps - FLAC__bitmath_ilog2(lpc_order), FLAC__MAX_QLP_COEFF_PRECISION); | |||
| max_qlp_coeff_precision = flac_max(max_qlp_coeff_precision, min_qlp_coeff_precision); | |||
| } | |||
| else | |||
| @@ -3556,7 +3740,7 @@ unsigned evaluate_lpc_subframe_( | |||
| FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents | |||
| ) | |||
| { | |||
| FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; | |||
| FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; /* WATCHOUT: the size is important; some x86 intrinsic routines need more than lpc order elements */ | |||
| unsigned i, residual_bits, estimate; | |||
| int quantization, ret; | |||
| const unsigned residual_samples = blocksize - order; | |||
| @@ -3671,7 +3855,7 @@ unsigned find_best_partition_order_( | |||
| max_partition_order = FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(max_partition_order, blocksize, predictor_order); | |||
| min_partition_order = flac_min(min_partition_order, max_partition_order); | |||
| precompute_partition_info_sums_(residual, abs_residual_partition_sums, residual_samples, predictor_order, min_partition_order, max_partition_order, bps); | |||
| private_->local_precompute_partition_info_sums(residual, abs_residual_partition_sums, residual_samples, predictor_order, min_partition_order, max_partition_order, bps); | |||
| if(do_escape_coding) | |||
| precompute_partition_info_escapes_(residual, raw_bits_per_partition, residual_samples, predictor_order, min_partition_order, max_partition_order); | |||
| @@ -3743,17 +3927,6 @@ unsigned find_best_partition_order_( | |||
| return best_residual_bits; | |||
| } | |||
| #if defined(FLAC__CPU_IA32) && !defined FLAC__NO_ASM && defined FLAC__HAS_NASM | |||
| extern void precompute_partition_info_sums_32bit_asm_ia32_( | |||
| const FLAC__int32 residual[], | |||
| FLAC__uint64 abs_residual_partition_sums[], | |||
| unsigned blocksize, | |||
| unsigned predictor_order, | |||
| unsigned min_partition_order, | |||
| unsigned max_partition_order | |||
| ); | |||
| #endif | |||
| void precompute_partition_info_sums_( | |||
| const FLAC__int32 residual[], | |||
| FLAC__uint64 abs_residual_partition_sums[], | |||
| @@ -3769,21 +3942,12 @@ void precompute_partition_info_sums_( | |||
| FLAC__ASSERT(default_partition_samples > predictor_order); | |||
| #if defined(FLAC__CPU_IA32) && !defined FLAC__NO_ASM && defined FLAC__HAS_NASM | |||
| /* slightly pessimistic but still catches all common cases */ | |||
| /* WATCHOUT: "+ bps" is an assumption that the average residual magnitude will not be more than "bps" bits */ | |||
| if(FLAC__bitmath_ilog2(default_partition_samples) + bps < 32) { | |||
| precompute_partition_info_sums_32bit_asm_ia32_(residual, abs_residual_partition_sums, residual_samples + predictor_order, predictor_order, min_partition_order, max_partition_order); | |||
| return; | |||
| } | |||
| #endif | |||
| /* first do max_partition_order */ | |||
| { | |||
| unsigned partition, residual_sample, end = (unsigned)(-(int)predictor_order); | |||
| /* slightly pessimistic but still catches all common cases */ | |||
| /* WATCHOUT: "+ bps" is an assumption that the average residual magnitude will not be more than "bps" bits */ | |||
| if(FLAC__bitmath_ilog2(default_partition_samples) + bps < 32) { | |||
| /* WATCHOUT: "+ bps + FLAC__MAX_EXTRA_RESIDUAL_BPS" is the maximum | |||
| * assumed size of the average residual magnitude */ | |||
| if(FLAC__bitmath_ilog2(default_partition_samples) + bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < 32) { | |||
| FLAC__uint32 abs_residual_partition_sum; | |||
| for(partition = residual_sample = 0; partition < partitions; partition++) { | |||
| @@ -4027,8 +4191,35 @@ FLAC__bool set_partitioned_rice_( | |||
| * in the partition, so the actual mean is | |||
| * mean/partition_samples | |||
| */ | |||
| #if 0 /* old simple code */ | |||
| for(rice_parameter = 0, k = partition_samples; k < mean; rice_parameter++, k <<= 1) | |||
| ; | |||
| #else | |||
| #if defined FLAC__CPU_X86_64 /* and other 64-bit arch, too */ | |||
| if(mean <= 0x80000000/512) { /* 512: more or less optimal for both 16- and 24-bit input */ | |||
| #else | |||
| if(mean <= 0x80000000/8) { /* 32-bit arch: use 32-bit math if possible */ | |||
| #endif | |||
| FLAC__uint32 k2, mean2 = (FLAC__uint32) mean; | |||
| rice_parameter = 0; k2 = partition_samples; | |||
| while(k2*8 < mean2) { /* requires: mean <= (2^31)/8 */ | |||
| rice_parameter += 4; k2 <<= 4; /* tuned for 16-bit input */ | |||
| } | |||
| while(k2 < mean2) { /* requires: mean <= 2^31 */ | |||
| rice_parameter++; k2 <<= 1; | |||
| } | |||
| } | |||
| else { | |||
| rice_parameter = 0; k = partition_samples; | |||
| if(mean <= FLAC__U64L(0x8000000000000000)/128) /* usually mean is _much_ smaller than this value */ | |||
| while(k*128 < mean) { /* requires: mean <= (2^63)/128 */ | |||
| rice_parameter += 8; k <<= 8; /* tuned for 24-bit input */ | |||
| } | |||
| while(k < mean) { /* requires: mean <= 2^63 */ | |||
| rice_parameter++; k <<= 1; | |||
| } | |||
| } | |||
| #endif | |||
| if(rice_parameter >= rice_parameter_limit) { | |||
| #ifdef DEBUG_VERBOSE | |||
| fprintf(stderr, "clipping rice_parameter (%u -> %u) @6\n", rice_parameter, rice_parameter_limit - 1); | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -30,7 +30,7 @@ | |||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #if HAVE_CONFIG_H | |||
| #ifdef HAVE_CONFIG_H | |||
| # include <config.h> | |||
| #endif | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2006-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -30,7 +30,7 @@ | |||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #if HAVE_CONFIG_H | |||
| #ifdef HAVE_CONFIG_H | |||
| # include <config.h> | |||
| #endif | |||
| @@ -41,11 +41,6 @@ | |||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||
| #ifndef M_PI | |||
| /* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */ | |||
| #define M_PI 3.14159265358979323846 | |||
| #endif | |||
| void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L) | |||
| { | |||
| @@ -62,7 +57,7 @@ void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L) | |||
| for (n = 0; n <= L/2-1; n++) | |||
| window[n] = 2.0f * n / (float)N; | |||
| for (; n <= N; n++) | |||
| window[n] = 2.0f - 2.0f * (N-n) / (float)N; | |||
| window[n] = 2.0f - 2.0f * n / (float)N; | |||
| } | |||
| } | |||
| @@ -72,7 +67,7 @@ void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L) | |||
| FLAC__int32 n; | |||
| for (n = 0; n < L; n++) | |||
| window[n] = (FLAC__real)(0.62f - 0.48f * fabs((float)n/(float)N+0.5f) + 0.38f * cos(2.0f * M_PI * ((float)n/(float)N+0.5f))); | |||
| window[n] = (FLAC__real)(0.62f - 0.48f * fabs((float)n/(float)N-0.5f) - 0.38f * cos(2.0f * M_PI * ((float)n/(float)N))); | |||
| } | |||
| void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L) | |||
| @@ -177,16 +172,16 @@ void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L) | |||
| FLAC__int32 n; | |||
| if (L & 1) { | |||
| for (n = 1; n <= L+1/2; n++) | |||
| for (n = 1; n <= (L+1)/2; n++) | |||
| window[n-1] = 2.0f * n / ((float)L + 1.0f); | |||
| for (; n <= L; n++) | |||
| window[n-1] = - (float)(2 * (L - n + 1)) / ((float)L + 1.0f); | |||
| window[n-1] = (float)(2 * (L - n + 1)) / ((float)L + 1.0f); | |||
| } | |||
| else { | |||
| for (n = 1; n <= L/2; n++) | |||
| window[n-1] = 2.0f * n / (float)L; | |||
| window[n-1] = 2.0f * n / ((float)L + 1.0f); | |||
| for (; n <= L; n++) | |||
| window[n-1] = ((float)(2 * (L - n)) + 1.0f) / (float)L; | |||
| window[n-1] = (float)(2 * (L - n + 1)) / ((float)L + 1.0f); | |||
| } | |||
| } | |||
| @@ -211,6 +206,66 @@ void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__rea | |||
| } | |||
| } | |||
| void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end) | |||
| { | |||
| const FLAC__int32 start_n = (FLAC__int32)(start * L); | |||
| const FLAC__int32 end_n = (FLAC__int32)(end * L); | |||
| const FLAC__int32 N = end_n - start_n; | |||
| FLAC__int32 Np, n, i; | |||
| if (p <= 0.0f) | |||
| FLAC__window_partial_tukey(window, L, 0.05f, start, end); | |||
| else if (p >= 1.0f) | |||
| FLAC__window_partial_tukey(window, L, 0.95f, start, end); | |||
| else { | |||
| Np = (FLAC__int32)(p / 2.0f * N); | |||
| for (n = 0; n < start_n && n < L; n++) | |||
| window[n] = 0.0f; | |||
| for (i = 1; n < (start_n+Np) && n < L; n++, i++) | |||
| window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Np)); | |||
| for (; n < (end_n-Np) && n < L; n++) | |||
| window[n] = 1.0f; | |||
| for (i = Np; n < end_n && n < L; n++, i--) | |||
| window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Np)); | |||
| for (; n < L; n++) | |||
| window[n] = 0.0f; | |||
| } | |||
| } | |||
| void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end) | |||
| { | |||
| const FLAC__int32 start_n = (FLAC__int32)(start * L); | |||
| const FLAC__int32 end_n = (FLAC__int32)(end * L); | |||
| FLAC__int32 Ns, Ne, n, i; | |||
| if (p <= 0.0f) | |||
| FLAC__window_punchout_tukey(window, L, 0.05f, start, end); | |||
| else if (p >= 1.0f) | |||
| FLAC__window_punchout_tukey(window, L, 0.95f, start, end); | |||
| else { | |||
| Ns = (FLAC__int32)(p / 2.0f * start_n); | |||
| Ne = (FLAC__int32)(p / 2.0f * (L - end_n)); | |||
| for (n = 0, i = 1; n < Ns && n < L; n++, i++) | |||
| window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ns)); | |||
| for (; n < start_n-Ns && n < L; n++) | |||
| window[n] = 1.0f; | |||
| for (i = Ns; n < start_n && n < L; n++, i--) | |||
| window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ns)); | |||
| for (; n < end_n && n < L; n++) | |||
| window[n] = 0.0f; | |||
| for (i = 1; n < end_n+Ne && n < L; n++, i++) | |||
| window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ne)); | |||
| for (; n < L - (Ne) && n < L; n++) | |||
| window[n] = 1.0f; | |||
| for (i = Ne; n < L; n++, i--) | |||
| window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ne)); | |||
| } | |||
| } | |||
| void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L) | |||
| { | |||
| const FLAC__int32 N = L - 1; | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2001-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -500,7 +500,7 @@ FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const | |||
| * \retval unsigned | |||
| * The length of the metadata block at the current iterator position. | |||
| * The is same length as that in the | |||
| * <a href="http://flac.sourceforge.net/format.html#metadata_block_header">metadata block header</a>, | |||
| * <a href="http://xiph.org/flac/format.html#metadata_block_header">metadata block header</a>, | |||
| * i.e. the length of the metadata body that follows the header. | |||
| */ | |||
| FLAC_API unsigned FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator); | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -1,6 +1,6 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2000-2009 Josh Coalson | |||
| * Copyright (C) 2011-2013 Xiph.Org Foundation | |||
| * Copyright (C) 2011-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| @@ -830,28 +830,28 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *en | |||
| * The actual values set for each level are: | |||
| * <table> | |||
| * <tr> | |||
| * <td><b>level</b><td> | |||
| * <td>do mid-side stereo<td> | |||
| * <td>loose mid-side stereo<td> | |||
| * <td>apodization<td> | |||
| * <td>max lpc order<td> | |||
| * <td>qlp coeff precision<td> | |||
| * <td>qlp coeff prec search<td> | |||
| * <td>escape coding<td> | |||
| * <td>exhaustive model search<td> | |||
| * <td>min residual partition order<td> | |||
| * <td>max residual partition order<td> | |||
| * <td>rice parameter search dist<td> | |||
| * <td><b>level</b></td> | |||
| * <td>do mid-side stereo</td> | |||
| * <td>loose mid-side stereo</td> | |||
| * <td>apodization</td> | |||
| * <td>max lpc order</td> | |||
| * <td>qlp coeff precision</td> | |||
| * <td>qlp coeff prec search</td> | |||
| * <td>escape coding</td> | |||
| * <td>exhaustive model search</td> | |||
| * <td>min residual partition order</td> | |||
| * <td>max residual partition order</td> | |||
| * <td>rice parameter search dist</td> | |||
| * </tr> | |||
| * <tr> <td><b>0</b><td> <td>false<td> <td>false<td> <td>tukey(0.5)<td> <td>0<td> <td>0<td> <td>false<td> <td>false<td> <td>false<td> <td>0<td> <td>3<td> <td>0<td> </tr> | |||
| * <tr> <td><b>1</b><td> <td>true<td> <td>true<td> <td>tukey(0.5)<td> <td>0<td> <td>0<td> <td>false<td> <td>false<td> <td>false<td> <td>0<td> <td>3<td> <td>0<td> </tr> | |||
| * <tr> <td><b>2</b><td> <td>true<td> <td>false<td> <td>tukey(0.5)<td> <td>0<td> <td>0<td> <td>false<td> <td>false<td> <td>false<td> <td>0<td> <td>3<td> <td>0<td> </tr> | |||
| * <tr> <td><b>3</b><td> <td>false<td> <td>false<td> <td>tukey(0.5)<td> <td>6<td> <td>0<td> <td>false<td> <td>false<td> <td>false<td> <td>0<td> <td>4<td> <td>0<td> </tr> | |||
| * <tr> <td><b>4</b><td> <td>true<td> <td>true<td> <td>tukey(0.5)<td> <td>8<td> <td>0<td> <td>false<td> <td>false<td> <td>false<td> <td>0<td> <td>4<td> <td>0<td> </tr> | |||
| * <tr> <td><b>5</b><td> <td>true<td> <td>false<td> <td>tukey(0.5)<td> <td>8<td> <td>0<td> <td>false<td> <td>false<td> <td>false<td> <td>0<td> <td>5<td> <td>0<td> </tr> | |||
| * <tr> <td><b>6</b><td> <td>true<td> <td>false<td> <td>tukey(0.5)<td> <td>8<td> <td>0<td> <td>false<td> <td>false<td> <td>false<td> <td>0<td> <td>6<td> <td>0<td> </tr> | |||
| * <tr> <td><b>7</b><td> <td>true<td> <td>false<td> <td>tukey(0.5)<td> <td>8<td> <td>0<td> <td>false<td> <td>false<td> <td>true<td> <td>0<td> <td>6<td> <td>0<td> </tr> | |||
| * <tr> <td><b>8</b><td> <td>true<td> <td>false<td> <td>tukey(0.5)<td> <td>12<td> <td>0<td> <td>false<td> <td>false<td> <td>true<td> <td>0<td> <td>6<td> <td>0<td> </tr> | |||
| * <tr> <td><b>0</b></td> <td>false</td> <td>false</td> <td>tukey(0.5)<td> <td>0</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr> | |||
| * <tr> <td><b>1</b></td> <td>true</td> <td>true</td> <td>tukey(0.5)<td> <td>0</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr> | |||
| * <tr> <td><b>2</b></td> <td>true</td> <td>false</td> <td>tukey(0.5)<td> <td>0</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr> | |||
| * <tr> <td><b>3</b></td> <td>false</td> <td>false</td> <td>tukey(0.5)<td> <td>6</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>4</td> <td>0</td> </tr> | |||
| * <tr> <td><b>4</b></td> <td>true</td> <td>true</td> <td>tukey(0.5)<td> <td>8</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>4</td> <td>0</td> </tr> | |||
| * <tr> <td><b>5</b></td> <td>true</td> <td>false</td> <td>tukey(0.5)<td> <td>8</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>5</td> <td>0</td> </tr> | |||
| * <tr> <td><b>6</b></td> <td>true</td> <td>false</td> <td>tukey(0.5);partial_tukey(2)<td> <td>8</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr> | |||
| * <tr> <td><b>7</b></td> <td>true</td> <td>false</td> <td>tukey(0.5);partial_tukey(2)<td> <td>12</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr> | |||
| * <tr> <td><b>8</b></td> <td>true</td> <td>false</td> <td>tukey(0.5);partial_tukey(2);punchout_tukey(3)</td> <td>12</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr> | |||
| * </table> | |||
| * | |||
| * \default \c 5 | |||
| @@ -920,7 +920,8 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamE | |||
| * The available functions are \c bartlett, \c bartlett_hann, | |||
| * \c blackman, \c blackman_harris_4term_92db, \c connes, \c flattop, | |||
| * \c gauss(STDDEV), \c hamming, \c hann, \c kaiser_bessel, \c nuttall, | |||
| * \c rectangle, \c triangle, \c tukey(P), \c welch. | |||
| * \c rectangle, \c triangle, \c tukey(P), \c partial_tukey(n[/ov[/P]]), | |||
| * \c punchout_tukey(n[/ov[/P]]), \c welch. | |||
| * | |||
| * For \c gauss(STDDEV), STDDEV specifies the standard deviation | |||
| * (0<STDDEV<=0.5). | |||
| @@ -929,6 +930,24 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamE | |||
| * tapered (0<=P<=1). P=0 corresponds to \c rectangle and P=1 | |||
| * corresponds to \c hann. | |||
| * | |||
| * Specifying \c partial_tukey or \c punchout_tukey works a little | |||
| * different. These do not specify a single apodization function, but | |||
| * a series of them with some overlap. partial_tukey specifies a series | |||
| * of small windows (all treated separately) while punchout_tukey | |||
| * specifies a series of windows that have a hole in them. In this way, | |||
| * the predictor is constructed with only a part of the block, which | |||
| * helps in case a block consists of dissimilar parts. | |||
| * | |||
| * The three parameters that can be specified for the functions are | |||
| * n, ov and P. n is the number of functions to add, ov is the overlap | |||
| * of the windows in case of partial_tukey and the overlap in the gaps | |||
| * in case of punchout_tukey. P is the fraction of the window that is | |||
| * tapered, like with a regular tukey window. The function can be | |||
| * specified with only a number, a number and an overlap, or a number | |||
| * an overlap and a P, for example, partial_tukey(3), partial_tukey(3/0.3) | |||
| * and partial_tukey(3/0.3/0.5) are all valid. ov should be smaller than 1 | |||
| * and can be negative. | |||
| * | |||
| * Example specifications are \c "blackman" or | |||
| * \c "hann;triangle;tukey(0.5);tukey(0.25);tukey(0.125)" | |||
| * | |||
| @@ -941,7 +960,9 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamE | |||
| * results in the smallest compressed subframe. | |||
| * | |||
| * Note that each function specified causes the encoder to occupy a | |||
| * floating point array in which to store the window. | |||
| * floating point array in which to store the window. Also note that the | |||
| * values of P, STDDEV and ov are locale-specific, so if the comma | |||
| * separator specified by the locale is a comma, a comma should be used. | |||
| * | |||
| * \default \c "tukey(0.5)" | |||
| * \param encoder An encoder instance to set. | |||
| @@ -0,0 +1,69 @@ | |||
| /* libFLAC - Free Lossless Audio Codec library | |||
| * Copyright (C) 2013-2014 Xiph.Org Foundation | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| * are met: | |||
| * | |||
| * - Redistributions of source code must retain the above copyright | |||
| * notice, this list of conditions and the following disclaimer. | |||
| * | |||
| * - Redistributions in binary form must reproduce the above copyright | |||
| * notice, this list of conditions and the following disclaimer in the | |||
| * documentation and/or other materials provided with the distribution. | |||
| * | |||
| * - Neither the name of the Xiph.org Foundation nor the names of its | |||
| * contributors may be used to endorse or promote products derived from | |||
| * this software without specific prior written permission. | |||
| * | |||
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||
| * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |||
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR | |||
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |||
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |||
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |||
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |||
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |||
| * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #ifdef _WIN32 | |||
| #ifndef flac__win_utf8_io_h | |||
| #define flac__win_utf8_io_h | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| #include <stdio.h> | |||
| #include <sys/stat.h> | |||
| #include <stdarg.h> | |||
| #include <windows.h> | |||
| int get_utf8_argv(int *argc, char ***argv); | |||
| int printf_utf8(const char *format, ...); | |||
| int fprintf_utf8(FILE *stream, const char *format, ...); | |||
| int vfprintf_utf8(FILE *stream, const char *format, va_list argptr); | |||
| FILE *fopen_utf8(const char *filename, const char *mode); | |||
| int stat_utf8(const char *path, struct stat *buffer); | |||
| int _stat64_utf8(const char *path, struct __stat64 *buffer); | |||
| int chmod_utf8(const char *filename, int pmode); | |||
| int utime_utf8(const char *filename, struct utimbuf *times); | |||
| int unlink_utf8(const char *filename); | |||
| int rename_utf8(const char *oldname, const char *newname); | |||
| size_t strlen_utf8(const char *str); | |||
| int win_get_console_width(void); | |||
| int print_console(FILE *stream, const wchar_t *text, size_t len); | |||
| HANDLE WINAPI CreateFile_utf8(const char *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); | |||
| #ifdef __cplusplus | |||
| } /* extern "C" */ | |||
| #endif | |||
| #endif | |||
| #endif | |||
| @@ -193,47 +193,72 @@ namespace AiffFileHelpers | |||
| #endif | |||
| //============================================================================== | |||
| static String readCATEChunk (InputStream& input, const uint32 length) | |||
| namespace CATEChunk | |||
| { | |||
| MemoryBlock mb; | |||
| input.skipNextBytes (4); | |||
| input.readIntoMemoryBlock (mb, (ssize_t) length - 4); | |||
| static const char* appleGenres[] = | |||
| { | |||
| "Rock/Blues", | |||
| "Electronic/Dance", | |||
| "Jazz", | |||
| "Urban", | |||
| "World/Ethnic", | |||
| "Cinematic/New Age", | |||
| "Orchestral", | |||
| "Country/Folk", | |||
| "Experimental", | |||
| "Other Genre", | |||
| nullptr | |||
| }; | |||
| static bool isValidTag (const char* d) noexcept | |||
| { | |||
| return CharacterFunctions::isLetterOrDigit (d[0]) && CharacterFunctions::isUpperCase (d[0]) | |||
| && CharacterFunctions::isLetterOrDigit (d[1]) && CharacterFunctions::isLowerCase (d[1]) | |||
| && CharacterFunctions::isLetterOrDigit (d[2]) && CharacterFunctions::isLowerCase (d[2]); | |||
| } | |||
| const StringArray genres (appleGenres); | |||
| StringArray tagsArray; | |||
| static bool isAppleGenre (const String& tag) noexcept | |||
| { | |||
| static const char* appleGenres[] = | |||
| { | |||
| "Rock/Blues", | |||
| "Electronic/Dance", | |||
| "Jazz", | |||
| "Urban", | |||
| "World/Ethnic", | |||
| "Cinematic/New Age", | |||
| "Orchestral", | |||
| "Country/Folk", | |||
| "Experimental", | |||
| "Other Genre" | |||
| }; | |||
| for (int i = 0; i < numElementsInArray (appleGenres); ++i) | |||
| if (tag == appleGenres[i]) | |||
| return true; | |||
| int bytesLeft = (int) mb.getSize(); | |||
| const char* data = static_cast<const char*> (mb.getData()); | |||
| return false; | |||
| } | |||
| while (bytesLeft > 0) | |||
| static String read (InputStream& input, const uint32 length) | |||
| { | |||
| const String tag (CharPointer_UTF8 (data), | |||
| CharPointer_UTF8 (data + bytesLeft)); | |||
| MemoryBlock mb; | |||
| input.skipNextBytes (4); | |||
| input.readIntoMemoryBlock (mb, (ssize_t) length - 4); | |||
| if (tag.isNotEmpty()) | |||
| tagsArray.add (data); | |||
| StringArray tagsArray; | |||
| const int numBytesInTag = genres.contains (tag) ? 118 : 50; | |||
| data += numBytesInTag; | |||
| bytesLeft -= numBytesInTag; | |||
| } | |||
| const char* data = static_cast<const char*> (mb.getData()); | |||
| const char* dataEnd = data + mb.getSize(); | |||
| while (data < dataEnd) | |||
| { | |||
| bool isGenre = false; | |||
| return tagsArray.joinIntoString (";"); | |||
| if (isValidTag (data)) | |||
| { | |||
| const String tag = String (CharPointer_UTF8 (data), CharPointer_UTF8 (dataEnd)); | |||
| isGenre = isAppleGenre (tag); | |||
| tagsArray.add (tag); | |||
| } | |||
| data += isGenre ? 118 : 50; | |||
| if (data[0] == 0) | |||
| { | |||
| if (data + 52 < dataEnd && isValidTag (data + 50)) data += 50; | |||
| else if (data + 120 < dataEnd && isValidTag (data + 118)) data += 118; | |||
| else if (data + 170 < dataEnd && isValidTag (data + 168)) data += 168; | |||
| } | |||
| } | |||
| return tagsArray.joinIntoString (";"); | |||
| } | |||
| } | |||
| //============================================================================== | |||
| @@ -518,7 +543,7 @@ public: | |||
| else if (type == chunkName ("cate")) | |||
| { | |||
| metadataValues.set (AiffAudioFormat::appleTag, | |||
| AiffFileHelpers::readCATEChunk (*input, length));; | |||
| AiffFileHelpers::CATEChunk::read (*input, length)); | |||
| } | |||
| else if ((hasGotVer && hasGotData && hasGotType) | |||
| || chunkEnd < input->getPosition() | |||
| @@ -821,12 +846,54 @@ public: | |||
| return true; | |||
| } | |||
| void readMaxLevels (int64 startSampleInFile, int64 numSamples, | |||
| float& min0, float& max0, float& min1, float& max1) | |||
| void getSample (int64 sample, float* result) const noexcept override | |||
| { | |||
| const int num = (int) numChannels; | |||
| if (map == nullptr || ! mappedSection.contains (sample)) | |||
| { | |||
| jassertfalse; // you must make sure that the window contains all the samples you're going to attempt to read. | |||
| zeromem (result, sizeof (float) * (size_t) num); | |||
| return; | |||
| } | |||
| float** dest = &result; | |||
| const void* source = sampleToPointer (sample); | |||
| if (littleEndian) | |||
| { | |||
| switch (bitsPerSample) | |||
| { | |||
| case 8: ReadHelper<AudioData::Float32, AudioData::UInt8, AudioData::LittleEndian>::read (dest, 0, 1, source, 1, num); break; | |||
| case 16: ReadHelper<AudioData::Float32, AudioData::Int16, AudioData::LittleEndian>::read (dest, 0, 1, source, 1, num); break; | |||
| case 24: ReadHelper<AudioData::Float32, AudioData::Int24, AudioData::LittleEndian>::read (dest, 0, 1, source, 1, num); break; | |||
| case 32: if (usesFloatingPointData) ReadHelper<AudioData::Float32, AudioData::Float32, AudioData::LittleEndian>::read (dest, 0, 1, source, 1, num); | |||
| else ReadHelper<AudioData::Float32, AudioData::Int32, AudioData::LittleEndian>::read (dest, 0, 1, source, 1, num); break; | |||
| default: jassertfalse; break; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| switch (bitsPerSample) | |||
| { | |||
| case 8: ReadHelper<AudioData::Float32, AudioData::UInt8, AudioData::BigEndian>::read (dest, 0, 1, source, 1, num); break; | |||
| case 16: ReadHelper<AudioData::Float32, AudioData::Int16, AudioData::BigEndian>::read (dest, 0, 1, source, 1, num); break; | |||
| case 24: ReadHelper<AudioData::Float32, AudioData::Int24, AudioData::BigEndian>::read (dest, 0, 1, source, 1, num); break; | |||
| case 32: if (usesFloatingPointData) ReadHelper<AudioData::Float32, AudioData::Float32, AudioData::BigEndian>::read (dest, 0, 1, source, 1, num); | |||
| else ReadHelper<AudioData::Float32, AudioData::Int32, AudioData::BigEndian>::read (dest, 0, 1, source, 1, num); break; | |||
| default: jassertfalse; break; | |||
| } | |||
| } | |||
| } | |||
| void readMaxLevels (int64 startSampleInFile, int64 numSamples, Range<float>* results, int numChannelsToRead) override | |||
| { | |||
| if (numSamples <= 0) | |||
| { | |||
| min0 = max0 = min1 = max1 = 0; | |||
| for (int i = 0; i < numChannelsToRead; ++i) | |||
| results[i] = Range<float>(); | |||
| return; | |||
| } | |||
| @@ -834,17 +901,19 @@ public: | |||
| { | |||
| jassertfalse; // you must make sure that the window contains all the samples you're going to attempt to read. | |||
| min0 = max0 = min1 = max1 = 0; | |||
| for (int i = 0; i < numChannelsToRead; ++i) | |||
| results[i] = Range<float>(); | |||
| return; | |||
| } | |||
| switch (bitsPerSample) | |||
| { | |||
| case 8: scanMinAndMax<AudioData::UInt8> (startSampleInFile, numSamples, min0, max0, min1, max1); break; | |||
| case 16: scanMinAndMax<AudioData::Int16> (startSampleInFile, numSamples, min0, max0, min1, max1); break; | |||
| case 24: scanMinAndMax<AudioData::Int24> (startSampleInFile, numSamples, min0, max0, min1, max1); break; | |||
| case 32: if (usesFloatingPointData) scanMinAndMax<AudioData::Float32> (startSampleInFile, numSamples, min0, max0, min1, max1); | |||
| else scanMinAndMax<AudioData::Int32> (startSampleInFile, numSamples, min0, max0, min1, max1); break; | |||
| case 8: scanMinAndMax<AudioData::UInt8> (startSampleInFile, numSamples, results, numChannelsToRead); break; | |||
| case 16: scanMinAndMax<AudioData::Int16> (startSampleInFile, numSamples, results, numChannelsToRead); break; | |||
| case 24: scanMinAndMax<AudioData::Int24> (startSampleInFile, numSamples, results, numChannelsToRead); break; | |||
| case 32: if (usesFloatingPointData) scanMinAndMax<AudioData::Float32> (startSampleInFile, numSamples, results, numChannelsToRead); | |||
| else scanMinAndMax<AudioData::Int32> (startSampleInFile, numSamples, results, numChannelsToRead); break; | |||
| default: jassertfalse; break; | |||
| } | |||
| } | |||
| @@ -853,24 +922,17 @@ private: | |||
| const bool littleEndian; | |||
| template <typename SampleType> | |||
| void scanMinAndMax (int64 startSampleInFile, int64 numSamples, | |||
| float& min0, float& max0, float& min1, float& max1) const noexcept | |||
| void scanMinAndMax (int64 startSampleInFile, int64 numSamples, Range<float>* results, int numChannelsToRead) const noexcept | |||
| { | |||
| scanMinAndMax2<SampleType> (0, startSampleInFile, numSamples, min0, max0); | |||
| if (numChannels > 1) | |||
| scanMinAndMax2<SampleType> (1, startSampleInFile, numSamples, min1, max1); | |||
| else | |||
| min1 = max1 = 0; | |||
| for (int i = 0; i < numChannelsToRead; ++i) | |||
| results[i] = scanMinAndMaxForChannel<SampleType> (i, startSampleInFile, numSamples); | |||
| } | |||
| template <typename SampleType> | |||
| void scanMinAndMax2 (int channel, int64 startSampleInFile, int64 numSamples, float& mn, float& mx) const noexcept | |||
| Range<float> scanMinAndMaxForChannel (int channel, int64 startSampleInFile, int64 numSamples) const noexcept | |||
| { | |||
| if (littleEndian) | |||
| scanMinAndMaxInterleaved<SampleType, AudioData::LittleEndian> (channel, startSampleInFile, numSamples, mn, mx); | |||
| else | |||
| scanMinAndMaxInterleaved<SampleType, AudioData::BigEndian> (channel, startSampleInFile, numSamples, mn, mx); | |||
| return littleEndian ? scanMinAndMaxInterleaved<SampleType, AudioData::LittleEndian> (channel, startSampleInFile, numSamples) | |||
| : scanMinAndMaxInterleaved<SampleType, AudioData::BigEndian> (channel, startSampleInFile, numSamples); | |||
| } | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryMappedAiffReader) | |||
| @@ -607,7 +607,7 @@ private: | |||
| float* costab = cosTables[i]; | |||
| for (int k = 0; k < kr; ++k) | |||
| costab[k] = (float) (1.0 / (2.0 * cos (double_Pi * (k * 2 + 1) / divv))); | |||
| costab[k] = (float) (1.0 / (2.0 * std::cos (double_Pi * (k * 2 + 1) / divv))); | |||
| } | |||
| for (i = 0, j = 0; i < 256; ++i, ++j, table += 32) | |||
| @@ -692,23 +692,23 @@ private: | |||
| for (i = 0; i < 18; ++i) | |||
| { | |||
| win[0][i] = win[1][i] = (float) (0.5 * sin (double_Pi / 72.0 * (2 * i + 1)) / cos (double_Pi * (2 * i + 19) / 72.0)); | |||
| win[0][i + 18] = win[3][i + 18] = (float) (0.5 * sin (double_Pi / 72.0 * (2 * (i + 18) + 1)) / cos (double_Pi * (2 * (i + 18) + 19) / 72.0)); | |||
| win[0][i] = win[1][i] = (float) (0.5 * std::sin (double_Pi / 72.0 * (2 * i + 1)) / std::cos (double_Pi * (2 * i + 19) / 72.0)); | |||
| win[0][i + 18] = win[3][i + 18] = (float) (0.5 * std::sin (double_Pi / 72.0 * (2 * (i + 18) + 1)) / std::cos (double_Pi * (2 * (i + 18) + 19) / 72.0)); | |||
| } | |||
| const double piOver72 = double_Pi; | |||
| for (i = 0; i < 6; ++i) | |||
| { | |||
| win[1][i + 18] = (float) (0.5 / cos (piOver72 * (2 * (i + 18) + 19))); | |||
| win[3][i + 12] = (float) (0.5 / cos (piOver72 * (2 * (i + 12) + 19))); | |||
| win[1][i + 24] = (float) (0.5 * sin (double_Pi / 24.0 * (2 * i + 13)) / cos (piOver72 * (2 * (i + 24) + 19))); | |||
| win[1][i + 18] = (float) (0.5 / std::cos (piOver72 * (2 * (i + 18) + 19))); | |||
| win[3][i + 12] = (float) (0.5 / std::cos (piOver72 * (2 * (i + 12) + 19))); | |||
| win[1][i + 24] = (float) (0.5 * std::sin (double_Pi / 24.0 * (2 * i + 13)) / std::cos (piOver72 * (2 * (i + 24) + 19))); | |||
| win[1][i + 30] = win[3][i] = 0; | |||
| win[3][i + 6] = (float) (0.5 * sin (double_Pi / 24.0 * (2 * i + 1)) / cos (piOver72 * (2 * (i + 6) + 19))); | |||
| win[3][i + 6] = (float) (0.5 * std::sin (double_Pi / 24.0 * (2 * i + 1)) / std::cos (piOver72 * (2 * (i + 6) + 19))); | |||
| } | |||
| for (i = 0; i < 12; ++i) | |||
| win[2][i] = (float) (0.5 * sin (double_Pi / 24.0 * (2 * i + 1)) / cos (double_Pi * (2 * i + 7) / 24.0)); | |||
| win[2][i] = (float) (0.5 * std::sin (double_Pi / 24.0 * (2 * i + 1)) / std::cos (double_Pi * (2 * i + 7) / 24.0)); | |||
| for (j = 0; j < 4; ++j) | |||
| { | |||
| @@ -721,7 +721,7 @@ private: | |||
| for (i = 0; i < 16; ++i) | |||
| { | |||
| const double t = tan (i * double_Pi / 12.0); | |||
| const double t = std::tan (i * double_Pi / 12.0); | |||
| tan1_1[i] = (float) (t / (1.0 + t)); | |||
| tan2_1[i] = (float) (1.0 / (1.0 + t)); | |||
| tan1_2[i] = (float) (sqrt2 * t / (1.0 + t)); | |||
| @@ -1289,12 +1289,39 @@ public: | |||
| return true; | |||
| } | |||
| void readMaxLevels (int64 startSampleInFile, int64 numSamples, | |||
| float& min0, float& max0, float& min1, float& max1) override | |||
| void getSample (int64 sample, float* result) const noexcept override | |||
| { | |||
| const int num = (int) numChannels; | |||
| if (map == nullptr || ! mappedSection.contains (sample)) | |||
| { | |||
| jassertfalse; // you must make sure that the window contains all the samples you're going to attempt to read. | |||
| zeromem (result, sizeof (float) * (size_t) num); | |||
| return; | |||
| } | |||
| float** dest = &result; | |||
| const void* source = sampleToPointer (sample); | |||
| switch (bitsPerSample) | |||
| { | |||
| case 8: ReadHelper<AudioData::Float32, AudioData::UInt8, AudioData::LittleEndian>::read (dest, 0, 1, source, 1, num); break; | |||
| case 16: ReadHelper<AudioData::Float32, AudioData::Int16, AudioData::LittleEndian>::read (dest, 0, 1, source, 1, num); break; | |||
| case 24: ReadHelper<AudioData::Float32, AudioData::Int24, AudioData::LittleEndian>::read (dest, 0, 1, source, 1, num); break; | |||
| case 32: if (usesFloatingPointData) ReadHelper<AudioData::Float32, AudioData::Float32, AudioData::LittleEndian>::read (dest, 0, 1, source, 1, num); | |||
| else ReadHelper<AudioData::Float32, AudioData::Int32, AudioData::LittleEndian>::read (dest, 0, 1, source, 1, num); break; | |||
| default: jassertfalse; break; | |||
| } | |||
| } | |||
| void readMaxLevels (int64 startSampleInFile, int64 numSamples, Range<float>* results, int numChannelsToRead) override | |||
| { | |||
| if (numSamples <= 0) | |||
| { | |||
| min0 = max0 = min1 = max1 = 0; | |||
| for (int i = 0; i < numChannelsToRead; ++i) | |||
| results[i] = Range<float>(); | |||
| return; | |||
| } | |||
| @@ -1302,32 +1329,29 @@ public: | |||
| { | |||
| jassertfalse; // you must make sure that the window contains all the samples you're going to attempt to read. | |||
| min0 = max0 = min1 = max1 = 0; | |||
| for (int i = 0; i < numChannelsToRead; ++i) | |||
| results[i] = Range<float>(); | |||
| return; | |||
| } | |||
| switch (bitsPerSample) | |||
| { | |||
| case 8: scanMinAndMax<AudioData::UInt8> (startSampleInFile, numSamples, min0, max0, min1, max1); break; | |||
| case 16: scanMinAndMax<AudioData::Int16> (startSampleInFile, numSamples, min0, max0, min1, max1); break; | |||
| case 24: scanMinAndMax<AudioData::Int24> (startSampleInFile, numSamples, min0, max0, min1, max1); break; | |||
| case 32: if (usesFloatingPointData) scanMinAndMax<AudioData::Float32> (startSampleInFile, numSamples, min0, max0, min1, max1); | |||
| else scanMinAndMax<AudioData::Int32> (startSampleInFile, numSamples, min0, max0, min1, max1); break; | |||
| case 8: scanMinAndMax<AudioData::UInt8> (startSampleInFile, numSamples, results, numChannelsToRead); break; | |||
| case 16: scanMinAndMax<AudioData::Int16> (startSampleInFile, numSamples, results, numChannelsToRead); break; | |||
| case 24: scanMinAndMax<AudioData::Int24> (startSampleInFile, numSamples, results, numChannelsToRead); break; | |||
| case 32: if (usesFloatingPointData) scanMinAndMax<AudioData::Float32> (startSampleInFile, numSamples, results, numChannelsToRead); | |||
| else scanMinAndMax<AudioData::Int32> (startSampleInFile, numSamples, results, numChannelsToRead); break; | |||
| default: jassertfalse; break; | |||
| } | |||
| } | |||
| private: | |||
| template <typename SampleType> | |||
| void scanMinAndMax (int64 startSampleInFile, int64 numSamples, | |||
| float& min0, float& max0, float& min1, float& max1) const noexcept | |||
| void scanMinAndMax (int64 startSampleInFile, int64 numSamples, Range<float>* results, int numChannelsToRead) const noexcept | |||
| { | |||
| scanMinAndMaxInterleaved<SampleType, AudioData::LittleEndian> (0, startSampleInFile, numSamples, min0, max0); | |||
| if (numChannels > 1) | |||
| scanMinAndMaxInterleaved<SampleType, AudioData::LittleEndian> (1, startSampleInFile, numSamples, min1, max1); | |||
| else | |||
| min1 = max1 = 0; | |||
| for (int i = 0; i < numChannelsToRead; ++i) | |||
| results[i] = scanMinAndMaxInterleaved<SampleType, AudioData::LittleEndian> (i, startSampleInFile, numSamples); | |||
| } | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryMappedWavReader) | |||
| @@ -46,6 +46,7 @@ bool AudioFormatReader::read (int* const* destSamples, | |||
| { | |||
| jassert (numDestChannels > 0); // you have to actually give this some channels to work with! | |||
| const size_t originalNumSamplesToRead = (size_t) numSamplesToRead; | |||
| int startOffsetInDestBuffer = 0; | |||
| if (startSampleInSource < 0) | |||
| @@ -64,7 +65,7 @@ bool AudioFormatReader::read (int* const* destSamples, | |||
| if (numSamplesToRead <= 0) | |||
| return true; | |||
| if (! readSamples (const_cast <int**> (destSamples), | |||
| if (! readSamples (const_cast<int**> (destSamples), | |||
| jmin ((int) numChannels, numDestChannels), startOffsetInDestBuffer, | |||
| startSampleInSource, numSamplesToRead)) | |||
| return false; | |||
| @@ -87,13 +88,13 @@ bool AudioFormatReader::read (int* const* destSamples, | |||
| if (lastFullChannel != nullptr) | |||
| for (int i = (int) numChannels; i < numDestChannels; ++i) | |||
| if (destSamples[i] != nullptr) | |||
| memcpy (destSamples[i], lastFullChannel, sizeof (int) * (size_t) numSamplesToRead); | |||
| memcpy (destSamples[i], lastFullChannel, sizeof (int) * originalNumSamplesToRead); | |||
| } | |||
| else | |||
| { | |||
| for (int i = (int) numChannels; i < numDestChannels; ++i) | |||
| if (destSamples[i] != nullptr) | |||
| zeromem (destSamples[i], sizeof (int) * (size_t) numSamplesToRead); | |||
| zeromem (destSamples[i], sizeof (int) * originalNumSamplesToRead); | |||
| } | |||
| } | |||
| @@ -229,20 +230,21 @@ void AudioFormatReader::readMaxLevels (int64 startSampleInFile, int64 numSamples | |||
| float& lowestRight, float& highestRight) | |||
| { | |||
| Range<float> levels[2]; | |||
| readMaxLevels (startSampleInFile, numSamples, levels, jmin (2, (int) numChannels)); | |||
| lowestLeft = levels[0].getStart(); | |||
| highestLeft = levels[0].getEnd(); | |||
| if (numChannels > 1) | |||
| if (numChannels < 2) | |||
| { | |||
| lowestRight = levels[1].getStart(); | |||
| highestRight = levels[1].getEnd(); | |||
| readMaxLevels (startSampleInFile, numSamples, levels, (int) numChannels); | |||
| levels[1] = levels[0]; | |||
| } | |||
| else | |||
| { | |||
| lowestRight = lowestLeft; | |||
| highestRight = highestLeft; | |||
| readMaxLevels (startSampleInFile, numSamples, levels, 2); | |||
| } | |||
| lowestLeft = levels[0].getStart(); | |||
| highestLeft = levels[0].getEnd(); | |||
| lowestRight = levels[1].getStart(); | |||
| highestRight = levels[1].getEnd(); | |||
| } | |||
| int64 AudioFormatReader::searchForLevel (int64 startSample, | |||
| @@ -44,7 +44,7 @@ protected: | |||
| @param sourceStream the stream to read from - this will be deleted | |||
| by this object when it is no longer needed. (Some | |||
| specialised readers might not use this parameter and | |||
| can leave it as 0). | |||
| can leave it as nullptr). | |||
| @param formatName the description that will be returned by the getFormatName() | |||
| method | |||
| */ | |||
| @@ -247,8 +247,8 @@ protected: | |||
| template <class DestSampleType, class SourceSampleType, class SourceEndianness> | |||
| struct ReadHelper | |||
| { | |||
| typedef AudioData::Pointer <DestSampleType, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DestType; | |||
| typedef AudioData::Pointer <SourceSampleType, SourceEndianness, AudioData::Interleaved, AudioData::Const> SourceType; | |||
| typedef AudioData::Pointer<DestSampleType, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DestType; | |||
| typedef AudioData::Pointer<SourceSampleType, SourceEndianness, AudioData::Interleaved, AudioData::Const> SourceType; | |||
| template <typename TargetType> | |||
| static void read (TargetType* const* destData, int destOffset, int numDestChannels, | |||
| @@ -57,17 +57,10 @@ bool AudioSubsectionReader::readSamples (int** destSamples, int numDestChannels, | |||
| startSampleInFile + startSample, numSamples); | |||
| } | |||
| void AudioSubsectionReader::readMaxLevels (int64 startSampleInFile, | |||
| int64 numSamples, | |||
| float& lowestLeft, | |||
| float& highestLeft, | |||
| float& lowestRight, | |||
| float& highestRight) | |||
| void AudioSubsectionReader::readMaxLevels (int64 startSampleInFile, int64 numSamples, Range<float>* results, int numChannelsToRead) | |||
| { | |||
| startSampleInFile = jmax ((int64) 0, startSampleInFile); | |||
| numSamples = jmax ((int64) 0, jmin (numSamples, length - startSampleInFile)); | |||
| source->readMaxLevels (startSampleInFile + startSample, numSamples, | |||
| lowestLeft, highestLeft, | |||
| lowestRight, highestRight); | |||
| source->readMaxLevels (startSampleInFile + startSample, numSamples, results, numChannelsToRead); | |||
| } | |||
| @@ -68,8 +68,7 @@ public: | |||
| int64 startSampleInFile, int numSamples) override; | |||
| void readMaxLevels (int64 startSample, int64 numSamples, | |||
| float& lowestLeft, float& highestLeft, | |||
| float& lowestRight, float& highestRight) override; | |||
| Range<float>* results, int numChannelsToRead) override; | |||
| private: | |||
| @@ -28,7 +28,8 @@ BufferingAudioReader::BufferingAudioReader (AudioFormatReader* sourceReader, | |||
| : AudioFormatReader (nullptr, sourceReader->getFormatName()), | |||
| source (sourceReader), thread (timeSliceThread), | |||
| nextReadPosition (0), | |||
| numBlocks (1 + (samplesToBuffer / samplesPerBlock)) | |||
| numBlocks (1 + (samplesToBuffer / samplesPerBlock)), | |||
| timeoutMs (0) | |||
| { | |||
| sampleRate = source->sampleRate; | |||
| lengthInSamples = source->lengthInSamples; | |||
| @@ -70,6 +70,12 @@ public: | |||
| /** Touches the memory for the given sample, to force it to be loaded into active memory. */ | |||
| void touchSample (int64 sample) const noexcept; | |||
| /** Returns the samples for all channels at a given sample position. | |||
| The result array must be large enough to hold a value for each channel | |||
| that this reader contains. | |||
| */ | |||
| virtual void getSample (int64 sampleIndex, float* result) const noexcept = 0; | |||
| /** Returns the number of bytes currently being mapped */ | |||
| size_t getNumBytesUsed() const { return map != nullptr ? map->getSize() : 0; } | |||
| @@ -91,12 +97,12 @@ protected: | |||
| /** Used by AudioFormatReader subclasses to scan for min/max ranges in interleaved data. */ | |||
| template <typename SampleType, typename Endianness> | |||
| void scanMinAndMaxInterleaved (int channel, int64 startSampleInFile, int64 numSamples, float& mn, float& mx) const noexcept | |||
| Range<float> scanMinAndMaxInterleaved (int channel, int64 startSampleInFile, int64 numSamples) const noexcept | |||
| { | |||
| typedef AudioData::Pointer <SampleType, Endianness, AudioData::Interleaved, AudioData::Const> SourceType; | |||
| SourceType (addBytesToPointer (sampleToPointer (startSampleInFile), ((int) bitsPerSample / 8) * channel), (int) numChannels) | |||
| .findMinAndMax ((size_t) numSamples, mn, mx); | |||
| return SourceType (addBytesToPointer (sampleToPointer (startSampleInFile), ((int) bitsPerSample / 8) * channel), (int) numChannels) | |||
| .findMinAndMax ((size_t) numSamples); | |||
| } | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryMappedAudioFormatReader) | |||
| @@ -119,7 +119,7 @@ void SamplerVoice::startNote (const int midiNoteNumber, | |||
| if (sound->releaseSamples > 0) | |||
| releaseDelta = (float) (-pitchRatio / sound->releaseSamples); | |||
| else | |||
| releaseDelta = 0.0f; | |||
| releaseDelta = -1.0f; | |||
| } | |||
| else | |||
| { | |||
| @@ -364,7 +364,6 @@ class VST3HostContext : public Vst::IComponentHandler, // From VST V3.0.0 | |||
| public Vst::IComponentHandler3, // From VST V3.5.0 (also very well named!) | |||
| public Vst::IContextMenuTarget, | |||
| public Vst::IHostApplication, | |||
| public Vst::IParamValueQueue, | |||
| public Vst::IUnitHandler | |||
| { | |||
| public: | |||
| @@ -684,31 +683,6 @@ public: | |||
| return kNotImplemented; | |||
| } | |||
| //============================================================================== | |||
| Vst::ParamID PLUGIN_API getParameterId() override | |||
| { | |||
| jassertfalse; | |||
| return 0; | |||
| } | |||
| Steinberg::int32 PLUGIN_API getPointCount() override | |||
| { | |||
| jassertfalse; | |||
| return 0; | |||
| } | |||
| tresult PLUGIN_API getPoint (Steinberg::int32, Steinberg::int32&, Vst::ParamValue&) override | |||
| { | |||
| jassertfalse; | |||
| return kResultFalse; | |||
| } | |||
| tresult PLUGIN_API addPoint (Steinberg::int32, Vst::ParamValue, Steinberg::int32&) override | |||
| { | |||
| jassertfalse; | |||
| return kResultFalse; | |||
| } | |||
| //============================================================================== | |||
| tresult PLUGIN_API notifyUnitSelection (Vst::UnitID) override | |||
| { | |||
| @@ -736,7 +710,6 @@ public: | |||
| TEST_FOR_AND_RETURN_IF_VALID (iid, Vst::IComponentHandler3) | |||
| TEST_FOR_AND_RETURN_IF_VALID (iid, Vst::IContextMenuTarget) | |||
| TEST_FOR_AND_RETURN_IF_VALID (iid, Vst::IHostApplication) | |||
| TEST_FOR_AND_RETURN_IF_VALID (iid, Vst::IParamValueQueue) | |||
| TEST_FOR_AND_RETURN_IF_VALID (iid, Vst::IUnitHandler) | |||
| TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (iid, FUnknown, Vst::IComponentHandler) | |||
| @@ -837,47 +810,26 @@ private: | |||
| //============================================================================== | |||
| tresult PLUGIN_API setInt (AttrID id, Steinberg::int64 value) override | |||
| { | |||
| jassert (id != nullptr); | |||
| if (! setValueForId (id, value)) | |||
| owner->messageQueue.add (ComSmartPtr<Message> (new Message (*owner, this, id, value))); | |||
| addMessageToQueue (id, value); | |||
| return kResultTrue; | |||
| } | |||
| tresult PLUGIN_API setFloat (AttrID id, double value) override | |||
| { | |||
| jassert (id != nullptr); | |||
| if (! setValueForId (id, value)) | |||
| owner->messageQueue.add (ComSmartPtr<Message> (new Message (*owner, this, id, value))); | |||
| addMessageToQueue (id, value); | |||
| return kResultTrue; | |||
| } | |||
| tresult PLUGIN_API setString (AttrID id, const Vst::TChar* string) override | |||
| { | |||
| jassert (id != nullptr); | |||
| jassert (string != nullptr); | |||
| const String text (toString (string)); | |||
| if (! setValueForId (id, text)) | |||
| owner->messageQueue.add (ComSmartPtr<Message> (new Message (*owner, this, id, text))); | |||
| addMessageToQueue (id, toString (string)); | |||
| return kResultTrue; | |||
| } | |||
| tresult PLUGIN_API setBinary (AttrID id, const void* data, Steinberg::uint32 size) override | |||
| { | |||
| jassert (id != nullptr); | |||
| jassert (data != nullptr && size > 0); | |||
| MemoryBlock block (data, (size_t) size); | |||
| if (! setValueForId (id, block)) | |||
| owner->messageQueue.add (ComSmartPtr<Message> (new Message (*owner, this, id, block))); | |||
| jassert (size >= 0 && (data != nullptr || size == 0)); | |||
| addMessageToQueue (id, MemoryBlock (data, (size_t) size)); | |||
| return kResultTrue; | |||
| } | |||
| @@ -886,7 +838,7 @@ private: | |||
| { | |||
| jassert (id != nullptr); | |||
| if (fetchValueForId (id, result)) | |||
| if (findMessageOnQueueWithID (id, result)) | |||
| return kResultTrue; | |||
| jassertfalse; | |||
| @@ -897,7 +849,7 @@ private: | |||
| { | |||
| jassert (id != nullptr); | |||
| if (fetchValueForId (id, result)) | |||
| if (findMessageOnQueueWithID (id, result)) | |||
| return kResultTrue; | |||
| jassertfalse; | |||
| @@ -909,7 +861,7 @@ private: | |||
| jassert (id != nullptr); | |||
| String stringToFetch; | |||
| if (fetchValueForId (id, stringToFetch)) | |||
| if (findMessageOnQueueWithID (id, stringToFetch)) | |||
| { | |||
| Steinberg::String str (stringToFetch.toRawUTF8()); | |||
| str.copyTo (result, 0, (Steinberg::int32) jmin (length, (Steinberg::uint32) std::numeric_limits<Steinberg::int32>::max())); | |||
| @@ -949,7 +901,7 @@ private: | |||
| //============================================================================== | |||
| template<typename Type> | |||
| bool setValueForId (AttrID id, const Type& value) | |||
| void addMessageToQueue (AttrID id, const Type& value) | |||
| { | |||
| jassert (id != nullptr); | |||
| @@ -960,15 +912,15 @@ private: | |||
| if (std::strcmp (message->getMessageID(), id) == 0) | |||
| { | |||
| message->value = value; | |||
| return true; | |||
| return; | |||
| } | |||
| } | |||
| return false; // No message found with that Id | |||
| owner->messageQueue.add (ComSmartPtr<Message> (new Message (*owner, this, id, value))); | |||
| } | |||
| template<typename Type> | |||
| bool fetchValueForId (AttrID id, Type& value) | |||
| bool findMessageOnQueueWithID (AttrID id, Type& value) | |||
| { | |||
| jassert (id != nullptr); | |||
| @@ -1632,8 +1584,8 @@ public: | |||
| : module (handle), | |||
| numInputAudioBusses (0), | |||
| numOutputAudioBusses (0), | |||
| inputParameterChanges (new ParameterChangeList()), | |||
| outputParameterChanges (new ParameterChangeList()), | |||
| inputParameterChanges (new ParamValueQueueList()), | |||
| outputParameterChanges (new ParamValueQueueList()), | |||
| midiInputs (new MidiEventList()), | |||
| midiOutputs (new MidiEventList()), | |||
| isComponentInitialised (false), | |||
| @@ -1847,6 +1799,8 @@ public: | |||
| processor->process (data); | |||
| MidiEventList::toMidiBuffer (midiMessages, *midiOutputs); | |||
| inputParameterChanges->clearAllQueues(); | |||
| } | |||
| } | |||
| @@ -1977,8 +1931,11 @@ public: | |||
| { | |||
| if (editController != nullptr) | |||
| { | |||
| const uint32 id = getParameterInfoForIndex (parameterIndex).id; | |||
| editController->setParamNormalized (id, (double) newValue); | |||
| const uint32 paramID = getParameterInfoForIndex (parameterIndex).id; | |||
| editController->setParamNormalized (paramID, (double) newValue); | |||
| Steinberg::int32 index; | |||
| inputParameterChanges->addParameterData (paramID, index)->addPoint (0, newValue, index); | |||
| } | |||
| } | |||
| @@ -2053,6 +2010,115 @@ public: | |||
| (void) sizeInBytes; | |||
| } | |||
| //============================================================================== | |||
| // NB: this class and its subclasses must be public to avoid problems in | |||
| // DLL builds under MSVC. | |||
| class ParamValueQueueList : public Vst::IParameterChanges | |||
| { | |||
| public: | |||
| ParamValueQueueList() {} | |||
| virtual ~ParamValueQueueList() {} | |||
| JUCE_DECLARE_VST3_COM_REF_METHODS | |||
| JUCE_DECLARE_VST3_COM_QUERY_METHODS | |||
| Steinberg::int32 PLUGIN_API getParameterCount() override { return (Steinberg::int32) queues.size(); } | |||
| Vst::IParamValueQueue* PLUGIN_API getParameterData (Steinberg::int32 index) override { return queues[(int) index]; } | |||
| Vst::IParamValueQueue* PLUGIN_API addParameterData (const Vst::ParamID& id, Steinberg::int32& index) override | |||
| { | |||
| for (int i = queues.size(); --i >= 0;) | |||
| { | |||
| if (queues.getUnchecked (i)->getParameterId() == id) | |||
| { | |||
| index = (Steinberg::int32) i; | |||
| return queues.getUnchecked (i); | |||
| } | |||
| } | |||
| index = getParameterCount(); | |||
| return queues.add (new ParamValueQueue (id)); | |||
| } | |||
| void clearAllQueues() noexcept | |||
| { | |||
| for (int i = queues.size(); --i >= 0;) | |||
| queues.getUnchecked (i)->clear(); | |||
| } | |||
| struct ParamValueQueue : public Vst::IParamValueQueue | |||
| { | |||
| ParamValueQueue (Vst::ParamID parameterID) : paramID (parameterID) | |||
| { | |||
| points.ensureStorageAllocated (1024); | |||
| } | |||
| virtual ~ParamValueQueue() {} | |||
| JUCE_DECLARE_VST3_COM_REF_METHODS | |||
| JUCE_DECLARE_VST3_COM_QUERY_METHODS | |||
| Steinberg::Vst::ParamID PLUGIN_API getParameterId() override { return paramID; } | |||
| Steinberg::int32 PLUGIN_API getPointCount() override { return (Steinberg::int32) points.size(); } | |||
| Steinberg::tresult PLUGIN_API getPoint (Steinberg::int32 index, | |||
| Steinberg::int32& sampleOffset, | |||
| Steinberg::Vst::ParamValue& value) override | |||
| { | |||
| const ScopedLock sl (pointLock); | |||
| if (isPositiveAndBelow ((int) index, points.size())) | |||
| { | |||
| ParamPoint e (points.getUnchecked ((int) index)); | |||
| sampleOffset = e.sampleOffset; | |||
| value = e.value; | |||
| return kResultTrue; | |||
| } | |||
| sampleOffset = -1; | |||
| value = 0.0; | |||
| return kResultFalse; | |||
| } | |||
| Steinberg::tresult PLUGIN_API addPoint (Steinberg::int32 sampleOffset, | |||
| Steinberg::Vst::ParamValue value, | |||
| Steinberg::int32& index) override | |||
| { | |||
| ParamPoint p = { sampleOffset, value }; | |||
| const ScopedLock sl (pointLock); | |||
| index = (Steinberg::int32) points.size(); | |||
| points.add (p); | |||
| return kResultTrue; | |||
| } | |||
| void clear() noexcept | |||
| { | |||
| const ScopedLock sl (pointLock); | |||
| points.clearQuick(); | |||
| } | |||
| private: | |||
| struct ParamPoint | |||
| { | |||
| Steinberg::int32 sampleOffset; | |||
| Steinberg::Vst::ParamValue value; | |||
| }; | |||
| Atomic<int> refCount; | |||
| const Vst::ParamID paramID; | |||
| Array<ParamPoint> points; | |||
| CriticalSection pointLock; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParamValueQueue) | |||
| }; | |||
| Atomic<int> refCount; | |||
| OwnedArray<ParamValueQueue> queues; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParamValueQueueList) | |||
| }; | |||
| private: | |||
| //============================================================================== | |||
| VST3ModuleHandle::Ptr module; | |||
| @@ -2098,7 +2164,7 @@ private: | |||
| if (object->getState (&stream) == kResultTrue) | |||
| { | |||
| MemoryBlock info (stream.getData(), (std::size_t) stream.getSize()); | |||
| MemoryBlock info (stream.getData(), (size_t) stream.getSize()); | |||
| head.createNewChildElement (identifier)->addTextElement (info.toBase64Encoding()); | |||
| } | |||
| } | |||
| @@ -2123,36 +2189,7 @@ private: | |||
| return stream; | |||
| } | |||
| //============================================================================== | |||
| class ParameterChangeList : public Vst::IParameterChanges | |||
| { | |||
| public: | |||
| ParameterChangeList() {} | |||
| virtual ~ParameterChangeList() {} | |||
| JUCE_DECLARE_VST3_COM_REF_METHODS | |||
| JUCE_DECLARE_VST3_COM_QUERY_METHODS | |||
| Steinberg::int32 PLUGIN_API getParameterCount() override { return 0; } | |||
| Vst::IParamValueQueue* PLUGIN_API getParameterData (Steinberg::int32) override | |||
| { | |||
| return nullptr; | |||
| } | |||
| Vst::IParamValueQueue* PLUGIN_API addParameterData (const Vst::ParamID&, Steinberg::int32& index) override | |||
| { | |||
| index = 0; | |||
| return nullptr; | |||
| } | |||
| private: | |||
| Atomic<int> refCount; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParameterChangeList) | |||
| }; | |||
| ComSmartPtr<ParameterChangeList> inputParameterChanges, outputParameterChanges; | |||
| ComSmartPtr<ParamValueQueueList> inputParameterChanges, outputParameterChanges; | |||
| ComSmartPtr<MidiEventList> midiInputs, midiOutputs; | |||
| Vst::ProcessContext timingInfo; //< Only use this in processBlock()! | |||
| bool isComponentInitialised, isControllerInitialised, isActive; | |||
| @@ -135,7 +135,14 @@ namespace | |||
| char chunk[8]; // variable | |||
| }; | |||
| static VstInt32 fxbName (const char* name) noexcept { return (VstInt32) ByteOrder::bigEndianInt (name); } | |||
| // Compares a magic value in either endianness. | |||
| static bool compareMagic (VstInt32 magic, const char* name) noexcept | |||
| { | |||
| return magic == (VstInt32) ByteOrder::littleEndianInt (name) | |||
| || magic == (VstInt32) ByteOrder::bigEndianInt (name); | |||
| } | |||
| static VstInt32 fxbName (const char* name) noexcept { return (VstInt32) ByteOrder::littleEndianInt (name); } | |||
| static VstInt32 fxbSwap (const VstInt32 x) noexcept { return (VstInt32) ByteOrder::swapIfLittleEndian ((uint32) x); } | |||
| static float fxbSwapFloat (const float x) noexcept | |||
| @@ -1013,12 +1020,12 @@ public: | |||
| if (position.isLooping) | |||
| { | |||
| vstHostTime.cycleStartPos = position.ppqLoopStart; | |||
| vstHostTime.cycleEndPos = position.ppqLoopEnd; | |||
| vstHostTime.flags |= kVstCyclePosValid; | |||
| vstHostTime.cycleEndPos = position.ppqLoopEnd; | |||
| vstHostTime.flags |= (kVstCyclePosValid | kVstTransportCycleActive); | |||
| } | |||
| else | |||
| { | |||
| vstHostTime.flags &= ~kVstCyclePosValid; | |||
| vstHostTime.flags &= ~(kVstCyclePosValid | kVstTransportCycleActive); | |||
| } | |||
| } | |||
| @@ -1432,11 +1439,10 @@ public: | |||
| const fxSet* const set = (const fxSet*) data; | |||
| if ((set->chunkMagic != fxbName ("CcnK") && set->chunkMagic != fxbName ("KncC")) | |||
| || fxbSwap (set->version) > fxbVersionNum) | |||
| if ((! compareMagic (set->chunkMagic, "CcnK")) || fxbSwap (set->version) > fxbVersionNum) | |||
| return false; | |||
| if (set->fxMagic == fxbName ("FxBk")) | |||
| if (compareMagic (set->fxMagic, "FxBk")) | |||
| { | |||
| // bank of programs | |||
| if (fxbSwap (set->numPrograms) >= 0) | |||
| @@ -1472,12 +1478,12 @@ public: | |||
| return false; | |||
| } | |||
| } | |||
| else if (set->fxMagic == fxbName ("FxCk")) | |||
| else if (compareMagic (set->fxMagic, "FxCk")) | |||
| { | |||
| // single program | |||
| const fxProgram* const prog = (const fxProgram*) data; | |||
| if (prog->chunkMagic != fxbName ("CcnK")) | |||
| if (! compareMagic (prog->chunkMagic, "CcnK")) | |||
| return false; | |||
| changeProgramName (getCurrentProgram(), prog->prgName); | |||
| @@ -1485,7 +1491,7 @@ public: | |||
| for (int i = 0; i < fxbSwap (prog->numParams); ++i) | |||
| setParameter (i, fxbSwapFloat (prog->params[i])); | |||
| } | |||
| else if (set->fxMagic == fxbName ("FBCh") || set->fxMagic == fxbName ("hCBF")) | |||
| else if (compareMagic (set->fxMagic, "FBCh")) | |||
| { | |||
| // non-preset chunk | |||
| const fxChunkSet* const cset = (const fxChunkSet*) data; | |||
| @@ -1495,7 +1501,7 @@ public: | |||
| setChunkData (cset->chunk, fxbSwap (cset->chunkSize), false); | |||
| } | |||
| else if (set->fxMagic == fxbName ("FPCh") || set->fxMagic == fxbName ("hCPF")) | |||
| else if (compareMagic (set->fxMagic, "FPCh")) | |||
| { | |||
| // preset chunk | |||
| const fxProgramSet* const cset = (const fxProgramSet*) data; | |||
| @@ -1671,7 +1677,8 @@ private: | |||
| bool restoreProgramSettings (const fxProgram* const prog) | |||
| { | |||
| if (prog->chunkMagic == fxbName ("CcnK") && prog->fxMagic == fxbName ("FxCk")) | |||
| if (compareMagic (prog->chunkMagic, "CcnK") | |||
| && compareMagic (prog->fxMagic, "FxCk")) | |||
| { | |||
| changeProgramName (getCurrentProgram(), prog->prgName); | |||
| @@ -79,71 +79,61 @@ static inline bool arrayContainsPlugin (const OwnedArray<PluginDescription>& lis | |||
| #if JUCE_MAC | |||
| //============================================================================== | |||
| struct AutoResizingNSViewComponent : public NSViewComponent, | |||
| private AsyncUpdater { | |||
| AutoResizingNSViewComponent(); | |||
| void childBoundsChanged(Component*) override; | |||
| void handleAsyncUpdate() override; | |||
| bool recursive; | |||
| }; | |||
| struct AutoResizingNSViewComponentWithParent : public AutoResizingNSViewComponent, | |||
| private Timer { | |||
| AutoResizingNSViewComponentWithParent(); | |||
| NSView* getChildView() const; | |||
| void timerCallback() override; | |||
| }; | |||
| //============================================================================== | |||
| AutoResizingNSViewComponent::AutoResizingNSViewComponent() | |||
| : recursive (false) {} | |||
| void AutoResizingNSViewComponent::childBoundsChanged(Component*) | |||
| struct AutoResizingNSViewComponent : public NSViewComponent, | |||
| private AsyncUpdater | |||
| { | |||
| if (recursive) | |||
| { | |||
| triggerAsyncUpdate(); | |||
| } | |||
| else | |||
| AutoResizingNSViewComponent() : recursive (false) {} | |||
| void childBoundsChanged (Component*) override | |||
| { | |||
| recursive = true; | |||
| resizeToFitView(); | |||
| recursive = true; | |||
| if (recursive) | |||
| { | |||
| triggerAsyncUpdate(); | |||
| } | |||
| else | |||
| { | |||
| recursive = true; | |||
| resizeToFitView(); | |||
| recursive = true; | |||
| } | |||
| } | |||
| } | |||
| void AutoResizingNSViewComponent::handleAsyncUpdate() | |||
| { | |||
| resizeToFitView(); | |||
| } | |||
| void handleAsyncUpdate() override { resizeToFitView(); } | |||
| bool recursive; | |||
| }; | |||
| //============================================================================== | |||
| AutoResizingNSViewComponentWithParent::AutoResizingNSViewComponentWithParent() | |||
| struct AutoResizingNSViewComponentWithParent : public AutoResizingNSViewComponent, | |||
| private Timer | |||
| { | |||
| NSView* v = [[NSView alloc] init]; | |||
| setView (v); | |||
| [v release]; | |||
| AutoResizingNSViewComponentWithParent() | |||
| { | |||
| NSView* v = [[NSView alloc] init]; | |||
| setView (v); | |||
| [v release]; | |||
| startTimer(500); | |||
| } | |||
| startTimer (30); | |||
| } | |||
| NSView* AutoResizingNSViewComponentWithParent::getChildView() const | |||
| { | |||
| if (NSView* parent = (NSView*)getView()) | |||
| if ([[parent subviews] count] > 0) | |||
| return [[parent subviews] objectAtIndex: 0]; | |||
| NSView* getChildView() const | |||
| { | |||
| if (NSView* parent = (NSView*) getView()) | |||
| if ([[parent subviews] count] > 0) | |||
| return [[parent subviews] objectAtIndex: 0]; | |||
| return nil; | |||
| } | |||
| return nil; | |||
| } | |||
| void AutoResizingNSViewComponentWithParent::timerCallback() | |||
| { | |||
| if (NSView* child = getChildView()) | |||
| void timerCallback() override | |||
| { | |||
| stopTimer(); | |||
| setView(child); | |||
| if (NSView* child = getChildView()) | |||
| { | |||
| stopTimer(); | |||
| setView (child); | |||
| } | |||
| } | |||
| } | |||
| }; | |||
| #endif | |||
| #if JUCE_CLANG | |||
| @@ -130,8 +130,10 @@ public: | |||
| /** Fills-in the given structure with details about the transport's | |||
| position at the start of the current processing block. | |||
| This method must ONLY be called from within your AudioProcessor::processBlock() | |||
| method. Calling it at any other time will probably cause a nasty crash. | |||
| You can ONLY call this from your processBlock() method! Calling it at other | |||
| times will produce undefined behaviour, as the host may not have any context | |||
| in which a time would make sense, and some hosts will almost certainly have | |||
| multithreading issues if it's not called on the audio thread. | |||
| */ | |||
| virtual bool getCurrentPosition (CurrentPositionInfo& result) = 0; | |||
| }; | |||
| @@ -140,11 +140,17 @@ public: | |||
| /** Returns the current AudioPlayHead object that should be used to find | |||
| out the state and position of the playhead. | |||
| You can call this from your processBlock() method, and use the AudioPlayHead | |||
| object to get the details about the time of the start of the block currently | |||
| being processed. | |||
| You can ONLY call this from your processBlock() method! Calling it at other | |||
| times will produce undefined behaviour, as the host may not have any context | |||
| in which a time would make sense, and some hosts will almost certainly have | |||
| multithreading issues if it's not called on the audio thread. | |||
| If the host hasn't supplied a playhead object, this will return nullptr. | |||
| The AudioPlayHead object that is returned can be used to get the details about | |||
| the time of the start of the block currently being processed. But do not | |||
| store this pointer or use it outside of the current audio callback, because | |||
| the host may delete or re-use it. | |||
| If the host can't or won't provide any time info, this will return nullptr. | |||
| */ | |||
| AudioPlayHead* getPlayHead() const noexcept { return playHead; } | |||
| @@ -29,151 +29,129 @@ namespace GraphRenderingOps | |||
| { | |||
| //============================================================================== | |||
| class AudioGraphRenderingOp | |||
| struct AudioGraphRenderingOp | |||
| { | |||
| public: | |||
| AudioGraphRenderingOp() {} | |||
| virtual ~AudioGraphRenderingOp() {} | |||
| AudioGraphRenderingOp() noexcept {} | |||
| virtual ~AudioGraphRenderingOp() {} | |||
| virtual void perform (AudioSampleBuffer& sharedBufferChans, | |||
| const OwnedArray <MidiBuffer>& sharedMidiBuffers, | |||
| const OwnedArray<MidiBuffer>& sharedMidiBuffers, | |||
| const int numSamples) = 0; | |||
| JUCE_LEAK_DETECTOR (AudioGraphRenderingOp) | |||
| }; | |||
| //============================================================================== | |||
| class ClearChannelOp : public AudioGraphRenderingOp | |||
| struct ClearChannelOp : public AudioGraphRenderingOp | |||
| { | |||
| public: | |||
| ClearChannelOp (const int channelNum_) | |||
| : channelNum (channelNum_) | |||
| {} | |||
| ClearChannelOp (const int channel) noexcept : channelNum (channel) {} | |||
| void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray <MidiBuffer>&, const int numSamples) | |||
| void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray<MidiBuffer>&, const int numSamples) | |||
| { | |||
| sharedBufferChans.clear (channelNum, 0, numSamples); | |||
| } | |||
| private: | |||
| const int channelNum; | |||
| JUCE_DECLARE_NON_COPYABLE (ClearChannelOp) | |||
| }; | |||
| //============================================================================== | |||
| class CopyChannelOp : public AudioGraphRenderingOp | |||
| struct CopyChannelOp : public AudioGraphRenderingOp | |||
| { | |||
| public: | |||
| CopyChannelOp (const int srcChannelNum_, const int dstChannelNum_) | |||
| : srcChannelNum (srcChannelNum_), | |||
| dstChannelNum (dstChannelNum_) | |||
| CopyChannelOp (const int srcChan, const int dstChan) noexcept | |||
| : srcChannelNum (srcChan), dstChannelNum (dstChan) | |||
| {} | |||
| void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray <MidiBuffer>&, const int numSamples) | |||
| void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray<MidiBuffer>&, const int numSamples) | |||
| { | |||
| sharedBufferChans.copyFrom (dstChannelNum, 0, sharedBufferChans, srcChannelNum, 0, numSamples); | |||
| } | |||
| private: | |||
| const int srcChannelNum, dstChannelNum; | |||
| JUCE_DECLARE_NON_COPYABLE (CopyChannelOp) | |||
| }; | |||
| //============================================================================== | |||
| class AddChannelOp : public AudioGraphRenderingOp | |||
| struct AddChannelOp : public AudioGraphRenderingOp | |||
| { | |||
| public: | |||
| AddChannelOp (const int srcChannelNum_, const int dstChannelNum_) | |||
| : srcChannelNum (srcChannelNum_), | |||
| dstChannelNum (dstChannelNum_) | |||
| AddChannelOp (const int srcChan, const int dstChan) noexcept | |||
| : srcChannelNum (srcChan), dstChannelNum (dstChan) | |||
| {} | |||
| void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray <MidiBuffer>&, const int numSamples) | |||
| void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray<MidiBuffer>&, const int numSamples) | |||
| { | |||
| sharedBufferChans.addFrom (dstChannelNum, 0, sharedBufferChans, srcChannelNum, 0, numSamples); | |||
| } | |||
| private: | |||
| const int srcChannelNum, dstChannelNum; | |||
| JUCE_DECLARE_NON_COPYABLE (AddChannelOp) | |||
| }; | |||
| //============================================================================== | |||
| class ClearMidiBufferOp : public AudioGraphRenderingOp | |||
| struct ClearMidiBufferOp : public AudioGraphRenderingOp | |||
| { | |||
| public: | |||
| ClearMidiBufferOp (const int bufferNum_) | |||
| : bufferNum (bufferNum_) | |||
| {} | |||
| ClearMidiBufferOp (const int buffer) noexcept : bufferNum (buffer) {} | |||
| void perform (AudioSampleBuffer&, const OwnedArray <MidiBuffer>& sharedMidiBuffers, const int) | |||
| void perform (AudioSampleBuffer&, const OwnedArray<MidiBuffer>& sharedMidiBuffers, const int) | |||
| { | |||
| sharedMidiBuffers.getUnchecked (bufferNum)->clear(); | |||
| } | |||
| private: | |||
| const int bufferNum; | |||
| JUCE_DECLARE_NON_COPYABLE (ClearMidiBufferOp) | |||
| }; | |||
| //============================================================================== | |||
| class CopyMidiBufferOp : public AudioGraphRenderingOp | |||
| struct CopyMidiBufferOp : public AudioGraphRenderingOp | |||
| { | |||
| public: | |||
| CopyMidiBufferOp (const int srcBufferNum_, const int dstBufferNum_) | |||
| : srcBufferNum (srcBufferNum_), | |||
| dstBufferNum (dstBufferNum_) | |||
| CopyMidiBufferOp (const int srcBuffer, const int dstBuffer) noexcept | |||
| : srcBufferNum (srcBuffer), dstBufferNum (dstBuffer) | |||
| {} | |||
| void perform (AudioSampleBuffer&, const OwnedArray <MidiBuffer>& sharedMidiBuffers, const int) | |||
| void perform (AudioSampleBuffer&, const OwnedArray<MidiBuffer>& sharedMidiBuffers, const int) | |||
| { | |||
| *sharedMidiBuffers.getUnchecked (dstBufferNum) = *sharedMidiBuffers.getUnchecked (srcBufferNum); | |||
| } | |||
| private: | |||
| const int srcBufferNum, dstBufferNum; | |||
| JUCE_DECLARE_NON_COPYABLE (CopyMidiBufferOp) | |||
| }; | |||
| //============================================================================== | |||
| class AddMidiBufferOp : public AudioGraphRenderingOp | |||
| struct AddMidiBufferOp : public AudioGraphRenderingOp | |||
| { | |||
| public: | |||
| AddMidiBufferOp (const int srcBufferNum_, const int dstBufferNum_) | |||
| : srcBufferNum (srcBufferNum_), | |||
| dstBufferNum (dstBufferNum_) | |||
| AddMidiBufferOp (const int srcBuffer, const int dstBuffer) | |||
| : srcBufferNum (srcBuffer), dstBufferNum (dstBuffer) | |||
| {} | |||
| void perform (AudioSampleBuffer&, const OwnedArray <MidiBuffer>& sharedMidiBuffers, const int numSamples) | |||
| void perform (AudioSampleBuffer&, const OwnedArray<MidiBuffer>& sharedMidiBuffers, const int numSamples) | |||
| { | |||
| sharedMidiBuffers.getUnchecked (dstBufferNum) | |||
| ->addEvents (*sharedMidiBuffers.getUnchecked (srcBufferNum), 0, numSamples, 0); | |||
| } | |||
| private: | |||
| const int srcBufferNum, dstBufferNum; | |||
| JUCE_DECLARE_NON_COPYABLE (AddMidiBufferOp) | |||
| }; | |||
| //============================================================================== | |||
| class DelayChannelOp : public AudioGraphRenderingOp | |||
| struct DelayChannelOp : public AudioGraphRenderingOp | |||
| { | |||
| public: | |||
| DelayChannelOp (const int channel_, const int numSamplesDelay_) | |||
| : channel (channel_), | |||
| bufferSize (numSamplesDelay_ + 1), | |||
| readIndex (0), writeIndex (numSamplesDelay_) | |||
| DelayChannelOp (const int chan, const int delaySize) | |||
| : channel (chan), | |||
| bufferSize (delaySize + 1), | |||
| readIndex (0), writeIndex (delaySize) | |||
| { | |||
| buffer.calloc ((size_t) bufferSize); | |||
| } | |||
| void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray <MidiBuffer>&, const int numSamples) | |||
| void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray<MidiBuffer>&, const int numSamples) | |||
| { | |||
| float* data = sharedBufferChans.getWritePointer (channel, 0); | |||
| @@ -197,18 +175,17 @@ private: | |||
| //============================================================================== | |||
| class ProcessBufferOp : public AudioGraphRenderingOp | |||
| struct ProcessBufferOp : public AudioGraphRenderingOp | |||
| { | |||
| public: | |||
| ProcessBufferOp (const AudioProcessorGraph::Node::Ptr& node_, | |||
| const Array <int>& audioChannelsToUse_, | |||
| const int totalChans_, | |||
| const int midiBufferToUse_) | |||
| : node (node_), | |||
| processor (node_->getProcessor()), | |||
| audioChannelsToUse (audioChannelsToUse_), | |||
| totalChans (jmax (1, totalChans_)), | |||
| midiBufferToUse (midiBufferToUse_) | |||
| ProcessBufferOp (const AudioProcessorGraph::Node::Ptr& n, | |||
| const Array<int>& audioChannels, | |||
| const int totalNumChans, | |||
| const int midiBuffer) | |||
| : node (n), | |||
| processor (n->getProcessor()), | |||
| audioChannelsToUse (audioChannels), | |||
| totalChans (jmax (1, totalNumChans)), | |||
| midiBufferToUse (midiBuffer) | |||
| { | |||
| channels.calloc ((size_t) totalChans); | |||
| @@ -216,7 +193,7 @@ public: | |||
| audioChannelsToUse.add (0); | |||
| } | |||
| void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray <MidiBuffer>& sharedMidiBuffers, const int numSamples) | |||
| void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray<MidiBuffer>& sharedMidiBuffers, const int numSamples) | |||
| { | |||
| for (int i = totalChans; --i >= 0;) | |||
| channels[i] = sharedBufferChans.getWritePointer (audioChannelsToUse.getUnchecked (i), 0); | |||
| @@ -232,8 +209,8 @@ public: | |||
| private: | |||
| Array<int> audioChannelsToUse; | |||
| HeapBlock<float*> channels; | |||
| int totalChans; | |||
| int midiBufferToUse; | |||
| const int totalChans; | |||
| const int midiBufferToUse; | |||
| JUCE_DECLARE_NON_COPYABLE (ProcessBufferOp) | |||
| }; | |||
| @@ -242,15 +219,13 @@ private: | |||
| /** Used to calculate the correct sequence of rendering ops needed, based on | |||
| the best re-use of shared buffers at each stage. | |||
| */ | |||
| class RenderingOpSequenceCalculator | |||
| struct RenderingOpSequenceCalculator | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| RenderingOpSequenceCalculator (AudioProcessorGraph& graph_, | |||
| const Array<void*>& orderedNodes_, | |||
| RenderingOpSequenceCalculator (AudioProcessorGraph& g, | |||
| const Array<AudioProcessorGraph::Node*>& nodes, | |||
| Array<void*>& renderingOps) | |||
| : graph (graph_), | |||
| orderedNodes (orderedNodes_), | |||
| : graph (g), | |||
| orderedNodes (nodes), | |||
| totalLatency (0) | |||
| { | |||
| nodeIds.add ((uint32) zeroNodeID); // first buffer is read-only zeros | |||
| @@ -260,34 +235,32 @@ public: | |||
| for (int i = 0; i < orderedNodes.size(); ++i) | |||
| { | |||
| createRenderingOpsForNode ((AudioProcessorGraph::Node*) orderedNodes.getUnchecked(i), | |||
| renderingOps, i); | |||
| createRenderingOpsForNode (*orderedNodes.getUnchecked(i), renderingOps, i); | |||
| markAnyUnusedBuffersAsFree (i); | |||
| } | |||
| graph.setLatencySamples (totalLatency); | |||
| } | |||
| int getNumBuffersNeeded() const { return nodeIds.size(); } | |||
| int getNumMidiBuffersNeeded() const { return midiNodeIds.size(); } | |||
| int getNumBuffersNeeded() const noexcept { return nodeIds.size(); } | |||
| int getNumMidiBuffersNeeded() const noexcept { return midiNodeIds.size(); } | |||
| private: | |||
| //============================================================================== | |||
| AudioProcessorGraph& graph; | |||
| const Array<void*>& orderedNodes; | |||
| Array <int> channels; | |||
| Array <uint32> nodeIds, midiNodeIds; | |||
| const Array<AudioProcessorGraph::Node*>& orderedNodes; | |||
| Array<int> channels; | |||
| Array<uint32> nodeIds, midiNodeIds; | |||
| enum { freeNodeID = 0xffffffff, zeroNodeID = 0xfffffffe }; | |||
| static bool isNodeBusy (uint32 nodeID) noexcept { return nodeID != freeNodeID && nodeID != zeroNodeID; } | |||
| static bool isNodeBusy (uint32 nodeID) noexcept { return nodeID != freeNodeID && nodeID != zeroNodeID; } | |||
| Array <uint32> nodeDelayIDs; | |||
| Array <int> nodeDelays; | |||
| Array<uint32> nodeDelayIDs; | |||
| Array<int> nodeDelays; | |||
| int totalLatency; | |||
| int getNodeDelay (const uint32 nodeID) const { return nodeDelays [nodeDelayIDs.indexOf (nodeID)]; } | |||
| int getNodeDelay (const uint32 nodeID) const { return nodeDelays [nodeDelayIDs.indexOf (nodeID)]; } | |||
| void setNodeDelay (const uint32 nodeID, const int latency) | |||
| { | |||
| @@ -320,30 +293,31 @@ private: | |||
| } | |||
| //============================================================================== | |||
| void createRenderingOpsForNode (AudioProcessorGraph::Node* const node, | |||
| void createRenderingOpsForNode (AudioProcessorGraph::Node& node, | |||
| Array<void*>& renderingOps, | |||
| const int ourRenderingIndex) | |||
| { | |||
| const int numIns = node->getProcessor()->getNumInputChannels(); | |||
| const int numOuts = node->getProcessor()->getNumOutputChannels(); | |||
| AudioProcessor& processor = *node.getProcessor(); | |||
| const int numIns = processor.getNumInputChannels(); | |||
| const int numOuts = processor.getNumOutputChannels(); | |||
| const int totalChans = jmax (numIns, numOuts); | |||
| Array <int> audioChannelsToUse; | |||
| Array<int> audioChannelsToUse; | |||
| int midiBufferToUse = -1; | |||
| int maxLatency = getInputLatencyForNode (node->nodeId); | |||
| int maxLatency = getInputLatencyForNode (node.nodeId); | |||
| for (int inputChan = 0; inputChan < numIns; ++inputChan) | |||
| { | |||
| // get a list of all the inputs to this node | |||
| Array <uint32> sourceNodes; | |||
| Array<uint32> sourceNodes; | |||
| Array<int> sourceOutputChans; | |||
| for (int i = graph.getNumConnections(); --i >= 0;) | |||
| { | |||
| const AudioProcessorGraph::Connection* const c = graph.getConnection (i); | |||
| if (c->destNodeId == node->nodeId && c->destChannelIndex == inputChan) | |||
| if (c->destNodeId == node.nodeId && c->destChannelIndex == inputChan) | |||
| { | |||
| sourceNodes.add (c->sourceNodeId); | |||
| sourceOutputChans.add (c->sourceChannelIndex); | |||
| @@ -493,7 +467,7 @@ private: | |||
| audioChannelsToUse.add (bufIndex); | |||
| if (inputChan < numOuts) | |||
| markBufferAsContaining (bufIndex, node->nodeId, inputChan); | |||
| markBufferAsContaining (bufIndex, node.nodeId, inputChan); | |||
| } | |||
| for (int outputChan = numIns; outputChan < numOuts; ++outputChan) | |||
| @@ -502,17 +476,17 @@ private: | |||
| jassert (bufIndex != 0); | |||
| audioChannelsToUse.add (bufIndex); | |||
| markBufferAsContaining (bufIndex, node->nodeId, outputChan); | |||
| markBufferAsContaining (bufIndex, node.nodeId, outputChan); | |||
| } | |||
| // Now the same thing for midi.. | |||
| Array <uint32> midiSourceNodes; | |||
| Array<uint32> midiSourceNodes; | |||
| for (int i = graph.getNumConnections(); --i >= 0;) | |||
| { | |||
| const AudioProcessorGraph::Connection* const c = graph.getConnection (i); | |||
| if (c->destNodeId == node->nodeId && c->destChannelIndex == AudioProcessorGraph::midiChannelIndex) | |||
| if (c->destNodeId == node.nodeId && c->destChannelIndex == AudioProcessorGraph::midiChannelIndex) | |||
| midiSourceNodes.add (c->sourceNodeId); | |||
| } | |||
| @@ -521,7 +495,7 @@ private: | |||
| // No midi inputs.. | |||
| midiBufferToUse = getFreeBuffer (true); // need to pick a buffer even if the processor doesn't use midi | |||
| if (node->getProcessor()->acceptsMidi() || node->getProcessor()->producesMidi()) | |||
| if (processor.acceptsMidi() || processor.producesMidi()) | |||
| renderingOps.add (new ClearMidiBufferOp (midiBufferToUse)); | |||
| } | |||
| else if (midiSourceNodes.size() == 1) | |||
| @@ -601,16 +575,16 @@ private: | |||
| } | |||
| } | |||
| if (node->getProcessor()->producesMidi()) | |||
| markBufferAsContaining (midiBufferToUse, node->nodeId, | |||
| if (processor.producesMidi()) | |||
| markBufferAsContaining (midiBufferToUse, node.nodeId, | |||
| AudioProcessorGraph::midiChannelIndex); | |||
| setNodeDelay (node->nodeId, maxLatency + node->getProcessor()->getLatencySamples()); | |||
| setNodeDelay (node.nodeId, maxLatency + processor.getLatencySamples()); | |||
| if (numOuts == 0) | |||
| totalLatency = maxLatency; | |||
| renderingOps.add (new ProcessBufferOp (node, audioChannelsToUse, | |||
| renderingOps.add (new ProcessBufferOp (&node, audioChannelsToUse, | |||
| totalChans, midiBufferToUse)); | |||
| } | |||
| @@ -872,18 +846,16 @@ struct ConnectionSorter | |||
| } | |||
| //============================================================================== | |||
| AudioProcessorGraph::Connection::Connection (const uint32 sourceNodeId_, const int sourceChannelIndex_, | |||
| const uint32 destNodeId_, const int destChannelIndex_) noexcept | |||
| : sourceNodeId (sourceNodeId_), sourceChannelIndex (sourceChannelIndex_), | |||
| destNodeId (destNodeId_), destChannelIndex (destChannelIndex_) | |||
| AudioProcessorGraph::Connection::Connection (const uint32 sourceID, const int sourceChannel, | |||
| const uint32 destID, const int destChannel) noexcept | |||
| : sourceNodeId (sourceID), sourceChannelIndex (sourceChannel), | |||
| destNodeId (destID), destChannelIndex (destChannel) | |||
| { | |||
| } | |||
| //============================================================================== | |||
| AudioProcessorGraph::Node::Node (const uint32 nodeId_, AudioProcessor* const processor_) noexcept | |||
| : nodeId (nodeId_), | |||
| processor (processor_), | |||
| isPrepared (false) | |||
| AudioProcessorGraph::Node::Node (const uint32 nodeID, AudioProcessor* const p) noexcept | |||
| : nodeId (nodeID), processor (p), isPrepared (false) | |||
| { | |||
| jassert (processor != nullptr); | |||
| } | |||
| @@ -916,7 +888,7 @@ void AudioProcessorGraph::Node::unprepare() | |||
| void AudioProcessorGraph::Node::setParentGraph (AudioProcessorGraph* const graph) const | |||
| { | |||
| if (AudioProcessorGraph::AudioGraphIOProcessor* const ioProc | |||
| = dynamic_cast <AudioProcessorGraph::AudioGraphIOProcessor*> (processor.get())) | |||
| = dynamic_cast<AudioProcessorGraph::AudioGraphIOProcessor*> (processor.get())) | |||
| ioProc->setParentGraph (graph); | |||
| } | |||
| @@ -1213,7 +1185,7 @@ void AudioProcessorGraph::buildRenderingSequence() | |||
| { | |||
| MessageManagerLock mml; | |||
| Array<void*> orderedNodes; | |||
| Array<Node*> orderedNodes; | |||
| { | |||
| const GraphRenderingOps::ConnectionLookupTable table (connections); | |||
| @@ -1298,6 +1270,22 @@ void AudioProcessorGraph::reset() | |||
| nodes.getUnchecked(i)->getProcessor()->reset(); | |||
| } | |||
| void AudioProcessorGraph::setNonRealtime (bool isNonRealtime) noexcept | |||
| { | |||
| const ScopedLock sl (getCallbackLock()); | |||
| for (int i = 0; i < nodes.size(); ++i) | |||
| nodes.getUnchecked(i)->getProcessor()->setNonRealtime (isNonRealtime); | |||
| } | |||
| void AudioProcessorGraph::setPlayHead (AudioPlayHead* audioPlayHead) | |||
| { | |||
| const ScopedLock sl (getCallbackLock()); | |||
| for (int i = 0; i < nodes.size(); ++i) | |||
| nodes.getUnchecked(i)->getProcessor()->setPlayHead (audioPlayHead); | |||
| } | |||
| void AudioProcessorGraph::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) | |||
| { | |||
| const int numSamples = buffer.getNumSamples(); | |||
| @@ -1333,20 +1321,19 @@ const String AudioProcessorGraph::getOutputChannelName (int channelIndex) const | |||
| return "Output " + String (channelIndex + 1); | |||
| } | |||
| bool AudioProcessorGraph::isInputChannelStereoPair (int /*index*/) const { return true; } | |||
| bool AudioProcessorGraph::isOutputChannelStereoPair (int /*index*/) const { return true; } | |||
| bool AudioProcessorGraph::silenceInProducesSilenceOut() const { return false; } | |||
| double AudioProcessorGraph::getTailLengthSeconds() const { return 0; } | |||
| bool AudioProcessorGraph::acceptsMidi() const { return true; } | |||
| bool AudioProcessorGraph::producesMidi() const { return true; } | |||
| void AudioProcessorGraph::getStateInformation (juce::MemoryBlock& /*destData*/) {} | |||
| void AudioProcessorGraph::setStateInformation (const void* /*data*/, int /*sizeInBytes*/) {} | |||
| bool AudioProcessorGraph::isInputChannelStereoPair (int) const { return true; } | |||
| bool AudioProcessorGraph::isOutputChannelStereoPair (int) const { return true; } | |||
| bool AudioProcessorGraph::silenceInProducesSilenceOut() const { return false; } | |||
| double AudioProcessorGraph::getTailLengthSeconds() const { return 0; } | |||
| bool AudioProcessorGraph::acceptsMidi() const { return true; } | |||
| bool AudioProcessorGraph::producesMidi() const { return true; } | |||
| void AudioProcessorGraph::getStateInformation (juce::MemoryBlock&) {} | |||
| void AudioProcessorGraph::setStateInformation (const void*, int) {} | |||
| //============================================================================== | |||
| AudioProcessorGraph::AudioGraphIOProcessor::AudioGraphIOProcessor (const IODeviceType type_) | |||
| : type (type_), | |||
| graph (nullptr) | |||
| AudioProcessorGraph::AudioGraphIOProcessor::AudioGraphIOProcessor (const IODeviceType deviceType) | |||
| : type (deviceType), graph (nullptr) | |||
| { | |||
| } | |||
| @@ -1492,19 +1479,12 @@ bool AudioProcessorGraph::AudioGraphIOProcessor::isOutputChannelStereoPair (int | |||
| return isInputChannelStereoPair (index); | |||
| } | |||
| bool AudioProcessorGraph::AudioGraphIOProcessor::isInput() const { return type == audioInputNode || type == midiInputNode; } | |||
| bool AudioProcessorGraph::AudioGraphIOProcessor::isOutput() const { return type == audioOutputNode || type == midiOutputNode; } | |||
| bool AudioProcessorGraph::AudioGraphIOProcessor::isInput() const noexcept { return type == audioInputNode || type == midiInputNode; } | |||
| bool AudioProcessorGraph::AudioGraphIOProcessor::isOutput() const noexcept { return type == audioOutputNode || type == midiOutputNode; } | |||
| bool AudioProcessorGraph::AudioGraphIOProcessor::hasEditor() const { return false; } | |||
| AudioProcessorEditor* AudioProcessorGraph::AudioGraphIOProcessor::createEditor() { return nullptr; } | |||
| int AudioProcessorGraph::AudioGraphIOProcessor::getNumParameters() { return 0; } | |||
| const String AudioProcessorGraph::AudioGraphIOProcessor::getParameterName (int) { return String(); } | |||
| float AudioProcessorGraph::AudioGraphIOProcessor::getParameter (int) { return 0.0f; } | |||
| const String AudioProcessorGraph::AudioGraphIOProcessor::getParameterText (int) { return String(); } | |||
| void AudioProcessorGraph::AudioGraphIOProcessor::setParameter (int, float) { } | |||
| int AudioProcessorGraph::AudioGraphIOProcessor::getNumPrograms() { return 0; } | |||
| int AudioProcessorGraph::AudioGraphIOProcessor::getCurrentProgram() { return 0; } | |||
| void AudioProcessorGraph::AudioGraphIOProcessor::setCurrentProgram (int) { } | |||
| @@ -1522,7 +1502,7 @@ void AudioProcessorGraph::AudioGraphIOProcessor::setParentGraph (AudioProcessorG | |||
| if (graph != nullptr) | |||
| { | |||
| setPlayConfigDetails (type == audioOutputNode ? graph->getNumOutputChannels() : 0, | |||
| type == audioInputNode ? graph->getNumInputChannels() : 0, | |||
| type == audioInputNode ? graph->getNumInputChannels() : 0, | |||
| getSampleRate(), | |||
| getBlockSize()); | |||
| @@ -80,7 +80,7 @@ public: | |||
| //============================================================================== | |||
| /** A convenient typedef for referring to a pointer to a node object. */ | |||
| typedef ReferenceCountedObjectPtr <Node> Ptr; | |||
| typedef ReferenceCountedObjectPtr<Node> Ptr; | |||
| private: | |||
| //============================================================================== | |||
| @@ -151,13 +151,13 @@ public: | |||
| void clear(); | |||
| /** Returns the number of nodes in the graph. */ | |||
| int getNumNodes() const { return nodes.size(); } | |||
| int getNumNodes() const noexcept { return nodes.size(); } | |||
| /** Returns a pointer to one of the nodes in the graph. | |||
| This will return nullptr if the index is out of range. | |||
| @see getNodeForId | |||
| */ | |||
| Node* getNode (const int index) const { return nodes [index]; } | |||
| Node* getNode (const int index) const noexcept { return nodes [index]; } | |||
| /** Searches the graph for a node with the given ID number and returns it. | |||
| If no such node was found, this returns nullptr. | |||
| @@ -289,54 +289,47 @@ public: | |||
| //============================================================================== | |||
| /** Returns the mode of this processor. */ | |||
| IODeviceType getType() const { return type; } | |||
| IODeviceType getType() const noexcept { return type; } | |||
| /** Returns the parent graph to which this processor belongs, or nullptr if it | |||
| hasn't yet been added to one. */ | |||
| AudioProcessorGraph* getParentGraph() const { return graph; } | |||
| AudioProcessorGraph* getParentGraph() const noexcept { return graph; } | |||
| /** True if this is an audio or midi input. */ | |||
| bool isInput() const; | |||
| bool isInput() const noexcept; | |||
| /** True if this is an audio or midi output. */ | |||
| bool isOutput() const; | |||
| bool isOutput() const noexcept; | |||
| //============================================================================== | |||
| AudioGraphIOProcessor (const IODeviceType type); | |||
| ~AudioGraphIOProcessor(); | |||
| const String getName() const; | |||
| void fillInPluginDescription (PluginDescription&) const; | |||
| void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); | |||
| void releaseResources(); | |||
| const String getName() const override; | |||
| void fillInPluginDescription (PluginDescription&) const override; | |||
| void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock) override; | |||
| void releaseResources() override; | |||
| void processBlock (AudioSampleBuffer&, MidiBuffer&); | |||
| const String getInputChannelName (int channelIndex) const; | |||
| const String getOutputChannelName (int channelIndex) const; | |||
| bool isInputChannelStereoPair (int index) const; | |||
| bool isOutputChannelStereoPair (int index) const; | |||
| bool silenceInProducesSilenceOut() const; | |||
| double getTailLengthSeconds() const; | |||
| bool acceptsMidi() const; | |||
| bool producesMidi() const; | |||
| bool hasEditor() const; | |||
| AudioProcessorEditor* createEditor(); | |||
| int getNumParameters(); | |||
| const String getParameterName (int); | |||
| float getParameter (int); | |||
| const String getParameterText (int); | |||
| void setParameter (int, float); | |||
| int getNumPrograms(); | |||
| int getCurrentProgram(); | |||
| void setCurrentProgram (int); | |||
| const String getProgramName (int); | |||
| void changeProgramName (int, const String&); | |||
| void getStateInformation (juce::MemoryBlock& destData); | |||
| void setStateInformation (const void* data, int sizeInBytes); | |||
| const String getInputChannelName (int channelIndex) const override; | |||
| const String getOutputChannelName (int channelIndex) const override; | |||
| bool isInputChannelStereoPair (int index) const override; | |||
| bool isOutputChannelStereoPair (int index) const override; | |||
| bool silenceInProducesSilenceOut() const override; | |||
| double getTailLengthSeconds() const override; | |||
| bool acceptsMidi() const override; | |||
| bool producesMidi() const override; | |||
| bool hasEditor() const override; | |||
| AudioProcessorEditor* createEditor() override; | |||
| int getNumPrograms() override; | |||
| int getCurrentProgram() override; | |||
| void setCurrentProgram (int) override; | |||
| const String getProgramName (int) override; | |||
| void changeProgramName (int, const String&) override; | |||
| void getStateInformation (juce::MemoryBlock& destData) override; | |||
| void setStateInformation (const void* data, int sizeInBytes) override; | |||
| /** @internal */ | |||
| void setParentGraph (AudioProcessorGraph*); | |||
| @@ -349,42 +342,34 @@ public: | |||
| }; | |||
| //============================================================================== | |||
| // AudioProcessor methods: | |||
| const String getName() const; | |||
| void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); | |||
| void releaseResources(); | |||
| void processBlock (AudioSampleBuffer&, MidiBuffer&); | |||
| void reset(); | |||
| const String getInputChannelName (int channelIndex) const; | |||
| const String getOutputChannelName (int channelIndex) const; | |||
| bool isInputChannelStereoPair (int index) const; | |||
| bool isOutputChannelStereoPair (int index) const; | |||
| bool silenceInProducesSilenceOut() const; | |||
| double getTailLengthSeconds() const; | |||
| bool acceptsMidi() const; | |||
| bool producesMidi() const; | |||
| bool hasEditor() const { return false; } | |||
| AudioProcessorEditor* createEditor() { return nullptr; } | |||
| int getNumParameters() { return 0; } | |||
| const String getParameterName (int) { return String(); } | |||
| float getParameter (int) { return 0; } | |||
| const String getParameterText (int) { return String(); } | |||
| void setParameter (int, float) { } | |||
| int getNumPrograms() { return 0; } | |||
| int getCurrentProgram() { return 0; } | |||
| void setCurrentProgram (int) { } | |||
| const String getProgramName (int) { return String(); } | |||
| void changeProgramName (int, const String&) { } | |||
| void getStateInformation (juce::MemoryBlock&); | |||
| void setStateInformation (const void* data, int sizeInBytes); | |||
| const String getName() const override; | |||
| void prepareToPlay (double, int) override; | |||
| void releaseResources() override; | |||
| void processBlock (AudioSampleBuffer&, MidiBuffer&) override; | |||
| void reset() override; | |||
| void setNonRealtime (bool) noexcept override; | |||
| void setPlayHead (AudioPlayHead*) override; | |||
| const String getInputChannelName (int) const override; | |||
| const String getOutputChannelName (int) const override; | |||
| bool isInputChannelStereoPair (int) const override; | |||
| bool isOutputChannelStereoPair (int) const override; | |||
| bool silenceInProducesSilenceOut() const override; | |||
| double getTailLengthSeconds() const override; | |||
| bool acceptsMidi() const override; | |||
| bool producesMidi() const override; | |||
| bool hasEditor() const override { return false; } | |||
| AudioProcessorEditor* createEditor() override { return nullptr; } | |||
| int getNumPrograms() override { return 0; } | |||
| int getCurrentProgram() override { return 0; } | |||
| void setCurrentProgram (int) override { } | |||
| const String getProgramName (int) override { return String(); } | |||
| void changeProgramName (int, const String&) override { } | |||
| void getStateInformation (juce::MemoryBlock&) override; | |||
| void setStateInformation (const void* data, int sizeInBytes) override; | |||
| private: | |||
| //============================================================================== | |||
| @@ -67,7 +67,7 @@ public: | |||
| if (paramHasChanged) | |||
| { | |||
| refresh(); | |||
| startTimer (1000 / 50); | |||
| startTimerHz (50); | |||
| } | |||
| else | |||
| { | |||
| @@ -96,8 +96,7 @@ public: | |||
| @param values the array to copy from | |||
| */ | |||
| template <typename TypeToCreateFrom> | |||
| explicit Array (const TypeToCreateFrom* values) | |||
| : numUsed (0) | |||
| explicit Array (const TypeToCreateFrom* values) : numUsed (0) | |||
| { | |||
| while (*values != TypeToCreateFrom()) | |||
| add (*values++); | |||
| @@ -109,8 +108,7 @@ public: | |||
| @param numValues the number of values in the array | |||
| */ | |||
| template <typename TypeToCreateFrom> | |||
| Array (const TypeToCreateFrom* values, int numValues) | |||
| : numUsed (numValues) | |||
| Array (const TypeToCreateFrom* values, int numValues) : numUsed (numValues) | |||
| { | |||
| data.setAllocatedSize (numValues); | |||
| @@ -118,6 +116,14 @@ public: | |||
| new (data.elements + i) ElementType (values[i]); | |||
| } | |||
| #if JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS | |||
| template <typename TypeToCreateFrom> | |||
| Array (const std::initializer_list<TypeToCreateFrom>& items) : numUsed (0) | |||
| { | |||
| addArray (items); | |||
| } | |||
| #endif | |||
| /** Destructor. */ | |||
| ~Array() | |||
| { | |||
| @@ -474,7 +480,11 @@ public: | |||
| numUsed += numberOfTimesToInsertIt; | |||
| while (--numberOfTimesToInsertIt >= 0) | |||
| new (insertPos++) ElementType (newElement); | |||
| { | |||
| new (insertPos) ElementType (newElement); | |||
| ++insertPos; // NB: this increment is done separately from the | |||
| // new statement to avoid a compiler bug in VS2014 | |||
| } | |||
| } | |||
| } | |||
| @@ -600,6 +610,21 @@ public: | |||
| } | |||
| } | |||
| #if JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS | |||
| template <typename TypeToCreateFrom> | |||
| void addArray (const std::initializer_list<TypeToCreateFrom>& items) | |||
| { | |||
| const ScopedLockType lock (getLock()); | |||
| data.ensureAllocatedSize (numUsed + (int) items.size()); | |||
| for (auto& item : items) | |||
| { | |||
| new (data.elements + numUsed) ElementType (item); | |||
| ++numUsed; | |||
| } | |||
| } | |||
| #endif | |||
| /** Adds elements from a null-terminated array of pointers to the end of this array. | |||
| @param elementsToAdd an array of pointers to some kind of object from which elements | |||
| @@ -45,7 +45,7 @@ bool DynamicObject::hasProperty (const Identifier& propertyName) const | |||
| return v != nullptr && ! v->isMethod(); | |||
| } | |||
| var DynamicObject::getProperty (const Identifier& propertyName) const | |||
| const var& DynamicObject::getProperty (const Identifier& propertyName) const | |||
| { | |||
| return properties [propertyName]; | |||
| } | |||
| @@ -60,7 +60,7 @@ public: | |||
| /** Returns a named property. | |||
| This returns var::null if no such property exists. | |||
| */ | |||
| virtual var getProperty (const Identifier& propertyName) const; | |||
| virtual const var& getProperty (const Identifier& propertyName) const; | |||
| /** Sets a named property. */ | |||
| virtual void setProperty (const Identifier& propertyName, const var& newValue); | |||
| @@ -38,7 +38,7 @@ | |||
| The template parameter specifies the class of the object you want to point to - the easiest | |||
| way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject | |||
| or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable | |||
| class by implementing a set of mathods called incReferenceCount(), decReferenceCount(), and | |||
| class by implementing a set of methods called incReferenceCount(), decReferenceCount(), and | |||
| decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods | |||
| should behave. | |||
| @@ -174,7 +174,7 @@ public: | |||
| int toInt (const ValueUnion& data) const noexcept override { return (int) data.doubleValue; }; | |||
| int64 toInt64 (const ValueUnion& data) const noexcept override { return (int64) data.doubleValue; }; | |||
| double toDouble (const ValueUnion& data) const noexcept override { return data.doubleValue; } | |||
| String toString (const ValueUnion& data) const override { return String (data.doubleValue); } | |||
| String toString (const ValueUnion& data) const override { return String (data.doubleValue, 20); } | |||
| bool toBool (const ValueUnion& data) const noexcept override { return data.doubleValue != 0; } | |||
| bool isDouble() const noexcept override { return true; } | |||
| @@ -253,8 +253,8 @@ public: | |||
| } | |||
| private: | |||
| static inline const String* getString (const ValueUnion& data) noexcept { return reinterpret_cast <const String*> (data.stringValue); } | |||
| static inline String* getString (ValueUnion& data) noexcept { return reinterpret_cast <String*> (data.stringValue); } | |||
| static inline const String* getString (const ValueUnion& data) noexcept { return reinterpret_cast<const String*> (data.stringValue); } | |||
| static inline String* getString (ValueUnion& data) noexcept { return reinterpret_cast<String*> (data.stringValue); } | |||
| }; | |||
| //============================================================================== | |||
| @@ -487,7 +487,7 @@ var::operator String() const { return type->toString | |||
| ReferenceCountedObject* var::getObject() const noexcept { return type->toObject (value); } | |||
| Array<var>* var::getArray() const noexcept { return type->toArray (value); } | |||
| MemoryBlock* var::getBinaryData() const noexcept { return type->toBinary (value); } | |||
| DynamicObject* var::getDynamicObject() const noexcept { return dynamic_cast <DynamicObject*> (getObject()); } | |||
| DynamicObject* var::getDynamicObject() const noexcept { return dynamic_cast<DynamicObject*> (getObject()); } | |||
| //============================================================================== | |||
| void var::swapWith (var& other) noexcept | |||
| @@ -576,15 +576,15 @@ var var::clone() const noexcept | |||
| } | |||
| //============================================================================== | |||
| var var::operator[] (const Identifier propertyName) const | |||
| const var& var::operator[] (Identifier propertyName) const | |||
| { | |||
| if (DynamicObject* const o = getDynamicObject()) | |||
| return o->getProperty (propertyName); | |||
| return var(); | |||
| return var::null; | |||
| } | |||
| var var::operator[] (const char* const propertyName) const | |||
| const var& var::operator[] (const char* const propertyName) const | |||
| { | |||
| return operator[] (Identifier (propertyName)); | |||
| } | |||