Work updates - add synths and improve
This commit is contained in:
		@@ -5,6 +5,8 @@ set(CMAKE_CXX_STANDARD 11)
 | 
			
		||||
 | 
			
		||||
include_directories(include)
 | 
			
		||||
 | 
			
		||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
 | 
			
		||||
 | 
			
		||||
find_package(PulseAudio)
 | 
			
		||||
if(PULSEAUDIO_FOUND)
 | 
			
		||||
    include_directories(${PULSEAUDIO_INCLUDE_DIR})
 | 
			
		||||
@@ -15,7 +17,12 @@ if (CURSES_FOUND)
 | 
			
		||||
    include_directories(${CURSES_INCLUDE_DIRS})
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
set(SINESYNTH_LIBS ${PULSEAUDIO_LIBRARY} ${CURSES_LIBRARIES} pulse-simple tinfo)
 | 
			
		||||
find_package(MPFR)
 | 
			
		||||
if (MPFR_FOUND)
 | 
			
		||||
    include_directories(${MPFR_INCLUDE_DIRS})
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
set(SINESYNTH_LIBS ${PULSEAUDIO_LIBRARY} ${CURSES_LIBRARIES} ${MPFR_LIBRARIES} pulse-simple tinfo)
 | 
			
		||||
 | 
			
		||||
file(GLOB SOURCES "src/*.cpp")
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										72
									
								
								cmake/FindMPFR.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								cmake/FindMPFR.cmake
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
			
		||||
# Try to find the MPFR library
 | 
			
		||||
# See http://www.mpfr.org/
 | 
			
		||||
#
 | 
			
		||||
# This module supports requiring a minimum version, e.g. you can do
 | 
			
		||||
#   find_package(MPFR 2.3.0)
 | 
			
		||||
# to require version 2.3.0 to newer of MPFR.
 | 
			
		||||
#
 | 
			
		||||
# Once done this will define
 | 
			
		||||
#
 | 
			
		||||
#  MPFR_FOUND - system has MPFR lib with correct version
 | 
			
		||||
#  MPFR_INCLUDES - the MPFR include directory
 | 
			
		||||
#  MPFR_LIBRARIES - the MPFR library
 | 
			
		||||
#  MPFR_VERSION - MPFR version
 | 
			
		||||
 | 
			
		||||
# Copyright (c) 2006, 2007 Montel Laurent, <montel@kde.org>
 | 
			
		||||
# Copyright (c) 2008, 2009 Gael Guennebaud, <g.gael@free.fr>
 | 
			
		||||
# Copyright (c) 2010 Jitse Niesen, <jitse@maths.leeds.ac.uk>
 | 
			
		||||
# Copyright (c) 2015 Jack Poulson, <jack.poulson@gmail.com>
 | 
			
		||||
# Redistribution and use is allowed according to the terms of the BSD license.
 | 
			
		||||
 | 
			
		||||
find_path(MPFR_INCLUDES NAMES mpfr.h PATHS $ENV{GMPDIR} $ENV{MPFRDIR}
 | 
			
		||||
  ${INCLUDE_INSTALL_DIR})
 | 
			
		||||
 | 
			
		||||
# Set MPFR_FIND_VERSION to 1.0.0 if no minimum version is specified
 | 
			
		||||
if(NOT MPFR_FIND_VERSION)
 | 
			
		||||
  if(NOT MPFR_FIND_VERSION_MAJOR)
 | 
			
		||||
    set(MPFR_FIND_VERSION_MAJOR 1)
 | 
			
		||||
  endif()
 | 
			
		||||
  if(NOT MPFR_FIND_VERSION_MINOR)
 | 
			
		||||
    set(MPFR_FIND_VERSION_MINOR 0)
 | 
			
		||||
  endif()
 | 
			
		||||
  if(NOT MPFR_FIND_VERSION_PATCH)
 | 
			
		||||
    set(MPFR_FIND_VERSION_PATCH 0)
 | 
			
		||||
  endif()
 | 
			
		||||
  set(MPFR_FIND_VERSION
 | 
			
		||||
    "${MPFR_FIND_VERSION_MAJOR}.${MPFR_FIND_VERSION_MINOR}.${MPFR_FIND_VERSION_PATCH}")
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if(MPFR_INCLUDES)
 | 
			
		||||
  # Query MPFR_VERSION
 | 
			
		||||
  file(READ "${MPFR_INCLUDES}/mpfr.h" _mpfr_version_header)
 | 
			
		||||
 | 
			
		||||
  string(REGEX MATCH "define[ \t]+MPFR_VERSION_MAJOR[ \t]+([0-9]+)"
 | 
			
		||||
    _mpfr_major_version_match "${_mpfr_version_header}")
 | 
			
		||||
  set(MPFR_MAJOR_VERSION "${CMAKE_MATCH_1}")
 | 
			
		||||
  string(REGEX MATCH "define[ \t]+MPFR_VERSION_MINOR[ \t]+([0-9]+)"
 | 
			
		||||
    _mpfr_minor_version_match "${_mpfr_version_header}")
 | 
			
		||||
  set(MPFR_MINOR_VERSION "${CMAKE_MATCH_1}")
 | 
			
		||||
  string(REGEX MATCH "define[ \t]+MPFR_VERSION_PATCHLEVEL[ \t]+([0-9]+)"
 | 
			
		||||
    _mpfr_patchlevel_version_match "${_mpfr_version_header}")
 | 
			
		||||
  set(MPFR_PATCHLEVEL_VERSION "${CMAKE_MATCH_1}")
 | 
			
		||||
 | 
			
		||||
  set(MPFR_VERSION
 | 
			
		||||
    ${MPFR_MAJOR_VERSION}.${MPFR_MINOR_VERSION}.${MPFR_PATCHLEVEL_VERSION})
 | 
			
		||||
 | 
			
		||||
  # Check whether found version exceeds minimum required
 | 
			
		||||
  if(${MPFR_VERSION} VERSION_LESS ${MPFR_FIND_VERSION})
 | 
			
		||||
    set(MPFR_VERSION_OK FALSE)
 | 
			
		||||
    message(STATUS "MPFR version ${MPFR_VERSION} found in ${MPFR_INCLUDES}, "
 | 
			
		||||
                   "but at least version ${MPFR_FIND_VERSION} is required")
 | 
			
		||||
  else()
 | 
			
		||||
    set(MPFR_VERSION_OK TRUE)
 | 
			
		||||
  endif()
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
find_library(MPFR_LIBRARIES mpfr
 | 
			
		||||
  PATHS $ENV{GMPDIR} $ENV{MPFRDIR} ${LIB_INSTALL_DIR})
 | 
			
		||||
 | 
			
		||||
include(FindPackageHandleStandardArgs)
 | 
			
		||||
find_package_handle_standard_args(MPFR DEFAULT_MSG
 | 
			
		||||
                                  MPFR_INCLUDES MPFR_LIBRARIES MPFR_VERSION_OK)
 | 
			
		||||
