space normalization and coding style guidelines

adpcm
Dimitri Diakopoulos 11 years ago
parent 2d8d4543b7
commit 28ef233715

@ -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/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/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/24/test.wav");
//auto result = loader.Load(fileData, "test_data/2ch/44100/32/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"); //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/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/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/KittyPurr16_Mono.flac");
//auto result = loader.Load(fileData, "test_data/ad_hoc/KittyPurr24_Stereo.flac"); //auto result = loader.Load(fileData, "test_data/ad_hoc/KittyPurr24_Stereo.flac");

@ -64,7 +64,7 @@ public:
~NyquistIO(); ~NyquistIO();
int Load(AudioData * data, const std::string & path); int Load(AudioData * data, const std::string & path);
int Load(AudioData *data, std::string extension, const std::vector<uint8_t> & buffer); int Load(AudioData *data, std::string extension, const std::vector<uint8_t> & buffer);
bool IsFileSupported(const std::string path) const; bool IsFileSupported(const std::string path) const;

@ -57,29 +57,29 @@ namespace nqr
/////////////////////// ///////////////////////
#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86) #if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
#define CPU_X86 1 #define CPU_X86 1
#endif #endif
#if defined(__arm__) || defined(_M_ARM) #if defined(__arm__) || defined(_M_ARM)
#define CPU_ARM 1 #define CPU_ARM 1
#endif #endif
#if defined(CPU_X86) && defined(CPU_ARM) #if defined(CPU_X86) && defined(CPU_ARM)
#error CPU_X86 and CPU_ARM both defined. #error CPU_X86 and CPU_ARM both defined.
#endif #endif
#if !defined(ARCH_CPU_BIG_ENDIAN) && !defined(ARCH_CPU_LITTLE_ENDIAN) #if !defined(ARCH_CPU_BIG_ENDIAN) && !defined(ARCH_CPU_LITTLE_ENDIAN)
#if CPU_X86 || CPU_ARM || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) #if CPU_X86 || CPU_ARM || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define ARCH_CPU_LITTLE_ENDIAN #define ARCH_CPU_LITTLE_ENDIAN
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define ARCH_CPU_BIG_ENDIAN #define ARCH_CPU_BIG_ENDIAN
#else #else
#error ARCH_CPU_BIG_ENDIAN or ARCH_CPU_LITTLE_ENDIAN should be defined. #error ARCH_CPU_BIG_ENDIAN or ARCH_CPU_LITTLE_ENDIAN should be defined.
#endif #endif
#endif #endif
#if defined(ARCH_CPU_BIG_ENDIAN) && defined(ARCH_CPU_LITTLE_ENDIAN) #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 #endif
static inline uint16_t Swap16(uint16_t value) static inline uint16_t Swap16(uint16_t value)
@ -114,7 +114,8 @@ static inline uint64_t Swap64(uint64_t value)
((value & 0xff00000000000000LL) >> 56)); ((value & 0xff00000000000000LL) >> 56));
} }
inline bool isOdd(const uint32_t x) template<typename T>
inline bool isOdd(const T x)
{ {
return (x & 0x1); return (x & 0x1);
} }
@ -224,14 +225,14 @@ static const float NQR_BYTE_2_FLT = 1.0f / 127.0f;
//@todo add 12, 20 for flac //@todo add 12, 20 for flac
enum PCMFormat enum PCMFormat
{ {
PCM_U8, PCM_U8,
PCM_S8, PCM_S8,
PCM_16, PCM_16,
PCM_24, PCM_24,
PCM_32, PCM_32,
PCM_64, PCM_64,
PCM_FLT, PCM_FLT,
PCM_DBL, PCM_DBL,
PCM_END PCM_END
}; };
@ -250,11 +251,11 @@ void ConvertFromFloat32(uint8_t * dst, const float * src, const size_t N, PCMFor
struct AudioData struct AudioData
{ {
int channelCount; int channelCount;
int sampleRate; int sampleRate;
double lengthSeconds; double lengthSeconds;
size_t frameSize; // channels * bits per sample size_t frameSize; // channels * bits per sample
std::vector<float> samples; std::vector<float> samples;
PCMFormat sourceFormat; PCMFormat sourceFormat;
//@todo: add field: channel layout //@todo: add field: channel layout
@ -272,8 +273,8 @@ struct StreamableAudioData : public AudioData
struct NyquistFileBuffer struct NyquistFileBuffer
{ {
std::vector<uint8_t> buffer; std::vector<uint8_t> buffer;
size_t size; size_t size;
}; };
NyquistFileBuffer ReadFile(std::string pathToFile); NyquistFileBuffer ReadFile(std::string pathToFile);

@ -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 <typename Buffer>
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<size_t(size_t, Buffer)> resize,
std::function<void()> 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<size_t(size_t, Buffer*)> _resize;
std::function<void()> _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);
}
}

@ -34,15 +34,15 @@ namespace nqr
template <typename T> template <typename T>
inline void DeinterleaveStereo(T * c1, T * c2, T const * src, size_t count) inline void DeinterleaveStereo(T * c1, T * c2, T const * src, size_t count)
{ {
auto src_end = src + count; auto src_end = src + count;
while (src != src_end) while (src != src_end)
{ {
*c1 = src[0]; *c1 = src[0];
*c2 = src[1]; *c2 = src[1];
c1++; c1++;
c2++; c2++;
src += 2; src += 2;
} }
} }
template<typename T> template<typename T>

@ -46,8 +46,8 @@ struct EncoderParams
struct ChunkHeaderInfo struct ChunkHeaderInfo
{ {
uint32_t offset; // Byte offset into chunk uint32_t offset; // Byte offset into chunk
uint32_t size; // Size of the chunk in bytes 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) inline uint32_t GenerateChunkCode(uint8_t a, uint8_t b, uint8_t c, uint8_t d)

@ -7,9 +7,9 @@
the following conditions are met: the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and * 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 * 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 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 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
@ -21,164 +21,179 @@
POSSIBILITY OF SUCH DAMAGE. POSSIBILITY OF SUCH DAMAGE.
*/ */
//! \brief Ringbuffer (aka circular buffer) data structure for use in concurrent audio scenarios. // \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 // 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 // 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. // 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. // The implementation remains lock-free and thread-safe within a single write thread / single read thread context.
#pragma once #pragma once
#ifndef CINDER_RINGBUFFER_H
#define CINDER_RINGBUFFER_H
#include <atomic> #include <atomic>
#include <assert.h> #include <assert.h>
template <typename T> template <typename T>
class RingBufferT { class RingBufferT
{
public: 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 ) // Constructs a RingBufferT with size = 0
: mData( other.mData ), mAllocatedSize( other.mAllocatedSize ), mWriteIndex( 0 ), mReadIndex( 0 ) RingBufferT() : mData(nullptr), mAllocatedSize(0), mWriteIndex(0), mReadIndex(0) {
{
other.mData = nullptr;
other.mAllocatedSize = 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 ) // Constructs a RingBufferT with \a count maximum elements.
mData = (T *)::realloc( mData, allocatedSize * sizeof( T ) ); RingBufferT(size_t count) : mAllocatedSize(0)
else {
mData = (T *)::calloc( allocatedSize, sizeof( T ) ); 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; ~RingBufferT()
clear(); {
} if (mData) free(mData);
//! 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 );
}
//! \brief Writes \a count elements into the internal buffer from \a array. \return `true` if all elements were successfully written, or `false` otherwise. // 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)
//! \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 size_t allocatedSize = count + 1; // one bin is used to distinguish between the read and write indices when full.
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( count > getAvailableWrite( writeIndex, readIndex ) ) if (mAllocatedSize)
return false; 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 ) { mAllocatedSize = allocatedSize;
size_t countA = mAllocatedSize - writeIndex; clear();
size_t countB = count - countA; }
std::memcpy( mData + writeIndex, array, countA * sizeof( T ) ); // Invalidates the internal buffer and resets read / write indices to 0. \note Must be synchronized with both read and write threads.
std::memcpy( mData, array + countA, countB * sizeof( T ) ); void clear()
writeIndexAfter -= mAllocatedSize; {
} mWriteIndex = 0;
else { mReadIndex = 0;
std::memcpy( mData + writeIndex, array, count * sizeof( T ) ); }
if( writeIndexAfter == mAllocatedSize )
writeIndexAfter = 0;
}
mWriteIndex.store( writeIndexAfter, std::memory_order_release ); // Returns the maximum number of elements.
return true; size_t getSize() const
} {
//! \brief Reads \a count elements from the internal buffer into \a array. \return `true` if all elements were successfully read, or `false` otherwise.
//! return mAllocatedSize - 1;
//! \note only safe to call from the read thread. }
bool read( T *array, size_t count ) // Returns the number of elements available for wrtiing. \note Only safe to call from the write thread.
{ size_t getAvailableWrite() const
const size_t writeIndex = mWriteIndex.load( std::memory_order_acquire ); {
const size_t readIndex = mReadIndex.load( std::memory_order_relaxed ); return getAvailableWrite(mWriteIndex, mReadIndex);
}
if( count > getAvailableRead( writeIndex, readIndex ) ) // Returns the number of elements available for wrtiing. \note Only safe to call from the read thread.
return false; 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 ) { if (count > getAvailableWrite(writeIndex, readIndex))
size_t countA = mAllocatedSize - readIndex; return false;
size_t countB = count - countA;
std::memcpy( array, mData + readIndex, countA * sizeof( T ) ); size_t writeIndexAfter = writeIndex + count;
std::memcpy( array + countA, mData, countB * sizeof( T ) );
readIndexAfter -= mAllocatedSize; if (writeIndex + count > mAllocatedSize)
} {
else { size_t countA = mAllocatedSize - writeIndex;
std::memcpy( array, mData + readIndex, count * sizeof( T ) ); size_t countB = count - countA;
if( readIndexAfter == mAllocatedSize )
readIndexAfter = 0;
}
mReadIndex.store( readIndexAfter, std::memory_order_release ); std::memcpy(mData + writeIndex, array, countA * sizeof(T));
return true; 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: private:
size_t getAvailableWrite( size_t writeIndex, size_t readIndex ) const size_t getAvailableWrite(size_t writeIndex, size_t readIndex) const
{ {
size_t result = readIndex - writeIndex - 1; size_t result = readIndex - writeIndex - 1;
if( writeIndex >= readIndex ) if (writeIndex >= readIndex)
result += mAllocatedSize; result += mAllocatedSize;
return result; return result;
} }
size_t getAvailableRead( size_t writeIndex, size_t readIndex ) const size_t getAvailableRead(size_t writeIndex, size_t readIndex) const
{ {
if( writeIndex >= readIndex ) if (writeIndex >= readIndex)
return writeIndex - readIndex; return writeIndex - readIndex;
return writeIndex + mAllocatedSize - readIndex; return writeIndex + mAllocatedSize - readIndex;
} }
T *mData; T *mData;
size_t mAllocatedSize; size_t mAllocatedSize;
std::atomic<size_t> mWriteIndex, mReadIndex; std::atomic<size_t> mWriteIndex, mReadIndex;
}; };
typedef RingBufferT<float> RingBuffer; typedef RingBufferT<float> RingBuffer;
#endif

@ -33,53 +33,53 @@ namespace nqr
enum WaveFormatCode enum WaveFormatCode
{ {
FORMAT_UNKNOWN = 0x0, // Unknown Wave Format FORMAT_UNKNOWN = 0x0, // Unknown Wave Format
FORMAT_PCM = 0x1, // PCM Format FORMAT_PCM = 0x1, // PCM Format
FORMAT_IEEE = 0x3, // IEEE float/double FORMAT_IEEE = 0x3, // IEEE float/double
FORMAT_ALAW = 0x6, // 8-bit ITU-T G.711 A-law FORMAT_ALAW = 0x6, // 8-bit ITU-T G.711 A-law
FORMAT_MULAW = 0x7, // 8-bit ITU-T G.711 µ-law FORMAT_MULAW = 0x7, // 8-bit ITU-T G.711 µ-law
FORMAT_EXT = 0xFFFE // Set via subformat FORMAT_EXT = 0xFFFE // Set via subformat
}; };
struct RiffChunkHeader struct RiffChunkHeader
{ {
uint32_t id_riff; // Chunk ID: 'RIFF' uint32_t id_riff; // Chunk ID: 'RIFF'
uint32_t file_size; // Entire file in bytes uint32_t file_size; // Entire file in bytes
uint32_t id_wave; // Chunk ID: 'WAVE' uint32_t id_wave; // Chunk ID: 'WAVE'
}; };
struct WaveChunkHeader struct WaveChunkHeader
{ {
uint32_t fmt_id; // Chunk ID: 'fmt ' uint32_t fmt_id; // Chunk ID: 'fmt '
uint32_t chunk_size; // Size in bytes uint32_t chunk_size; // Size in bytes
uint16_t format; // Format code uint16_t format; // Format code
uint16_t channel_count; // Num interleaved channels uint16_t channel_count; // Num interleaved channels
uint32_t sample_rate; // SR uint32_t sample_rate; // SR
uint32_t data_rate; // Data rate uint32_t data_rate; // Data rate
uint16_t frame_size; // 1 frame = channels * bits per sample (also known as block align) uint16_t frame_size; // 1 frame = channels * bits per sample (also known as block align)
uint16_t bit_depth; // Bits per sample uint16_t bit_depth; // Bits per sample
}; };
struct BextChunk struct BextChunk
{ {
uint32_t fmt_id; // Chunk ID: 'bext' uint32_t fmt_id; // Chunk ID: 'bext'
uint32_t chunk_size; // Size in bytes uint32_t chunk_size; // Size in bytes
uint8_t description[256]; // Description of the sound (ascii) uint8_t description[256]; // Description of the sound (ascii)
uint8_t origin[32]; // Name of the originator (ascii) uint8_t origin[32]; // Name of the originator (ascii)
uint8_t origin_ref[32]; // Reference 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 orgin_date[10]; // yyyy-mm-dd (ascii)
uint8_t origin_time[8]; // hh-mm-ss (ascii) uint8_t origin_time[8]; // hh-mm-ss (ascii)
uint64_t time_ref; // First sample count since midnight uint64_t time_ref; // First sample count since midnight
uint32_t version; // Version of the BWF uint32_t version; // Version of the BWF
uint8_t uimd[64]; // Byte 0 of SMPTE UMID uint8_t uimd[64]; // Byte 0 of SMPTE UMID
uint8_t reserved[188]; // 190 bytes, reserved for future use & set to NULL uint8_t reserved[188]; // 190 bytes, reserved for future use & set to NULL
}; };
struct FactChunk struct FactChunk
{ {
uint32_t fact_id; // Chunk ID: 'fact' uint32_t fact_id; // Chunk ID: 'fact'
uint32_t chunk_size; // Size in bytes uint32_t chunk_size; // Size in bytes
uint32_t sample_length; // number of samples per channel uint32_t sample_length; // number of samples per channel
}; };
struct ExtensibleData struct ExtensibleData
@ -100,15 +100,15 @@ struct ExtensibleData
template<class C, class R> template<class C, class R>
std::basic_ostream<C,R> & operator << (std::basic_ostream<C,R> & a, const WaveChunkHeader & b) std::basic_ostream<C,R> & operator << (std::basic_ostream<C,R> & a, const WaveChunkHeader & b)
{ {
return a << return a <<
"Format ID:\t\t" << b.fmt_id << "Format ID:\t\t" << b.fmt_id <<
"\nChunk Size:\t\t" << b.chunk_size << "\nChunk Size:\t\t" << b.chunk_size <<
"\nFormat Code:\t\t" << b.format << "\nFormat Code:\t\t" << b.format <<
"\nChannels:\t\t" << b.channel_count << "\nChannels:\t\t" << b.channel_count <<
"\nSample Rate:\t\t" << b.sample_rate << "\nSample Rate:\t\t" << b.sample_rate <<
"\nData Rate:\t\t" << b.data_rate << "\nData Rate:\t\t" << b.data_rate <<
"\nFrame Size:\t\t" << b.frame_size << "\nFrame Size:\t\t" << b.frame_size <<
"\nBit Depth:\t\t" << b.bit_depth << std::endl; "\nBit Depth:\t\t" << b.bit_depth << std::endl;
} }
//@todo expose speaker/channel/layout masks in the API: //@todo expose speaker/channel/layout masks in the API:
@ -154,23 +154,16 @@ enum SpeakerLayoutMask
//@todo verify mask values //@todo verify mask values
inline int ComputeChannelMask(const size_t channels) inline int ComputeChannelMask(const size_t channels)
{ {
switch (channels) switch (channels)
{ {
case 1: case 1: return SPEAKER_MONO;
return SPEAKER_MONO; case 2: return SPEAKER_STEREO;
case 2: case 3: return SPEAKER_2POINT1;
return SPEAKER_STEREO; case 4: return SPEAKER_QUAD;
case 3: case 5: return SPEAKER_4POINT1;
return SPEAKER_2POINT1; case 6: return SPEAKER_5POINT1;
case 4: default: return -1;
return SPEAKER_QUAD; }
case 5:
return SPEAKER_4POINT1;
case 6:
return SPEAKER_5POINT1;
default:
return -1;
}
} }
struct WavDecoder : public nqr::BaseDecoder struct WavDecoder : public nqr::BaseDecoder

@ -33,7 +33,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace nqr namespace nqr
{ {
// A simplistic encoder that takes a blob of data, conforms it to the user's // 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! // EncoderParams preference, and writes to disk. Be warned, does not support resampling!
// @todo support dithering, samplerate conversion, etc. // @todo support dithering, samplerate conversion, etc.
@ -53,14 +52,11 @@ class WavEncoder
public: public:
WavEncoder();
~WavEncoder();
// Assume data adheres to EncoderParams, except for bit depth and fmt // 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 } // end namespace nqr
#endif #endif

@ -30,7 +30,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace nqr namespace nqr
{ {
struct WavPackDecoder : public nqr::BaseDecoder struct WavPackDecoder : public nqr::BaseDecoder
{ {
WavPackDecoder() {}; WavPackDecoder() {};
@ -39,7 +39,7 @@ struct WavPackDecoder : public nqr::BaseDecoder
virtual int LoadFromBuffer(nqr::AudioData * data, const std::vector<uint8_t> & memory) override; virtual int LoadFromBuffer(nqr::AudioData * data, const std::vector<uint8_t> & memory) override;
virtual std::vector<std::string> GetSupportedFileExtensions() override; virtual std::vector<std::string> GetSupportedFileExtensions() override;
}; };
} // end namespace nqr } // end namespace nqr
#endif #endif

@ -41,7 +41,7 @@ NyquistIO::NyquistIO()
NyquistIO::~NyquistIO() NyquistIO::~NyquistIO()
{ {
} }
int NyquistIO::Load(AudioData * data, const std::string & path) 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<uint8_t> & buffer) int NyquistIO::Load(AudioData * data, std::string extension, const std::vector<uint8_t> & buffer)
{ {
if (decoderTable.find(extension) == decoderTable.end()) if (decoderTable.find(extension) == decoderTable.end())
{ {
return IOError::ExtensionNotSupported; return IOError::ExtensionNotSupported;
} }
if (decoderTable.size() > 0) if (decoderTable.size() > 0)
{ {
auto decoder = GetDecoderForExtension(extension); auto decoder = GetDecoderForExtension(extension);
try
try {
{ return decoder->LoadFromBuffer(data, buffer);
return decoder->LoadFromBuffer(data, buffer); }
} catch (std::exception e)
catch (std::exception e) {
{ std::cerr << "Caught fatal exception: " << e.what() << std::endl;
std::cerr << "Caught fatal exception: " << e.what() << std::endl; }
} }
} else
else {
{ return IOError::NoDecodersLoaded;
return IOError::NoDecodersLoaded; }
}
// Should never be reached // Should never be reached
return IOError::UnknownError; return IOError::UnknownError;

@ -35,70 +35,70 @@ static RingBufferT<float> 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) 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()) if (buffer.getAvailableRead())
{ {
buffer.read((float*) output_buffer, BUFFER_LENGTH); buffer.read((float*) output_buffer, BUFFER_LENGTH);
} }
else else
{ {
memset(output_buffer, 0, BUFFER_LENGTH * sizeof(float)); memset(output_buffer, 0, BUFFER_LENGTH * sizeof(float));
} }
return 0; return 0;
} }
bool AudioDevice::Open(const int deviceId) 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; RtAudio::StreamParameters parameters;
parameters.deviceId = info.id; parameters.deviceId = info.id;
parameters.nChannels = info.numChannels; parameters.nChannels = info.numChannels;
parameters.firstChannel = 0; parameters.firstChannel = 0;
rtaudio->openStream(&parameters, NULL, RTAUDIO_FLOAT32, info.sampleRate, &info.frameSize, &rt_callback, (void*) & buffer); rtaudio->openStream(&parameters, NULL, RTAUDIO_FLOAT32, info.sampleRate, &info.frameSize, &rt_callback, (void*) & buffer);
if (rtaudio->isStreamOpen()) if (rtaudio->isStreamOpen())
{ {
rtaudio->startStream(); rtaudio->startStream();
return true; return true;
} }
return false; return false;
} }
void AudioDevice::ListAudioDevices() void AudioDevice::ListAudioDevices()
{ {
std::unique_ptr<RtAudio> tempDevice(new RtAudio); std::unique_ptr<RtAudio> tempDevice(new RtAudio);
RtAudio::DeviceInfo info; RtAudio::DeviceInfo info;
unsigned int devices = tempDevice->getDeviceCount(); 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) for (unsigned int i = 0; i < devices; ++i)
{ {
info = tempDevice->getDeviceInfo(i); info = tempDevice->getDeviceInfo(i);
std::cout << "\tDevice: " << i << " - " << info.name << std::endl; std::cout << "\tDevice: " << i << " - " << info.name << std::endl;
} }
std::cout << std::endl; std::cout << std::endl;
} }
bool AudioDevice::Play(const std::vector<float> & data) bool AudioDevice::Play(const std::vector<float> & data)
{ {
if (!rtaudio->isStreamOpen()) return false; if (!rtaudio->isStreamOpen()) return false;
// Each frame is the (size/2) cause interleaved channels!
int sizeInFrames = ((int) data.size()) / (BUFFER_LENGTH);
int writeCount = 0; // Each frame is the (size/2) cause interleaved channels!
int sizeInFrames = ((int) data.size()) / (BUFFER_LENGTH);
while(writeCount < sizeInFrames) int writeCount = 0;
{
bool status = buffer.write((data.data() + (writeCount * BUFFER_LENGTH)), BUFFER_LENGTH); while(writeCount < sizeInFrames)
if (status) writeCount++; {
} bool status = buffer.write((data.data() + (writeCount * BUFFER_LENGTH)), BUFFER_LENGTH);
if (status) writeCount++;
}
return true; return true;
} }

