Updates
This commit is contained in:
parent
b0a7cd9fae
commit
d1a57b09af
7
CMakeLists.txt
Normal file → Executable file
7
CMakeLists.txt
Normal file → Executable file
@ -10,7 +10,12 @@ if(PULSEAUDIO_FOUND)
|
|||||||
include_directories(${PULSEAUDIO_INCLUDE_DIR})
|
include_directories(${PULSEAUDIO_INCLUDE_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(SINESYNTH_LIBS ${PULSEAUDIO_LIBRARY} pulse-simple)
|
find_package(Curses)
|
||||||
|
if (CURSES_FOUND)
|
||||||
|
include_directories(${CURSES_INCLUDE_DIRS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(SINESYNTH_LIBS ${PULSEAUDIO_LIBRARY} ${CURSES_LIBRARIES} pulse-simple tinfo)
|
||||||
|
|
||||||
file(GLOB SOURCES "src/*.cpp")
|
file(GLOB SOURCES "src/*.cpp")
|
||||||
|
|
||||||
|
91
include/SineSynth.h
Normal file → Executable file
91
include/SineSynth.h
Normal file → Executable file
@ -1,49 +1,106 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <algorithm>
|
||||||
#include <vector>
|
|
||||||
#include <iterator>
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using std::shared_ptr;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using std::iterator_traits;
|
|
||||||
|
|
||||||
using std::sin;
|
|
||||||
using std::cos;
|
using std::cos;
|
||||||
|
using std::for_each;
|
||||||
|
using std::sin;
|
||||||
|
|
||||||
class Generator
|
class Generator {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
virtual void getSamples(const uint16_t nSamples, float *buf) = 0;
|
virtual float getSample() = 0;
|
||||||
|
virtual void getSamples(size_t nSamples, float* buf);
|
||||||
|
|
||||||
|
virtual float getFrequency() const;
|
||||||
|
virtual void setFrequency(float _frequency);
|
||||||
|
|
||||||
|
virtual bool isEnabled() const;
|
||||||
|
virtual void enable();
|
||||||
|
virtual void disable();
|
||||||
|
|
||||||
virtual ~Generator();
|
virtual ~Generator();
|
||||||
|
|
||||||
// disallow copy of virtual interface
|
// disallow copy of virtual interface
|
||||||
Generator(Generator const &) = delete;
|
Generator(Generator const&) = delete;
|
||||||
Generator &operator=(Generator const &) = delete;
|
Generator& operator=(Generator const&) = delete;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Generator(uint32_t _sampleRate, float _frequency, float _amplitude);
|
Generator(uint32_t _sampleRate, float _frequency, float _amplitude);
|
||||||
uint32_t sampleRate;
|
uint32_t sampleRate;
|
||||||
float frequency;
|
float frequency;
|
||||||
float amplitude;
|
float amplitude;
|
||||||
|
bool enabled;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class SineGenerator : public Generator
|
class SineGenerator : public Generator {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
SineGenerator(uint32_t _sampleRate, float _frequency, float _amplitude);
|
SineGenerator(uint32_t _sampleRate, float _frequency, float _amplitude);
|
||||||
void getSamples(uint16_t nSamples, float *buf) final;
|
|
||||||
|
float getSample() final;
|
||||||
|
|
||||||
|
void setFrequency(float _frequency) final;
|
||||||
|
|
||||||
virtual ~SineGenerator();
|
virtual ~SineGenerator();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t tick;
|
float instPhase;
|
||||||
float phaseIncr;
|
float phaseIncr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SineSynth
|
class NoiseGenerator : public Generator {
|
||||||
{
|
public:
|
||||||
|
NoiseGenerator(uint32_t _sampleRate, uint8_t rate, float _amplitude);
|
||||||
|
|
||||||
|
float getSample() final;
|
||||||
|
virtual ~NoiseGenerator();
|
||||||
|
|
||||||
|
uint8_t rate;
|
||||||
|
static const uint16_t rateTable[];
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vector<SineGenerator> generators;
|
int16_t level;
|
||||||
|
uint16_t sampleCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SampleGenerator : public Generator {
|
||||||
|
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);
|
||||||
|
|
||||||
|
float getSample() final;
|
||||||
|
virtual ~SampleGenerator();
|
||||||
|
|
||||||
|
uint16_t playbackRate;
|
||||||
|
|
||||||
|
private:
|
||||||
|
vector<float> sample;
|
||||||
|
float oldest, older, old;
|
||||||
|
uint32_t counter;
|
||||||
|
static const uint16_t gaussTable[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class SineSynth {
|
||||||
|
public:
|
||||||
|
SineSynth(uint32_t _sampleRate);
|
||||||
|
|
||||||
|
void addSynth(shared_ptr<Generator>);
|
||||||
|
vector<shared_ptr<Generator>> getSynths() const;
|
||||||
|
void clearSynths();
|
||||||
|
|
||||||
|
void getSamples(size_t nSamples, float* buf);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t sampleRate;
|
||||||
|
vector<shared_ptr<Generator>> generators;
|
||||||
};
|
};
|
204
src/SineSynth.cpp
Normal file → Executable file
204
src/SineSynth.cpp
Normal file → Executable file
@ -2,27 +2,195 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
Generator::Generator(uint32_t _sampleRate, float _frequency, float _amplitude) : sampleRate(_sampleRate), frequency(_frequency), amplitude(_amplitude)
|
Generator::Generator(uint32_t _sampleRate, float _frequency, float _amplitude)
|
||||||
|
: sampleRate(_sampleRate)
|
||||||
|
, frequency(_frequency)
|
||||||
|
, amplitude(_amplitude)
|
||||||
|
, enabled(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Generator::~Generator()
|
Generator::~Generator() {}
|
||||||
|
|
||||||
|
void Generator::getSamples(size_t nSamples, float* buf)
|
||||||
{
|
{
|
||||||
}
|
for (; nSamples > 0; nSamples--) {
|
||||||
|
*buf++ = getSample();
|
||||||
SineGenerator::SineGenerator(uint32_t _sampleRate, float _frequency, float _amplitude = 1) : Generator(_sampleRate, _frequency, _amplitude), tick(0) {
|
|
||||||
phaseIncr = 2 * M_PI * frequency / sampleRate;
|
|
||||||
|
|
||||||
std::cout << "Constructed SineGenerator with freq " << frequency << " phaseIncr " << phaseIncr << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
SineGenerator::~SineGenerator() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void SineGenerator::getSamples(uint16_t nSamples, float *buf) {
|
|
||||||
for (;nSamples>0;nSamples--) {
|
|
||||||
std::cout << "Generating tick " << tick << std::endl;
|
|
||||||
*buf++ = cos(phaseIncr * tick++) * amplitude;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float Generator::getFrequency() const { return frequency; }
|
||||||
|
|
||||||
|
void Generator::setFrequency(float _frequency) { frequency = _frequency; }
|
||||||
|
|
||||||
|
bool Generator::isEnabled() const { return enabled; }
|
||||||
|
|
||||||
|
void Generator::enable() { enabled = true; }
|
||||||
|
|
||||||
|
void Generator::disable() { enabled = false; }
|
||||||
|
|
||||||
|
SineGenerator::SineGenerator(
|
||||||
|
uint32_t _sampleRate, float _frequency, float _amplitude = 1)
|
||||||
|
: Generator(_sampleRate, _frequency, _amplitude)
|
||||||
|
, instPhase(0)
|
||||||
|
{
|
||||||
|
setFrequency(_frequency);
|
||||||
|
enable();
|
||||||
|
std::cout << "Constructed SineGenerator with freq " << frequency
|
||||||
|
<< " phaseIncr " << phaseIncr << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
SineGenerator::~SineGenerator() {}
|
||||||
|
|
||||||
|
float SineGenerator::getSample()
|
||||||
|
{
|
||||||
|
if (instPhase > 2 * M_PI)
|
||||||
|
instPhase -= 2 * M_PI;
|
||||||
|
return cos(instPhase += phaseIncr) * amplitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SineGenerator::setFrequency(float _frequency)
|
||||||
|
{
|
||||||
|
frequency = _frequency;
|
||||||
|
phaseIncr = 2 * M_PI * frequency / sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
SineSynth::SineSynth(uint32_t _sampleRate)
|
||||||
|
: sampleRate(_sampleRate)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SineSynth::addSynth(shared_ptr<Generator> synth)
|
||||||
|
{
|
||||||
|
generators.push_back(synth);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<shared_ptr<Generator>> SineSynth::getSynths() const
|
||||||
|
{
|
||||||
|
return generators;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SineSynth::clearSynths() { generators.resize(0); }
|
||||||
|
|
||||||
|
void SineSynth::getSamples(size_t nSamples, float* buf)
|
||||||
|
{
|
||||||
|
for (; nSamples > 0; nSamples--) {
|
||||||
|
*buf = 0;
|
||||||
|
for_each(std::begin(generators), std::end(generators),
|
||||||
|
[buf](std::shared_ptr<Generator> g) {
|
||||||
|
if (g->isEnabled())
|
||||||
|
*buf += g->getSample();
|
||||||
|
});
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
NoiseGenerator::~NoiseGenerator() {}
|
||||||
|
|
||||||
|
float NoiseGenerator::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 (level / 32768.0f) * amplitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
oldest = older = old = 0;
|
||||||
|
enable();
|
||||||
|
sample.resize(nSamples);
|
||||||
|
for (auto i = std::begin(sample); i != std::end(sample); i++)
|
||||||
|
*i = *samples++;
|
||||||
|
}
|
||||||
|
|
||||||
|
SampleGenerator::~SampleGenerator() {}
|
||||||
|
|
||||||
|
float SampleGenerator::getSample()
|
||||||
|
{
|
||||||
|
counter += playbackRate;
|
||||||
|
if ((counter >> 12) > sample.size())
|
||||||
|
counter &= 0xfff;
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
213
src/main.cpp
Normal file → Executable file
213
src/main.cpp
Normal file → Executable file
@ -1,23 +1,208 @@
|
|||||||
|
#include <cmath>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <curses.h>
|
||||||
|
#include <pulse/error.h>
|
||||||
#include <pulse/simple.h>
|
#include <pulse/simple.h>
|
||||||
|
|
||||||
#include "SineSynth.h"
|
#include "SineSynth.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
WINDOW* win;
|
||||||
SineGenerator sg(44100, 440.0f, 0.1);
|
|
||||||
static const pa_sample_spec ss = {
|
|
||||||
.format = PA_SAMPLE_FLOAT32,
|
|
||||||
.rate = 44100,
|
|
||||||
.channels = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
pa_simple *s = NULL;
|
constexpr int SAMPLERATE = 32000;
|
||||||
int error;
|
constexpr size_t BUFSIZE = 64;
|
||||||
s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &error);
|
|
||||||
|
|
||||||
float buf[1024];
|
void majorChord(SineSynth& synth, const double root)
|
||||||
for (;;) {
|
{
|
||||||
sg.getSamples(1024, buf);
|
wprintw(win, "majorChord root: %f\n", root);
|
||||||
pa_simple_write(s, buf, sizeof(buf), &error);
|
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));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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*
|
||||||
|
init_curses()
|
||||||
|
{
|
||||||
|
WINDOW* win = initscr();
|
||||||
|
nodelay(win, TRUE);
|
||||||
|
keypad(win, TRUE);
|
||||||
|
cbreak();
|
||||||
|
|
||||||
|
return win;
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_simple*
|
||||||
|
init_pulse()
|
||||||
|
{
|
||||||
|
static const pa_sample_spec ss = { .format = PA_SAMPLE_FLOAT32,
|
||||||
|
.rate = SAMPLERATE,
|
||||||
|
.channels = 1 };
|
||||||
|
|
||||||
|
int error = 0;
|
||||||
|
pa_simple* s = pa_simple_new(NULL,
|
||||||
|
"sinesynth",
|
||||||
|
PA_STREAM_PLAYBACK,
|
||||||
|
NULL,
|
||||||
|
"playback",
|
||||||
|
&ss,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&error);
|
||||||
|
if (error) {
|
||||||
|
std::cerr << "Error initializing PulseAudio: " << pa_strerror(error) << " ("
|
||||||
|
<< error << ")" << std::endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 };
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
sampled->enable();
|
||||||
|
noise->disable();
|
||||||
|
|
||||||
|
auto s = init_pulse();
|
||||||
|
auto win = init_curses();
|
||||||
|
|
||||||
|
mvwprintw(win, 0, 0, "Initialized\n");
|
||||||
|
|
||||||
|
int error = 0;
|
||||||
|
pa_usec_t latency = pa_simple_get_latency(s, &error);
|
||||||
|
wprintw(win,
|
||||||
|
"Error: %s (%d) Latency: %d usec\n",
|
||||||
|
pa_strerror(error),
|
||||||
|
error,
|
||||||
|
latency);
|
||||||
|
|
||||||
|
float buf[BUFSIZE];
|
||||||
|
long long i;
|
||||||
|
mvwprintw(win, 2, 0, "Loops: ");
|
||||||
|
mvwprintw(win, 3, 0, "Rate: ");
|
||||||
|
for (i = 0;; i++) {
|
||||||
|
auto c = getch();
|
||||||
|
switch (c) {
|
||||||
|
case KEY_UP:
|
||||||
|
sampled->playbackRate+=8;
|
||||||
|
sampled->playbackRate &= 0x3fff;
|
||||||
|
break;
|
||||||
|
case KEY_DOWN:
|
||||||
|
sampled->playbackRate-=8;
|
||||||
|
sampled->playbackRate &= 0x3fff;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
endwin();
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user