Fixed many bugs, IMD tests working, wav writing
* Fixed many sample generation bugs * IMD tests now generating as expected * WAV writing fundamentals in place
This commit is contained in:
		@@ -4,24 +4,29 @@
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <random>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <random>
 | 
			
		||||
#include <mpfr.h>
 | 
			
		||||
 | 
			
		||||
#include <boost/math/constants/constants.hpp>
 | 
			
		||||
#include <boost/multiprecision/cpp_bin_float.hpp>
 | 
			
		||||
#include <boost/multiprecision/mpfr.hpp>
 | 
			
		||||
 | 
			
		||||
using std::shared_ptr;
 | 
			
		||||
using std::vector;
 | 
			
		||||
 | 
			
		||||
using std::cos;
 | 
			
		||||
using std::for_each;
 | 
			
		||||
using std::sin;
 | 
			
		||||
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
class Generator
 | 
			
		||||
{
 | 
			
		||||
using namespace boost::multiprecision;
 | 
			
		||||
 | 
			
		||||
typedef cpp_bin_float_double MP_TYPE;
 | 
			
		||||
 | 
			
		||||
const MP_TYPE two_pi = boost::math::constants::two_pi<MP_TYPE>();
 | 
			
		||||
 | 
			
		||||
template <typename dataType> class Generator {
 | 
			
		||||
public:
 | 
			
		||||
    virtual dataType getSample() = 0;
 | 
			
		||||
    virtual void getSamples(size_t nSamples, dataType *buf);
 | 
			
		||||
    virtual void getSamples(size_t nSamples, dataType* buf);
 | 
			
		||||
 | 
			
		||||
    virtual float getFrequency() const;
 | 
			
		||||
    virtual void setFrequency(float frequency);
 | 
			
		||||
@@ -29,6 +34,9 @@ public:
 | 
			
		||||
    virtual float getAmplitude() const;
 | 
			
		||||
    virtual void setAmplitude(float amplitude);
 | 
			
		||||
 | 
			
		||||
    virtual float getAmplitudeDb() const;
 | 
			
		||||
    virtual void setAmplitudeDb(float amplitude);
 | 
			
		||||
 | 
			
		||||
    virtual bool isEnabled() const;
 | 
			
		||||
    virtual void enable();
 | 
			
		||||
    virtual void disable();
 | 
			
		||||
@@ -36,8 +44,8 @@ public:
 | 
			
		||||
    virtual ~Generator();
 | 
			
		||||
 | 
			
		||||
    // disallow copy of virtual interface
 | 
			
		||||
    Generator(Generator const &) = delete;
 | 
			
		||||
    Generator &operator=(Generator const &) = delete;
 | 
			
		||||
    Generator(Generator const&) = delete;
 | 
			
		||||
    Generator& operator=(Generator const&) = delete;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    Generator(uint32_t _sampleRate, float _frequency, float _amplitude = 1);
 | 
			
		||||
@@ -49,35 +57,37 @@ protected:
 | 
			
		||||
private:
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
class SineGenerator : public Generator<dataType>
 | 
			
		||||
{
 | 
			
		||||
template <typename dataType> class SineGenerator : public Generator<dataType> {
 | 
			
		||||
public:
 | 
			
		||||
    SineGenerator(uint32_t _sampleRate, float _frequency, float _amplitude = 1);
 | 
			
		||||
    SineGenerator(uint32_t _sampleRate, float _frequency, float _amplitude = 1,
 | 
			
		||||
        bool caching = true);
 | 
			
		||||
 | 
			
		||||
    dataType getSample() final;
 | 
			
		||||
 | 
			
		||||
    void setFrequency(float _frequency) final;
 | 
			
		||||
    void setFrequency(mpfr_t frequency);
 | 
			
		||||
    void setFrequency(MP_TYPE frequency);
 | 
			
		||||
 | 
			
		||||
    void setAmplitude(float amplitude);
 | 
			
		||||
 | 
			
		||||
    virtual ~SineGenerator();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    mpfr_t instPhase;
 | 
			
		||||
    mpfr_t phaseIncr;
 | 
			
		||||
    MP_TYPE instPhase;
 | 
			
		||||
    MP_TYPE phaseIncr;
 | 
			
		||||
 | 
			
		||||
    // Constant 2*pi
 | 
			
		||||
    mpfr_t PI_2;
 | 
			
		||||
    void dirtyCache();
 | 
			
		||||
    dataType unCachedGetSample();
 | 
			
		||||
    dataType cachedGetSample();
 | 
			
		||||
 | 
			
		||||
    mpfr_t tmpA;
 | 
			
		||||
    vector<dataType> sampleCache;
 | 
			
		||||
    typename vector<dataType>::const_iterator cachePos;
 | 
			
		||||
    const bool caching;
 | 
			
		||||
    bool cacheInvalid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
class NoiseGenerator : public Generator<dataType>
 | 
			
		||||
{
 | 
			
		||||
template <typename dataType> class NoiseGenerator : public Generator<dataType> {
 | 
			
		||||
public:
 | 
			
		||||
    enum NOISE_TYPE
 | 
			
		||||
    {
 | 
			
		||||
    enum NOISE_TYPE {
 | 
			
		||||
        WHITE,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@@ -90,9 +100,7 @@ private:
 | 
			
		||||
    std::mt19937_64 rand_gen;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
class JTestGenerator : public Generator<dataType>
 | 
			
		||||
{
 | 
			
		||||
template <typename dataType> class JTestGenerator : public Generator<dataType> {
 | 
			
		||||
public:
 | 
			
		||||
    JTestGenerator(uint32_t sampleRate, uint8_t nbits);
 | 
			
		||||
 | 
			
		||||
@@ -104,29 +112,27 @@ private:
 | 
			
		||||
    typename std::vector<dataType>::const_iterator pos;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
class SweepGenerator : public Generator<dataType>
 | 
			
		||||
{
 | 
			
		||||
template <typename dataType> class SweepGenerator : public Generator<dataType> {
 | 
			
		||||
public:
 | 
			
		||||
    SweepGenerator(uint32_t sampleRate, float startFreq, float endFreq, float length, float amplitude = 1);
 | 
			
		||||
    SweepGenerator(uint32_t sampleRate, float startFreq, float endFreq,
 | 
			
		||||
        float length, float amplitude = 1);
 | 
			
		||||
    virtual ~SweepGenerator();
 | 
			
		||||
 | 
			
		||||
    dataType getSample() final;
 | 
			
		||||
    float getFrequency() const;
 | 
			
		||||
 | 
			
		||||
    void setAmplitude(float amplitude);
 | 
			
		||||
    void setFrequency(float frequency);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    SineGenerator<dataType> sg;
 | 
			
		||||
    mpfr_t startFreq;
 | 
			
		||||
    mpfr_t curFreq;
 | 
			
		||||
    mpfr_t freqStep;
 | 
			
		||||
    mpfr_t endFreq;
 | 
			
		||||
    float length;
 | 
			
		||||
    MP_TYPE startFreq;
 | 
			
		||||
    MP_TYPE curFreq;
 | 
			
		||||
    MP_TYPE freqStep;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
class SineSynth
 | 
			
		||||
{
 | 
			
		||||
template <typename dataType> class SineSynth {
 | 
			
		||||
public:
 | 
			
		||||
    SineSynth(uint32_t _sampleRate);
 | 
			
		||||
 | 
			
		||||
@@ -134,7 +140,7 @@ public:
 | 
			
		||||
    vector<shared_ptr<Generator<dataType>>> getSynths() const;
 | 
			
		||||
    void clearSynths();
 | 
			
		||||
 | 
			
		||||
    void getSamples(size_t nSamples, dataType *buf);
 | 
			
		||||
    void getSamples(size_t nSamples, dataType* buf);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    uint32_t sampleRate;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										137
									
								
								include/WavWriter.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								include/WavWriter.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,137 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <ostream>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
using std::array;
 | 
			
		||||
using std::ofstream;
 | 
			
		||||
using std::ostream;
 | 
			
		||||
using std::string;
 | 
			
		||||
 | 
			
		||||
class WavWriter {
 | 
			
		||||
public:
 | 
			
		||||
    enum FormatCode : uint16_t {
 | 
			
		||||
        WAVE_FORMAT_PCM = 0x01,
 | 
			
		||||
        WAVE_FORMAT_IEEE_FLOAT = 0x03,
 | 
			
		||||
        WAVE_FORMAT_ALAW = 0x06,
 | 
			
		||||
        WAVE_FORMAT_MULAW = 0x07,
 | 
			
		||||
        WAVE_FORMAT_EXTENSIBLE = 0xfffe,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    WavWriter(const string& filename, WavWriter::FormatCode format,
 | 
			
		||||
        uint16_t nChannels, uint16_t nBitsPerSample, uint32_t nSamplesPerSec)
 | 
			
		||||
        : f(filename, std::ofstream::binary)
 | 
			
		||||
        , format(format)
 | 
			
		||||
        , nChannels(nChannels)
 | 
			
		||||
        , nBitsPerSample(nBitsPerSample)
 | 
			
		||||
        , nSamplesPerSec(nSamplesPerSec)
 | 
			
		||||
    {
 | 
			
		||||
        f.write("RIFF\0\0\0\0WAVE", 12);
 | 
			
		||||
        updateHeader();
 | 
			
		||||
        f.seekp(0, std::ios_base::end);
 | 
			
		||||
    };
 | 
			
		||||
    ~WavWriter() { f.close(); }
 | 
			
		||||
 | 
			
		||||
    template <typename T> void writeSamples(const T data[], size_t n)
 | 
			
		||||
    {
 | 
			
		||||
        f.write(reinterpret_cast<const char*>(data), n);
 | 
			
		||||
        updateHeader();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    void close();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    uint32_t dataSize;
 | 
			
		||||
    FormatCode format;
 | 
			
		||||
    uint16_t nChannels;
 | 
			
		||||
    uint32_t nSamplesPerSec;
 | 
			
		||||
    uint16_t nBitsPerSample;
 | 
			
		||||
    ofstream f;
 | 
			
		||||
 | 
			
		||||
    void updateHeader()
 | 
			
		||||
    {
 | 
			
		||||
        auto curPos = f.tellp();
 | 
			
		||||
        dataSize = curPos - std::streamoff(8);
 | 
			
		||||
        f.seekp(0);
 | 
			
		||||
        // Update main header total size
 | 
			
		||||
        f.write("RIFF", 4);
 | 
			
		||||
        f.write(reinterpret_cast<const char*>(&dataSize), sizeof(dataSize));
 | 
			
		||||
        f.write("WAVE", 4);
 | 
			
		||||
        // Write new format and data size
 | 
			
		||||
        WavWriter::fmtChunk fmt(this);
 | 
			
		||||
        fmt.writeTo(f);
 | 
			
		||||
        f.write("data", 4);
 | 
			
		||||
        uint32_t ckSize = curPos - f.tellp();
 | 
			
		||||
        f.write(reinterpret_cast<const char*>(&ckSize), sizeof(ckSize));
 | 
			
		||||
 | 
			
		||||
        f.seekp(curPos);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct Chunk {
 | 
			
		||||
    public:
 | 
			
		||||
        char ckID[4];
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
        Chunk(WavWriter* parent, const char* ckID)
 | 
			
		||||
            : parent(parent)
 | 
			
		||||
            , ckID{ ckID[0], ckID[1], ckID[2], ckID[3] } {};
 | 
			
		||||
        virtual void writeTo(ostream& of) = 0;
 | 
			
		||||
 | 
			
		||||
        WavWriter* parent;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct fmtChunk : public Chunk {
 | 
			
		||||
        fmtChunk(WavWriter* parent)
 | 
			
		||||
            : Chunk(parent, "fmt ")
 | 
			
		||||
            {};
 | 
			
		||||
 | 
			
		||||
        uint32_t cksize;
 | 
			
		||||
        uint16_t cbSize = 0;
 | 
			
		||||
        uint32_t dwChannelMask;
 | 
			
		||||
        char SubFormat[16];
 | 
			
		||||
 | 
			
		||||
        void writeTo(ostream& of)
 | 
			
		||||
        {
 | 
			
		||||
            of.write(this->ckID, sizeof(this->ckID));
 | 
			
		||||
            cksize = parent->format == WAVE_FORMAT_PCM ? 16 : 18;
 | 
			
		||||
            of.write(reinterpret_cast<const char*>(&cksize), sizeof(cksize));
 | 
			
		||||
            of.write(reinterpret_cast<const char*>(&parent->format),
 | 
			
		||||
                sizeof(parent->format));
 | 
			
		||||
            of.write(reinterpret_cast<const char*>(&parent->nChannels),
 | 
			
		||||
                sizeof(parent->nChannels));
 | 
			
		||||
            of.write(reinterpret_cast<const char*>(&parent->nSamplesPerSec),
 | 
			
		||||
                sizeof(parent->nSamplesPerSec));
 | 
			
		||||
            uint32_t byteRate = parent->nSamplesPerSec * parent->nChannels
 | 
			
		||||
                * parent->nBitsPerSample / 8;
 | 
			
		||||
            of.write(
 | 
			
		||||
                reinterpret_cast<const char*>(&byteRate), sizeof(byteRate));
 | 
			
		||||
            uint16_t blockAlign
 | 
			
		||||
                = parent->nChannels * parent->nBitsPerSample / 8;
 | 
			
		||||
            of.write(
 | 
			
		||||
                reinterpret_cast<const char*>(&blockAlign), sizeof(blockAlign));
 | 
			
		||||
            of.write(reinterpret_cast<const char*>(&parent->nBitsPerSample),
 | 
			
		||||
                sizeof(parent->nBitsPerSample));
 | 
			
		||||
            if (parent->format != WAVE_FORMAT_PCM)
 | 
			
		||||
                of.write(
 | 
			
		||||
                    reinterpret_cast<const char*>(&cbSize), sizeof(cbSize));
 | 
			
		||||
            if (parent->format == WAVE_FORMAT_EXTENSIBLE) {
 | 
			
		||||
                of.write(reinterpret_cast<const char*>(&parent->nBitsPerSample),
 | 
			
		||||
                    sizeof(parent->nBitsPerSample));
 | 
			
		||||
                of.write(reinterpret_cast<const char*>(&dwChannelMask),
 | 
			
		||||
                    sizeof(dwChannelMask));
 | 
			
		||||
                of.write(reinterpret_cast<const char*>(SubFormat),
 | 
			
		||||
                    sizeof(SubFormat));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    struct factChunk : public Chunk {
 | 
			
		||||
        factChunk(WavWriter* parent)
 | 
			
		||||
            : Chunk(parent, "fact"){};
 | 
			
		||||
        uint32_t cksize = 4;
 | 
			
		||||
        uint32_t dwSampleLength();
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
		Reference in New Issue
	
	Block a user