@ -29,7 +29,7 @@ using namespace nqr;
NyquistFileBuffer nqr::ReadFile(std::string pathToFile) 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"); FILE * audioFile = fopen(pathToFile.c_str(), "rb");
if (!audioFile) if (!audioFile)
@ -51,12 +51,12 @@ NyquistFileBuffer nqr::ReadFile(std::string pathToFile)
throw std::runtime_error("error reading file or file too small"); 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 // Copy out to user
return data; return data;
} }
// Src data is aligned to PCMFormat // Src data is aligned to PCMFormat
@ -218,17 +218,11 @@ PCMFormat nqr::MakeFormatForBits(int bits, bool floatingPt, bool isSigned)
{ {
switch(bits) switch(bits)
{ {
case 8: case 8: return (isSigned) ? PCM_S8 : PCM_U8;
return (isSigned) ? PCM_S8 : PCM_U8; case 16: return PCM_16;
case 16: case 24: return PCM_24;
return PCM_16; case 32: return (floatingPt) ? PCM_FLT : PCM_32;
case 24: case 64: return (floatingPt) ? PCM_DBL : PCM_64;
return PCM_24; default: return PCM_END;
case 32:
return (floatingPt) ? PCM_FLT : PCM_32;
case 64:
return (floatingPt) ? PCM_DBL : PCM_64;
default:
return PCM_END;
} }
} }

@ -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 // https://dxr.mozilla.org/mozilla-central/source/media/libopus
#if (_MSC_VER) #if (_MSC_VER)
#pragma warning (push) #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 (disable: 181 111 4267 4996 4244 4701 4702 4133 4100 4127 4206 4312 4505 4365 4005 4013 4334 4703)
#endif #endif
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion" #pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshadow" #pragma clang diagnostic ignored "-Wshadow"
#pragma clang diagnostic ignored "-Wdeprecated-register" #pragma clang diagnostic ignored "-Wdeprecated-register"
#endif #endif
#undef HAVE_CONFIG_H #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" //#include "opus/celt/celt_encoder.c"
/* /*
See celt/celt_decoder.c + celt/celt_encoder.c in the project browser. 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, These files need to be in separate translation units due to name clashes,
unfortunately. unfortunately.
*/ */
///////////////// /////////////////
// SILK Common // // SILK Common //
@ -273,9 +273,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "opus/opusfile/src/wincerts.c" #include "opus/opusfile/src/wincerts.c"
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif
#if (_MSC_VER) #if (_MSC_VER)
#pragma warning (pop) #pragma warning (pop)
#endif #endif

@ -24,15 +24,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#if (_MSC_VER) #if (_MSC_VER)
#pragma warning (push) #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 (disable: 181 111 4267 4996 4244 4701 4702 4133 4100 4127 4206 4312 4505 4365 4005 4013 4334)
#endif #endif
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion" #pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshadow" #pragma clang diagnostic ignored "-Wshadow"
#pragma clang diagnostic ignored "-Wdeprecated-register" #pragma clang diagnostic ignored "-Wdeprecated-register"
#endif #endif
#include "libvorbis/include/vorbis/vorbisenc.h" #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/bitwise.c"
#include "libogg/src/framing.c" #include "libogg/src/framing.c"
#include "libvorbis/src/analysis.c" #include "libvorbis/src/analysis.c"
#include "libvorbis/src/bitrate.c" #include "libvorbis/src/bitrate.c"
#include "libvorbis/src/block.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" #include "libvorbis/src/mdct.c"
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif
#if (_MSC_VER) #if (_MSC_VER)
#pragma warning (pop) #pragma warning (pop)
#endif #endif

