voice assignment

This commit is contained in:
Gordon JC Pearce 2024-09-03 12:42:16 +01:00
parent 284ce7193c
commit 766e4f7a2b
4 changed files with 102 additions and 113 deletions

View File

@ -1,5 +1,5 @@
/* /*
Chassis reverb plugin Chassis softsynth framework
Copyright 2024 Gordon JC Pearce <gordonjcp@gjcp.net> Copyright 2024 Gordon JC Pearce <gordonjcp@gjcp.net>
@ -18,80 +18,14 @@
#include "chassis.hpp" #include "chassis.hpp"
SVF::SVF(float cutoff = 0, float q = 0, float samplerate = 0) {
z1 = z2 = 0;
setFreq(cutoff, q, samplerate);
}
void SVF::setFreq(float cutoff, float q, float samplerate) {
z1 = z2 = 0;
printf("called with %f %f %f\n", cutoff, q, samplerate);
w = 2 * tan(3.14159 * (cutoff / samplerate));
a = w / q;
b = w * w;
// corrected SVF params, per Fons Adriaensen
c1 = (a + b) / (1 + a / 2 + b / 4);
c2 = b / (a + b);
d0 = c1 * c2 / 4;
printf("c1 %f c2 %f d0 %f\n", c1, c2, d0);
}
inline float SVF::lpStep(float in) {
x = in - z1 - z2;
z2 += c2 * z1;
z1 += c1 * x;
return d0 * x + z2;
}
START_NAMESPACE_DISTRHO START_NAMESPACE_DISTRHO
Chassis::Chassis() : Plugin(kParameterCount, 0, 0) { // one parameter, no programs, no states Chassis::Chassis() : Plugin(kParameterCount, 0, 0) { // one parameter, no programs, no states
// lowpass = new float[getBufferSize()];
// ram = new int16_t[16384];
// bzero(lowpass, sizeof(float) * getBufferSize());
// bzero(ram, sizeof(int16_t) * 16384);
// f1.setFreq(5916, .6572, getSampleRate());
// f2.setFreq(9458, 2.536, getSampleRate());
} }
// Initialisation functions // Initialisation functions
void Chassis::initParameter(uint32_t index, Parameter &parameter) { void Chassis::initParameter(uint32_t index, Parameter &parameter) {
if (index == p_saw) {
parameter.hints = kParameterIsAutomatable | kParameterIsInteger;
parameter.name = "Saw";
parameter.symbol = "saw";
parameter.ranges.max = 1.0f;
}
if (index == p_sqr) {
parameter.hints = kParameterIsAutomatable | kParameterIsInteger;
parameter.name = "Square";
parameter.symbol = "sqr";
parameter.ranges.max = 4.0f;
}
if (index == p_sublev) {
parameter.hints = kParameterIsAutomatable;
parameter.name = "Sub";
parameter.symbol = "sub";
parameter.ranges.def = 20.0f;
parameter.ranges.min = 1.0f;
parameter.ranges.max = 64.0f;
}
if (index == paramProgram) {
parameter.hints = kParameterIsAutomatable;
parameter.name = "prog";
parameter.symbol = "prog";
parameter.ranges.def = 1.0f;
parameter.ranges.min = 0.0f;
parameter.ranges.max = 1.0f;
}
} }
void Chassis::setParameterValue(uint32_t index, float value) { void Chassis::setParameterValue(uint32_t index, float value) {
@ -123,67 +57,71 @@ void Chassis::loadProgram(uint32_t index) {
void Chassis::activate() { void Chassis::activate() {
// calculate filter coefficients // calculate filter coefficients
printf("called activate()\n"); printf("called activate()\n");
for (uint32_t i = 0; i< NUM_VOICES; i++ ) {
assign[i] = 0x80 | i;
}
} }
void Chassis::deactivate() { void Chassis::deactivate() {
// zero out the outputs, maybe // zero out the outputs, maybe
printf("called deactivate()\n"); printf("called deactivate()\n");
printf("%02x", assign[1]); // printf("%02x", assign[1]);
} }
void Chassis::noteOn(uint8_t note) { void Chassis::noteOn(uint8_t note) {
for (uint32_t i = 0; i < NUM_VOICES; i++) { uint32_t i;
printf("note on, finding free voice in %02x for %d\n", assign[i], note); for (i = 0; i < NUM_VOICES; i++) {
if (assign[i] & 0x80) { // top bit is voice free flag // printf("note on, finding free voice in %02x for %d\n", assign[i], note);
assign[i] &= 0x7f; // enable if (voice[i].state == V_OFF) { // top bit is voice free flag
printf("voice %d would be set to note %d\n", assign[i], note); voice[i].state = V_ON; // enable
voice[i].note = note;
printf("voice %d set to note %d\n", i, note);
break; break;
} }
}
if (i == NUM_VOICES) { // didn't find a free voice if (i == NUM_VOICES) { // didn't find a free voice
uint32_t v = assign[0]; // Voice v = voice[0];
memmove(assign, assign + 1, NUM_VOICES - 1); // shunt all voices down by one memmove(voice, voice + 1, sizeof(Voice) * (NUM_VOICES - 1)); // shunt all voices down by one
assign[NUM_VOICES - 1] = v; // oldest voice goes at the top of the queue // lessvoice[NUM_VOICES - 1] = v; // oldest voice goes at the top of the queue
printf("no free voices, reused %d for note %d\n", v, note); voice[NUM_VOICES - 1].note = note; // set note, assume state is still set
printf("no free voices, reused %d for note %d\n", 0, note);
} }
}
printf("note table is now "); printf("note table is now\n");
for (uint32_t i=0; i < NUM_VOICES; i++ ) { for (i = 0; i < NUM_VOICES; i++) {
printf("%02x = ", assign[i]); printf("%2d = %3d %01x\n", i, voice[i].note, voice[i].state);
} }
printf("----------------------------\n"); printf("----------------------------\n");
} }
/*
void Chassis::noteOff(uint8_t note) { void Chassis::noteOff(uint8_t note) {
uint32_t v; uint32_t v;
printf("note off called for %3d\n", note); printf("note off called for %3d\n", note);
printf("trying voice ");
for (uint32_t i = 0; i < NUM_VOICES; i++) { for (uint32_t i = 0; i < NUM_VOICES; i++) {
v = assign[i]; printf("%02x ", i);
printf("trying voice %02x\n", v);
if (v < 0x80) {
printf("note %02x is playing\n", v);
if (voice[i].note == note && voice[i].state != V_OFF) {
printf("note off for %d playing %02x\n", i, note);
//memmove(voice + i, voice + i + 1, sizeof(Voice) * (NUM_VOICES - i));
voice[i].state = V_OFF;
break;
} }
} }
printf("\n note table is now\n");
for (uint32_t i = 0; i < NUM_VOICES; i++) {
printf("%2d = %3d %01x\n", i, voice[i].note, voice[i].state);
}
} }
*/
void Chassis::run(const float **, float **outputs, uint32_t frames, const MidiEvent *MidiEvents, uint32_t midiEventCount) { void Chassis::run(const float **, float **outputs, uint32_t frames, const MidiEvent *MidiEvents, uint32_t midiEventCount) {
if (midiEventCount > 0) printf("\n--------------------\n"); // if (midiEventCount > 0) printf("\n--------------------\n");
for (uint32_t i = 0; i < midiEventCount; i++) { for (uint32_t i = 0; i < midiEventCount; i++) {
printf("%4d %02x %02x\n", MidiEvents[i].frame, MidiEvents[i].data[0], MidiEvents[i].data[1]); // printf("%4d %02x %02x\n", MidiEvents[i].frame, MidiEvents[i].data[0], MidiEvents[i].data[1]);
if (MidiEvents[i].data[0] == 0x90) { if (MidiEvents[i].data[0] == 0x90) {
noteOn(MidiEvents[i].data[1]); noteOn(MidiEvents[i].data[1]);
} }
if (MidiEvents[i].data[0] == 0x80) {
noteOff(MidiEvents[i].data[1]);
}
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
Chassis reverb plugin Chassis softsynth framework
Copyright 2024 Gordon JC Pearce <gordonjcp@gjcp.net> Copyright 2024 Gordon JC Pearce <gordonjcp@gjcp.net>
@ -16,12 +16,13 @@
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#ifndef BARRVERB_HPP #ifndef _CHASSIS_HPP
#define BARRVERB_HPP #define _CHASSIS_HPP
#define NUM_VOICES 8 #define NUM_VOICES 8
#include "DistrhoPlugin.hpp" #include "DistrhoPlugin.hpp"
#include "voice.hpp"
class SVF { class SVF {
public: public:
@ -40,8 +41,6 @@ START_NAMESPACE_DISTRHO
class Chassis : public Plugin { class Chassis : public Plugin {
public: public:
enum Parameters { enum Parameters {
p_saw, p_sqr, p_sublev,
paramProgram,
kParameterCount kParameterCount
}; };
@ -72,17 +71,16 @@ class Chassis : public Plugin {
void deactivate() override; void deactivate() override;
void run(const float **, float **outputs, uint32_t frames, const MidiEvent *MidiEvents, uint32_t midiEventCount) override; void run(const float **, float **outputs, uint32_t frames, const MidiEvent *MidiEvents, uint32_t midiEventCount) override;
void noteOn(uint8_t note);
void noteOn(uint8_t note); void noteOff(uint8_t note);
private: private:
uint8_t assign[NUM_VOICES]; // assigner table Voice voice[NUM_VOICES];
//uint32_t
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Chassis); DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Chassis);
}; };
END_NAMESPACE_DISTRHO END_NAMESPACE_DISTRHO
#endif // BARRVERB_HPP #endif // _CHASSIS_HPP

17
plugin/voice.cpp Normal file
View File

@ -0,0 +1,17 @@
/*
Chassis softsynth framework
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.
*/

36
plugin/voice.hpp Normal file
View File

@ -0,0 +1,36 @@
/*
Chassis softsynth framework
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 _VOICE_HPP
#define _VOICE_HPP
#include <cstdint>
enum VoiceState {
V_OFF,
V_ON
};
class Voice {
public:
uint8_t note;
VoiceState state = V_OFF;
};
#endif // _VOICE_HPP