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

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

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

@ -21,32 +21,40 @@
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 );
// Constructs a RingBufferT with size = 0
RingBufferT() : mData(nullptr), mAllocatedSize(0), mWriteIndex(0), mReadIndex(0) {
}
RingBufferT( RingBufferT &&other )
: mData( other.mData ), mAllocatedSize( other.mAllocatedSize ), 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;
@ -54,123 +62,127 @@ class RingBufferT {
~RingBufferT()
{
if( mData )
free( mData );
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 )
// 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 ) );
if (mAllocatedSize)
mData = (T *)::realloc(mData, allocatedSize * sizeof(T));
else
mData = (T *)::calloc( allocatedSize, sizeof( T ) );
mData = (T *)::calloc(allocatedSize, sizeof(T));
assert( mData );
assert(mData);
mAllocatedSize = allocatedSize;
clear();
}
//! Invalidates the internal buffer and resets read / write indices to 0. \note Must be synchronized with both read and write threads.
// 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.
// 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.
// 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 );
return getAvailableWrite(mWriteIndex, mReadIndex);
}
//! Returns the number of elements available for wrtiing. \note Only safe to call from the read thread.
// 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 );
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.
//!
//! \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 )
// 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 );
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 (count > getAvailableWrite(writeIndex, readIndex))
return false;
size_t writeIndexAfter = writeIndex + count;
if( writeIndex + count > mAllocatedSize ) {
if (writeIndex + count > mAllocatedSize)
{
size_t countA = mAllocatedSize - writeIndex;
size_t countB = count - countA;
std::memcpy( mData + writeIndex, array, countA * sizeof( T ) );
std::memcpy( mData, array + countA, countB * sizeof( T ) );
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 )
else
{
std::memcpy(mData + writeIndex, array, count * sizeof(T));
if (writeIndexAfter == mAllocatedSize)
writeIndexAfter = 0;
}
mWriteIndex.store( writeIndexAfter, std::memory_order_release );
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 );
if( count > getAvailableRead( writeIndex, readIndex ) )
// 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 ) {
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 ) );
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 )
else
{
std::memcpy(array, mData + readIndex, count * sizeof(T));
if (readIndexAfter == mAllocatedSize)
readIndexAfter = 0;
}
mReadIndex.store( readIndexAfter, std::memory_order_release );
mReadIndex.store(readIndexAfter, std::memory_order_release);
return true;
}
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;
if( writeIndex >= readIndex )
if (writeIndex >= readIndex)
result += mAllocatedSize;
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 + mAllocatedSize - readIndex;
@ -182,3 +194,6 @@ class RingBufferT {
};
typedef RingBufferT<float> RingBuffer;
#endif

@ -156,20 +156,13 @@ 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;
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;
}
}

@ -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,11 +52,8 @@ 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);
};

@ -84,7 +84,6 @@ int NyquistIO::Load(AudioData * data, std::string extension, const std::vector<u
if (decoderTable.size() > 0)
{
auto decoder = GetDecoderForExtension(extension);
try
{
return decoder->LoadFromBuffer(data, buffer);

@ -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
@ -100,7 +100,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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"
@ -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;
@ -180,21 +181,11 @@ int WavDecoder::LoadFromBuffer(AudioData * data, const std::vector<uint8_t> & me
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;
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);

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