@ -167,9 +167,10 @@ int WavDecoder::LoadFromBuffer(AudioData * data, const std::vector<uint8_t> & me
auto DataChunkInfo = ScanForChunk(memory, GenerateChunkCode('d', 'a', 't', 'a')); 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; data->lengthSeconds = ((float) DataChunkInfo.size / (float) wavHeader.sample_rate) / wavHeader.frame_size;
@ -178,26 +179,16 @@ int WavDecoder::LoadFromBuffer(AudioData * data, const std::vector<uint8_t> & me
size_t totalSamples = (DataChunkInfo.size / wavHeader.frame_size) * wavHeader.channel_count; size_t totalSamples = (DataChunkInfo.size / wavHeader.frame_size) * wavHeader.channel_count;
data->samples.resize(totalSamples); data->samples.resize(totalSamples);
switch (bit_depth) switch (bit_depth)
{ {
case 8: case 8: data->sourceFormat = PCMFormat::PCM_U8; break;
data->sourceFormat = PCMFormat::PCM_U8; case 16: data->sourceFormat = PCMFormat::PCM_16; break;
break; case 24: data->sourceFormat = PCMFormat::PCM_24; break;
case 16: case 32: data->sourceFormat = (wavHeader.format == WaveFormatCode::FORMAT_IEEE) ? PCMFormat::PCM_FLT : PCMFormat::PCM_32; break;
data->sourceFormat = PCMFormat::PCM_16; case 64: data->sourceFormat = (wavHeader.format == WaveFormatCode::FORMAT_IEEE) ? PCMFormat::PCM_DBL : PCMFormat::PCM_64; break;
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; return IOError::NoError;
} }

@ -36,10 +36,6 @@ inline void toBytes(int value, char * arr)
arr[3] = (value >> 24) & 0xFF; arr[3] = (value >> 24) & 0xFF;
} }
WavEncoder::WavEncoder() {}
WavEncoder::~WavEncoder() {}
int WavEncoder::WriteFile(const EncoderParams p, const AudioData * d, const std::string & path) int WavEncoder::WriteFile(const EncoderParams p, const AudioData * d, const std::string & path)
{ {
// Cast away const because we know what we are doing (Hopefully?) // Cast away const because we know what we are doing (Hopefully?)

Loading…
Cancel
Save