added assigner
This commit is contained in:
parent
7e55a0fe5e
commit
aa9448cac5
|
|
@ -31,4 +31,7 @@
|
|||
#define DISTRHO_PLUGIN_HAS_UI 0
|
||||
#define DISTRHO_PLUGIN_WANT_PROGRAMS 0
|
||||
|
||||
// synth configuration
|
||||
#define NUM_VOICES 8
|
||||
|
||||
#endif
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
NAME = peacock
|
||||
|
||||
FILES_DSP = \
|
||||
assigner.cpp \
|
||||
peacock.cpp
|
||||
|
||||
include ../dpf/Makefile.plugins.mk
|
||||
|
|
|
|||
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
Peacock-8 VA polysynth
|
||||
|
||||
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 @@
|
|||
/*
|
||||
Peacock-8 VA polysynth
|
||||
|
||||
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 _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
|
||||
|
|
@ -22,8 +22,7 @@ START_NAMESPACE_DISTRHO
|
|||
|
||||
Peacock::Peacock() : Plugin(0, 0, 0) {
|
||||
d_debug("peacock constructor\n");
|
||||
|
||||
|
||||
ic1 = new Assigner;
|
||||
}
|
||||
|
||||
void Peacock::initAudioPort(bool input, uint32_t index, AudioPort &port) {
|
||||
|
|
@ -34,10 +33,25 @@ void Peacock::initAudioPort(bool input, uint32_t index, AudioPort &port) {
|
|||
if (!input && index == 1) port.name = "Right Out";
|
||||
}
|
||||
|
||||
void Peacock::runMidi(const MidiEvent *ev, uint32_t ev_count, uint32_t timeLimit) {
|
||||
// handle a sample chunk of MIDI events
|
||||
uint32_t i;
|
||||
if (ev_count == 0) return; // nothing to do anyway
|
||||
|
||||
// there are MIDI events, loop through them
|
||||
for (i = lastEvent; i < ev_count; i++) {
|
||||
if (ev[i].frame > timeLimit) break; // only up to the start of the next chunk
|
||||
ic1->handleMidi((MidiEvent *)&ev[i]);
|
||||
}
|
||||
lastEvent = i;
|
||||
}
|
||||
|
||||
void Peacock::run(const float **, float **outputs, uint32_t frames, const MidiEvent *midiEvents, uint32_t midiEventCount) {
|
||||
memset(outputs[0], 0, frames * sizeof(float));
|
||||
memset(outputs[1], 0, frames * sizeof(float));
|
||||
|
||||
lastEvent = 0;
|
||||
runMidi(midiEvents, midiEventCount, frames);
|
||||
}
|
||||
|
||||
Plugin *createPlugin() { return new Peacock(); }
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#define DEBUG
|
||||
|
||||
#include "DistrhoPlugin.hpp"
|
||||
#include "assigner.hpp"
|
||||
|
||||
START_NAMESPACE_DISTRHO
|
||||
|
||||
|
|
@ -43,9 +44,11 @@ class Peacock : public Plugin {
|
|||
void initAudioPort(bool input, uint32_t index, AudioPort &port) override;
|
||||
|
||||
void run(const float **, float **outputs, uint32_t frames, const MidiEvent *midiEvents, uint32_t midiEventCount) override;
|
||||
void runMidi(const MidiEvent *ev, uint32_t ev_count, uint32_t timeLimit);
|
||||
|
||||
private:
|
||||
|
||||
uint32_t lastEvent = 0; // event number of last MIDI event processed in a chunk
|
||||
Assigner *ic1;
|
||||
|
||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Peacock);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue