diff --git a/examples/src/Main.cpp b/examples/src/Main.cpp index f7c9a4f..5b3fd6a 100644 --- a/examples/src/Main.cpp +++ b/examples/src/Main.cpp @@ -37,7 +37,7 @@ int main() //auto result = loader.Load(fileData, "test_data/1ch/44100/64/test.wav"); //auto result = loader.Load(fileData, "test_data/2ch/44100/8/test.wav"); - //auto result = loader.Load(fileData, "test_data/2ch/44100/16/test.wav"); + auto result = loader.Load(fileData, "test_data/2ch/44100/16/test.wav"); //auto result = loader.Load(fileData, "test_data/2ch/44100/24/test.wav"); //auto result = loader.Load(fileData, "test_data/2ch/44100/32/test.wav"); //auto result = loader.Load(fileData, "test_data/2ch/44100/64/test.wav"); @@ -51,7 +51,7 @@ int main() //auto result = loader.Load(fileData, "test_data/ad_hoc/BlockWoosh_Stereo.ogg"); //auto result = loader.Load(fileData, "test_data/ad_hoc/KittyPurr8_Stereo_Dithered.flac"); - auto result = loader.Load(fileData, "test_data/ad_hoc/KittyPurr16_Stereo.flac"); + //auto result = loader.Load(fileData, "test_data/ad_hoc/KittyPurr16_Stereo.flac"); //auto result = loader.Load(fileData, "test_data/ad_hoc/KittyPurr16_Mono.flac"); //auto result = loader.Load(fileData, "test_data/ad_hoc/KittyPurr24_Stereo.flac"); diff --git a/include/libnyquist/AudioDecoder.h b/include/libnyquist/AudioDecoder.h index a1ef51c..3ee5a35 100644 --- a/include/libnyquist/AudioDecoder.h +++ b/include/libnyquist/AudioDecoder.h @@ -64,7 +64,7 @@ public: ~NyquistIO(); int Load(AudioData * data, const std::string & path); - int Load(AudioData *data, std::string extension, const std::vector & buffer); + int Load(AudioData *data, std::string extension, const std::vector & buffer); bool IsFileSupported(const std::string path) const; diff --git a/include/libnyquist/Common.h b/include/libnyquist/Common.h index 6d895a5..e91753a 100644 --- a/include/libnyquist/Common.h +++ b/include/libnyquist/Common.h @@ -57,29 +57,29 @@ namespace nqr /////////////////////// #if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86) - #define CPU_X86 1 + #define CPU_X86 1 #endif #if defined(__arm__) || defined(_M_ARM) - #define CPU_ARM 1 + #define CPU_ARM 1 #endif #if defined(CPU_X86) && defined(CPU_ARM) - #error CPU_X86 and CPU_ARM both defined. + #error CPU_X86 and CPU_ARM both defined. #endif #if !defined(ARCH_CPU_BIG_ENDIAN) && !defined(ARCH_CPU_LITTLE_ENDIAN) - #if CPU_X86 || CPU_ARM || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - #define ARCH_CPU_LITTLE_ENDIAN - #elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - #define ARCH_CPU_BIG_ENDIAN - #else - #error ARCH_CPU_BIG_ENDIAN or ARCH_CPU_LITTLE_ENDIAN should be defined. - #endif + #if CPU_X86 || CPU_ARM || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + #define ARCH_CPU_LITTLE_ENDIAN + #elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + #define ARCH_CPU_BIG_ENDIAN + #else + #error ARCH_CPU_BIG_ENDIAN or ARCH_CPU_LITTLE_ENDIAN should be defined. + #endif #endif #if defined(ARCH_CPU_BIG_ENDIAN) && defined(ARCH_CPU_LITTLE_ENDIAN) - #error ARCH_CPU_BIG_ENDIAN and ARCH_CPU_LITTLE_ENDIAN both defined. + #error ARCH_CPU_BIG_ENDIAN and ARCH_CPU_LITTLE_ENDIAN both defined. #endif static inline uint16_t Swap16(uint16_t value) @@ -114,7 +114,8 @@ static inline uint64_t Swap64(uint64_t value) ((value & 0xff00000000000000LL) >> 56)); } -inline bool isOdd(const uint32_t x) +template +inline bool isOdd(const T x) { return (x & 0x1); } @@ -224,14 +225,14 @@ static const float NQR_BYTE_2_FLT = 1.0f / 127.0f; //@todo add 12, 20 for flac enum PCMFormat { - PCM_U8, - PCM_S8, - PCM_16, - PCM_24, - PCM_32, - PCM_64, - PCM_FLT, - PCM_DBL, + PCM_U8, + PCM_S8, + PCM_16, + PCM_24, + PCM_32, + PCM_64, + PCM_FLT, + PCM_DBL, PCM_END }; @@ -250,11 +251,11 @@ void ConvertFromFloat32(uint8_t * dst, const float * src, const size_t N, PCMFor struct AudioData { - int channelCount; - int sampleRate; - double lengthSeconds; - size_t frameSize; // channels * bits per sample - std::vector samples; + int channelCount; + int sampleRate; + double lengthSeconds; + size_t frameSize; // channels * bits per sample + std::vector samples; PCMFormat sourceFormat; //@todo: add field: channel layout @@ -272,8 +273,8 @@ struct StreamableAudioData : public AudioData struct NyquistFileBuffer { - std::vector buffer; - size_t size; + std::vector buffer; + size_t size; }; NyquistFileBuffer ReadFile(std::string pathToFile); diff --git a/include/libnyquist/NickPrototypes.h b/include/libnyquist/NickPrototypes.h deleted file mode 100644 index a4c1bf4..0000000 --- a/include/libnyquist/NickPrototypes.h +++ /dev/null @@ -1,280 +0,0 @@ -/* -Copyright (c) 2015, Dimitri Diakopoulos All rights reserved. - -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. - -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 COPYRIGHT HOLDER 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. -*/ - -#include "Common.h" - -/* - - AudioSampleBuffer can be backed by a memory store such as standard vector, - - a file, such as NyquistFileBuffer, or some platform specific DMA backed - - thingamajig, or a memmaped file. - - */ - - -template - -struct AudioSampleBuffer - -{ - - // RAII object to temporarily map a data buffer into R/O memory - - struct Data - - { - - Data(AudioSampleBuffer&); // map data into CPU memory - - ~Data(); // unmap data - - - - void *data(); - - size_t size(); - - }; - - - // RAII object to temporarily map a data buffer into R/W memory - - struct MutableData - - { - - MutableData(AudioSampleBuffer&); // map data into CPU memory - - ~MutableData(); // unmap data after copying contents back to backing store - - - - void *data(); - - size_t size(); - - }; - - - - AudioSampleBuffer(std::function resize, - - std::function dealloc) - - : resize(resize), dealloc(dealloc) - - { - - } - - - - ~AudioSampleBuffer() - - { - - if (dealloc) - - dealloc(); - - } - - - - size_t resize(size_t sz) - - { - - if (resize) - - return resize(sz, &buffer); - - - return buffer.size(); - - } - - - -private: - - AudioSampleBuffer() = 0; - - - - Buffer buffer; - - std::function _resize; - - std::function _dealloc; - -}; - - - -struct AudioData - -{ - - AudioData() : channelCount(0), sampleRate(0), bitDepth(0), lengthSeconds(0), frameSize(0) { } - - - - AudioData(const AudioData& rhs) - - : channelCount(rhs.channelCount), sampleRate(rhs.sampleRate), bitDepth(rhs.bitDepth) - - , lengthInSeconds(rhs.lengthInSeconds), frameSize(rhs.frameSize), samples(rhs.samples) { } - - - - int channelCount; // unsigned? - - int sampleRate; // ditto? - - int bitDepth; // ditto? - - double lengthSeconds; - - - - // since it does make sense to set this (does it?) it should probably be a function not a data value - - size_t frameSize; // channels * bits per sample - - - AudioSampleBuffer samples; - - //@todo: add field: streamable - - //@todo: add field: channel layout - - //@todo: add field: lossy / lossless - - - - void mixToChannels(int channelCount); - - void resample(int sampleRate); - - void setBitDepth(int bitDepth); - - void setLength(double lengthInSeconds); - -}; - - - -// in general nice to pass string ref - - - -void LoadFile(AudioData * dataResult, const std::string & path) - -{ - - string extension = path.substr(path.rfind('.') + 1, path.length()); - - if (!extension.length()) - - return; - - - - if (extension == "ogg") - - { - - VorbisDecoder::LoadFile(dataResult, path); - - } - - else if (extension == "wav") - - { - - VorbisDecoder::LoadFile(dataResult, path); - - } - - else - - { - - // etc. - - } - -} - - -void LoadFile(AudioData * dataResult, const std::string & path, bool conformToData) - -{ - - if (!conformToData) - - { - - LoadFile(dataResult, path); - - } - - else - - { - - AudioData * conform = new dataResult(dataResult); // add copy constructor - - LoadFile(dataResult, path); - - - if (conform->channelCount && (conform->channelCount != dataResult->channelCount)) - - dataResult->mixToChannels(conform->channelCount); - - - - if (conform->sampleRate && (conform->sampleRate != dataResult->sampleRate)) - - dataResult->resample(conform->sampleRate); - - - - if (conform->bitDepth && (conform->bitDepth != dataResult->bitDepth)) - - dataResult->setBitDepth(conform->bitDepth); - - - - if (conform->lengthInSeconds > 0 && (conform->lengthSeconds != dataResult->lengthSeconds)) - - dataResult->setLength(conform->lengthSeconds); - - } - -} \ No newline at end of file diff --git a/include/libnyquist/PostProcess.h b/include/libnyquist/PostProcess.h index 0ce39e5..08c517d 100644 --- a/include/libnyquist/PostProcess.h +++ b/include/libnyquist/PostProcess.h @@ -34,15 +34,15 @@ namespace nqr template inline void DeinterleaveStereo(T * c1, T * c2, T const * src, size_t count) { - auto src_end = src + count; - while (src != src_end) - { - *c1 = src[0]; - *c2 = src[1]; - c1++; - c2++; - src += 2; - } + auto src_end = src + count; + while (src != src_end) + { + *c1 = src[0]; + *c2 = src[1]; + c1++; + c2++; + src += 2; + } } template diff --git a/include/libnyquist/RiffUtils.h b/include/libnyquist/RiffUtils.h index 95bda8c..e136bc2 100644 --- a/include/libnyquist/RiffUtils.h +++ b/include/libnyquist/RiffUtils.h @@ -46,8 +46,8 @@ struct EncoderParams struct ChunkHeaderInfo { - uint32_t offset; // Byte offset into chunk - uint32_t size; // Size of the chunk in bytes + uint32_t offset; // Byte offset into chunk + uint32_t size; // Size of the chunk in bytes }; inline uint32_t GenerateChunkCode(uint8_t a, uint8_t b, uint8_t c, uint8_t d) diff --git a/include/libnyquist/RingBuffer.h b/include/libnyquist/RingBuffer.h index 9e579d5..bcfa315 100644 --- a/include/libnyquist/RingBuffer.h +++ b/include/libnyquist/RingBuffer.h @@ -7,9 +7,9 @@ the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and - the following disclaimer. + 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. + the following disclaimer in the documentation and/or other materials provided with the distribution. 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 @@ -21,164 +21,179 @@ POSSIBILITY OF SUCH DAMAGE. */ -//! \brief Ringbuffer (aka circular buffer) data structure for use in concurrent audio scenarios. -//! -//! Other than minor modifications, this ringbuffer is a copy of Tim Blechmann's fine work, found as the base -//! structure of boost::lockfree::spsc_queue (ringbuffer_base). Whereas the boost::lockfree data structures -//! are meant for a wide range of applications / archs, this version specifically caters to audio processing. -//! -//! The implementation remains lock-free and thread-safe within a single write thread / single read thread context. +// \brief Ringbuffer (aka circular buffer) data structure for use in concurrent audio scenarios. +// +// Other than minor modifications, this ringbuffer is a copy of Tim Blechmann's fine work, found as the base +// structure of boost::lockfree::spsc_queue (ringbuffer_base). Whereas the boost::lockfree data structures +// are meant for a wide range of applications / archs, this version specifically caters to audio processing. +// +// The implementation remains lock-free and thread-safe within a single write thread / single read thread context. #pragma once +#ifndef CINDER_RINGBUFFER_H +#define CINDER_RINGBUFFER_H + #include #include template -class RingBufferT { +class RingBufferT +{ public: - //! Constructs a RingBufferT with size = 0 - RingBufferT() : mData( nullptr ), mAllocatedSize( 0 ), mWriteIndex( 0 ), mReadIndex( 0 ) {} - //! Constructs a RingBufferT with \a count maximum elements. - RingBufferT( size_t count ) : mAllocatedSize( 0 ) - { - resize( count ); - } - RingBufferT( RingBufferT &&other ) - : mData( other.mData ), mAllocatedSize( other.mAllocatedSize ), mWriteIndex( 0 ), mReadIndex( 0 ) - { - other.mData = nullptr; - other.mAllocatedSize = 0; - } + // Constructs a RingBufferT with size = 0 + RingBufferT() : mData(nullptr), mAllocatedSize(0), mWriteIndex(0), mReadIndex(0) { - ~RingBufferT() - { - if( mData ) - free( mData ); - } - //! Resizes the container to contain \a count maximum elements. Invalidates the internal buffer and resets read / write indices to 0. \note Must be synchronized with both read and write threads. - void resize( size_t count ) - { - size_t allocatedSize = count + 1; // one bin is used to distinguish between the read and write indices when full. + } - if( mAllocatedSize ) - mData = (T *)::realloc( mData, allocatedSize * sizeof( T ) ); - else - mData = (T *)::calloc( allocatedSize, sizeof( T ) ); + // Constructs a RingBufferT with \a count maximum elements. + RingBufferT(size_t count) : mAllocatedSize(0) + { + resize(count); + } - assert( mData ); + RingBufferT(RingBufferT &&other) + : mData(other.mData), mAllocatedSize(other.mAllocatedSize), mWriteIndex(0), mReadIndex(0) + { + other.mData = nullptr; + other.mAllocatedSize = 0; + } - mAllocatedSize = allocatedSize; - clear(); - } - //! Invalidates the internal buffer and resets read / write indices to 0. \note Must be synchronized with both read and write threads. - void clear() - { - mWriteIndex = 0; - mReadIndex = 0; - } - //! Returns the maximum number of elements. - size_t getSize() const - { - return mAllocatedSize - 1; - } - //! Returns the number of elements available for wrtiing. \note Only safe to call from the write thread. - size_t getAvailableWrite() const - { - return getAvailableWrite( mWriteIndex, mReadIndex ); - } - //! Returns the number of elements available for wrtiing. \note Only safe to call from the read thread. - size_t getAvailableRead() const - { - return getAvailableRead( mWriteIndex, mReadIndex ); - } + ~RingBufferT() + { + if (mData) free(mData); + } - //! \brief Writes \a count elements into the internal buffer from \a array. \return `true` if all elements were successfully written, or `false` otherwise. - //! - //! \note only safe to call from the write thread. - //! TODO: consider renaming this to writeAll / readAll, and having generic read / write that just does as much as it can - bool write( const T *array, size_t count ) - { - const size_t writeIndex = mWriteIndex.load( std::memory_order_relaxed ); - const size_t readIndex = mReadIndex.load( std::memory_order_acquire ); + // Resizes the container to contain \a count maximum elements. Invalidates the internal buffer and resets read / write indices to 0. \note Must be synchronized with both read and write threads. + void resize(size_t count) + { + size_t allocatedSize = count + 1; // one bin is used to distinguish between the read and write indices when full. - if( count > getAvailableWrite( writeIndex, readIndex ) ) - return false; + if (mAllocatedSize) + mData = (T *)::realloc(mData, allocatedSize * sizeof(T)); + else + mData = (T *)::calloc(allocatedSize, sizeof(T)); - size_t writeIndexAfter = writeIndex + count; + assert(mData); - if( writeIndex + count > mAllocatedSize ) { - size_t countA = mAllocatedSize - writeIndex; - size_t countB = count - countA; + mAllocatedSize = allocatedSize; + clear(); + } - std::memcpy( mData + writeIndex, array, countA * sizeof( T ) ); - std::memcpy( mData, array + countA, countB * sizeof( T ) ); - writeIndexAfter -= mAllocatedSize; - } - else { - std::memcpy( mData + writeIndex, array, count * sizeof( T ) ); - if( writeIndexAfter == mAllocatedSize ) - writeIndexAfter = 0; - } + // Invalidates the internal buffer and resets read / write indices to 0. \note Must be synchronized with both read and write threads. + void clear() + { + mWriteIndex = 0; + mReadIndex = 0; + } - mWriteIndex.store( writeIndexAfter, std::memory_order_release ); - return true; - } - //! \brief Reads \a count elements from the internal buffer into \a array. \return `true` if all elements were successfully read, or `false` otherwise. - //! - //! \note only safe to call from the read thread. - bool read( T *array, size_t count ) - { - const size_t writeIndex = mWriteIndex.load( std::memory_order_acquire ); - const size_t readIndex = mReadIndex.load( std::memory_order_relaxed ); + // Returns the maximum number of elements. + size_t getSize() const + { + + return mAllocatedSize - 1; + } + // Returns the number of elements available for wrtiing. \note Only safe to call from the write thread. + size_t getAvailableWrite() const + { + return getAvailableWrite(mWriteIndex, mReadIndex); + } - if( count > getAvailableRead( writeIndex, readIndex ) ) - return false; + // Returns the number of elements available for wrtiing. \note Only safe to call from the read thread. + size_t getAvailableRead() const + { + return getAvailableRead(mWriteIndex, mReadIndex); + } - size_t readIndexAfter = readIndex + count; + // Only safe to call from the write thread. + bool write(const T *array, size_t count) + { + const size_t writeIndex = mWriteIndex.load(std::memory_order_relaxed); + const size_t readIndex = mReadIndex.load(std::memory_order_acquire); - if( readIndex + count > mAllocatedSize ) { - size_t countA = mAllocatedSize - readIndex; - size_t countB = count - countA; + if (count > getAvailableWrite(writeIndex, readIndex)) + return false; - std::memcpy( array, mData + readIndex, countA * sizeof( T ) ); - std::memcpy( array + countA, mData, countB * sizeof( T ) ); + size_t writeIndexAfter = writeIndex + count; - readIndexAfter -= mAllocatedSize; - } - else { - std::memcpy( array, mData + readIndex, count * sizeof( T ) ); - if( readIndexAfter == mAllocatedSize ) - readIndexAfter = 0; - } + if (writeIndex + count > mAllocatedSize) + { + size_t countA = mAllocatedSize - writeIndex; + size_t countB = count - countA; - mReadIndex.store( readIndexAfter, std::memory_order_release ); - return true; - } + std::memcpy(mData + writeIndex, array, countA * sizeof(T)); + std::memcpy(mData, array + countA, countB * sizeof(T)); + writeIndexAfter -= mAllocatedSize; + } + else + { + std::memcpy(mData + writeIndex, array, count * sizeof(T)); + if (writeIndexAfter == mAllocatedSize) + writeIndexAfter = 0; + } + + mWriteIndex.store(writeIndexAfter, std::memory_order_release); + return true; + } + + // Only safe to call from the read thread. + bool read(T *array, size_t count) + { + const size_t writeIndex = mWriteIndex.load(std::memory_order_acquire); + const size_t readIndex = mReadIndex.load(std::memory_order_relaxed); + + if (count > getAvailableRead(writeIndex, readIndex)) + return false; + + size_t readIndexAfter = readIndex + count; + + if (readIndex + count > mAllocatedSize) + { + size_t countA = mAllocatedSize - readIndex; + size_t countB = count - countA; + + std::memcpy(array, mData + readIndex, countA * sizeof(T)); + std::memcpy(array + countA, mData, countB * sizeof(T)); + + readIndexAfter -= mAllocatedSize; + } + else + { + std::memcpy(array, mData + readIndex, count * sizeof(T)); + if (readIndexAfter == mAllocatedSize) + readIndexAfter = 0; + } + + mReadIndex.store(readIndexAfter, std::memory_order_release); + return true; + } private: - size_t getAvailableWrite( size_t writeIndex, size_t readIndex ) const - { - size_t result = readIndex - writeIndex - 1; - if( writeIndex >= readIndex ) - result += mAllocatedSize; + size_t getAvailableWrite(size_t writeIndex, size_t readIndex) const + { + size_t result = readIndex - writeIndex - 1; + if (writeIndex >= readIndex) + result += mAllocatedSize; - return result; - } + return result; + } - size_t getAvailableRead( size_t writeIndex, size_t readIndex ) const - { - if( writeIndex >= readIndex ) - return writeIndex - readIndex; + size_t getAvailableRead(size_t writeIndex, size_t readIndex) const + { + if (writeIndex >= readIndex) + return writeIndex - readIndex; - return writeIndex + mAllocatedSize - readIndex; - } - - T *mData; - size_t mAllocatedSize; - std::atomic mWriteIndex, mReadIndex; + return writeIndex + mAllocatedSize - readIndex; + } + + T *mData; + size_t mAllocatedSize; + std::atomic mWriteIndex, mReadIndex; }; typedef RingBufferT RingBuffer; + +#endif + diff --git a/include/libnyquist/WavDecoder.h b/include/libnyquist/WavDecoder.h index 83bb4fe..59963c4 100644 --- a/include/libnyquist/WavDecoder.h +++ b/include/libnyquist/WavDecoder.h @@ -33,53 +33,53 @@ namespace nqr enum WaveFormatCode { - FORMAT_UNKNOWN = 0x0, // Unknown Wave Format - FORMAT_PCM = 0x1, // PCM Format - FORMAT_IEEE = 0x3, // IEEE float/double - FORMAT_ALAW = 0x6, // 8-bit ITU-T G.711 A-law - FORMAT_MULAW = 0x7, // 8-bit ITU-T G.711 µ-law - FORMAT_EXT = 0xFFFE // Set via subformat + FORMAT_UNKNOWN = 0x0, // Unknown Wave Format + FORMAT_PCM = 0x1, // PCM Format + FORMAT_IEEE = 0x3, // IEEE float/double + FORMAT_ALAW = 0x6, // 8-bit ITU-T G.711 A-law + FORMAT_MULAW = 0x7, // 8-bit ITU-T G.711 µ-law + FORMAT_EXT = 0xFFFE // Set via subformat }; struct RiffChunkHeader { - uint32_t id_riff; // Chunk ID: 'RIFF' - uint32_t file_size; // Entire file in bytes - uint32_t id_wave; // Chunk ID: 'WAVE' + uint32_t id_riff; // Chunk ID: 'RIFF' + uint32_t file_size; // Entire file in bytes + uint32_t id_wave; // Chunk ID: 'WAVE' }; struct WaveChunkHeader { - uint32_t fmt_id; // Chunk ID: 'fmt ' - uint32_t chunk_size; // Size in bytes - uint16_t format; // Format code - uint16_t channel_count; // Num interleaved channels - uint32_t sample_rate; // SR - uint32_t data_rate; // Data rate - uint16_t frame_size; // 1 frame = channels * bits per sample (also known as block align) - uint16_t bit_depth; // Bits per sample + uint32_t fmt_id; // Chunk ID: 'fmt ' + uint32_t chunk_size; // Size in bytes + uint16_t format; // Format code + uint16_t channel_count; // Num interleaved channels + uint32_t sample_rate; // SR + uint32_t data_rate; // Data rate + uint16_t frame_size; // 1 frame = channels * bits per sample (also known as block align) + uint16_t bit_depth; // Bits per sample }; struct BextChunk { - uint32_t fmt_id; // Chunk ID: 'bext' - uint32_t chunk_size; // Size in bytes - uint8_t description[256]; // Description of the sound (ascii) - uint8_t origin[32]; // Name of the originator (ascii) - uint8_t origin_ref[32]; // Reference of the originator (ascii) - uint8_t orgin_date[10]; // yyyy-mm-dd (ascii) - uint8_t origin_time[8]; // hh-mm-ss (ascii) - uint64_t time_ref; // First sample count since midnight - uint32_t version; // Version of the BWF - uint8_t uimd[64]; // Byte 0 of SMPTE UMID - uint8_t reserved[188]; // 190 bytes, reserved for future use & set to NULL + uint32_t fmt_id; // Chunk ID: 'bext' + uint32_t chunk_size; // Size in bytes + uint8_t description[256]; // Description of the sound (ascii) + uint8_t origin[32]; // Name of the originator (ascii) + uint8_t origin_ref[32]; // Reference of the originator (ascii) + uint8_t orgin_date[10]; // yyyy-mm-dd (ascii) + uint8_t origin_time[8]; // hh-mm-ss (ascii) + uint64_t time_ref; // First sample count since midnight + uint32_t version; // Version of the BWF + uint8_t uimd[64]; // Byte 0 of SMPTE UMID + uint8_t reserved[188]; // 190 bytes, reserved for future use & set to NULL }; struct FactChunk { - uint32_t fact_id; // Chunk ID: 'fact' - uint32_t chunk_size; // Size in bytes - uint32_t sample_length; // number of samples per channel + uint32_t fact_id; // Chunk ID: 'fact' + uint32_t chunk_size; // Size in bytes + uint32_t sample_length; // number of samples per channel }; struct ExtensibleData @@ -100,15 +100,15 @@ struct ExtensibleData template std::basic_ostream & operator << (std::basic_ostream & a, const WaveChunkHeader & b) { - return a << - "Format ID:\t\t" << b.fmt_id << - "\nChunk Size:\t\t" << b.chunk_size << - "\nFormat Code:\t\t" << b.format << - "\nChannels:\t\t" << b.channel_count << - "\nSample Rate:\t\t" << b.sample_rate << - "\nData Rate:\t\t" << b.data_rate << - "\nFrame Size:\t\t" << b.frame_size << - "\nBit Depth:\t\t" << b.bit_depth << std::endl; + return a << + "Format ID:\t\t" << b.fmt_id << + "\nChunk Size:\t\t" << b.chunk_size << + "\nFormat Code:\t\t" << b.format << + "\nChannels:\t\t" << b.channel_count << + "\nSample Rate:\t\t" << b.sample_rate << + "\nData Rate:\t\t" << b.data_rate << + "\nFrame Size:\t\t" << b.frame_size << + "\nBit Depth:\t\t" << b.bit_depth << std::endl; } //@todo expose speaker/channel/layout masks in the API: @@ -154,23 +154,16 @@ enum SpeakerLayoutMask //@todo verify mask values inline int ComputeChannelMask(const size_t channels) { - switch (channels) - { - case 1: - return SPEAKER_MONO; - case 2: - return SPEAKER_STEREO; - case 3: - return SPEAKER_2POINT1; - case 4: - return SPEAKER_QUAD; - case 5: - return SPEAKER_4POINT1; - case 6: - return SPEAKER_5POINT1; - default: - return -1; - } + switch (channels) + { + case 1: return SPEAKER_MONO; + case 2: return SPEAKER_STEREO; + case 3: return SPEAKER_2POINT1; + case 4: return SPEAKER_QUAD; + case 5: return SPEAKER_4POINT1; + case 6: return SPEAKER_5POINT1; + default: return -1; + } } struct WavDecoder : public nqr::BaseDecoder diff --git a/include/libnyquist/WavEncoder.h b/include/libnyquist/WavEncoder.h index a7dd72d..2bc5d23 100644 --- a/include/libnyquist/WavEncoder.h +++ b/include/libnyquist/WavEncoder.h @@ -33,7 +33,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace nqr { - // A simplistic encoder that takes a blob of data, conforms it to the user's // EncoderParams preference, and writes to disk. Be warned, does not support resampling! // @todo support dithering, samplerate conversion, etc. @@ -53,14 +52,11 @@ class WavEncoder public: - WavEncoder(); - ~WavEncoder(); - // Assume data adheres to EncoderParams, except for bit depth and fmt - int WriteFile(const EncoderParams p, const AudioData * d, const std::string & path); + static int WriteFile(const EncoderParams p, const AudioData * d, const std::string & path); }; - + } // end namespace nqr #endif diff --git a/include/libnyquist/WavPackDecoder.h b/include/libnyquist/WavPackDecoder.h index 41e58ac..21f52e4 100644 --- a/include/libnyquist/WavPackDecoder.h +++ b/include/libnyquist/WavPackDecoder.h @@ -30,7 +30,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace nqr { - + struct WavPackDecoder : public nqr::BaseDecoder { WavPackDecoder() {}; @@ -39,7 +39,7 @@ struct WavPackDecoder : public nqr::BaseDecoder virtual int LoadFromBuffer(nqr::AudioData * data, const std::vector & memory) override; virtual std::vector GetSupportedFileExtensions() override; }; - + } // end namespace nqr #endif diff --git a/src/AudioDecoder.cpp b/src/AudioDecoder.cpp index 4b48bfd..05c5dd5 100644 --- a/src/AudioDecoder.cpp +++ b/src/AudioDecoder.cpp @@ -41,7 +41,7 @@ NyquistIO::NyquistIO() NyquistIO::~NyquistIO() { - + } int NyquistIO::Load(AudioData * data, const std::string & path) @@ -76,28 +76,27 @@ int NyquistIO::Load(AudioData * data, const std::string & path) int NyquistIO::Load(AudioData * data, std::string extension, const std::vector & buffer) { - if (decoderTable.find(extension) == decoderTable.end()) + if (decoderTable.find(extension) == decoderTable.end()) { return IOError::ExtensionNotSupported; } - if (decoderTable.size() > 0) - { - auto decoder = GetDecoderForExtension(extension); - - try - { - return decoder->LoadFromBuffer(data, buffer); - } - catch (std::exception e) - { - std::cerr << "Caught fatal exception: " << e.what() << std::endl; - } - } - else - { - return IOError::NoDecodersLoaded; - } + if (decoderTable.size() > 0) + { + auto decoder = GetDecoderForExtension(extension); + try + { + return decoder->LoadFromBuffer(data, buffer); + } + catch (std::exception e) + { + std::cerr << "Caught fatal exception: " << e.what() << std::endl; + } + } + else + { + return IOError::NoDecodersLoaded; + } // Should never be reached return IOError::UnknownError; diff --git a/src/AudioDevice.cpp b/src/AudioDevice.cpp index d002be6..a931d46 100644 --- a/src/AudioDevice.cpp +++ b/src/AudioDevice.cpp @@ -35,70 +35,70 @@ static RingBufferT buffer(BUFFER_LENGTH); static int rt_callback(void * output_buffer, void * input_buffer, unsigned int num_bufferframes, double stream_time, RtAudioStreamStatus status, void * user_data) { - if (status) std::cerr << "[rtaudio] Buffer over or underflow" << std::endl; + if (status) std::cerr << "[rtaudio] Buffer over or underflow" << std::endl; - if (buffer.getAvailableRead()) - { - buffer.read((float*) output_buffer, BUFFER_LENGTH); - } - else - { - memset(output_buffer, 0, BUFFER_LENGTH * sizeof(float)); - } + if (buffer.getAvailableRead()) + { + buffer.read((float*) output_buffer, BUFFER_LENGTH); + } + else + { + memset(output_buffer, 0, BUFFER_LENGTH * sizeof(float)); + } - return 0; + return 0; } bool AudioDevice::Open(const int deviceId) { - if (!rtaudio) throw std::runtime_error("rtaudio not created yet"); + if (!rtaudio) throw std::runtime_error("rtaudio not created yet"); - RtAudio::StreamParameters parameters; - parameters.deviceId = info.id; - parameters.nChannels = info.numChannels; - parameters.firstChannel = 0; + RtAudio::StreamParameters parameters; + parameters.deviceId = info.id; + parameters.nChannels = info.numChannels; + parameters.firstChannel = 0; - rtaudio->openStream(¶meters, NULL, RTAUDIO_FLOAT32, info.sampleRate, &info.frameSize, &rt_callback, (void*) & buffer); + rtaudio->openStream(¶meters, NULL, RTAUDIO_FLOAT32, info.sampleRate, &info.frameSize, &rt_callback, (void*) & buffer); - if (rtaudio->isStreamOpen()) - { - rtaudio->startStream(); - return true; - } - return false; + if (rtaudio->isStreamOpen()) + { + rtaudio->startStream(); + return true; + } + return false; } void AudioDevice::ListAudioDevices() { - std::unique_ptr tempDevice(new RtAudio); + std::unique_ptr tempDevice(new RtAudio); - RtAudio::DeviceInfo info; - unsigned int devices = tempDevice->getDeviceCount(); + RtAudio::DeviceInfo info; + unsigned int devices = tempDevice->getDeviceCount(); - std::cout << "[rtaudio] Found: " << devices << " device(s)\n"; + std::cout << "[rtaudio] Found: " << devices << " device(s)\n"; - for (unsigned int i = 0; i < devices; ++i) - { - info = tempDevice->getDeviceInfo(i); - std::cout << "\tDevice: " << i << " - " << info.name << std::endl; - } - std::cout << std::endl; + for (unsigned int i = 0; i < devices; ++i) + { + info = tempDevice->getDeviceInfo(i); + std::cout << "\tDevice: " << i << " - " << info.name << std::endl; + } + std::cout << std::endl; } bool AudioDevice::Play(const std::vector & data) { - if (!rtaudio->isStreamOpen()) return false; - - // Each frame is the (size/2) cause interleaved channels! - int sizeInFrames = ((int) data.size()) / (BUFFER_LENGTH); + if (!rtaudio->isStreamOpen()) return false; - int writeCount = 0; + // Each frame is the (size/2) cause interleaved channels! + int sizeInFrames = ((int) data.size()) / (BUFFER_LENGTH); - while(writeCount < sizeInFrames) - { - bool status = buffer.write((data.data() + (writeCount * BUFFER_LENGTH)), BUFFER_LENGTH); - if (status) writeCount++; - } + int writeCount = 0; + + while(writeCount < sizeInFrames) + { + bool status = buffer.write((data.data() + (writeCount * BUFFER_LENGTH)), BUFFER_LENGTH); + if (status) writeCount++; + } - return true; + return true; } \ No newline at end of file diff --git a/src/Common.cpp b/src/Common.cpp index e6fdc9e..b61b4c4 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -29,7 +29,7 @@ using namespace nqr; NyquistFileBuffer nqr::ReadFile(std::string pathToFile) { - //std::cout << "[Debug] Open: " << pathToFile << std::endl; + //std::cout << "[Debug] Open: " << pathToFile << std::endl; FILE * audioFile = fopen(pathToFile.c_str(), "rb"); if (!audioFile) @@ -51,12 +51,12 @@ NyquistFileBuffer nqr::ReadFile(std::string pathToFile) throw std::runtime_error("error reading file or file too small"); } - NyquistFileBuffer data = {std::move(fileBuffer), elementsRead}; + NyquistFileBuffer data = {std::move(fileBuffer), elementsRead}; - fclose(audioFile); + fclose(audioFile); - // Copy out to user - return data; + // Copy out to user + return data; } // Src data is aligned to PCMFormat @@ -218,17 +218,11 @@ PCMFormat nqr::MakeFormatForBits(int bits, bool floatingPt, bool isSigned) { switch(bits) { - case 8: - return (isSigned) ? PCM_S8 : PCM_U8; - case 16: - return PCM_16; - case 24: - return PCM_24; - case 32: - return (floatingPt) ? PCM_FLT : PCM_32; - case 64: - return (floatingPt) ? PCM_DBL : PCM_64; - default: - return PCM_END; + case 8: return (isSigned) ? PCM_S8 : PCM_U8; + case 16: return PCM_16; + case 24: return PCM_24; + case 32: return (floatingPt) ? PCM_FLT : PCM_32; + case 64: return (floatingPt) ? PCM_DBL : PCM_64; + default: return PCM_END; } } diff --git a/src/OpusDependencies.c b/src/OpusDependencies.c index cac5249..708a07f 100644 --- a/src/OpusDependencies.c +++ b/src/OpusDependencies.c @@ -26,15 +26,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // https://dxr.mozilla.org/mozilla-central/source/media/libopus #if (_MSC_VER) -#pragma warning (push) -#pragma warning (disable: 181 111 4267 4996 4244 4701 4702 4133 4100 4127 4206 4312 4505 4365 4005 4013 4334 4703) + #pragma warning (push) + #pragma warning (disable: 181 111 4267 4996 4244 4701 4702 4133 4100 4127 4206 4312 4505 4365 4005 4013 4334 4703) #endif #ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#pragma clang diagnostic ignored "-Wshadow" -#pragma clang diagnostic ignored "-Wdeprecated-register" + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wconversion" + #pragma clang diagnostic ignored "-Wshadow" + #pragma clang diagnostic ignored "-Wdeprecated-register" #endif #undef HAVE_CONFIG_H @@ -97,10 +97,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //#include "opus/celt/celt_encoder.c" /* - See celt/celt_decoder.c + celt/celt_encoder.c in the project browser. - These files need to be in separate translation units due to name clashes, - unfortunately. - */ + See celt/celt_decoder.c + celt/celt_encoder.c in the project browser. + These files need to be in separate translation units due to name clashes, + unfortunately. +*/ ///////////////// // SILK Common // @@ -273,9 +273,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "opus/opusfile/src/wincerts.c" #ifdef __clang__ -#pragma clang diagnostic pop + #pragma clang diagnostic pop #endif #if (_MSC_VER) -#pragma warning (pop) + #pragma warning (pop) #endif diff --git a/src/VorbisDependencies.c b/src/VorbisDependencies.c index a6497c5..cca7e8b 100644 --- a/src/VorbisDependencies.c +++ b/src/VorbisDependencies.c @@ -24,15 +24,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if (_MSC_VER) -#pragma warning (push) -#pragma warning (disable: 181 111 4267 4996 4244 4701 4702 4133 4100 4127 4206 4312 4505 4365 4005 4013 4334) + #pragma warning (push) + #pragma warning (disable: 181 111 4267 4996 4244 4701 4702 4133 4100 4127 4206 4312 4505 4365 4005 4013 4334) #endif - + #ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#pragma clang diagnostic ignored "-Wshadow" -#pragma clang diagnostic ignored "-Wdeprecated-register" + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wconversion" + #pragma clang diagnostic ignored "-Wshadow" + #pragma clang diagnostic ignored "-Wdeprecated-register" #endif #include "libvorbis/include/vorbis/vorbisenc.h" @@ -41,7 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "libogg/src/bitwise.c" #include "libogg/src/framing.c" - + #include "libvorbis/src/analysis.c" #include "libvorbis/src/bitrate.c" #include "libvorbis/src/block.c" @@ -65,9 +65,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "libvorbis/src/mdct.c" #ifdef __clang__ -#pragma clang diagnostic pop + #pragma clang diagnostic pop #endif - + #if (_MSC_VER) -#pragma warning (pop) + #pragma warning (pop) #endif diff --git a/src/WavDecoder.cpp b/src/WavDecoder.cpp index 493f6b7..cb72d77 100644 --- a/src/WavDecoder.cpp +++ b/src/WavDecoder.cpp @@ -167,9 +167,10 @@ int WavDecoder::LoadFromBuffer(AudioData * data, const std::vector & me auto DataChunkInfo = ScanForChunk(memory, GenerateChunkCode('d', 'a', 't', 'a')); - if (DataChunkInfo.offset == 0) throw std::runtime_error("couldn't find data chunk"); + if (DataChunkInfo.offset == 0) + throw std::runtime_error("couldn't find data chunk"); - DataChunkInfo.offset += 8; // ignore the header and size fields (2 uint32s) + DataChunkInfo.offset += 2 * sizeof(uint32_t); // ignore the header and size fields data->lengthSeconds = ((float) DataChunkInfo.size / (float) wavHeader.sample_rate) / wavHeader.frame_size; @@ -178,26 +179,16 @@ int WavDecoder::LoadFromBuffer(AudioData * data, const std::vector & me size_t totalSamples = (DataChunkInfo.size / wavHeader.frame_size) * wavHeader.channel_count; data->samples.resize(totalSamples); - switch (bit_depth) - { - case 8: - data->sourceFormat = PCMFormat::PCM_U8; - break; - case 16: - data->sourceFormat = PCMFormat::PCM_16; - break; - case 24: - data->sourceFormat = PCMFormat::PCM_24; - break; - case 32: - data->sourceFormat = (wavHeader.format == WaveFormatCode::FORMAT_IEEE) ? PCMFormat::PCM_FLT : PCMFormat::PCM_32; - break; - case 64: - data->sourceFormat = (wavHeader.format == WaveFormatCode::FORMAT_IEEE) ? PCMFormat::PCM_DBL : PCMFormat::PCM_64; - break; - } + switch (bit_depth) + { + case 8: data->sourceFormat = PCMFormat::PCM_U8; break; + case 16: data->sourceFormat = PCMFormat::PCM_16; break; + case 24: data->sourceFormat = PCMFormat::PCM_24; break; + case 32: data->sourceFormat = (wavHeader.format == WaveFormatCode::FORMAT_IEEE) ? PCMFormat::PCM_FLT : PCMFormat::PCM_32; break; + case 64: data->sourceFormat = (wavHeader.format == WaveFormatCode::FORMAT_IEEE) ? PCMFormat::PCM_DBL : PCMFormat::PCM_64; break; + } - ConvertToFloat32(data->samples.data(), memory.data() + DataChunkInfo.offset, totalSamples, data->sourceFormat); + ConvertToFloat32(data->samples.data(), memory.data() + DataChunkInfo.offset, totalSamples, data->sourceFormat); return IOError::NoError; } diff --git a/src/WavEncoder.cpp b/src/WavEncoder.cpp index ec046c2..53434f6 100644 --- a/src/WavEncoder.cpp +++ b/src/WavEncoder.cpp @@ -36,10 +36,6 @@ inline void toBytes(int value, char * arr) arr[3] = (value >> 24) & 0xFF; } -WavEncoder::WavEncoder() {} - -WavEncoder::~WavEncoder() {} - int WavEncoder::WriteFile(const EncoderParams p, const AudioData * d, const std::string & path) { // Cast away const because we know what we are doing (Hopefully?)