generates sine tones
This commit is contained in:
parent
e8fc2fbfec
commit
5cda4f0132
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
NAME = tonewheel
|
NAME = tonewheel
|
||||||
|
|
||||||
FILES_DSP = assigner.cpp tonewheel.cpp
|
FILES_DSP = generator.cpp assigner.cpp tonewheel.cpp
|
||||||
include ../dpf/Makefile.plugins.mk
|
include ../dpf/Makefile.plugins.mk
|
||||||
|
|
||||||
TARGETS += vst2 vst3 jack lv2_dsp
|
TARGETS += vst2 vst3 jack lv2_dsp
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
#include "assigner.hpp"
|
#include "assigner.hpp"
|
||||||
|
|
||||||
#define DEBUG
|
//#define DEBUG
|
||||||
|
|
||||||
void Assigner::dumpTables() {
|
void Assigner::dumpTables() {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -32,7 +32,7 @@ void Assigner::dumpTables() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Assigner::Assigner() {
|
Assigner::Assigner(Voice *v) {
|
||||||
d_debug("assigner constructor");
|
d_debug("assigner constructor");
|
||||||
|
|
||||||
// set up the assigner tables
|
// set up the assigner tables
|
||||||
|
@ -40,6 +40,9 @@ Assigner::Assigner() {
|
||||||
voiceTbl[i] = i;
|
voiceTbl[i] = i;
|
||||||
noteTbl[i] = 0x80;
|
noteTbl[i] = 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// populate the pointer to the generator voice table
|
||||||
|
voices = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Assigner::handleMidi(MidiEvent *ev) {
|
void Assigner::handleMidi(MidiEvent *ev) {
|
||||||
|
@ -92,6 +95,7 @@ void Assigner::noteOff(uint8_t note) {
|
||||||
memmove(voiceTbl + i, voiceTbl + i + 1, NUM_VOICES - i - 1);
|
memmove(voiceTbl + i, voiceTbl + i + 1, NUM_VOICES - i - 1);
|
||||||
voiceTbl[NUM_VOICES - 1] = v;
|
voiceTbl[NUM_VOICES - 1] = v;
|
||||||
noteTbl[v] |= 0x80;
|
noteTbl[v] |= 0x80;
|
||||||
|
voices[v].stopNote();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Assigner::noteOn(uint8_t note) {
|
void Assigner::noteOn(uint8_t note) {
|
||||||
|
@ -137,5 +141,6 @@ void Assigner::noteOn(uint8_t note) {
|
||||||
while(note>96) note -= 12;
|
while(note>96) note -= 12;
|
||||||
while(note<36) note += 12;
|
while(note<36) note += 12;
|
||||||
|
|
||||||
|
voices[v].startNote(note);
|
||||||
d_debug("send voice on note %3d to voice %d", note, v);
|
d_debug("send voice on note %3d to voice %d", note, v);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,11 @@
|
||||||
#define _ASSIGNER_HPP
|
#define _ASSIGNER_HPP
|
||||||
|
|
||||||
#include "DistrhoPlugin.hpp"
|
#include "DistrhoPlugin.hpp"
|
||||||
|
#include "generator.hpp"
|
||||||
|
|
||||||
class Assigner {
|
class Assigner {
|
||||||
public:
|
public:
|
||||||
Assigner();
|
Assigner(Voice *v);
|
||||||
void handleMidi(MidiEvent *ev);
|
void handleMidi(MidiEvent *ev);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -33,6 +34,7 @@ class Assigner {
|
||||||
|
|
||||||
uint8_t voiceTbl[NUM_VOICES]; // voices in order of use
|
uint8_t voiceTbl[NUM_VOICES]; // voices in order of use
|
||||||
uint8_t noteTbl[NUM_VOICES]; // note played by voice
|
uint8_t noteTbl[NUM_VOICES]; // note played by voice
|
||||||
|
Voice *voices;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
tonewheel organ plugin
|
||||||
|
|
||||||
|
Copyright 2025 Gordon JC Pearce <gordonjcp@gjcp.net>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "generator.hpp"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include "DistrhoPluginInfo.h"
|
||||||
|
|
||||||
|
// globals set when the plugin is activated
|
||||||
|
// sample rate or buffer size may actually change!
|
||||||
|
extern double sampleRate;
|
||||||
|
extern uint32_t bufferSize;
|
||||||
|
|
||||||
|
Generator::Generator() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Generator::~Generator() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Generator::activate() {
|
||||||
|
// create a sine table
|
||||||
|
for (uint16_t i = 0; i < 256; i++) {
|
||||||
|
sine[i] = sin((float)i / 128.0 * 3.14159);
|
||||||
|
}
|
||||||
|
// create the phase increments for each semitone
|
||||||
|
for (uint8_t i = 0; i < 12; i++) {
|
||||||
|
phase[i] = 0;
|
||||||
|
uint32_t f;
|
||||||
|
f = (1 << 30) * (32.703 * powf(2, 0.083334 * i) / sampleRate);
|
||||||
|
omega[i] = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Generator::run(float *output, uint32_t frames) {
|
||||||
|
Voice *v;
|
||||||
|
uint32_t i;
|
||||||
|
uint8_t k, p;
|
||||||
|
uint32_t d = 0;
|
||||||
|
|
||||||
|
memset(output, 0, frames * sizeof(float));
|
||||||
|
|
||||||
|
// for every frame of the output...
|
||||||
|
for (i = 0; i < frames; i++) {
|
||||||
|
// loop over all twelve semitones adding on the phase increment
|
||||||
|
// these are 32-bit unsigned values and will wrap
|
||||||
|
for (p = 0; p < 12; p++) {
|
||||||
|
phase[p] += omega[p];
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop over all the voices, calculating what they need
|
||||||
|
for (k = 0; k < NUM_VOICES; k++) {
|
||||||
|
v = &voices[k];
|
||||||
|
|
||||||
|
// 8' stop
|
||||||
|
d = (phase[v->semi] >> (24 - v->oct)) & 0xff;
|
||||||
|
output[i] += .25 * (sine[d] * v->gate);
|
||||||
|
|
||||||
|
// mutation stops are a fifth up
|
||||||
|
d = (phase[(v->semi + 7) % 12] >> (22 - v->oct)) & 0xff;
|
||||||
|
output[i] += .25 * (sine[d] * v->gate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Voice::startNote(uint8_t key) {
|
||||||
|
// start a new note
|
||||||
|
semi = key % 12, oct = (key / 12);
|
||||||
|
gate = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Voice::stopNote() {
|
||||||
|
gate = 0;
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
tonewheel organ plugin
|
||||||
|
|
||||||
|
Copyright 2025 Gordon JC Pearce <gordonjcp@gjcp.net>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GENERATOR_HPP
|
||||||
|
#define GENERATOR_HPP
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "DistrhoPluginInfo.h"
|
||||||
|
|
||||||
|
class Generator;
|
||||||
|
|
||||||
|
class Voice {
|
||||||
|
friend Generator;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void startNote(uint8_t key);
|
||||||
|
void stopNote();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t semi, oct;
|
||||||
|
float gate;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Generator {
|
||||||
|
public:
|
||||||
|
// Generator(uint32_t bufferSize, double xSampleRate);
|
||||||
|
Generator();
|
||||||
|
|
||||||
|
~Generator();
|
||||||
|
void run(float *output, uint32_t frames);
|
||||||
|
void activate();
|
||||||
|
Voice voices[NUM_VOICES];
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t phase[12];
|
||||||
|
uint32_t omega[12];
|
||||||
|
float sine[256];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -24,11 +24,15 @@ uint32_t bufferSize;
|
||||||
START_NAMESPACE_DISTRHO
|
START_NAMESPACE_DISTRHO
|
||||||
|
|
||||||
Tonewheel::Tonewheel() : Plugin(kParameterCount, 0, 0) {
|
Tonewheel::Tonewheel() : Plugin(kParameterCount, 0, 0) {
|
||||||
assigner = new Assigner;
|
generator = new Generator;
|
||||||
|
assigner = new Assigner(generator->voices);
|
||||||
|
printf("Tonewheel constructor\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
Tonewheel::~Tonewheel() {
|
Tonewheel::~Tonewheel() {
|
||||||
delete assigner;
|
delete assigner;
|
||||||
|
delete generator;
|
||||||
|
printf("Tonewheel destructor\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tonewheel::initAudioPort(bool input, uint32_t index, AudioPort& port) {
|
void Tonewheel::initAudioPort(bool input, uint32_t index, AudioPort& port) {
|
||||||
|
@ -42,6 +46,7 @@ void Tonewheel::initAudioPort(bool input, uint32_t index, AudioPort& port) {
|
||||||
void Tonewheel::activate() {
|
void Tonewheel::activate() {
|
||||||
sampleRate = getSampleRate();
|
sampleRate = getSampleRate();
|
||||||
bufferSize = getBufferSize();
|
bufferSize = getBufferSize();
|
||||||
|
generator->activate();
|
||||||
printf("In activate, bufSz=%d smpRt=%f\n", bufferSize, sampleRate);
|
printf("In activate, bufSz=%d smpRt=%f\n", bufferSize, sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,11 +56,11 @@ void Tonewheel::deactivate() {
|
||||||
void Tonewheel::run(const float**, float** outputs, uint32_t frames,
|
void Tonewheel::run(const float**, float** outputs, uint32_t frames,
|
||||||
const MidiEvent* ev, uint32_t evCount) {
|
const MidiEvent* ev, uint32_t evCount) {
|
||||||
|
|
||||||
(void) frames;
|
|
||||||
(void) outputs;
|
|
||||||
for (uint32_t i = 0; i < evCount; i++) {
|
for (uint32_t i = 0; i < evCount; i++) {
|
||||||
assigner->handleMidi((MidiEvent*)&ev[i]);
|
assigner->handleMidi((MidiEvent*)&ev[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generator->run(outputs[0], frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
Plugin* createPlugin() { return new Tonewheel(); }
|
Plugin* createPlugin() { return new Tonewheel(); }
|
||||||
|
|
|
@ -65,6 +65,7 @@ class Tonewheel : public Plugin {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Assigner *assigner;
|
Assigner *assigner;
|
||||||
|
Generator *generator;
|
||||||
|
|
||||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Tonewheel);
|
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Tonewheel);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue