assigner
This commit is contained in:
parent
8661286e79
commit
5bfe06f721
|
@ -32,9 +32,5 @@
|
|||
|
||||
#define DISTRHO_PLUGIN_IS_SYNTH 1
|
||||
|
||||
enum Parameters {
|
||||
bass,
|
||||
kParameterCount
|
||||
};
|
||||
|
||||
#define NUM_VOICES 8
|
||||
#endif
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
NAME = sonnenlicht
|
||||
|
||||
FILES_DSP = sonnenlicht.cpp
|
||||
FILES_DSP = assigner.cpp sonnenlicht.cpp
|
||||
include ../dpf/Makefile.plugins.mk
|
||||
|
||||
TARGETS += vst2 vst3 jack lv2_dsp
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
sonnenlicht poly ensemble
|
||||
|
||||
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 "assigner.hpp"
|
||||
|
||||
#define DEBUG
|
||||
|
||||
void Assigner::dumpTables() {
|
||||
#ifdef DEBUG
|
||||
printf("table state is:\n");
|
||||
for (uint8_t i = 0; i < NUM_VOICES; i++) {
|
||||
uint8_t e = voiceTbl[i];
|
||||
uint8_t a = noteTbl[e];
|
||||
printf("%2d=%3d%c ", e, a & 0x7f, (a & 0x80) ? '^' : 'v');
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
Assigner::Assigner() {
|
||||
d_debug("assigner constructor");
|
||||
|
||||
// set up the assigner tables
|
||||
for (uint8_t i = 0; i < NUM_VOICES; i++) {
|
||||
voiceTbl[i] = i;
|
||||
noteTbl[i] = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
void Assigner::handleMidi(MidiEvent *ev) {
|
||||
uint8_t status = ev->data[0];
|
||||
switch (status & 0xf0) {
|
||||
case 0x80:
|
||||
noteOff(ev->data[1]);
|
||||
dumpTables();
|
||||
break;
|
||||
case 0x90:
|
||||
// dumpTables();
|
||||
noteOn(ev->data[1]);
|
||||
dumpTables();
|
||||
break;
|
||||
case 0xb0:
|
||||
switch (ev->data[1]) {
|
||||
// handle the following
|
||||
// CC 1 - modwheel
|
||||
// CC 64 - sustain
|
||||
// possibly JU-06 CC values
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break; // nothing to do here except in special cases where we don't expect the host to pass on controls
|
||||
case 0xc0: // program change
|
||||
break;
|
||||
case 0xe0: // pitch bend;
|
||||
break;
|
||||
case 0xf0: // sysex
|
||||
break;
|
||||
|
||||
default:
|
||||
d_debug("unhandled MIDI event, status %02x value %02x\n", ev->data[0], ev->data[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void Assigner::noteOff(uint8_t note) {
|
||||
d_debug("note off %3d", note);
|
||||
|
||||
uint8_t i, v;
|
||||
// scan for note in table
|
||||
for (i = 0; i < NUM_VOICES; i++) {
|
||||
if ((noteTbl[voiceTbl[i]] & 0x7f) == note) break;
|
||||
}
|
||||
if (i == NUM_VOICES) return; // got note off for note that isn't in the table
|
||||
|
||||
// get the voice at this slot
|
||||
// then move the rest down and place this at the end
|
||||
// and mark the note for this voice as "off" by setting bit 7
|
||||
v = voiceTbl[i];
|
||||
memmove(voiceTbl + i, voiceTbl + i + 1, NUM_VOICES - i - 1);
|
||||
voiceTbl[NUM_VOICES - 1] = v;
|
||||
noteTbl[v] |= 0x80;
|
||||
}
|
||||
|
||||
void Assigner::noteOn(uint8_t note) {
|
||||
d_debug("note on %3d", note);
|
||||
|
||||
int8_t i, a, v;
|
||||
|
||||
// don't even attempt to steal voices
|
||||
// by overwriting the last voice in the table
|
||||
// we could actually do voice stealing
|
||||
if ((noteTbl[voiceTbl[NUM_VOICES - 1]] & 0x80) == 0x00) {
|
||||
d_debug("note table full");
|
||||
return;
|
||||
}
|
||||
|
||||
// loop around the voices
|
||||
for (i = NUM_VOICES - 1; i >= 0; i--) {
|
||||
v = voiceTbl[i];
|
||||
a = noteTbl[v];
|
||||
|
||||
// if this note is playing we've gone too far
|
||||
// we need to back up a slot and consider it for use
|
||||
if ((a & 0x80) == 0) {
|
||||
i++;
|
||||
|
||||
// shunt them all up to the end
|
||||
v = voiceTbl[i];
|
||||
memmove(voiceTbl + 1, voiceTbl, i);
|
||||
voiceTbl[0] = v;
|
||||
break; // note is already playing in table
|
||||
}
|
||||
|
||||
if ((a & 0x7f) == note) {
|
||||
memmove(voiceTbl + 1, voiceTbl, i);
|
||||
voiceTbl[0] = v;
|
||||
a &= 0x7f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// printf("at end, l=%d e=%d\n", l,e);
|
||||
noteTbl[v] = note;
|
||||
|
||||
d_debug("send voice on %3d to voice %d", note, v);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
sonnenlicht poly ensemble
|
||||
|
||||
Copyright 2024 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 _ASSIGNER_HPP
|
||||
#define _ASSIGNER_HPP
|
||||
|
||||
#include "DistrhoPlugin.hpp"
|
||||
|
||||
class Assigner {
|
||||
public:
|
||||
Assigner();
|
||||
void handleMidi(MidiEvent *ev);
|
||||
|
||||
private:
|
||||
void noteOn(uint8_t note); // incoming note on (or off, if velocity = 0)
|
||||
void noteOff(uint8_t note); // incoming note off
|
||||
uint8_t voiceTbl[NUM_VOICES]; // voices in order of use
|
||||
uint8_t noteTbl[NUM_VOICES]; // note played by voice
|
||||
|
||||
void dumpTables();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -18,34 +18,48 @@
|
|||
|
||||
#include "sonnenlicht.hpp"
|
||||
|
||||
#include "assigner.hpp"
|
||||
|
||||
START_NAMESPACE_DISTRHO
|
||||
|
||||
Sonnenlicht::Sonnenlicht() : Plugin(kParameterCount, 0, 0), fSampleRate(getSampleRate()) {
|
||||
printf("initialiser called\n");
|
||||
w = 440.0 / fSampleRate;
|
||||
phase = 0;
|
||||
assigner = new Assigner;
|
||||
}
|
||||
|
||||
Sonnenlicht::~Sonnenlicht() {
|
||||
delete assigner;
|
||||
}
|
||||
|
||||
void Sonnenlicht::setParameterValue(uint32_t index, float value) {
|
||||
printf("got parameter %d, %f\n", index, value);
|
||||
}
|
||||
|
||||
void Sonnenlicht::initAudioPort(bool input, uint32_t index, AudioPort& port) {
|
||||
port.groupId = kPortGroupStereo;
|
||||
Plugin::initAudioPort(input, index, port);
|
||||
|
||||
if (!input && index == 0) port.symbol = "Left";
|
||||
if (!input && index == 1) port.symbol = "Right";
|
||||
}
|
||||
|
||||
void Sonnenlicht::activate() {
|
||||
}
|
||||
|
||||
void Sonnenlicht::deactivate() {
|
||||
}
|
||||
|
||||
void Sonnenlicht::initParameter(uint32_t index, Parameter& parameter) {
|
||||
return;
|
||||
}
|
||||
|
||||
void Sonnenlicht::run(const float**, float** outputs, uint32_t frames,
|
||||
const MidiEvent* midiEvents, uint32_t midiEventCount) {
|
||||
|
||||
if (midiEventCount > 0) {
|
||||
for (uint32_t i=0; i < midiEventCount; i++ ) {
|
||||
const uint8_t *data = midiEvents[i].data;
|
||||
const uint8_t status = data[0] & 0xf0;
|
||||
|
||||
|
||||
if (status == 0x90) {
|
||||
w = (261.6 * (powf(2, (data[1]-60)/12.0f)))/fSampleRate;
|
||||
printf("set w to %f\n", w);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < frames; i++) {
|
||||
phase += w;
|
||||
if (phase > 1) phase -= 1;
|
||||
outputs[0][i] = phase - 0.5;
|
||||
outputs[1][i] = phase - 0.5;
|
||||
const MidiEvent* ev, uint32_t evCount) {
|
||||
for (uint32_t i = 0; i < evCount; i++) {
|
||||
//printf("%3d: %02x %02x\n", i, midiEvents[i].data[0], midiEvents[i].data[1]);
|
||||
assigner->handleMidi((MidiEvent *)&ev[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Sonnenlicht reverb plugin
|
||||
sonnenlicht poly ensemble
|
||||
|
||||
Copyright 2024 Gordon JC Pearce <gordonjcp@gjcp.net>
|
||||
|
||||
|
@ -20,17 +20,18 @@
|
|||
#define SONNENLICHT_HPP
|
||||
|
||||
#include "DistrhoPlugin.hpp"
|
||||
#include "assigner.hpp"
|
||||
|
||||
START_NAMESPACE_DISTRHO
|
||||
|
||||
class Sonnenlicht : public Plugin {
|
||||
public:
|
||||
enum Parameters {
|
||||
bass,
|
||||
kParameterCount
|
||||
};
|
||||
|
||||
Sonnenlicht();
|
||||
~Sonnenlicht();
|
||||
|
||||
protected:
|
||||
const char *getLabel() const override { return "sonnenlicht"; }
|
||||
|
@ -42,17 +43,21 @@ class Sonnenlicht : public Plugin {
|
|||
uint32_t getVersion() const override { return d_version(1, 0, 0); }
|
||||
int64_t getUniqueId() const override { return d_cconst('S', 'L', 'C', 'T'); }
|
||||
|
||||
void initParameter(uint32_t index, Parameter ¶meter) override;
|
||||
void setParameterValue(uint32_t index, float value) override;
|
||||
|
||||
// Initialisation
|
||||
// void initAudioPort(bool input, uint32_t index, AudioPort &port) override;
|
||||
void initAudioPort(bool input, uint32_t index, AudioPort &port) override;
|
||||
|
||||
// Processing
|
||||
// void activate() override;
|
||||
// void deactivate() override;
|
||||
void activate() override;
|
||||
void deactivate() override;
|
||||
|
||||
void run(const float **, float **outputs, uint32_t frames,
|
||||
const MidiEvent *midiEvents, uint32_t midiEventCount) override;
|
||||
|
||||
private:
|
||||
Assigner *assigner;
|
||||
double fSampleRate;
|
||||
float phase;
|
||||
float w;
|
||||
|
|
Loading…
Reference in New Issue