@@ -38,8 +38,10 @@ _old | |||
ports/_todo | |||
libs/juce/source/.gitignore | |||
libs/juce/source/ChangeList.txt | |||
libs/juce/source/amalgamation/ | |||
libs/juce/source/docs/ | |||
libs/juce/source/examples/ | |||
libs/juce/source/extras/ | |||
libs/juce/source/juce.h | |||
libs/juce/source/juce_amalgamated.cpp | |||
@@ -47,7 +49,5 @@ libs/juce/source/juce_amalgamated.h | |||
libs/juce/source/juce_amalgamated.mm | |||
libs/juce/source/modules/juce_box2d/ | |||
libs/juce/source/modules/juce_browser_plugin_client/ | |||
libs/juce/source/modules/juce_cryptography/ | |||
libs/juce/source/modules/juce_opengl/ | |||
libs/juce/source/modules/juce_tracktion_marketplace/ | |||
libs/juce/source/modules/juce_video/ |
@@ -1,16 +0,0 @@ | |||
diff --git a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp b/libs/juce/source/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp | |||
index b88a3b2..d057fb0 100644 | |||
--- a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp | |||
+++ b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp | |||
@@ -1180,8 +1180,10 @@ public: | |||
editorComp->addToDesktop (0, ptr); | |||
hostWindow = (HWND) ptr; | |||
#elif JUCE_LINUX | |||
- editorComp->addToDesktop (0, ptr); | |||
+ editorComp->addToDesktop (0); | |||
hostWindow = (Window) ptr; | |||
+ Window editorWnd = (Window) editorComp->getWindowHandle(); | |||
+ XReparentWindow (display, editorWnd, hostWindow, 0, 0); | |||
#else | |||
hostWindow = attachComponentToWindowRef (editorComp, ptr, useNSView); | |||
#endif |
@@ -0,0 +1,12 @@ | |||
--- a/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp | |||
+++ b/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp | |||
@@ -1403,7 +1403,8 @@ class VST3ModuleHandle : public ReferenceCountedObject | |||
const Result result (finder.findDescriptionsAndPerform (f)); | |||
- if (result.getErrorMessage() == MatchingDescriptionFinder::getSuccessString()) | |||
+ if (result.getErrorMessage() == MatchingDescriptionFinder::getSuccessString() || | |||
+ result.getErrorMessage().isEmpty()) | |||
{ | |||
name = description.name; | |||
return true; |
@@ -7,5 +7,11 @@ It contains pretty much everything you're likely to need to create | |||
most applications, and is particularly well-suited for building | |||
highly-customised GUIs, and for handling graphics and sound. | |||
Most JUCE modules are shared under the GNU Public Licence | |||
(GPLv2, v3, and the AGPLv3). This means that the code can | |||
be freely copied and distributed, and costs nothing to use | |||
in other GPL applications. One module (the juce_core module) | |||
is permissively licensed under the ISC. | |||
For more information, visit the website: | |||
http://www.juce.com |
@@ -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); | |||
@@ -1,239 +0,0 @@ | |||
/* | |||
============================================================================== | |||
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. | |||
============================================================================== | |||
*/ | |||
#if JUCE_INTEL | |||
#define JUCE_SNAP_TO_ZERO(n) if (! (n < -1.0e-8 || n > 1.0e-8)) n = 0; | |||
#else | |||
#define JUCE_SNAP_TO_ZERO(n) | |||
#endif | |||
//============================================================================== | |||
IIRFilterOld::IIRFilterOld() | |||
: active (false), v1 (0), v2 (0) | |||
{ | |||
zeromem (coefficients, sizeof (coefficients)); | |||
} | |||
IIRFilterOld::IIRFilterOld (const IIRFilterOld& other) | |||
: active (other.active), v1 (0), v2 (0) | |||
{ | |||
const SpinLock::ScopedLockType sl (other.processLock); | |||
memcpy (coefficients, other.coefficients, sizeof (coefficients)); | |||
} | |||
IIRFilterOld::~IIRFilterOld() | |||
{ | |||
} | |||
//============================================================================== | |||
void IIRFilterOld::reset() noexcept | |||
{ | |||
const SpinLock::ScopedLockType sl (processLock); | |||
v1 = v2 = 0; | |||
} | |||
float IIRFilterOld::processSingleSampleRaw (const float in) noexcept | |||
{ | |||
float out = coefficients[0] * in + v1; | |||
JUCE_SNAP_TO_ZERO (out); | |||
v1 = coefficients[1] * in - coefficients[3] * out + v2; | |||
v2 = coefficients[2] * in - coefficients[4] * out; | |||
return out; | |||
} | |||
void IIRFilterOld::processSamples (float* const samples, | |||
const int numSamples) noexcept | |||
{ | |||
const SpinLock::ScopedLockType sl (processLock); | |||
if (active) | |||
{ | |||
const float c0 = coefficients[0]; | |||
const float c1 = coefficients[1]; | |||
const float c2 = coefficients[2]; | |||
const float c3 = coefficients[3]; | |||
const float c4 = coefficients[4]; | |||
float lv1 = v1, lv2 = v2; | |||
for (int i = 0; i < numSamples; ++i) | |||
{ | |||
const float in = samples[i]; | |||
const float out = c0 * in + lv1; | |||
samples[i] = out; | |||
lv1 = c1 * in - c3 * out + lv2; | |||
lv2 = c2 * in - c4 * out; | |||
} | |||
JUCE_SNAP_TO_ZERO (lv1); v1 = lv1; | |||
JUCE_SNAP_TO_ZERO (lv2); v2 = lv2; | |||
} | |||
} | |||
//============================================================================== | |||
void IIRFilterOld::makeLowPass (const double sampleRate, | |||
const double frequency) noexcept | |||
{ | |||
jassert (sampleRate > 0); | |||
const double n = 1.0 / tan (double_Pi * frequency / sampleRate); | |||
const double nSquared = n * n; | |||
const double c1 = 1.0 / (1.0 + std::sqrt (2.0) * n + nSquared); | |||
setCoefficients (c1, | |||
c1 * 2.0f, | |||
c1, | |||
1.0, | |||
c1 * 2.0 * (1.0 - nSquared), | |||
c1 * (1.0 - std::sqrt (2.0) * n + nSquared)); | |||
} | |||
void IIRFilterOld::makeHighPass (const double sampleRate, | |||
const double frequency) noexcept | |||
{ | |||
const double n = tan (double_Pi * frequency / sampleRate); | |||
const double nSquared = n * n; | |||
const double c1 = 1.0 / (1.0 + std::sqrt (2.0) * n + nSquared); | |||
setCoefficients (c1, | |||
c1 * -2.0f, | |||
c1, | |||
1.0, | |||
c1 * 2.0 * (nSquared - 1.0), | |||
c1 * (1.0 - std::sqrt (2.0) * n + nSquared)); | |||
} | |||
void IIRFilterOld::makeLowShelf (const double sampleRate, | |||
const double cutOffFrequency, | |||
const double Q, | |||
const float gainFactor) noexcept | |||
{ | |||
jassert (sampleRate > 0); | |||
jassert (Q > 0); | |||
const double A = jmax (0.0f, gainFactor); | |||
const double aminus1 = A - 1.0; | |||
const double aplus1 = A + 1.0; | |||
const double omega = (double_Pi * 2.0 * jmax (cutOffFrequency, 2.0)) / sampleRate; | |||
const double coso = std::cos (omega); | |||
const double beta = std::sin (omega) * std::sqrt (A) / Q; | |||
const double aminus1TimesCoso = aminus1 * coso; | |||
setCoefficients (A * (aplus1 - aminus1TimesCoso + beta), | |||
A * 2.0 * (aminus1 - aplus1 * coso), | |||
A * (aplus1 - aminus1TimesCoso - beta), | |||
aplus1 + aminus1TimesCoso + beta, | |||
-2.0 * (aminus1 + aplus1 * coso), | |||
aplus1 + aminus1TimesCoso - beta); | |||
} | |||
void IIRFilterOld::makeHighShelf (const double sampleRate, | |||
const double cutOffFrequency, | |||
const double Q, | |||
const float gainFactor) noexcept | |||
{ | |||
jassert (sampleRate > 0); | |||
jassert (Q > 0); | |||
const double A = jmax (0.0f, gainFactor); | |||
const double aminus1 = A - 1.0; | |||
const double aplus1 = A + 1.0; | |||
const double omega = (double_Pi * 2.0 * jmax (cutOffFrequency, 2.0)) / sampleRate; | |||
const double coso = std::cos (omega); | |||
const double beta = std::sin (omega) * std::sqrt (A) / Q; | |||
const double aminus1TimesCoso = aminus1 * coso; | |||
setCoefficients (A * (aplus1 + aminus1TimesCoso + beta), | |||
A * -2.0 * (aminus1 + aplus1 * coso), | |||
A * (aplus1 + aminus1TimesCoso - beta), | |||
aplus1 - aminus1TimesCoso + beta, | |||
2.0 * (aminus1 - aplus1 * coso), | |||
aplus1 - aminus1TimesCoso - beta); | |||
} | |||
void IIRFilterOld::makeBandPass (const double sampleRate, | |||
const double centreFrequency, | |||
const double Q, | |||
const float gainFactor) noexcept | |||
{ | |||
jassert (sampleRate > 0); | |||
jassert (Q > 0); | |||
const double A = jmax (0.0f, gainFactor); | |||
const double omega = (double_Pi * 2.0 * jmax (centreFrequency, 2.0)) / sampleRate; | |||
const double alpha = 0.5 * std::sin (omega) / Q; | |||
const double c2 = -2.0 * std::cos (omega); | |||
const double alphaTimesA = alpha * A; | |||
const double alphaOverA = alpha / A; | |||
setCoefficients (1.0 + alphaTimesA, | |||
c2, | |||
1.0 - alphaTimesA, | |||
1.0 + alphaOverA, | |||
c2, | |||
1.0 - alphaOverA); | |||
} | |||
void IIRFilterOld::makeInactive() noexcept | |||
{ | |||
const SpinLock::ScopedLockType sl (processLock); | |||
active = false; | |||
} | |||
//============================================================================== | |||
void IIRFilterOld::copyCoefficientsFrom (const IIRFilterOld& other) noexcept | |||
{ | |||
const SpinLock::ScopedLockType sl (processLock); | |||
memcpy (coefficients, other.coefficients, sizeof (coefficients)); | |||
active = other.active; | |||
} | |||
//============================================================================== | |||
void IIRFilterOld::setCoefficients (double c1, double c2, double c3, | |||
double c4, double c5, double c6) noexcept | |||
{ | |||
const double a = 1.0 / c4; | |||
c1 *= a; | |||
c2 *= a; | |||
c3 *= a; | |||
c5 *= a; | |||
c6 *= a; | |||
const SpinLock::ScopedLockType sl (processLock); | |||
coefficients[0] = (float) c1; | |||
coefficients[1] = (float) c2; | |||
coefficients[2] = (float) c3; | |||
coefficients[3] = (float) c5; | |||
coefficients[4] = (float) c6; | |||
active = true; | |||
} | |||
#undef JUCE_SNAP_TO_ZERO |
@@ -1,148 +0,0 @@ | |||
/* | |||
============================================================================== | |||
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. | |||
============================================================================== | |||
*/ | |||
#ifndef __JUCE_IIRFILTER_OLD_JUCEHEADER__ | |||
#define __JUCE_IIRFILTER_OLD_JUCEHEADER__ | |||
//============================================================================== | |||
/** | |||
An IIR filter that can perform low, high, or band-pass filtering on an | |||
audio signal. | |||
@see IIRFilterAudioSource | |||
*/ | |||
class JUCE_API IIRFilterOld | |||
{ | |||
public: | |||
//============================================================================== | |||
/** Creates a filter. | |||
Initially the filter is inactive, so will have no effect on samples that | |||
you process with it. Use the appropriate method to turn it into the type | |||
of filter needed. | |||
*/ | |||
IIRFilterOld(); | |||
/** Creates a copy of another filter. */ | |||
IIRFilterOld (const IIRFilterOld& other); | |||
/** Destructor. */ | |||
~IIRFilterOld(); | |||
//============================================================================== | |||
/** Resets the filter's processing pipeline, ready to start a new stream of data. | |||
Note that this clears the processing state, but the type of filter and | |||
its coefficients aren't changed. To put a filter into an inactive state, use | |||
the makeInactive() method. | |||
*/ | |||
void reset() noexcept; | |||
/** Performs the filter operation on the given set of samples. | |||
*/ | |||
void processSamples (float* samples, | |||
int numSamples) noexcept; | |||
/** Processes a single sample, without any locking or checking. | |||
Use this if you need fast processing of a single value, but be aware that | |||
this isn't thread-safe in the way that processSamples() is. | |||
*/ | |||
float processSingleSampleRaw (float sample) noexcept; | |||
//============================================================================== | |||
/** Sets the filter up to act as a low-pass filter. | |||
*/ | |||
void makeLowPass (double sampleRate, | |||
double frequency) noexcept; | |||
/** Sets the filter up to act as a high-pass filter. | |||
*/ | |||
void makeHighPass (double sampleRate, | |||
double frequency) noexcept; | |||
//============================================================================== | |||
/** Sets the filter up to act as a low-pass shelf filter with variable Q and gain. | |||
The gain is a scale factor that the low frequencies are multiplied by, so values | |||
greater than 1.0 will boost the low frequencies, values less than 1.0 will | |||
attenuate them. | |||
*/ | |||
void makeLowShelf (double sampleRate, | |||
double cutOffFrequency, | |||
double Q, | |||
float gainFactor) noexcept; | |||
/** Sets the filter up to act as a high-pass shelf filter with variable Q and gain. | |||
The gain is a scale factor that the high frequencies are multiplied by, so values | |||
greater than 1.0 will boost the high frequencies, values less than 1.0 will | |||
attenuate them. | |||
*/ | |||
void makeHighShelf (double sampleRate, | |||
double cutOffFrequency, | |||
double Q, | |||
float gainFactor) noexcept; | |||
/** Sets the filter up to act as a band pass filter centred around a | |||
frequency, with a variable Q and gain. | |||
The gain is a scale factor that the centre frequencies are multiplied by, so | |||
values greater than 1.0 will boost the centre frequencies, values less than | |||
1.0 will attenuate them. | |||
*/ | |||
void makeBandPass (double sampleRate, | |||
double centreFrequency, | |||
double Q, | |||
float gainFactor) noexcept; | |||
/** Clears the filter's coefficients so that it becomes inactive. | |||
*/ | |||
void makeInactive() noexcept; | |||
//============================================================================== | |||
/** Makes this filter duplicate the set-up of another one. | |||
*/ | |||
void copyCoefficientsFrom (const IIRFilterOld& other) noexcept; | |||
protected: | |||
//============================================================================== | |||
SpinLock processLock; | |||
void setCoefficients (double c1, double c2, double c3, | |||
double c4, double c5, double c6) noexcept; | |||
bool active; | |||
float coefficients[5]; | |||
float v1, v2; | |||
// (use the copyCoefficientsFrom() method instead of this operator) | |||
IIRFilterOld& operator= (const IIRFilterOld&); | |||
JUCE_LEAK_DETECTOR (IIRFilterOld) | |||
}; | |||
#endif // __JUCE_IIRFILTER_OLD_JUCEHEADER__ |
@@ -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) | |||
}; | |||
@@ -76,8 +76,8 @@ namespace juce | |||
#include "buffers/juce_AudioSampleBuffer.cpp" | |||
#include "buffers/juce_FloatVectorOperations.cpp" | |||
#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,13 +31,16 @@ | |||
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" | |||
#include "effects/juce_Decibels.h" | |||
#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" | |||
@@ -1,7 +1,7 @@ | |||
{ | |||
"id": "juce_audio_basics", | |||
"name": "JUCE audio and midi data classes", | |||
"version": "3.0.8", | |||
"version": "3.1.1", | |||
"description": "Classes for audio buffer manipulation, midi message handling, synthesis, etc", | |||
"website": "http://www.juce.com/juce", | |||
"license": "GPL/Commercial", | |||
@@ -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,13 +153,14 @@ 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()); | |||
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_iOSAudio()); | |||
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_JACK()); | |||
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ALSA()); | |||
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_JACK()); | |||
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_OpenSLES()); | |||
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Android()); | |||
} | |||
@@ -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). | |||
*/ | |||
@@ -1,7 +1,7 @@ | |||
{ | |||
"id": "juce_audio_devices", | |||
"name": "JUCE audio and midi I/O device classes", | |||
"version": "3.0.8", | |||
"version": "3.1.1", | |||
"description": "Classes to play and record from audio and midi i/o devices.", | |||
"website": "http://www.juce.com/juce", | |||
"license": "GPL/Commercial", | |||
@@ -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: | |||
@@ -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) | |||
@@ -1,7 +1,7 @@ | |||
{ | |||
"id": "juce_audio_formats", | |||
"name": "JUCE audio file format codecs", | |||
"version": "3.0.8", | |||
"version": "3.1.1", | |||
"description": "Classes for reading and writing various audio file formats.", | |||
"website": "http://www.juce.com/juce", | |||
"license": "GPL/Commercial", | |||
@@ -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 | |||
{ | |||
@@ -495,6 +495,18 @@ struct AAXClasses | |||
return AAX_CEffectParameters::SetChunk (chunkID, chunk); | |||
pluginInstance->setStateInformation ((void*) chunk->fData, chunk->fSize); | |||
// Notify Pro Tools that the parameters were updated. | |||
// Without it a bug happens in these circumstances: | |||
// * A preset is saved with the RTAS version of the plugin (".tfx" preset format). | |||
// * The preset is loaded in PT 10 using the AAX version. | |||
// * The session is then saved, and closed. | |||
// * The saved session is loaded, but acting as if the preset was never loaded. | |||
const int numParameters = pluginInstance->getNumParameters(); | |||
for (int i = 0; i < numParameters; ++i) | |||
SetParameterNormalizedValue (IndexAsParamID (i), (double) pluginInstance->getParameter(i)); | |||
return AAX_SUCCESS; | |||
} | |||
@@ -781,10 +793,8 @@ struct AAXClasses | |||
for (uint32_t i = 0; i < numMidiEvents; ++i) | |||
{ | |||
// (This 8-byte alignment is a workaround to a bug in the AAX SDK. Hopefully can be | |||
// removed in future when the packet structure size is fixed) | |||
const AAX_CMidiPacket& m = *addBytesToPointer (midiStream->mBuffer, | |||
i * ((sizeof (AAX_CMidiPacket) + 7) & ~(size_t) 7)); | |||
const AAX_CMidiPacket& m = midiStream->mBuffer[i]; | |||
jassert ((int) m.mTimestamp < bufferSize); | |||
midiBuffer.addEvent (m.mData, (int) m.mLength, | |||
jlimit (0, (int) bufferSize - 1, (int) m.mTimestamp)); | |||
@@ -223,47 +223,57 @@ public: | |||
{ | |||
switch (inID) | |||
{ | |||
case juceFilterObjectPropertyID: | |||
outWritable = false; | |||
outDataSize = sizeof (void*) * 2; | |||
return noErr; | |||
case kAudioUnitProperty_OfflineRender: | |||
outWritable = true; | |||
outDataSize = sizeof (UInt32); | |||
return noErr; | |||
case kMusicDeviceProperty_InstrumentCount: | |||
outDataSize = sizeof (UInt32); | |||
outWritable = false; | |||
return noErr; | |||
case kAudioUnitProperty_CocoaUI: | |||
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 | |||
// (On 10.4, there's a random obj-c dispatching crash when trying to load a cocoa UI) | |||
if (SystemStats::getOperatingSystemType() >= SystemStats::MacOSX_10_5) | |||
#endif | |||
{ | |||
outDataSize = sizeof (AudioUnitCocoaViewInfo); | |||
case juceFilterObjectPropertyID: | |||
outWritable = false; | |||
outDataSize = sizeof (void*) * 2; | |||
return noErr; | |||
case kAudioUnitProperty_OfflineRender: | |||
outWritable = true; | |||
outDataSize = sizeof (UInt32); | |||
return noErr; | |||
} | |||
break; | |||
case kMusicDeviceProperty_InstrumentCount: | |||
outDataSize = sizeof (UInt32); | |||
outWritable = false; | |||
return noErr; | |||
case kAudioUnitProperty_CocoaUI: | |||
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 | |||
// (On 10.4, there's a random obj-c dispatching crash when trying to load a cocoa UI) | |||
if (SystemStats::getOperatingSystemType() >= SystemStats::MacOSX_10_5) | |||
#endif | |||
{ | |||
outDataSize = sizeof (AudioUnitCocoaViewInfo); | |||
outWritable = true; | |||
return noErr; | |||
} | |||
#if JucePlugin_ProducesMidiOutput | |||
case kAudioUnitProperty_MIDIOutputCallbackInfo: | |||
outDataSize = sizeof (CFArrayRef); | |||
outWritable = false; | |||
return noErr; | |||
break; | |||
case kAudioUnitProperty_MIDIOutputCallback: | |||
outDataSize = sizeof (AUMIDIOutputCallbackStruct); | |||
outWritable = true; | |||
return noErr; | |||
#endif | |||
#if JucePlugin_ProducesMidiOutput | |||
case kAudioUnitProperty_MIDIOutputCallbackInfo: | |||
outDataSize = sizeof (CFArrayRef); | |||
outWritable = false; | |||
return noErr; | |||
default: break; | |||
case kAudioUnitProperty_MIDIOutputCallback: | |||
outDataSize = sizeof (AUMIDIOutputCallbackStruct); | |||
outWritable = true; | |||
return noErr; | |||
#endif | |||
case kAudioUnitProperty_ParameterStringFromValue: | |||
outDataSize = sizeof (AudioUnitParameterStringFromValue); | |||
outWritable = false; | |||
return noErr; | |||
case kAudioUnitProperty_ParameterValueFromString: | |||
outDataSize = sizeof (AudioUnitParameterValueFromString); | |||
outWritable = false; | |||
return noErr; | |||
default: break; | |||
} | |||
} | |||
@@ -280,7 +290,7 @@ public: | |||
switch (inID) | |||
{ | |||
case juceFilterObjectPropertyID: | |||
((void**) outData)[0] = (void*) static_cast <AudioProcessor*> (juceFilter); | |||
((void**) outData)[0] = (void*) static_cast<AudioProcessor*> (juceFilter); | |||
((void**) outData)[1] = (void*) this; | |||
return noErr; | |||
@@ -305,7 +315,7 @@ public: | |||
// (NB: this may be the host's bundle, not necessarily the component's) | |||
NSBundle* bundle = [NSBundle bundleForClass: cls.cls]; | |||
AudioUnitCocoaViewInfo* info = static_cast <AudioUnitCocoaViewInfo*> (outData); | |||
AudioUnitCocoaViewInfo* info = static_cast<AudioUnitCocoaViewInfo*> (outData); | |||
info->mCocoaAUViewClass[0] = (CFStringRef) [juceStringToNS (class_getName (cls.cls)) retain]; | |||
info->mCocoaAUViewBundleLocation = (CFURLRef) [[NSURL fileURLWithPath: [bundle bundlePath]] retain]; | |||
} | |||
@@ -327,7 +337,48 @@ public: | |||
} | |||
#endif | |||
default: break; | |||
case kAudioUnitProperty_ParameterValueFromString: | |||
{ | |||
if (AudioUnitParameterValueFromString* pv = (AudioUnitParameterValueFromString*) outData) | |||
{ | |||
if (juceFilter != nullptr) | |||
{ | |||
const String text (String::fromCFString (pv->inString)); | |||
if (AudioProcessorParameter* param = juceFilter->getParameters() [(int) pv->inParamID]) | |||
pv->outValue = param->getValueForText (text); | |||
else | |||
pv->outValue = text.getFloatValue(); | |||
return noErr; | |||
} | |||
} | |||
} | |||
break; | |||
case kAudioUnitProperty_ParameterStringFromValue: | |||
{ | |||
if (AudioUnitParameterStringFromValue* pv = (AudioUnitParameterStringFromValue*) outData) | |||
{ | |||
if (juceFilter != nullptr) | |||
{ | |||
const float value = (float) *(pv->inValue); | |||
String text; | |||
if (AudioProcessorParameter* param = juceFilter->getParameters() [(int) pv->inParamID]) | |||
text = param->getText ((float) *(pv->inValue), 0); | |||
else | |||
text = String (value); | |||
pv->outString = text.toCFString(); | |||
return noErr; | |||
} | |||
} | |||
} | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
@@ -466,7 +517,8 @@ public: | |||
{ | |||
outParameterInfo.flags = (UInt32) (kAudioUnitParameterFlag_IsWritable | |||
| kAudioUnitParameterFlag_IsReadable | |||
| kAudioUnitParameterFlag_HasCFNameString); | |||
| kAudioUnitParameterFlag_HasCFNameString | |||
| kAudioUnitParameterFlag_ValuesHaveStrings); | |||
const String name (juceFilter->getParameterName (index)); | |||
@@ -606,9 +658,11 @@ public: | |||
&outCurrentSampleInTimeLine, | |||
&looping, | |||
&outCycleStartBeat, | |||
&outCycleEndBeat) != noErr) | |||
&outCycleEndBeat) != noErr | |||
|| getHostType().isLogic()) | |||
{ | |||
// If the host doesn't support this callback, use the sample time from lastTimeStamp: | |||
// If the host doesn't support this callback (or if it's Logic, which has a bug), | |||
// then fallback to using the sample time from lastTimeStamp: | |||
outCurrentSampleInTimeLine = lastTimeStamp.mSampleTime; | |||
} | |||
@@ -647,7 +701,9 @@ public: | |||
void audioProcessorChanged (AudioProcessor*) | |||
{ | |||
PropertyChanged (kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0); | |||
PropertyChanged (kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0); | |||
PropertyChanged (kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0); | |||
PropertyChanged (kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, 0); | |||
} | |||
bool StreamFormatWritable (AudioUnitScope, AudioUnitElement) override | |||
@@ -664,9 +720,9 @@ public: | |||
ComponentResult Initialize() override | |||
{ | |||
#if ! JucePlugin_IsSynth | |||
const int numIns = GetInput(0) != 0 ? (int) GetInput(0)->GetStreamFormat().mChannelsPerFrame : 0; | |||
const int numIns = findNumInputChannels(); | |||
#endif | |||
const int numOuts = GetOutput(0) != 0 ? (int) GetOutput(0)->GetStreamFormat().mChannelsPerFrame : 0; | |||
const int numOuts = findNumOutputChannels(); | |||
bool isValidChannelConfig = false; | |||
@@ -710,19 +766,32 @@ public: | |||
return JuceAUBaseClass::Reset (inScope, inElement); | |||
} | |||
int findNumInputChannels() | |||
{ | |||
#if ! JucePlugin_IsSynth | |||
if (AUInputElement* e = GetInput(0)) | |||
return (int) e->GetStreamFormat().mChannelsPerFrame; | |||
#endif | |||
return 0; | |||
} | |||
int findNumOutputChannels() | |||
{ | |||
if (AUOutputElement* e = GetOutput(0)) | |||
return (int) e->GetStreamFormat().mChannelsPerFrame; | |||
return 0; | |||
} | |||
void prepareToPlay() | |||
{ | |||
if (juceFilter != nullptr) | |||
{ | |||
juceFilter->setPlayConfigDetails ( | |||
#if ! JucePlugin_IsSynth | |||
(int) GetInput(0)->GetStreamFormat().mChannelsPerFrame, | |||
#else | |||
0, | |||
#endif | |||
(int) GetOutput(0)->GetStreamFormat().mChannelsPerFrame, | |||
getSampleRate(), | |||
(int) GetMaxFramesPerSlice()); | |||
juceFilter->setPlayConfigDetails (findNumInputChannels(), | |||
findNumOutputChannels(), | |||
getSampleRate(), | |||
(int) GetMaxFramesPerSlice()); | |||
bufferSpace.setSize (juceFilter->getNumInputChannels() + juceFilter->getNumOutputChannels(), | |||
(int) GetMaxFramesPerSlice() + 32); | |||
@@ -1129,9 +1198,9 @@ public: | |||
}; | |||
//============================================================================== | |||
struct JuceUIViewClass : public ObjCClass <NSView> | |||
struct JuceUIViewClass : public ObjCClass<NSView> | |||
{ | |||
JuceUIViewClass() : ObjCClass <NSView> ("JUCEAUView_") | |||
JuceUIViewClass() : ObjCClass<NSView> ("JUCEAUView_") | |||
{ | |||
addIvar<AudioProcessor*> ("filter"); | |||
addIvar<JuceAU*> ("au"); | |||
@@ -1220,9 +1289,9 @@ public: | |||
}; | |||
//============================================================================== | |||
struct JuceUICreationClass : public ObjCClass <NSObject> | |||
struct JuceUICreationClass : public ObjCClass<NSObject> | |||
{ | |||
JuceUICreationClass() : ObjCClass <NSObject> ("JUCE_AUCocoaViewClass_") | |||
JuceUICreationClass() : ObjCClass<NSObject> ("JUCE_AUCocoaViewClass_") | |||
{ | |||
addMethod (@selector (interfaceVersion), interfaceVersion, @encode (unsigned int), "@:"); | |||
addMethod (@selector (description), description, @encode (NSString*), "@:"); | |||
@@ -1249,9 +1318,9 @@ public: | |||
if (AudioUnitGetProperty (inAudioUnit, juceFilterObjectPropertyID, | |||
kAudioUnitScope_Global, 0, pointers, &propertySize) == noErr) | |||
{ | |||
if (AudioProcessor* filter = static_cast <AudioProcessor*> (pointers[0])) | |||
if (AudioProcessor* filter = static_cast<AudioProcessor*> (pointers[0])) | |||
if (AudioProcessorEditor* editorComp = filter->createEditorIfNeeded()) | |||
return EditorCompHolder::createViewFor (filter, static_cast <JuceAU*> (pointers[1]), editorComp); | |||
return EditorCompHolder::createViewFor (filter, static_cast<JuceAU*> (pointers[1]), editorComp); | |||
} | |||
return nil; | |||
@@ -1262,7 +1331,7 @@ private: | |||
//============================================================================== | |||
ScopedPointer<AudioProcessor> juceFilter; | |||
AudioSampleBuffer bufferSpace; | |||
HeapBlock <float*> channels; | |||
HeapBlock<float*> channels; | |||
MidiBuffer midiEvents, incomingEvents; | |||
bool prepared; | |||
AUChannelInfo channelInfo [numChannelConfigs]; | |||
@@ -1363,8 +1432,8 @@ private: | |||
aren't so careful) */ | |||
jassert (Component::getCurrentlyModalComponent() == nullptr); | |||
if (JuceAU::EditorCompHolder* editorCompHolder = dynamic_cast <JuceAU::EditorCompHolder*> (windowComp->getChildComponent(0))) | |||
if (AudioProcessorEditor* audioProcessEditor = dynamic_cast <AudioProcessorEditor*> (editorCompHolder->getChildComponent(0))) | |||
if (JuceAU::EditorCompHolder* editorCompHolder = dynamic_cast<JuceAU::EditorCompHolder*> (windowComp->getChildComponent(0))) | |||
if (AudioProcessorEditor* audioProcessEditor = dynamic_cast<AudioProcessorEditor*> (editorCompHolder->getChildComponent(0))) | |||
juceFilter->editorBeingDeleted (audioProcessEditor); | |||
windowComp = nullptr; | |||
@@ -1,83 +0,0 @@ | |||
/* | |||
base64.cpp and base64.h | |||
Copyright (C) 2004-2008 René Nyffenegger | |||
This source code is provided 'as-is', without any express or implied | |||
warranty. In no event will the author be held liable for any damages | |||
arising from the use of this software. | |||
Permission is granted to anyone to use this software for any purpose, | |||
including commercial applications, and to alter it and redistribute it | |||
freely, subject to the following restrictions: | |||
1. The origin of this source code must not be misrepresented; you must not | |||
claim that you wrote the original source code. If you use this source code | |||
in a product, an acknowledgment in the product documentation would be | |||
appreciated but is not required. | |||
2. Altered source versions must be plainly marked as such, and must not be | |||
misrepresented as being the original source code. | |||
3. This notice may not be removed or altered from any source distribution. | |||
René Nyffenegger rene.nyffenegger@adp-gmbh.ch | |||
*/ | |||
// source code was edited - removed everything not needed for juce-lv2 | |||
#include <iostream> | |||
static const std::string base64_chars = | |||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |||
"abcdefghijklmnopqrstuvwxyz" | |||
"0123456789+/"; | |||
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { | |||
std::string ret; | |||
int i = 0; | |||
int j = 0; | |||
unsigned char char_array_3[3]; | |||
unsigned char char_array_4[4]; | |||
while (in_len--) { | |||
char_array_3[i++] = *(bytes_to_encode++); | |||
if (i == 3) { | |||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; | |||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); | |||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); | |||
char_array_4[3] = char_array_3[2] & 0x3f; | |||
for(i = 0; (i <4) ; i++) | |||
ret += base64_chars[char_array_4[i]]; | |||
i = 0; | |||
} | |||
} | |||
if (i) | |||
{ | |||
for(j = i; j < 3; j++) | |||
char_array_3[j] = '\0'; | |||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; | |||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); | |||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); | |||
char_array_4[3] = char_array_3[2] & 0x3f; | |||
for (j = 0; (j < i + 1); j++) | |||
ret += base64_chars[char_array_4[j]]; | |||
while((i++ < 3)) | |||
ret += '='; | |||
} | |||
return ret; | |||
} | |||
const String Base64Encode (const MemoryBlock &dataToEncode) | |||
{ | |||
return (base64_encode ((unsigned char const *)dataToEncode.getData(), dataToEncode.getSize()).c_str()); | |||
} |
@@ -1,446 +0,0 @@ | |||
/* | |||
Copyright 2008-2013 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file util.h Helper functions for the LV2 Atom extension. | |||
Note these functions are all static inline, do not take their address. | |||
This header is non-normative, it is provided for convenience. | |||
*/ | |||
#ifndef LV2_ATOM_UTIL_H | |||
#define LV2_ATOM_UTIL_H | |||
#include <stdarg.h> | |||
#include <stdint.h> | |||
#include <string.h> | |||
#include "atom.h" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#else | |||
# include <stdbool.h> | |||
#endif | |||
/** Pad a size to 64 bits. */ | |||
static inline uint32_t | |||
lv2_atom_pad_size(uint32_t size) | |||
{ | |||
return (size + 7U) & (~7U); | |||
} | |||
/** Return the total size of @p atom, including the header. */ | |||
static inline uint32_t | |||
lv2_atom_total_size(const LV2_Atom* atom) | |||
{ | |||
return (uint32_t)sizeof(LV2_Atom) + atom->size; | |||
} | |||
/** Return true iff @p atom is null. */ | |||
static inline bool | |||
lv2_atom_is_null(const LV2_Atom* atom) | |||
{ | |||
return !atom || (atom->type == 0 && atom->size == 0); | |||
} | |||
/** Return true iff @p a is equal to @p b. */ | |||
static inline bool | |||
lv2_atom_equals(const LV2_Atom* a, const LV2_Atom* b) | |||
{ | |||
return (a == b) || ((a->type == b->type) && | |||
(a->size == b->size) && | |||
!memcmp(a + 1, b + 1, a->size)); | |||
} | |||
/** | |||
@name Sequence Iterator | |||
@{ | |||
*/ | |||
/** Get an iterator pointing to the first event in a Sequence body. */ | |||
static inline const LV2_Atom_Event* | |||
lv2_atom_sequence_begin(const LV2_Atom_Sequence_Body* body) | |||
{ | |||
return (const LV2_Atom_Event*)(body + 1); | |||
} | |||
/** Get an iterator pointing to the end of a Sequence body. */ | |||
static inline LV2_Atom_Event* | |||
lv2_atom_sequence_end(LV2_Atom_Sequence_Body* body, uint32_t size) | |||
{ | |||
return (LV2_Atom_Event*)((uint8_t*)body + lv2_atom_pad_size(size)); | |||
} | |||
/** Return true iff @p i has reached the end of @p body. */ | |||
static inline bool | |||
lv2_atom_sequence_is_end(const LV2_Atom_Sequence_Body* body, | |||
uint32_t size, | |||
const LV2_Atom_Event* i) | |||
{ | |||
return (const uint8_t*)i >= ((const uint8_t*)body + size); | |||
} | |||
/** Return an iterator to the element following @p i. */ | |||
static inline const LV2_Atom_Event* | |||
lv2_atom_sequence_next(const LV2_Atom_Event* i) | |||
{ | |||
return (const LV2_Atom_Event*)((const uint8_t*)i | |||
+ sizeof(LV2_Atom_Event) | |||
+ lv2_atom_pad_size(i->body.size)); | |||
} | |||
/** | |||
A macro for iterating over all events in a Sequence. | |||
@param seq The sequence to iterate over | |||
@param iter The name of the iterator | |||
This macro is used similarly to a for loop (which it expands to), e.g.: | |||
@code | |||
LV2_ATOM_SEQUENCE_FOREACH(sequence, ev) { | |||
// Do something with ev (an LV2_Atom_Event*) here... | |||
} | |||
@endcode | |||
*/ | |||
#define LV2_ATOM_SEQUENCE_FOREACH(seq, iter) \ | |||
for (const LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(&(seq)->body); \ | |||
!lv2_atom_sequence_is_end(&(seq)->body, (seq)->atom.size, (iter)); \ | |||
(iter) = lv2_atom_sequence_next(iter)) | |||
/** Like LV2_ATOM_SEQUENCE_FOREACH but for a headerless sequence body. */ | |||
#define LV2_ATOM_SEQUENCE_BODY_FOREACH(body, size, iter) \ | |||
for (const LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(body); \ | |||
!lv2_atom_sequence_is_end(body, size, (iter)); \ | |||
(iter) = lv2_atom_sequence_next(iter)) | |||
/** | |||
@} | |||
@name Sequence Utilities | |||
@{ | |||
*/ | |||
/** | |||
Clear all events from @p sequence. | |||
This simply resets the size field, the other fields are left untouched. | |||
*/ | |||
static inline void | |||
lv2_atom_sequence_clear(LV2_Atom_Sequence* seq) | |||
{ | |||
seq->atom.size = sizeof(LV2_Atom_Sequence_Body); | |||
} | |||
/** | |||
Append an event at the end of @p sequence. | |||
@param seq Sequence to append to. | |||
@param capacity Total capacity of the sequence atom | |||
(e.g. as set by the host for sequence output ports). | |||
@param event Event to write. | |||
@return A pointer to the newly written event in @p seq, | |||
or NULL on failure (insufficient space). | |||
*/ | |||
static inline LV2_Atom_Event* | |||
lv2_atom_sequence_append_event(LV2_Atom_Sequence* seq, | |||
uint32_t capacity, | |||
const LV2_Atom_Event* event) | |||
{ | |||
const uint32_t total_size = (uint32_t)sizeof(*event) + event->body.size; | |||
if (capacity - seq->atom.size < total_size) { | |||
return NULL; | |||
} | |||
LV2_Atom_Event* e = lv2_atom_sequence_end(&seq->body, seq->atom.size); | |||
memcpy(e, event, total_size); | |||
seq->atom.size += lv2_atom_pad_size(total_size); | |||
return e; | |||
} | |||
/** | |||
@} | |||
@name Tuple Iterator | |||
@{ | |||
*/ | |||
/** Get an iterator pointing to the first element in @p tup. */ | |||
static inline const LV2_Atom* | |||
lv2_atom_tuple_begin(const LV2_Atom_Tuple* tup) | |||
{ | |||
return (const LV2_Atom*)(LV2_ATOM_BODY_CONST(tup)); | |||
} | |||
/** Return true iff @p i has reached the end of @p body. */ | |||
static inline bool | |||
lv2_atom_tuple_is_end(const void* body, uint32_t size, const LV2_Atom* i) | |||
{ | |||
return (const uint8_t*)i >= ((const uint8_t*)body + size); | |||
} | |||
/** Return an iterator to the element following @p i. */ | |||
static inline const LV2_Atom* | |||
lv2_atom_tuple_next(const LV2_Atom* i) | |||
{ | |||
return (const LV2_Atom*)( | |||
(const uint8_t*)i + sizeof(LV2_Atom) + lv2_atom_pad_size(i->size)); | |||
} | |||
/** | |||
A macro for iterating over all properties of a Tuple. | |||
@param tuple The tuple to iterate over | |||
@param iter The name of the iterator | |||
This macro is used similarly to a for loop (which it expands to), e.g.: | |||
@code | |||
LV2_ATOMO_TUPLE_FOREACH(tuple, elem) { | |||
// Do something with elem (an LV2_Atom*) here... | |||
} | |||
@endcode | |||
*/ | |||
#define LV2_ATOM_TUPLE_FOREACH(tuple, iter) \ | |||
for (const LV2_Atom* (iter) = lv2_atom_tuple_begin(tuple); \ | |||
!lv2_atom_tuple_is_end(LV2_ATOM_BODY_CONST(tuple), (tuple)->size, (iter)); \ | |||
(iter) = lv2_atom_tuple_next(iter)) | |||
/** Like LV2_ATOM_TUPLE_FOREACH but for a headerless tuple body. */ | |||
#define LV2_ATOM_TUPLE_BODY_FOREACH(body, size, iter) \ | |||
for (const LV2_Atom* (iter) = (const LV2_Atom*)body; \ | |||
!lv2_atom_tuple_is_end(body, size, (iter)); \ | |||
(iter) = lv2_atom_tuple_next(iter)) | |||
/** | |||
@} | |||
@name Object Iterator | |||
@{ | |||
*/ | |||
/** Return a pointer to the first property in @p body. */ | |||
static inline const LV2_Atom_Property_Body* | |||
lv2_atom_object_begin(const LV2_Atom_Object_Body* body) | |||
{ | |||
return (const LV2_Atom_Property_Body*)(body + 1); | |||
} | |||
/** Return true iff @p i has reached the end of @p obj. */ | |||
static inline bool | |||
lv2_atom_object_is_end(const LV2_Atom_Object_Body* body, | |||
uint32_t size, | |||
const LV2_Atom_Property_Body* i) | |||
{ | |||
return (const uint8_t*)i >= ((const uint8_t*)body + size); | |||
} | |||
/** Return an iterator to the property following @p i. */ | |||
static inline const LV2_Atom_Property_Body* | |||
lv2_atom_object_next(const LV2_Atom_Property_Body* i) | |||
{ | |||
const LV2_Atom* const value = (const LV2_Atom*)( | |||
(const uint8_t*)i + 2 * sizeof(uint32_t)); | |||
return (const LV2_Atom_Property_Body*)( | |||
(const uint8_t*)i + lv2_atom_pad_size( | |||
(uint32_t)sizeof(LV2_Atom_Property_Body) + value->size)); | |||
} | |||
/** | |||
A macro for iterating over all properties of an Object. | |||
@param obj The object to iterate over | |||
@param iter The name of the iterator | |||
This macro is used similarly to a for loop (which it expands to), e.g.: | |||
@code | |||
LV2_ATOM_OBJECT_FOREACH(object, i) { | |||
// Do something with prop (an LV2_Atom_Property_Body*) here... | |||
} | |||
@endcode | |||
*/ | |||
#define LV2_ATOM_OBJECT_FOREACH(obj, iter) \ | |||
for (const LV2_Atom_Property_Body* (iter) = lv2_atom_object_begin(&(obj)->body); \ | |||
!lv2_atom_object_is_end(&(obj)->body, (obj)->atom.size, (iter)); \ | |||
(iter) = lv2_atom_object_next(iter)) | |||
/** Like LV2_ATOM_OBJECT_FOREACH but for a headerless object body. */ | |||
#define LV2_ATOM_OBJECT_BODY_FOREACH(body, size, iter) \ | |||
for (const LV2_Atom_Property_Body* (iter) = lv2_atom_object_begin(body); \ | |||
!lv2_atom_object_is_end(body, size, (iter)); \ | |||
(iter) = lv2_atom_object_next(iter)) | |||
/** | |||
@} | |||
@name Object Query | |||
@{ | |||
*/ | |||
/** A single entry in an Object query. */ | |||
typedef struct { | |||
uint32_t key; /**< Key to query (input set by user) */ | |||
const LV2_Atom** value; /**< Found value (output set by query function) */ | |||
} LV2_Atom_Object_Query; | |||
static const LV2_Atom_Object_Query LV2_ATOM_OBJECT_QUERY_END = { 0, NULL }; | |||
/** | |||
Get an object's values for various keys. | |||
The value pointer of each item in @p query will be set to the location of | |||
the corresponding value in @p object. Every value pointer in @p query MUST | |||
be initialised to NULL. This function reads @p object in a single linear | |||
sweep. By allocating @p query on the stack, objects can be "queried" | |||
quickly without allocating any memory. This function is realtime safe. | |||
This function can only do "flat" queries, it is not smart enough to match | |||
variables in nested objects. | |||
For example: | |||
@code | |||
const LV2_Atom* name = NULL; | |||
const LV2_Atom* age = NULL; | |||
LV2_Atom_Object_Query q[] = { | |||
{ urids.eg_name, &name }, | |||
{ urids.eg_age, &age }, | |||
LV2_ATOM_OBJECT_QUERY_END | |||
}; | |||
lv2_atom_object_query(obj, q); | |||
// name and age are now set to the appropriate values in obj, or NULL. | |||
@endcode | |||
*/ | |||
static inline int | |||
lv2_atom_object_query(const LV2_Atom_Object* object, | |||
LV2_Atom_Object_Query* query) | |||
{ | |||
int matches = 0; | |||
int n_queries = 0; | |||
/* Count number of query keys so we can short-circuit when done */ | |||
for (LV2_Atom_Object_Query* q = query; q->key; ++q) { | |||
++n_queries; | |||
} | |||
LV2_ATOM_OBJECT_FOREACH(object, prop) { | |||
for (LV2_Atom_Object_Query* q = query; q->key; ++q) { | |||
if (q->key == prop->key && !*q->value) { | |||
*q->value = &prop->value; | |||
if (++matches == n_queries) { | |||
return matches; | |||
} | |||
break; | |||
} | |||
} | |||
} | |||
return matches; | |||
} | |||
/** | |||
Body only version of lv2_atom_object_get(). | |||
*/ | |||
static inline int | |||
lv2_atom_object_body_get(uint32_t size, const LV2_Atom_Object_Body* body, ...) | |||
{ | |||
int matches = 0; | |||
int n_queries = 0; | |||
/* Count number of keys so we can short-circuit when done */ | |||
va_list args; | |||
va_start(args, body); | |||
for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) { | |||
if (!va_arg(args, const LV2_Atom**)) { | |||
return -1; | |||
} | |||
} | |||
va_end(args); | |||
LV2_ATOM_OBJECT_BODY_FOREACH(body, size, prop) { | |||
va_start(args, body); | |||
for (int i = 0; i < n_queries; ++i) { | |||
uint32_t qkey = va_arg(args, uint32_t); | |||
const LV2_Atom** qval = va_arg(args, const LV2_Atom**); | |||
if (qkey == prop->key && !*qval) { | |||
*qval = &prop->value; | |||
if (++matches == n_queries) { | |||
return matches; | |||
} | |||
break; | |||
} | |||
} | |||
va_end(args); | |||
} | |||
return matches; | |||
} | |||
/** | |||
Variable argument version of lv2_atom_object_query(). | |||
This is nicer-looking in code, but a bit more error-prone since it is not | |||
type safe and the argument list must be terminated. | |||
The arguments should be a series of uint32_t key and const LV2_Atom** value | |||
pairs, terminated by a zero key. The value pointers MUST be initialized to | |||
NULL. For example: | |||
@code | |||
const LV2_Atom* name = NULL; | |||
const LV2_Atom* age = NULL; | |||
lv2_atom_object_get(obj, | |||
uris.name_key, &name, | |||
uris.age_key, &age, | |||
0); | |||
@endcode | |||
*/ | |||
static inline int | |||
lv2_atom_object_get(const LV2_Atom_Object* object, ...) | |||
{ | |||
int matches = 0; | |||
int n_queries = 0; | |||
/* Count number of keys so we can short-circuit when done */ | |||
va_list args; | |||
va_start(args, object); | |||
for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) { | |||
if (!va_arg(args, const LV2_Atom**)) { | |||
return -1; | |||
} | |||
} | |||
va_end(args); | |||
LV2_ATOM_OBJECT_FOREACH(object, prop) { | |||
va_start(args, object); | |||
for (int i = 0; i < n_queries; ++i) { | |||
uint32_t qkey = va_arg(args, uint32_t); | |||
const LV2_Atom** qval = va_arg(args, const LV2_Atom**); | |||
if (qkey == prop->key && !*qval) { | |||
*qval = &prop->value; | |||
if (++matches == n_queries) { | |||
return matches; | |||
} | |||
break; | |||
} | |||
} | |||
va_end(args); | |||
} | |||
return matches; | |||
} | |||
/** | |||
@} | |||
*/ | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_ATOM_UTIL_H */ |
@@ -1,246 +0,0 @@ | |||
/* | |||
Copyright 2008-2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file atom.h C header for the LV2 Atom extension | |||
<http://lv2plug.in/ns/ext/atom>. | |||
*/ | |||
#ifndef LV2_ATOM_H | |||
#define LV2_ATOM_H | |||
#include <stdint.h> | |||
#include <stddef.h> | |||
#define LV2_ATOM_URI "http://lv2plug.in/ns/ext/atom" | |||
#define LV2_ATOM_PREFIX LV2_ATOM_URI "#" | |||
#define LV2_ATOM__Atom LV2_ATOM_PREFIX "Atom" | |||
#define LV2_ATOM__AtomPort LV2_ATOM_PREFIX "AtomPort" | |||
#define LV2_ATOM__Blank LV2_ATOM_PREFIX "Blank" | |||
#define LV2_ATOM__Bool LV2_ATOM_PREFIX "Bool" | |||
#define LV2_ATOM__Chunk LV2_ATOM_PREFIX "Chunk" | |||
#define LV2_ATOM__Double LV2_ATOM_PREFIX "Double" | |||
#define LV2_ATOM__Event LV2_ATOM_PREFIX "Event" | |||
#define LV2_ATOM__Float LV2_ATOM_PREFIX "Float" | |||
#define LV2_ATOM__Int LV2_ATOM_PREFIX "Int" | |||
#define LV2_ATOM__Literal LV2_ATOM_PREFIX "Literal" | |||
#define LV2_ATOM__Long LV2_ATOM_PREFIX "Long" | |||
#define LV2_ATOM__Number LV2_ATOM_PREFIX "Number" | |||
#define LV2_ATOM__Object LV2_ATOM_PREFIX "Object" | |||
#define LV2_ATOM__Path LV2_ATOM_PREFIX "Path" | |||
#define LV2_ATOM__Property LV2_ATOM_PREFIX "Property" | |||
#define LV2_ATOM__Resource LV2_ATOM_PREFIX "Resource" | |||
#define LV2_ATOM__Sequence LV2_ATOM_PREFIX "Sequence" | |||
#define LV2_ATOM__Sound LV2_ATOM_PREFIX "Sound" | |||
#define LV2_ATOM__String LV2_ATOM_PREFIX "String" | |||
#define LV2_ATOM__Tuple LV2_ATOM_PREFIX "Tuple" | |||
#define LV2_ATOM__URI LV2_ATOM_PREFIX "URI" | |||
#define LV2_ATOM__URID LV2_ATOM_PREFIX "URID" | |||
#define LV2_ATOM__Vector LV2_ATOM_PREFIX "Vector" | |||
#define LV2_ATOM__atomTransfer LV2_ATOM_PREFIX "atomTransfer" | |||
#define LV2_ATOM__beatTime LV2_ATOM_PREFIX "beatTime" | |||
#define LV2_ATOM__bufferType LV2_ATOM_PREFIX "bufferType" | |||
#define LV2_ATOM__childType LV2_ATOM_PREFIX "childType" | |||
#define LV2_ATOM__eventTransfer LV2_ATOM_PREFIX "eventTransfer" | |||
#define LV2_ATOM__frameTime LV2_ATOM_PREFIX "frameTime" | |||
#define LV2_ATOM__supports LV2_ATOM_PREFIX "supports" | |||
#define LV2_ATOM__timeUnit LV2_ATOM_PREFIX "timeUnit" | |||
#define LV2_ATOM_REFERENCE_TYPE 0 | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** This expression will fail to compile if double does not fit in 64 bits. */ | |||
typedef char lv2_atom_assert_double_fits_in_64_bits[ | |||
((sizeof(double) <= sizeof(uint64_t)) * 2) - 1]; | |||
/** | |||
Return a pointer to the contents of an Atom. The "contents" of an atom | |||
is the data past the complete type-specific header. | |||
@param type The type of the atom, e.g. LV2_Atom_String. | |||
@param atom A variable-sized atom. | |||
*/ | |||
#define LV2_ATOM_CONTENTS(type, atom) \ | |||
((uint8_t*)(atom) + sizeof(type)) | |||
/** | |||
Const version of LV2_ATOM_CONTENTS. | |||
*/ | |||
#define LV2_ATOM_CONTENTS_CONST(type, atom) \ | |||
((const uint8_t*)(atom) + sizeof(type)) | |||
/** | |||
Return a pointer to the body of an Atom. The "body" of an atom is the | |||
data just past the LV2_Atom head (i.e. the same offset for all types). | |||
*/ | |||
#define LV2_ATOM_BODY(atom) LV2_ATOM_CONTENTS(LV2_Atom, atom) | |||
/** | |||
Const version of LV2_ATOM_BODY. | |||
*/ | |||
#define LV2_ATOM_BODY_CONST(atom) LV2_ATOM_CONTENTS_CONST(LV2_Atom, atom) | |||
/** The header of an atom:Atom. */ | |||
typedef struct { | |||
uint32_t size; /**< Size in bytes, not including type and size. */ | |||
uint32_t type; /**< Type of this atom (mapped URI). */ | |||
} LV2_Atom; | |||
/** An atom:Int or atom:Bool. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
int32_t body; /**< Integer value. */ | |||
} LV2_Atom_Int; | |||
/** An atom:Long. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
int64_t body; /**< Integer value. */ | |||
} LV2_Atom_Long; | |||
/** An atom:Float. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
float body; /**< Floating point value. */ | |||
} LV2_Atom_Float; | |||
/** An atom:Double. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
double body; /**< Floating point value. */ | |||
} LV2_Atom_Double; | |||
/** An atom:Bool. May be cast to LV2_Atom. */ | |||
typedef LV2_Atom_Int LV2_Atom_Bool; | |||
/** An atom:URID. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
uint32_t body; /**< URID. */ | |||
} LV2_Atom_URID; | |||
/** An atom:String. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
/* Contents (a null-terminated UTF-8 string) follow here. */ | |||
} LV2_Atom_String; | |||
/** The body of an atom:Literal. */ | |||
typedef struct { | |||
uint32_t datatype; /**< Datatype URID. */ | |||
uint32_t lang; /**< Language URID. */ | |||
/* Contents (a null-terminated UTF-8 string) follow here. */ | |||
} LV2_Atom_Literal_Body; | |||
/** An atom:Literal. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
LV2_Atom_Literal_Body body; /**< Body. */ | |||
} LV2_Atom_Literal; | |||
/** An atom:Tuple. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
/* Contents (a series of complete atoms) follow here. */ | |||
} LV2_Atom_Tuple; | |||
/** The body of an atom:Vector. */ | |||
typedef struct { | |||
uint32_t child_size; /**< The size of each element in the vector. */ | |||
uint32_t child_type; /**< The type of each element in the vector. */ | |||
/* Contents (a series of packed atom bodies) follow here. */ | |||
} LV2_Atom_Vector_Body; | |||
/** An atom:Vector. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
LV2_Atom_Vector_Body body; /**< Body. */ | |||
} LV2_Atom_Vector; | |||
/** The body of an atom:Property (e.g. in an atom:Object). */ | |||
typedef struct { | |||
uint32_t key; /**< Key (predicate) (mapped URI). */ | |||
uint32_t context; /**< Context URID (may be, and generally is, 0). */ | |||
LV2_Atom value; /**< Value atom header. */ | |||
/* Value atom body follows here. */ | |||
} LV2_Atom_Property_Body; | |||
/** An atom:Property. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
LV2_Atom_Property_Body body; /**< Body. */ | |||
} LV2_Atom_Property; | |||
/** The body of an atom:Object. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
uint32_t id; /**< URID, or 0 for blank. */ | |||
uint32_t otype; /**< Type URID (same as rdf:type, for fast dispatch). */ | |||
/* Contents (a series of property bodies) follow here. */ | |||
} LV2_Atom_Object_Body; | |||
/** An atom:Object. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
LV2_Atom_Object_Body body; /**< Body. */ | |||
} LV2_Atom_Object; | |||
/** The header of an atom:Event. Note this type is NOT an LV2_Atom. */ | |||
typedef struct { | |||
/** Time stamp. Which type is valid is determined by context. */ | |||
union { | |||
int64_t frames; /**< Time in audio frames. */ | |||
double beats; /**< Time in beats. */ | |||
} time; | |||
LV2_Atom body; /**< Event body atom header. */ | |||
/* Body atom contents follow here. */ | |||
} LV2_Atom_Event; | |||
/** | |||
The body of an atom:Sequence (a sequence of events). | |||
The unit field is either a URID that described an appropriate time stamp | |||
type, or may be 0 where a default stamp type is known. For | |||
LV2_Descriptor::run(), the default stamp type is audio frames. | |||
The contents of a sequence is a series of LV2_Atom_Event, each aligned | |||
to 64-bits, e.g.: | |||
<pre> | |||
| Event 1 (size 6) | Event 2 | |||
| | | | | | | | | | |||
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |||
|FRAMES |SUBFRMS|TYPE |SIZE |DATADATADATAPAD|FRAMES |SUBFRMS|... | |||
</pre> | |||
*/ | |||
typedef struct { | |||
uint32_t unit; /**< URID of unit of event time stamps. */ | |||
uint32_t pad; /**< Currently unused. */ | |||
/* Contents (a series of events) follow here. */ | |||
} LV2_Atom_Sequence_Body; | |||
/** An atom:Sequence. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
LV2_Atom_Sequence_Body body; /**< Body. */ | |||
} LV2_Atom_Sequence; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_ATOM_H */ |