mark_as_advanced(MPFR_INCLUDES MPFR_LIBRARIES)
 | 
			
		||||
@@ -1,12 +1,13 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <random>
 | 
			
		||||
#include <mpfr.h>
 | 
			
		||||
 | 
			
		||||
using std::shared_ptr;
 | 
			
		||||
using std::vector;
 | 
			
		||||
@@ -15,13 +16,18 @@ using std::cos;
 | 
			
		||||
using std::for_each;
 | 
			
		||||
using std::sin;
 | 
			
		||||
 | 
			
		||||
class Generator {
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
class Generator
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    virtual float getSample() = 0;
 | 
			
		||||
    virtual void getSamples(size_t nSamples, float* buf);
 | 
			
		||||
    virtual dataType getSample() = 0;
 | 
			
		||||
    virtual void getSamples(size_t nSamples, dataType *buf);
 | 
			
		||||
 | 
			
		||||
    virtual float getFrequency() const;
 | 
			
		||||
    virtual void setFrequency(float _frequency);
 | 
			
		||||
    virtual void setFrequency(float frequency);
 | 
			
		||||
 | 
			
		||||
    virtual float getAmplitude() const;
 | 
			
		||||
    virtual void setAmplitude(float amplitude);
 | 
			
		||||
 | 
			
		||||
    virtual bool isEnabled() const;
 | 
			
		||||
    virtual void enable();
 | 
			
		||||
@@ -30,11 +36,11 @@ 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);
 | 
			
		||||
    Generator(uint32_t _sampleRate, float _frequency, float _amplitude = 1);
 | 
			
		||||
    uint32_t sampleRate;
 | 
			
		||||
    float frequency;
 | 
			
		||||
    float amplitude;
 | 
			
		||||
@@ -43,64 +49,94 @@ protected:
 | 
			
		||||
private:
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class SineGenerator : public Generator {
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
class SineGenerator : public Generator<dataType>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    SineGenerator(uint32_t _sampleRate, float _frequency, float _amplitude);
 | 
			
		||||
    SineGenerator(uint32_t _sampleRate, float _frequency, float _amplitude = 1);
 | 
			
		||||
 | 
			
		||||
    float getSample() final;
 | 
			
		||||
    dataType getSample() final;
 | 
			
		||||
 | 
			
		||||
    void setFrequency(float _frequency) final;
 | 
			
		||||
    void setFrequency(mpfr_t frequency);
 | 
			
		||||
 | 
			
		||||
    virtual ~SineGenerator();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    float instPhase;
 | 
			
		||||
    float phaseIncr;
 | 
			
		||||
    mpfr_t instPhase;
 | 
			
		||||
    mpfr_t phaseIncr;
 | 
			
		||||
 | 
			
		||||
    // Constant 2*pi
 | 
			
		||||
    mpfr_t PI_2;
 | 
			
		||||
 | 
			
		||||
    mpfr_t tmpA;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class NoiseGenerator : public Generator {
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
class NoiseGenerator : public Generator<dataType>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    NoiseGenerator(uint32_t _sampleRate, uint8_t rate, float _amplitude);
 | 
			
		||||
    enum NOISE_TYPE
 | 
			
		||||
    {
 | 
			
		||||
        WHITE,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    float getSample() final;
 | 
			
		||||
    NoiseGenerator(uint32_t _sampleRate, NOISE_TYPE type, float _amplitude = 1);
 | 
			
		||||
 | 
			
		||||
    dataType getSample() final;
 | 
			
		||||
    virtual ~NoiseGenerator();
 | 
			
		||||
 | 
			
		||||
    uint8_t rate;
 | 
			
		||||
    static const uint16_t rateTable[];
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    int16_t level;
 | 
			
		||||
    uint16_t sampleCount;
 | 
			
		||||
    std::mt19937_64 rand_gen;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class SampleGenerator : public Generator {
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
class JTestGenerator : public Generator<dataType>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    SampleGenerator(uint32_t _sampleRate, uint16_t _playbackRate, float _amplitude, size_t nSamples, const float* samples);
 | 
			
		||||
    SampleGenerator(uint32_t _sampleRate, uint16_t _playbackRate, float _amplitude, size_t nSamples, const int16_t* samples);
 | 
			
		||||
    JTestGenerator(uint32_t sampleRate, uint8_t nbits);
 | 
			
		||||
 | 
			
		||||
    float getSample() final;
 | 
			
		||||
    virtual ~SampleGenerator();
 | 
			
		||||
 | 
			
		||||
    uint16_t playbackRate;
 | 
			
		||||
    dataType getSample() final;
 | 
			
		||||
    virtual ~JTestGenerator();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    vector<float> sample;
 | 
			
		||||
    float oldest, older, old;
 | 
			
		||||
    uint32_t counter;
 | 
			
		||||
    static const uint16_t gaussTable[];
 | 
			
		||||
    std::vector<dataType> loop;
 | 
			
		||||
    typename std::vector<dataType>::const_iterator pos;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class SineSynth {
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
class SweepGenerator : public Generator<dataType>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    SineGenerator<dataType> sg;
 | 
			
		||||
    mpfr_t startFreq;
 | 
			
		||||
    mpfr_t curFreq;
 | 
			
		||||
    mpfr_t freqStep;
 | 
			
		||||
    mpfr_t endFreq;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
class SineSynth
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    SineSynth(uint32_t _sampleRate);
 | 
			
		||||
 | 
			
		||||
    void addSynth(shared_ptr<Generator>);
 | 
			
		||||
    vector<shared_ptr<Generator>> getSynths() const;
 | 
			
		||||
    void addSynth(shared_ptr<Generator<dataType>>);
 | 
			
		||||
    vector<shared_ptr<Generator<dataType>>> getSynths() const;
 | 
			
		||||
    void clearSynths();
 | 
			
		||||
 | 
			
		||||
    void getSamples(size_t nSamples, float* buf);
 | 
			
		||||
    void getSamples(size_t nSamples, dataType *buf);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    uint32_t sampleRate;
 | 
			
		||||
    vector<shared_ptr<Generator>> generators;
 | 
			
		||||
    vector<shared_ptr<Generator<dataType>>> generators;
 | 
			
		||||
};
 | 
			
		||||
@@ -1,83 +1,151 @@
 | 
			
		||||
#include "SineSynth.h"
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <random>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
 | 
			
		||||
Generator::Generator(uint32_t _sampleRate, float _frequency, float _amplitude)
 | 
			
		||||
    : sampleRate(_sampleRate)
 | 
			
		||||
    , frequency(_frequency)
 | 
			
		||||
    , amplitude(_amplitude)
 | 
			
		||||
    , enabled(false)
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
Generator<dataType>::Generator(uint32_t _sampleRate, float _frequency, float _amplitude)
 | 
			
		||||
    : sampleRate(_sampleRate), frequency(_frequency), amplitude(_amplitude), enabled(false)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Generator::~Generator() {}
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
Generator<dataType>::~Generator() {}
 | 
			
		||||
 | 
			
		||||
void Generator::getSamples(size_t nSamples, float* buf)
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
void Generator<dataType>::getSamples(size_t nSamples, dataType *buf)
 | 
			
		||||
{
 | 
			
		||||
    for (; nSamples > 0; nSamples--) {
 | 
			
		||||
    for (; nSamples > 0; nSamples--)
 | 
			
		||||
    {
 | 
			
		||||
        *buf++ = getSample();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float Generator::getFrequency() const { return frequency; }
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
float Generator<dataType>::getFrequency() const { return this->frequency; }
 | 
			
		||||
 | 
			
		||||
void Generator::setFrequency(float _frequency) { frequency = _frequency; }
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
void Generator<dataType>::setFrequency(float frequency) { this->frequency = frequency; }
 | 
			
		||||
 | 
			
		||||
bool Generator::isEnabled() const { return enabled; }
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
float Generator<dataType>::getAmplitude() const { return this->amplitude; }
 | 
			
		||||
 | 
			
		||||
void Generator::enable() { enabled = true; }
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
void Generator<dataType>::setAmplitude(float amplitude) { this->amplitude = amplitude; }
 | 
			
		||||
 | 
			
		||||
void Generator::disable() { enabled = false; }
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
bool Generator<dataType>::isEnabled() const { return enabled; }
 | 
			
		||||
 | 
			
		||||
SineGenerator::SineGenerator(
 | 
			
		||||
    uint32_t _sampleRate, float _frequency, float _amplitude = 1)
 | 
			
		||||
    : Generator(_sampleRate, _frequency, _amplitude)
 | 
			
		||||
    , instPhase(0)
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
void Generator<dataType>::enable() { enabled = true; }
 | 
			
		||||
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
void Generator<dataType>::disable() { enabled = false; }
 | 
			
		||||
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
SineGenerator<dataType>::SineGenerator(
 | 
			
		||||
    uint32_t _sampleRate, float _frequency, float _amplitude)
 | 
			
		||||
    : Generator<dataType>(_sampleRate, _frequency, _amplitude)
 | 
			
		||||
{
 | 
			
		||||
    mpfr_init_set_ui(instPhase, 0, MPFR_RNDN);
 | 
			
		||||
    mpfr_init(phaseIncr);
 | 
			
		||||
    mpfr_init(PI_2);
 | 
			
		||||
    mpfr_init(tmpA);
 | 
			
		||||
 | 
			
		||||
    mpfr_const_pi(PI_2, MPFR_RNDN);
 | 
			
		||||
    mpfr_mul_ui(PI_2, PI_2, 2, MPFR_RNDN);
 | 
			
		||||
 | 
			
		||||
    setFrequency(_frequency);
 | 
			
		||||
    enable();
 | 
			
		||||
    std::cout << "Constructed SineGenerator with freq " << frequency
 | 
			
		||||
              << " phaseIncr " << phaseIncr << std::endl;
 | 
			
		||||
    this->enable();
 | 
			
		||||
    std::cout << "Constructed SineGenerator with freq " << this->frequency
 | 
			
		||||
              << " phaseIncr " << mpfr_get_d(phaseIncr, MPFR_RNDN) << " rads/cycle" << std::endl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SineGenerator::~SineGenerator() {}
 | 
			
		||||
 | 
			
		||||
float SineGenerator::getSample()
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
SineGenerator<dataType>::~SineGenerator()
 | 
			
		||||
{
 | 
			
		||||
    if (instPhase > 2 * M_PI)
 | 
			
		||||
        instPhase -= 2 * M_PI;
 | 
			
		||||
    return cos(instPhase += phaseIncr) * amplitude;
 | 
			
		||||
    mpfr_clear(instPhase);
 | 
			
		||||
    mpfr_clear(phaseIncr);
 | 
			
		||||
    mpfr_clear(PI_2);
 | 
			
		||||
    mpfr_clear(tmpA);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SineGenerator::setFrequency(float _frequency)
 | 
			
		||||
template <>
 | 
			
		||||
float SineGenerator<float>::getSample()
 | 
			
		||||
{
 | 
			
		||||
    frequency = _frequency;
 | 
			
		||||
    phaseIncr = 2 * M_PI * frequency / sampleRate;
 | 
			
		||||
    mpfr_add(instPhase, instPhase, phaseIncr, MPFR_RNDN);
 | 
			
		||||
    if (mpfr_cmp(instPhase, PI_2) > 0)
 | 
			
		||||
    {
 | 
			
		||||
        mpfr_sub(instPhase, instPhase, PI_2, MPFR_RNDN);
 | 
			
		||||
    }
 | 
			
		||||
    mpfr_cos(tmpA, instPhase, MPFR_RNDN);
 | 
			
		||||
    mpfr_mul_d(tmpA, tmpA, this->amplitude, MPFR_RNDN);
 | 
			
		||||
 | 
			
		||||
    return mpfr_get_flt(tmpA, MPFR_RNDN);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SineSynth::SineSynth(uint32_t _sampleRate)
 | 
			
		||||
template <>
 | 
			
		||||
uint32_t SineGenerator<uint32_t>::getSample()
 | 
			
		||||
{
 | 
			
		||||
    mpfr_add(instPhase, instPhase, phaseIncr, MPFR_RNDN);
 | 
			
		||||
    if (mpfr_cmp(instPhase, PI_2) > 0)
 | 
			
		||||
    {
 | 
			
		||||
        mpfr_sub(instPhase, instPhase, PI_2, MPFR_RNDN);
 | 
			
		||||
    }
 | 
			
		||||
    mpfr_cos(tmpA, instPhase, MPFR_RNDN);
 | 
			
		||||
    mpfr_mul_d(tmpA, tmpA, this->amplitude, MPFR_RNDN);
 | 
			
		||||
    mpfr_mul_ui(tmpA, tmpA, (uint32_t)INT32_MAX+1, MPFR_RNDN);
 | 
			
		||||
 | 
			
		||||
    return (uint32_t)(mpfr_get_si(tmpA, MPFR_RNDN));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//phaseIncr = 2 * M_PI * this->frequency / this->sampleRate;
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
void SineGenerator<dataType>::setFrequency(mpfr_t _frequency)
 | 
			
		||||
{
 | 
			
		||||
    mpfr_mul(phaseIncr, PI_2, _frequency, MPFR_RNDN);
 | 
			
		||||
    mpfr_div_ui(phaseIncr, phaseIncr, this->sampleRate, MPFR_RNDN);
 | 
			
		||||
    this->frequency = mpfr_get_flt(_frequency, MPFR_RNDN);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
void SineGenerator<dataType>::setFrequency(float _frequency)
 | 
			
		||||
{
 | 
			
		||||
    mpfr_mul_d(phaseIncr, PI_2, _frequency, MPFR_RNDN);             // 2*pi*frequency
 | 
			
		||||
    mpfr_div_ui(phaseIncr, phaseIncr, this->sampleRate, MPFR_RNDN); // 2*pi*frequency / samplerate
 | 
			
		||||
    this->frequency = _frequency;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
SineSynth<dataType>::SineSynth(uint32_t _sampleRate)
 | 
			
		||||
    : sampleRate(_sampleRate)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SineSynth::addSynth(shared_ptr<Generator> synth)
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
void SineSynth<dataType>::addSynth(shared_ptr<Generator<dataType>> synth)
 | 
			
		||||
{
 | 
			
		||||
    generators.push_back(synth);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vector<shared_ptr<Generator>> SineSynth::getSynths() const
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
vector<shared_ptr<Generator<dataType>>> SineSynth<dataType>::getSynths() const
 | 
			
		||||
{
 | 
			
		||||
    return generators;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SineSynth::clearSynths() { generators.resize(0); }
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
void SineSynth<dataType>::clearSynths() { generators.resize(0); }
 | 
			
		||||
 | 
			
		||||
void SineSynth::getSamples(size_t nSamples, float* buf)
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
void SineSynth<dataType>::getSamples(size_t nSamples, dataType *buf)
 | 
			
		||||
{
 | 
			
		||||
    for (; nSamples > 0; nSamples--) {
 | 
			
		||||
    for (; nSamples > 0; nSamples--)
 | 
			
		||||
    {
 | 
			
		||||
        *buf = 0;
 | 
			
		||||
        for_each(std::begin(generators), std::end(generators),
 | 
			
		||||
            [buf](std::shared_ptr<Generator> g) {
 | 
			
		||||
                 [buf](std::shared_ptr<Generator<dataType>> g) {
 | 
			
		||||
                     if (g->isEnabled())
 | 
			
		||||
                         *buf += g->getSample();
 | 
			
		||||
                 });
 | 
			
		||||
@@ -85,112 +153,134 @@ void SineSynth::getSamples(size_t nSamples, float* buf)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const uint16_t NoiseGenerator::rateTable[]
 | 
			
		||||
    = { 0, 2048, 1536, 1280, 1024, 768, 640, 512, 384, 320, 256, 192, 160, 128,
 | 
			
		||||
          96, 80, 64, 48, 40, 32, 24, 20, 16, 12, 10, 8, 6, 5, 4, 3, 2, 1 };
 | 
			
		||||
 | 
			
		||||
NoiseGenerator::NoiseGenerator(
 | 
			
		||||
    uint32_t _sampleRate, uint8_t _rate, float _amplitude)
 | 
			
		||||
    : Generator(_sampleRate, 0, _amplitude)
 | 
			
		||||
    , level(-0x4000)
 | 
			
		||||
    , sampleCount(0)
 | 
			
		||||
    , rate(_rate)
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
NoiseGenerator<dataType>::NoiseGenerator(
 | 
			
		||||
    uint32_t _sampleRate, NOISE_TYPE type, float _amplitude)
 | 
			
		||||
    : Generator<dataType>(_sampleRate, 0, _amplitude), rand_gen()
 | 
			
		||||
{
 | 
			
		||||
    enable();
 | 
			
		||||
    this->enable();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NoiseGenerator::~NoiseGenerator() {}
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
NoiseGenerator<dataType>::~NoiseGenerator() {}
 | 
			
		||||
 | 
			
		||||
float NoiseGenerator::getSample()
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
dataType NoiseGenerator<dataType>::getSample()
 | 
			
		||||
{
 | 
			
		||||
    if (rate == 0)
 | 
			
		||||
        return 0;
 | 
			
		||||
    if (sampleCount++ % rateTable[rate] == 0) {
 | 
			
		||||
        auto retLevel = level;
 | 
			
		||||
        level = ((level >> 1) & 0x3fff)
 | 
			
		||||
            | (((level & 0x01) ^ ((level & 0x02) >> 1)) << 14);
 | 
			
		||||
        return (retLevel / 32768.0f) * amplitude;
 | 
			
		||||
    return std::uniform_real_distribution<float>(-this->amplitude, std::nextafter(this->amplitude, std::numeric_limits<float>::max()))(rand_gen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
JTestGenerator<dataType>::JTestGenerator(uint32_t sampleRate, uint8_t nbits) : Generator<dataType>(sampleRate, 0, 1)
 | 
			
		||||
{
 | 
			
		||||
    size_t loopLength;
 | 
			
		||||
    if (sampleRate % 250 == 0)
 | 
			
		||||
        loopLength = sampleRate / 250;
 | 
			
		||||
    else if (sampleRate % 245 == 0)
 | 
			
		||||
        loopLength = sampleRate / 245;
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        std::cerr << "Unable to generate non-integral fundamental frequency for JTest";
 | 
			
		||||
        exit(-1);
 | 
			
		||||
    }
 | 
			
		||||
    return (level / 32768.0f) * amplitude;
 | 
			
		||||
 | 
			
		||||
    this->loop.resize(loopLength);
 | 
			
		||||
 | 
			
		||||
    // Build signal
 | 
			
		||||
    const auto shift = nbits - 8;
 | 
			
		||||
    const uint8_t posbase = 0x40;
 | 
			
		||||
    const uint8_t negbase = 0xc0;
 | 
			
		||||
 | 
			
		||||
    const auto posval_first = posbase << shift;
 | 
			
		||||
    const auto negval_first = negbase << shift;
 | 
			
		||||
    const auto posval_last = posval_first - 1;
 | 
			
		||||
    const auto negval_last = negval_first - 1;
 | 
			
		||||
 | 
			
		||||
    for (auto i = 0; i < loopLength / 2; i += 4)
 | 
			
		||||
    {
 | 
			
		||||
        this->loop[i + 0] = negval_first;
 | 
			
		||||
        this->loop[i + 1] = negval_first;
 | 
			
		||||
        this->loop[i + 2] = posval_first;
 | 
			
		||||
        this->loop[i + 3] = posval_first;
 | 
			
		||||
    }
 | 
			
		||||
    for (auto i = loopLength / 2; i < loopLength; i += 4)
 | 
			
		||||
    {
 | 
			
		||||
        this->loop[i + 0] = negval_last;
 | 
			
		||||
        this->loop[i + 1] = negval_last;
 | 
			
		||||
        this->loop[i + 2] = posval_last;
 | 
			
		||||
        this->loop[i + 3] = posval_last;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this->pos = this->loop.begin();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const uint16_t SampleGenerator::gaussTable[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
 | 
			
		||||
    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1,
 | 
			
		||||
    0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x3, 0x3,
 | 
			
		||||
    0x3, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5, 0x5, 0x6, 0x6, 0x6,
 | 
			
		||||
    0x6, 0x7, 0x7, 0x7, 0x8, 0x8, 0x8, 0x9, 0x9, 0x9, 0xa, 0xa, 0xa, 0xb, 0xb,
 | 
			
		||||
    0xb, 0xc, 0xc, 0xd, 0xd, 0xe, 0xe, 0xf, 0xf, 0xf, 0x10, 0x10, 0x11, 0x11,
 | 
			
		||||
    0x12, 0x13, 0x13, 0x14, 0x14, 0x15, 0x15, 0x16, 0x17, 0x17, 0x18, 0x18,
 | 
			
		||||
    0x19, 0x1a, 0x1b, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0x1f, 0x20, 0x20, 0x21,
 | 
			
		||||
    0x22, 0x23, 0x24, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
 | 
			
		||||
    0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
 | 
			
		||||
    0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x40, 0x41, 0x42, 0x43, 0x45, 0x46, 0x47,
 | 
			
		||||
    0x49, 0x4a, 0x4c, 0x4d, 0x4e, 0x50, 0x51, 0x53, 0x54, 0x56, 0x57, 0x59,
 | 
			
		||||
    0x5a, 0x5c, 0x5e, 0x5f, 0x61, 0x63, 0x64, 0x66, 0x68, 0x6a, 0x6b, 0x6d,
 | 
			
		||||
    0x6f, 0x71, 0x73, 0x75, 0x76, 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84,
 | 
			
		||||
    0x86, 0x89, 0x8b, 0x8d, 0x8f, 0x91, 0x93, 0x96, 0x98, 0x9a, 0x9c, 0x9f,
 | 
			
		||||
    0xa1, 0xa3, 0xa6, 0xa8, 0xab, 0xad, 0xaf, 0xb2, 0xb4, 0xb7, 0xba, 0xbc,
 | 
			
		||||
    0xbf, 0xc1, 0xc4, 0xc7, 0xc9, 0xcc, 0xcf, 0xd2, 0xd4, 0xd7, 0xda, 0xdd,
 | 
			
		||||
    0xe0, 0xe3, 0xe6, 0xe9, 0xec, 0xef, 0xf2, 0xf5, 0xf8, 0xfb, 0xfe, 0x101,
 | 
			
		||||
    0x104, 0x107, 0x10b, 0x10e, 0x111, 0x114, 0x118, 0x11b, 0x11e, 0x122, 0x125,
 | 
			
		||||
    0x129, 0x12c, 0x130, 0x133, 0x137, 0x13a, 0x13e, 0x141, 0x145, 0x148, 0x14c,
 | 
			
		||||
    0x150, 0x153, 0x157, 0x15b, 0x15f, 0x162, 0x166, 0x16a, 0x16e, 0x172, 0x176,
 | 
			
		||||
    0x17a, 0x17d, 0x181, 0x185, 0x189, 0x18d, 0x191, 0x195, 0x19a, 0x19e, 0x1a2,
 | 
			
		||||
    0x1a6, 0x1aa, 0x1ae, 0x1b2, 0x1b7, 0x1bb, 0x1bf, 0x1c3, 0x1c8, 0x1cc, 0x1d0,
 | 
			
		||||
    0x1d5, 0x1d9, 0x1dd, 0x1e2, 0x1e6, 0x1eb, 0x1ef, 0x1f3, 0x1f8, 0x1fc, 0x201,
 | 
			
		||||
    0x205, 0x20a, 0x20f, 0x213, 0x218, 0x21c, 0x221, 0x226, 0x22a, 0x22f, 0x233,
 | 
			
		||||
    0x238, 0x23d, 0x241, 0x246, 0x24b, 0x250, 0x254, 0x259, 0x25e, 0x263, 0x267,
 | 
			
		||||
    0x26c, 0x271, 0x276, 0x27b, 0x280, 0x284, 0x289, 0x28e, 0x293, 0x298, 0x29d,
 | 
			
		||||
    0x2a2, 0x2a6, 0x2ab, 0x2b0, 0x2b5, 0x2ba, 0x2bf, 0x2c4, 0x2c9, 0x2ce, 0x2d3,
 | 
			
		||||
    0x2d8, 0x2dc, 0x2e1, 0x2e6, 0x2eb, 0x2f0, 0x2f5, 0x2fa, 0x2ff, 0x304, 0x309,
 | 
			
		||||
    0x30e, 0x313, 0x318, 0x31d, 0x322, 0x326, 0x32b, 0x330, 0x335, 0x33a, 0x33f,
 | 
			
		||||
    0x344, 0x349, 0x34e, 0x353, 0x357, 0x35c, 0x361, 0x366, 0x36b, 0x370, 0x374,
 | 
			
		||||
    0x379, 0x37e, 0x383, 0x388, 0x38c, 0x391, 0x396, 0x39b, 0x39f, 0x3a4, 0x3a9,
 | 
			
		||||
    0x3ad, 0x3b2, 0x3b7, 0x3bb, 0x3c0, 0x3c5, 0x3c9, 0x3ce, 0x3d2, 0x3d7, 0x3dc,
 | 
			
		||||
    0x3e0, 0x3e5, 0x3e9, 0x3ed, 0x3f2, 0x3f6, 0x3fb, 0x3ff, 0x403, 0x408, 0x40c,
 | 
			
		||||
    0x410, 0x415, 0x419, 0x41d, 0x421, 0x425, 0x42a, 0x42e, 0x432, 0x436, 0x43a,
 | 
			
		||||
    0x43e, 0x442, 0x446, 0x44a, 0x44e, 0x452, 0x455, 0x459, 0x45d, 0x461, 0x465,
 | 
			
		||||
    0x468, 0x46c, 0x470, 0x473, 0x477, 0x47a, 0x47e, 0x481, 0x485, 0x488, 0x48c,
 | 
			
		||||
    0x48f, 0x492, 0x496, 0x499, 0x49c, 0x49f, 0x4a2, 0x4a6, 0x4a9, 0x4ac, 0x4af,
 | 
			
		||||
    0x4b2, 0x4b5, 0x4b7, 0x4ba, 0x4bd, 0x4c0, 0x4c3, 0x4c5, 0x4c8, 0x4cb, 0x4cd,
 | 
			
		||||
    0x4d0, 0x4d2, 0x4d5, 0x4d7, 0x4d9, 0x4dc, 0x4de, 0x4e0, 0x4e3, 0x4e5, 0x4e7,
 | 
			
		||||
    0x4e9, 0x4eb, 0x4ed, 0x4ef, 0x4f1, 0x4f3, 0x4f5, 0x4f6, 0x4f8, 0x4fa, 0x4fb,
 | 
			
		||||
    0x4fd, 0x4ff, 0x500, 0x502, 0x503, 0x504, 0x506, 0x507, 0x508, 0x50a, 0x50b,
 | 
			
		||||
    0x50c, 0x50d, 0x50e, 0x50f, 0x510, 0x511, 0x511, 0x512, 0x513, 0x514, 0x514,
 | 
			
		||||
    0x515, 0x516, 0x516, 0x517, 0x517, 0x517, 0x518, 0x518, 0x518, 0x518, 0x518,
 | 
			
		||||
    0x519, 0x519 };
 | 
			
		||||
 | 
			
		||||
SampleGenerator::SampleGenerator(uint32_t _sampleRate, uint16_t _playbackRate,
 | 
			
		||||
    float _amplitude, size_t nSamples, const float* samples)
 | 
			
		||||
    : Generator(_sampleRate, 0, _amplitude)
 | 
			
		||||
    , playbackRate(_playbackRate)
 | 
			
		||||
    , counter(0)
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
dataType JTestGenerator<dataType>::getSample()
 | 
			
		||||
{
 | 
			
		||||
    oldest = older = old = 0;
 | 
			
		||||
    enable();
 | 
			
		||||
    sample.resize(nSamples);
 | 
			
		||||
    for (auto i = std::begin(sample); i != std::end(sample); i++)
 | 
			
		||||
        *i = *samples++;
 | 
			
		||||
    if (this->pos == this->loop.end())
 | 
			
		||||
        this->pos = this->loop.begin();
 | 
			
		||||
    return *(this->pos++);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SampleGenerator::~SampleGenerator() {}
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
JTestGenerator<dataType>::~JTestGenerator() {}
 | 
			
		||||
 | 
			
		||||
float SampleGenerator::getSample()
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
SweepGenerator<dataType>::SweepGenerator(uint32_t sampleRate, float startFreq, float endFreq, float length, float amplitude) : Generator<dataType>(sampleRate, startFreq, amplitude),
 | 
			
		||||
                                                                                                                               sg(sampleRate, startFreq, amplitude)
 | 
			
		||||
{
 | 
			
		||||
    counter += playbackRate;
 | 
			
		||||
    if ((counter >> 12) > sample.size())
 | 
			
		||||
        counter &= 0xfff;
 | 
			
		||||
    this->enable();
 | 
			
		||||
    mpfr_init(freqStep);
 | 
			
		||||
    mpfr_init_set_d(this->startFreq, startFreq, MPFR_RNDN);
 | 
			
		||||
    mpfr_init_set(curFreq, this->startFreq, MPFR_RNDN);
 | 
			
		||||
    mpfr_init_set_d(this->endFreq, endFreq, MPFR_RNDN);
 | 
			
		||||
 | 
			
		||||
    auto gaussIndex = (counter >> 4) & 0x3f;
 | 
			
		||||
    float out = ((gaussTable[0xff - gaussIndex] / 32768.0f * oldest) / 1024);
 | 
			
		||||
    out += ((gaussTable[0x1ff - gaussIndex] / 32768.0f * older) / 1024);
 | 
			
		||||
    out += ((gaussTable[0x100 + gaussIndex] / 32768.0f * old) / 1024);
 | 
			
		||||
    out += ((gaussTable[0x000 + gaussIndex] / 32768.0f * sample[counter>>12]) / 1024);
 | 
			
		||||
    out /= 2;
 | 
			
		||||
 | 
			
		||||
    oldest = older;
 | 
			
		||||
    older = old;
 | 
			
		||||
    old = sample[counter>>12];
 | 
			
		||||
 | 
			
		||||
    return out * amplitude;
 | 
			
		||||
    // Linear frequency step = ((endFreq - startFreq) / length) / sampleRate
 | 
			
		||||
    mpfr_sub(freqStep, this->endFreq, this->startFreq, MPFR_RNDN);
 | 
			
		||||
    mpfr_div_d(freqStep, freqStep, length, MPFR_RNDN);
 | 
			
		||||
    mpfr_div_ui(freqStep, freqStep, sampleRate, MPFR_RNDN);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
SweepGenerator<dataType>::~SweepGenerator()
 | 
			
		||||
{
 | 
			
		||||
    mpfr_clear(startFreq);
 | 
			
		||||
    mpfr_clear(curFreq);
 | 
			
		||||
    mpfr_clear(endFreq);
 | 
			
		||||
    mpfr_clear(freqStep);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
dataType SweepGenerator<dataType>::getSample()
 | 
			
		||||
{
 | 
			
		||||
    dataType sample = sg.getSample();
 | 
			
		||||
    mpfr_add(curFreq, curFreq, freqStep, MPFR_RNDN);
 | 
			
		||||
    if (mpfr_cmp(curFreq, endFreq) > 0)
 | 
			
		||||
    {
 | 
			
		||||
        mpfr_set(curFreq, startFreq, MPFR_RNDN);
 | 
			
		||||
    }
 | 
			
		||||
    sg.setFrequency(curFreq);
 | 
			
		||||
    return sample;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
float SweepGenerator<dataType>::getFrequency() const
 | 
			
		||||
{
 | 
			
		||||
    return mpfr_get_flt(curFreq, MPFR_RNDN);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename dataType>
 | 
			
		||||
void SweepGenerator<dataType>::setAmplitude(float amplitude) {
 | 
			
		||||
    sg.setAmplitude(amplitude);
 | 
			
		||||
    this->amplitude = amplitude;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template class NoiseGenerator<float>;
 | 
			
		||||
template class SineGenerator<float>;
 | 
			
		||||
template class SweepGenerator<float>;
 | 
			
		||||
template class SineSynth<float>;
 | 
			
		||||
 | 
			
		||||
template class SineSynth<uint32_t>;
 | 
			
		||||
template class SineGenerator<uint32_t>;
 | 
			
		||||
template class JTestGenerator<uint32_t>;
 | 
			
		||||
template class SweepGenerator<uint32_t>;
 | 
			
		||||
							
								
								
									
										211
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										211
									
								
								src/main.cpp
									
									
									
									
									
								
							@@ -1,7 +1,9 @@
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
#include <curses.h>
 | 
			
		||||
#include <pulse/error.h>
 | 
			
		||||
@@ -9,57 +11,17 @@
 | 
			
		||||
 | 
			
		||||
#include "SineSynth.h"
 | 
			
		||||
 | 
			
		||||
WINDOW* win;
 | 
			
		||||
WINDOW *win;
 | 
			
		||||
 | 
			
		||||
constexpr int SAMPLERATE = 32000;
 | 
			
		||||
constexpr size_t BUFSIZE = 64;
 | 
			
		||||
constexpr int SAMPLERATE = 48000;
 | 
			
		||||
constexpr size_t BUFSIZE = (48000/1000)*4;
 | 
			
		||||
 | 
			
		||||
void majorChord(SineSynth& synth, const double root)
 | 
			
		||||
{
 | 
			
		||||
    wprintw(win, "majorChord root: %f\n", root);
 | 
			
		||||
    if (synth.getSynths().size() != 3) {
 | 
			
		||||
        synth.clearSynths();
 | 
			
		||||
        auto sg = std::make_shared<SineGenerator>(SAMPLERATE, root, 0.1);
 | 
			
		||||
        synth.addSynth(sg);
 | 
			
		||||
        sg = std::make_shared<SineGenerator>(
 | 
			
		||||
            SAMPLERATE, root * pow(2, 4.0 / 12.0), 0.1);
 | 
			
		||||
        synth.addSynth(sg);
 | 
			
		||||
        sg = std::make_shared<SineGenerator>(
 | 
			
		||||
            SAMPLERATE, root * pow(2, 7.0 / 12.0), 0.1);
 | 
			
		||||
        synth.addSynth(sg);
 | 
			
		||||
    } else {
 | 
			
		||||
        auto synths = synth.getSynths();
 | 
			
		||||
        synths[0]->setFrequency(root);
 | 
			
		||||
        synths[1]->setFrequency(root * pow(2, 4.0 / 12.0));
 | 
			
		||||
        synths[2]->setFrequency(root * pow(2, 7.0 / 12.0));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#define SAMPTYPE    uint32_t
 | 
			
		||||
 | 
			
		||||
void minorChord(SineSynth& synth, const double root)
 | 
			
		||||
{
 | 
			
		||||
    wprintw(win, "minorChord root: %f\n", root);
 | 
			
		||||
    if (synth.getSynths().size() != 3) {
 | 
			
		||||
        synth.clearSynths();
 | 
			
		||||
        auto sg = std::make_shared<SineGenerator>(SAMPLERATE, root, 0.1);
 | 
			
		||||
        synth.addSynth(sg);
 | 
			
		||||
        sg = std::make_shared<SineGenerator>(
 | 
			
		||||
            SAMPLERATE, root * pow(2, 3.0 / 12.0), 0.1);
 | 
			
		||||
        synth.addSynth(sg);
 | 
			
		||||
        sg = std::make_shared<SineGenerator>(
 | 
			
		||||
            SAMPLERATE, root * pow(2, 7.0 / 12.0), 0.1);
 | 
			
		||||
        synth.addSynth(sg);
 | 
			
		||||
    } else {
 | 
			
		||||
        auto synths = synth.getSynths();
 | 
			
		||||
        synths[0]->setFrequency(root);
 | 
			
		||||
        synths[1]->setFrequency(root * pow(2, 3.0 / 12.0));
 | 
			
		||||
        synths[2]->setFrequency(root * pow(2, 7.0 / 12.0));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WINDOW*
 | 
			
		||||
WINDOW *
 | 
			
		||||
init_curses()
 | 
			
		||||
{
 | 
			
		||||
    WINDOW* win = initscr();
 | 
			
		||||
    WINDOW *win = initscr();
 | 
			
		||||
    nodelay(win, TRUE);
 | 
			
		||||
    keypad(win, TRUE);
 | 
			
		||||
    cbreak();
 | 
			
		||||
@@ -67,15 +29,15 @@ init_curses()
 | 
			
		||||
    return win;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pa_simple*
 | 
			
		||||
pa_simple *
 | 
			
		||||
init_pulse()
 | 
			
		||||
{
 | 
			
		||||
    static const pa_sample_spec ss = { .format = PA_SAMPLE_FLOAT32,
 | 
			
		||||
    static const pa_sample_spec ss = {.format = PA_SAMPLE_S32NE,
 | 
			
		||||
                                      .rate = SAMPLERATE,
 | 
			
		||||
        .channels = 1 };
 | 
			
		||||
                                      .channels = 1};
 | 
			
		||||
 | 
			
		||||
    int error = 0;
 | 
			
		||||
    pa_simple* s = pa_simple_new(NULL,
 | 
			
		||||
    pa_simple *s = pa_simple_new(NULL,
 | 
			
		||||
                                 "sinesynth",
 | 
			
		||||
                                 PA_STREAM_PLAYBACK,
 | 
			
		||||
                                 NULL,
 | 
			
		||||
@@ -84,7 +46,8 @@ init_pulse()
 | 
			
		||||
                                 NULL,
 | 
			
		||||
                                 NULL,
 | 
			
		||||
                                 &error);
 | 
			
		||||
    if (error) {
 | 
			
		||||
    if (error)
 | 
			
		||||
    {
 | 
			
		||||
        std::cerr << "Error initializing PulseAudio: " << pa_strerror(error) << " ("
 | 
			
		||||
                  << error << ")" << std::endl;
 | 
			
		||||
        exit(-1);
 | 
			
		||||
@@ -93,81 +56,48 @@ init_pulse()
 | 
			
		||||
    return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const float testSample[] = { 0.0,
 | 
			
		||||
    0.0980171403295606,
 | 
			
		||||
    0.19509032201612825,
 | 
			
		||||
    0.29028467725446233,
 | 
			
		||||
    0.3826834323650898,
 | 
			
		||||
    0.47139673682599764,
 | 
			
		||||
    0.5555702330196022,
 | 
			
		||||
    0.6343932841636455,
 | 
			
		||||
    0.7071067811865475,
 | 
			
		||||
    0.773010453362737,
 | 
			
		||||
    0.8314696123025452,
 | 
			
		||||
    0.8819212643483549,
 | 
			
		||||
    0.9238795325112867,
 | 
			
		||||
    0.9569403357322089,
 | 
			
		||||
    0.9807852804032304,
 | 
			
		||||
    0.9951847266721968,
 | 
			
		||||
    1.0,
 | 
			
		||||
    0.9951847266721969,
 | 
			
		||||
    0.9807852804032304,
 | 
			
		||||
    0.9569403357322089,
 | 
			
		||||
    0.9238795325112867,
 | 
			
		||||
    0.881921264348355,
 | 
			
		||||
    0.8314696123025455,
 | 
			
		||||
    0.7730104533627371,
 | 
			
		||||
    0.7071067811865476,
 | 
			
		||||
    0.6343932841636455,
 | 
			
		||||
    0.5555702330196022,
 | 
			
		||||
    0.47139673682599786,
 | 
			
		||||
    0.3826834323650899,
 | 
			
		||||
    0.2902846772544624,
 | 
			
		||||
    0.1950903220161286,
 | 
			
		||||
    0.09801714032956083,
 | 
			
		||||
    1.2246467991473532e-16,
 | 
			
		||||
    -0.09801714032956059,
 | 
			
		||||
    -0.19509032201612836,
 | 
			
		||||
    -0.2902846772544621,
 | 
			
		||||
    -0.38268343236508967,
 | 
			
		||||
    -0.47139673682599764,
 | 
			
		||||
    -0.555570233019602,
 | 
			
		||||
    -0.6343932841636453,
 | 
			
		||||
    -0.7071067811865475,
 | 
			
		||||
    -0.7730104533627367,
 | 
			
		||||
    -0.8314696123025452,
 | 
			
		||||
    -0.8819212643483549,
 | 
			
		||||
    -0.9238795325112865,
 | 
			
		||||
    -0.9569403357322088,
 | 
			
		||||
    -0.9807852804032303,
 | 
			
		||||
    -0.9951847266721969,
 | 
			
		||||
    -1.0,
 | 
			
		||||
    -0.9951847266721969,
 | 
			
		||||
    -0.9807852804032304,
 | 
			
		||||
    -0.9569403357322089,
 | 
			
		||||
    -0.9238795325112866,
 | 
			
		||||
    -0.881921264348355,
 | 
			
		||||
    -0.8314696123025455,
 | 
			
		||||
    -0.7730104533627369,
 | 
			
		||||
    -0.7071067811865477,
 | 
			
		||||
    -0.6343932841636459,
 | 
			
		||||
    -0.5555702330196022,
 | 
			
		||||
    -0.4713967368259979,
 | 
			
		||||
    -0.3826834323650904,
 | 
			
		||||
    -0.2902846772544625,
 | 
			
		||||
    -0.19509032201612872,
 | 
			
		||||
    -0.0980171403295605 };
 | 
			
		||||
template <typename T>
 | 
			
		||||
void smpte_imd_test(SineSynth<T> &synth) {
 | 
			
		||||
    synth.clearSynths();
 | 
			
		||||
    synth.addSynth(std::make_shared<SineGenerator<T>>(
 | 
			
		||||
        SAMPLERATE, 60, 0.8
 | 
			
		||||
    ));
 | 
			
		||||
    synth.addSynth(std::make_shared<SineGenerator<T>>(
 | 
			
		||||
        SAMPLERATE, 7000, 0.2
 | 
			
		||||
    ));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char* argv[])
 | 
			
		||||
template <typename T>
 | 
			
		||||
void ccif_imd_test(SineSynth<T> &synth, float amplitude) {
 | 
			
		||||
    assert(amplitude >= 0 && amplitude <= 1);
 | 
			
		||||
    synth.clearSynths();
 | 
			
		||||
    synth.addSynth(std::make_shared<SineGenerator<T>>(
 | 
			
		||||
        SAMPLERATE, 19000, amplitude / 2
 | 
			
		||||
    ));
 | 
			
		||||
    synth.addSynth(std::make_shared<SineGenerator<T>>(
 | 
			
		||||
        SAMPLERATE, 20000, amplitude / 2
 | 
			
		||||
    ));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
    SineSynth synth(SAMPLERATE);
 | 
			
		||||
    auto noise = std::make_shared<NoiseGenerator>(SAMPLERATE, 0x1f, 0.1);
 | 
			
		||||
    //synth.addSynth(noise);
 | 
			
		||||
    auto sampled = std::make_shared<SampleGenerator>(SAMPLERATE, 0x1000, 0.1, sizeof(testSample)/sizeof(float), testSample);
 | 
			
		||||
    synth.addSynth(sampled);
 | 
			
		||||
    SineSynth<SAMPTYPE> synth(SAMPLERATE);
 | 
			
		||||
    auto gen = std::make_shared<SineGenerator<SAMPTYPE>>(SAMPLERATE, 1000, 1);
 | 
			
		||||
    synth.addSynth(gen);
 | 
			
		||||
    SAMPTYPE buf2[BUFSIZE];
 | 
			
		||||
    synth.getSamples(BUFSIZE, buf2);
 | 
			
		||||
    for (auto i = 0; i < BUFSIZE; i++)
 | 
			
		||||
        std::cout << i << "," << (int32_t)buf2[i] << std::endl;
 | 
			
		||||
 | 
			
		||||
    sampled->enable();
 | 
			
		||||
    noise->disable();
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
    // auto gen = std::make_shared<SweepGenerator<SAMPTYPE>>(SAMPLERATE, 10, 10000, 5, 1);
 | 
			
		||||
    // synth.addSynth(gen);
 | 
			
		||||
 | 
			
		||||
    // auto gen2 = std::make_shared<JTestGenerator<uint32_t>>(SAMPLERATE, 32);
 | 
			
		||||
    // synth.addSynth(gen2);
 | 
			
		||||
 | 
			
		||||
    //smpte_imd_test(synth);
 | 
			
		||||
 | 
			
		||||
    auto s = init_pulse();
 | 
			
		||||
    auto win = init_curses();
 | 
			
		||||
@@ -182,26 +112,39 @@ int main(int argc, char* argv[])
 | 
			
		||||
            error,
 | 
			
		||||
            latency);
 | 
			
		||||
 | 
			
		||||
    float buf[BUFSIZE];
 | 
			
		||||
    SAMPTYPE buf[BUFSIZE];
 | 
			
		||||
    long long i;
 | 
			
		||||
    mvwprintw(win, 2, 0, "Loops: ");
 | 
			
		||||
    mvwprintw(win, 3, 0, "Rate: ");
 | 
			
		||||
    for (i = 0;; i++) {
 | 
			
		||||
    mvwprintw(win, 3, 0, "Freq: ");
 | 
			
		||||
    mvwprintw(win, 4, 0, "Ampl: ");
 | 
			
		||||
    for (i = 0;; i++)
 | 
			
		||||
    {
 | 
			
		||||
        auto c = getch();
 | 
			
		||||
        switch (c) {
 | 
			
		||||
        switch (c)
 | 
			
		||||
        {
 | 
			
		||||
        case KEY_UP:
 | 
			
		||||
            sampled->playbackRate+=8;
 | 
			
		||||
            sampled->playbackRate &= 0x3fff;
 | 
			
		||||
            gen->setFrequency(gen->getFrequency() + 100);
 | 
			
		||||
            break;
 | 
			
		||||
        case KEY_DOWN:
 | 
			
		||||
            sampled->playbackRate-=8;
 | 
			
		||||
            sampled->playbackRate &= 0x3fff;
 | 
			
		||||
            gen->setFrequency(gen->getFrequency() - 100);
 | 
			
		||||
            break;
 | 
			
		||||
        case '+':
 | 
			
		||||
            gen->setAmplitude(gen->getAmplitude() + 0.1);
 | 
			
		||||
            break;
 | 
			
		||||
        case '-':
 | 
			
		||||
            gen->setAmplitude(gen->getAmplitude() - 0.1);
 | 
			
		||||
            break;
 | 
			
		||||
        case 'q':
 | 
			
		||||
        case 'Q':
 | 
			
		||||
            endwin();
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        synth.getSamples(BUFSIZE, buf);
 | 
			
		||||
        pa_simple_write(s, buf, sizeof(buf), &error);
 | 
			
		||||
        mvwprintw(win, 2, 8, "%d", i);
 | 
			
		||||
        mvwprintw(win, 3, 7, "%2x", sampled->playbackRate);
 | 
			
		||||
        mvwprintw(win, 2, 8, "%6d", i);
 | 
			
		||||
        mvwprintw(win, 3, 8, "%6.0f", gen->getFrequency());
 | 
			
		||||
        mvwprintw(win, 4, 9, "%1.3f (%f)", gen->getAmplitude(), 20 * log10(gen->getAmplitude()/1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    endwin();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user