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/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");

@ -64,7 +64,7 @@ public:
~NyquistIO();
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;

@ -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<typename T>
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<float> samples;
int channelCount;
int sampleRate;
double lengthSeconds;
size_t frameSize; // channels * bits per sample
std::vector<float> samples;
PCMFormat sourceFormat;
//@todo: add field: channel layout
@ -272,8 +273,8 @@ struct StreamableAudioData : public AudioData
struct NyquistFileBuffer
{
std::vector<uint8_t> buffer;
size_t size;
std::vector<uint8_t> buffer;
size_t size;
};
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>
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<typename T>

@ -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)

@ -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 <atomic>
#include <assert.h>
template <typename T>
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<size_t> mWriteIndex, mReadIndex;
return writeIndex + mAllocatedSize - readIndex;
}
T *mData;
size_t mAllocatedSize;
std::atomic<size_t> mWriteIndex, mReadIndex;
};
typedef RingBufferT<float> RingBuffer;
#endif

@ -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<class C, class R>
std::basic_ostream<C,R> & operator << (std::basic_ostream<C,R> & 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

@ -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

@ -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<uint8_t> & memory) override;
virtual std::vector<std::string> GetSupportedFileExtensions() override;
};
} // end namespace nqr
#endif

@ -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<uint8_t> & 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;

@ -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)
{
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(&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())
{
rtaudio->startStream();
return true;
}
return false;
if (rtaudio->isStreamOpen())
{
rtaudio->startStream();
return true;
}
return false;
}
void AudioDevice::ListAudioDevices()
{
std::unique_ptr<RtAudio> tempDevice(new RtAudio);
std::unique_ptr<RtAudio> 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<float> & 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;
}

@ -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;
}
}

@ -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

@ -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

@ -167,9 +167,10 @@ int WavDecoder::LoadFromBuffer(AudioData * data, const std::vector<uint8_t> & 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<uint8_t> & 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;
}

@ -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?)

Loading…
Cancel
Save