diff --git a/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h b/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h index 706584700a..b3f49a63df 100644 --- a/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h +++ b/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h @@ -71,9 +71,9 @@ public: { public: template static inline float getAsFloat (SampleFormatType& s) noexcept { return s.getAsFloatBE(); } - template static inline void setAsFloat (SampleFormatType& s, float newValue) noexcept { s.setAsFloatBE (newValue); } + template static inline void setAsFloat (SampleFormatType& s, float newValue) noexcept { s.setAsFloatBE (newValue); } template static inline int32 getAsInt32 (SampleFormatType& s) noexcept { return s.getAsInt32BE(); } - template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) noexcept { s.setAsInt32BE (newValue); } + template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) noexcept { s.setAsInt32BE (newValue); } template static inline void copyFrom (DestType& dest, SourceType& source) noexcept { dest.copyFromBE (source); } enum { isBigEndian = 1 }; }; @@ -82,9 +82,9 @@ public: { public: template static inline float getAsFloat (SampleFormatType& s) noexcept { return s.getAsFloatLE(); } - template static inline void setAsFloat (SampleFormatType& s, float newValue) noexcept { s.setAsFloatLE (newValue); } + template static inline void setAsFloat (SampleFormatType& s, float newValue) noexcept { s.setAsFloatLE (newValue); } template static inline int32 getAsInt32 (SampleFormatType& s) noexcept { return s.getAsInt32LE(); } - template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) noexcept { s.setAsInt32LE (newValue); } + template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) noexcept { s.setAsInt32LE (newValue); } template static inline void copyFrom (DestType& dest, SourceType& source) noexcept { dest.copyFromLE (source); } enum { isBigEndian = 0 }; }; @@ -205,11 +205,11 @@ public: inline void skip (int numSamples) noexcept { data += numSamples; } inline float getAsFloatLE() const noexcept { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); } inline float getAsFloatBE() const noexcept { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); } - inline void setAsFloatLE (float newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) (maxValue * jlimit (-1.0, 1.0, (double) newValue))); } + inline void setAsFloatLE (float newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) (maxValue * jlimit (-1.0, 1.0, (double) newValue))); } inline void setAsFloatBE (float newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint32) (maxValue * jlimit (-1.0, 1.0, (double) newValue))); } - inline int32 getAsInt32LE() const noexcept { return (int32) ByteOrder::swapIfBigEndian (*data); } + inline int32 getAsInt32LE() const noexcept { return (int32) ByteOrder::swapIfBigEndian (*data); } inline int32 getAsInt32BE() const noexcept { return (int32) ByteOrder::swapIfLittleEndian (*data); } - inline void setAsInt32LE (int32 newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) newValue); } + inline void setAsInt32LE (int32 newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) newValue); } inline void setAsInt32BE (int32 newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint32) newValue); } inline void clear() noexcept { *data = 0; } inline void clearMultiple (int num) noexcept { zeromem (data, (size_t) (num * bytesPerSample)) ;} @@ -221,6 +221,27 @@ public: enum { bytesPerSample = 4, maxValue = 0x7fffffff, resolution = 1, isFloat = 0 }; }; + /** A 32-bit integer type, of which only the bottom 24 bits are used. */ + class Int24in32 : public Int32 + { + public: + inline Int24in32 (void* d) noexcept : Int32 (d) {} + + inline float getAsFloatLE() const noexcept { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); } + inline float getAsFloatBE() const noexcept { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); } + inline void setAsFloatLE (float newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) (maxValue * jlimit (-1.0, 1.0, (double) newValue))); } + inline void setAsFloatBE (float newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint32) (maxValue * jlimit (-1.0, 1.0, (double) newValue))); } + inline int32 getAsInt32LE() const noexcept { return (int32) ByteOrder::swapIfBigEndian (*data) << 8; } + inline int32 getAsInt32BE() const noexcept { return (int32) ByteOrder::swapIfLittleEndian (*data) << 8; } + inline void setAsInt32LE (int32 newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) newValue >> 8); } + inline void setAsInt32BE (int32 newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint32) newValue >> 8); } + template inline void copyFromLE (SourceType& source) noexcept { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) noexcept { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int24in32& source) noexcept { *data = *source.data; } + + enum { bytesPerSample = 4, maxValue = 0x7fffff, resolution = (1 << 8), isFloat = 0 }; + }; + class Float32 { public: @@ -591,9 +612,7 @@ public: : sourceChannels (numSourceChannels), destChannels (numDestChannels) {} - ~ConverterInstance() {} - - void convertSamples (void* dest, const void* source, int numSamples) const + void convertSamples (void* dest, const void* source, int numSamples) const override { SourceSampleType s (source, sourceChannels); DestSampleType d (dest, destChannels); @@ -601,7 +620,7 @@ public: } void convertSamples (void* dest, int destSubChannel, - const void* source, int sourceSubChannel, int numSamples) const + const void* source, int sourceSubChannel, int numSamples) const override { jassert (destSubChannel < destChannels && sourceSubChannel < sourceChannels); diff --git a/modules/juce_audio_devices/native/juce_linux_ALSA.cpp b/modules/juce_audio_devices/native/juce_linux_ALSA.cpp index 2a31f715e3..b58f667324 100644 --- a/modules/juce_audio_devices/native/juce_linux_ALSA.cpp +++ b/modules/juce_audio_devices/native/juce_linux_ALSA.cpp @@ -211,7 +211,7 @@ public: return false; } - enum { isFloatBit = 1 << 16, isLittleEndianBit = 1 << 17 }; + enum { isFloatBit = 1 << 16, isLittleEndianBit = 1 << 17, onlyUseLower24Bits = 1 << 18 }; const int formatsToTry[] = { SND_PCM_FORMAT_FLOAT_LE, 32 | isFloatBit | isLittleEndianBit, SND_PCM_FORMAT_FLOAT_BE, 32 | isFloatBit, @@ -219,6 +219,7 @@ public: SND_PCM_FORMAT_S32_BE, 32, SND_PCM_FORMAT_S24_3LE, 24 | isLittleEndianBit, SND_PCM_FORMAT_S24_3BE, 24, + SND_PCM_FORMAT_S24_LE, 32 | isLittleEndianBit | onlyUseLower24Bits, SND_PCM_FORMAT_S16_LE, 16 | isLittleEndianBit, SND_PCM_FORMAT_S16_BE, 16 }; bitDepth = 0; @@ -227,14 +228,14 @@ public: { if (snd_pcm_hw_params_set_format (handle, hwParams, (_snd_pcm_format) formatsToTry [i]) >= 0) { - bitDepth = formatsToTry [i + 1] & 255; - const bool isFloat = (formatsToTry [i + 1] & isFloatBit) != 0; - const bool isLittleEndian = (formatsToTry [i + 1] & isLittleEndianBit) != 0; - converter = createConverter (isInput, bitDepth, isFloat, isLittleEndian, numChannels); + const int type = formatsToTry [i + 1]; + bitDepth = type & 255; - JUCE_ALSA_LOG ("format: bitDepth=" << bitDepth << ", isFloat=" - << isFloat << ", isLittleEndian=" << isLittleEndian - << ", numChannels=" << numChannels); + converter = createConverter (isInput, bitDepth, + (type & isFloatBit) != 0, + (type & isLittleEndianBit) != 0, + (type & onlyUseLower24Bits) != 0, + numChannels); break; } } @@ -397,30 +398,33 @@ private: return new AudioData::ConverterInstance , DestType> (numInterleavedChannels, 1); } - else - { - typedef AudioData::Pointer SourceType; - if (isLittleEndian) - return new AudioData::ConverterInstance > (1, numInterleavedChannels); + typedef AudioData::Pointer SourceType; - return new AudioData::ConverterInstance > (1, numInterleavedChannels); - } + if (isLittleEndian) + return new AudioData::ConverterInstance > (1, numInterleavedChannels); + + return new AudioData::ConverterInstance > (1, numInterleavedChannels); } }; - static AudioData::Converter* createConverter (const bool forInput, const int bitDepth, const bool isFloat, const bool isLittleEndian, const int numInterleavedChannels) + static AudioData::Converter* createConverter (bool forInput, int bitDepth, + bool isFloat, bool isLittleEndian, bool useOnlyLower24Bits, + int numInterleavedChannels) { - switch (bitDepth) - { - case 16: return ConverterHelper ::createConverter (forInput, isLittleEndian, numInterleavedChannels); - case 24: return ConverterHelper ::createConverter (forInput, isLittleEndian, numInterleavedChannels); - case 32: return isFloat ? ConverterHelper ::createConverter (forInput, isLittleEndian, numInterleavedChannels) - : ConverterHelper ::createConverter (forInput, isLittleEndian, numInterleavedChannels); - default: jassertfalse; break; // unsupported format! - } + JUCE_ALSA_LOG ("format: bitDepth=" << bitDepth << ", isFloat=" << isFloat + << ", isLittleEndian=" << isLittleEndian << ", numChannels=" << numInterleavedChannels); - return nullptr; + if (isFloat) return ConverterHelper ::createConverter (forInput, isLittleEndian, numInterleavedChannels); + if (bitDepth == 16) return ConverterHelper ::createConverter (forInput, isLittleEndian, numInterleavedChannels); + if (bitDepth == 24) return ConverterHelper ::createConverter (forInput, isLittleEndian, numInterleavedChannels); + + jassert (bitDepth == 32); + + if (useOnlyLower24Bits) + return ConverterHelper ::createConverter (forInput, isLittleEndian, numInterleavedChannels); + + return ConverterHelper ::createConverter (forInput, isLittleEndian, numInterleavedChannels); } //==============================================================================