first noise, pitches about correct
This commit is contained in:
parent
0fe57ff017
commit
5c1c79464e
@ -17,10 +17,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ic1.hpp"
|
#include "ic1.hpp"
|
||||||
#include "ic29.hpp"
|
|
||||||
|
|
||||||
|
#include "ic29.hpp"
|
||||||
#include "peacock.hpp"
|
#include "peacock.hpp"
|
||||||
|
|
||||||
|
Assigner ic1;
|
||||||
|
|
||||||
void Assigner::printMap() {
|
void Assigner::printMap() {
|
||||||
printf("note memory:\n");
|
printf("note memory:\n");
|
||||||
for (uint8_t i = 0; i < NUM_VOICES; i++) printf("%02x ", voicemap[i]);
|
for (uint8_t i = 0; i < NUM_VOICES; i++) printf("%02x ", voicemap[i]);
|
||||||
@ -54,36 +56,30 @@ void Assigner::handleMidi(const MidiEvent *ev) {
|
|||||||
}
|
}
|
||||||
void Assigner::noteOff(uint8_t note) {
|
void Assigner::noteOff(uint8_t note) {
|
||||||
// Poly 1 note off
|
// Poly 1 note off
|
||||||
d_debug("Note Off %02x", note);
|
|
||||||
for (uint8_t i = 0; i < NUM_VOICES; i++) {
|
for (uint8_t i = 0; i < NUM_VOICES; i++) {
|
||||||
if (keymap[i] == note) {
|
if (keymap[i] == note) {
|
||||||
d_debug("Found note at slot %02x, moving to last", i);
|
|
||||||
uint8_t voice = voicemap[i]; // save the voice
|
uint8_t voice = voicemap[i]; // save the voice
|
||||||
memmove(voicemap + i, voicemap + i + 1, NUM_VOICES - i - 1);
|
memmove(voicemap + i, voicemap + i + 1, NUM_VOICES - i - 1);
|
||||||
memmove(keymap + i, keymap + i + 1, NUM_VOICES - i - 1);
|
memmove(keymap + i, keymap + i + 1, NUM_VOICES - i - 1);
|
||||||
voicemap[NUM_VOICES - 1] = voice;
|
voicemap[NUM_VOICES - 1] = voice;
|
||||||
keymap[NUM_VOICES - 1] = note | 0x80;
|
keymap[NUM_VOICES - 1] = note | 0x80;
|
||||||
s.voiceOff(voice);
|
ic29.voiceOff(voice);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printMap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Assigner::noteOn(uint8_t note) {
|
void Assigner::noteOn(uint8_t note) {
|
||||||
// Poly 1 assigner
|
// Poly 1 assigner
|
||||||
|
|
||||||
// scan for the same note
|
// scan for the same note
|
||||||
for (uint8_t i = 0; i < NUM_VOICES; i++) {
|
for (uint8_t i = 0; i < NUM_VOICES; i++) {
|
||||||
if ((keymap[i] & 0x7f) == note) {
|
if ((keymap[i] & 0x7f) == note) {
|
||||||
// note found, move it to the front of the queue
|
// note found, move it to the front of the queue
|
||||||
d_debug("voice %02x on in slot %02x, existing note %02x", voicemap[i], i, keymap[i]);
|
|
||||||
uint8_t voice = voicemap[i];
|
uint8_t voice = voicemap[i];
|
||||||
memmove(voicemap + 1, voicemap, i);
|
memmove(voicemap + 1, voicemap, i);
|
||||||
memmove(keymap + 1, keymap, i);
|
memmove(keymap + 1, keymap, i);
|
||||||
keymap[0] = note; // show note as on
|
keymap[0] = note; // show note as on
|
||||||
voicemap[0] = voice;
|
voicemap[0] = voice;
|
||||||
s.voiceOn(voice, note);
|
ic29.voiceOn(voice, note);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,17 +88,13 @@ void Assigner::noteOn(uint8_t note) {
|
|||||||
for (uint8_t i = 0; i < NUM_VOICES; i++) {
|
for (uint8_t i = 0; i < NUM_VOICES; i++) {
|
||||||
if (keymap[i] & 0x80) {
|
if (keymap[i] & 0x80) {
|
||||||
// voice is free
|
// voice is free
|
||||||
d_debug("voice %02x on in slot %02x, setting note %02x", voicemap[i], i, note);
|
|
||||||
|
|
||||||
uint8_t voice = voicemap[i];
|
uint8_t voice = voicemap[i];
|
||||||
memmove(voicemap + 1, voicemap, i);
|
memmove(voicemap + 1, voicemap, i);
|
||||||
memmove(keymap + 1, keymap, i);
|
memmove(keymap + 1, keymap, i);
|
||||||
keymap[0] = note; // show note as on
|
keymap[0] = note; // show note as on
|
||||||
voicemap[0] = voice;
|
voicemap[0] = voice;
|
||||||
s.voiceOn(voice, note);
|
ic29.voiceOn(voice, note);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d_debug("unable to allocate a voice for note %02x\n", note);
|
|
||||||
}
|
}
|
||||||
|
@ -33,3 +33,5 @@ class Assigner {
|
|||||||
uint8_t keymap[NUM_VOICES];
|
uint8_t keymap[NUM_VOICES];
|
||||||
uint8_t voicemap[NUM_VOICES];
|
uint8_t voicemap[NUM_VOICES];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern Assigner ic1;
|
@ -18,13 +18,20 @@
|
|||||||
|
|
||||||
#include "ic29.hpp"
|
#include "ic29.hpp"
|
||||||
|
|
||||||
Synth s;
|
Synth ic29;
|
||||||
|
|
||||||
Synth::Synth() {
|
Synth::Synth() {
|
||||||
d_debug("initialising synth\n");
|
d_debug("initialising synth\n");
|
||||||
envAtk = 0x007f;
|
envAtk = 0x007f;
|
||||||
envDcy = envRls = 0xfe90;
|
envDcy = envRls = 0xfe90;
|
||||||
envStn = 0x1fff;
|
envStn = 0x1fff;
|
||||||
|
portaCoeff = 0x0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Synth::buildTables(double sampleRate) {
|
||||||
|
for (uint8_t i = 0; i < 104; i++) {
|
||||||
|
pitchTable[i] = 440.0f * powf(2, (i - 45) / 12.0f) / sampleRate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::run() {
|
void Synth::run() {
|
||||||
@ -32,23 +39,33 @@ void Synth::run() {
|
|||||||
// callled once every 4.3ms block of samples
|
// callled once every 4.3ms block of samples
|
||||||
|
|
||||||
for (uint8_t i = 0; i < NUM_VOICES; i++) {
|
for (uint8_t i = 0; i < NUM_VOICES; i++) {
|
||||||
s.voices[i].env.run();
|
ic29.voices[i].env.run();
|
||||||
|
ic29.voices[i].calcPitch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::voiceOn(uint8_t voice, uint8_t note) {
|
void Synth::voiceOn(uint8_t voice, uint8_t note) {
|
||||||
// enable synth voice, start it all running
|
// enable synth voice, start it all running
|
||||||
voice &= 0x7f;
|
voice &= 0x7f;
|
||||||
s.voices[voice].env.on();
|
ic29.voices[voice].env.on();
|
||||||
|
|
||||||
// FIXME determine if we need to reset the counter
|
// FIXME determine if we need to reset the counter
|
||||||
s.voices[voice].note = note;
|
ic29.voices[voice].note = note;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::voiceOff(uint8_t voice) {
|
void Synth::voiceOff(uint8_t voice) {
|
||||||
// enable synth voice, start it all running
|
// enable synth voice, start it all running
|
||||||
voice &= 0x7f;
|
voice &= 0x7f;
|
||||||
s.voices[voice].env.off();
|
ic29.voices[voice].env.off();
|
||||||
|
}
|
||||||
|
void Synth::basePitch() {
|
||||||
|
uint16_t pitch = 0x1818;
|
||||||
|
|
||||||
|
pitch += lfoPitch;
|
||||||
|
pitch += bendPitch;
|
||||||
|
// tuning too but that's zero by default;
|
||||||
|
|
||||||
|
masterPitch = pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
Envelope::Envelope() {
|
Envelope::Envelope() {
|
||||||
@ -59,23 +76,23 @@ Envelope::Envelope() {
|
|||||||
void Envelope::run() {
|
void Envelope::run() {
|
||||||
switch (phase) {
|
switch (phase) {
|
||||||
case ENV_ATK:
|
case ENV_ATK:
|
||||||
level += s.envAtk;
|
level += ic29.envAtk;
|
||||||
if (level > 0x3fff) {
|
if (level > 0x3fff) {
|
||||||
level = 0x3fff;
|
level = 0x3fff;
|
||||||
phase = ENV_DCY;
|
phase = ENV_DCY;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ENV_DCY:
|
case ENV_DCY:
|
||||||
if (level > s.envStn) {
|
if (level > ic29.envStn) {
|
||||||
level -= s.envStn;
|
level -= ic29.envStn;
|
||||||
level = (level * s.envDcy) >> 16;
|
level = (level * ic29.envDcy) >> 16;
|
||||||
level += s.envStn;
|
level += ic29.envStn;
|
||||||
} else {
|
} else {
|
||||||
level = s.envStn;
|
level = ic29.envStn;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ENV_RLS:
|
case ENV_RLS:
|
||||||
level = (level * s.envRls) >> 16;
|
level = (level * ic29.envRls) >> 16;
|
||||||
break;
|
break;
|
||||||
case ENV_IDLE:
|
case ENV_IDLE:
|
||||||
default:
|
default:
|
||||||
@ -86,4 +103,37 @@ void Envelope::run() {
|
|||||||
Voice::Voice() {
|
Voice::Voice() {
|
||||||
}
|
}
|
||||||
|
|
||||||
extern Synth s;
|
void Voice::calcPitch() {
|
||||||
|
uint16_t target = (note - 24) << 8;
|
||||||
|
|
||||||
|
if (ic29.portaCoeff != 0) {
|
||||||
|
// porta up
|
||||||
|
if (pitch < target) {
|
||||||
|
pitch += ic29.portaCoeff;
|
||||||
|
if (pitch > target) pitch = target;
|
||||||
|
}
|
||||||
|
// porta down
|
||||||
|
if (pitch > target) {
|
||||||
|
pitch -= ic29.portaCoeff;
|
||||||
|
if (pitch < target) pitch = target;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pitch = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
double o1 = ic29.pitchTable[pitch >> 8];
|
||||||
|
double o2 = ic29.pitchTable[(pitch >> 8) + 1];
|
||||||
|
double frac = (pitch & 0xff) / 255.0;
|
||||||
|
|
||||||
|
omega = ((o2 - o1) * frac) + o1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Voice::run(float *buffer, uint32_t samples) {
|
||||||
|
float gain = env.level / 16384.0;
|
||||||
|
gain *= 0.125;
|
||||||
|
for (uint32_t i = 0; i < samples; i++) {
|
||||||
|
phase += omega;
|
||||||
|
if (phase > 1.0f) phase -= 1.0f;
|
||||||
|
buffer[i] += phase * gain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -46,19 +46,22 @@ class Voice {
|
|||||||
public:
|
public:
|
||||||
Voice();
|
Voice();
|
||||||
void run();
|
void run();
|
||||||
uint8_t note;
|
uint8_t note = 0x3c; // middle C
|
||||||
|
|
||||||
// private:
|
// private:
|
||||||
Envelope env; // calculated envelope value
|
Envelope env; // calculated envelope value
|
||||||
uint16_t pitch; // calculated pitch value with porta and master pitch etc
|
uint16_t pitch = 0x1818; // calculated pitch value with porta and master pitch etc
|
||||||
|
float phase=0, omega=0;
|
||||||
enum { V_DONE,
|
enum { V_DONE,
|
||||||
V_OFF,
|
V_OFF,
|
||||||
V_ON } voiceState;
|
V_ON } voiceState;
|
||||||
|
void calcPitch();
|
||||||
|
void run(float *buffer, uint32_t samples);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Synth {
|
class Synth {
|
||||||
friend Envelope;
|
friend Envelope;
|
||||||
friend Peacock;
|
friend Voice;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Synth();
|
Synth();
|
||||||
@ -68,15 +71,24 @@ class Synth {
|
|||||||
void sustainSwitch(uint8_t val);
|
void sustainSwitch(uint8_t val);
|
||||||
void pitchBend(int16_t bend);
|
void pitchBend(int16_t bend);
|
||||||
void modWheel(uint8_t wheel);
|
void modWheel(uint8_t wheel);
|
||||||
uint16_t masterPitch; // sum of bend and LFO, plus any other pitch-setting value
|
void buildTables(double sampleRate);
|
||||||
protected:
|
|
||||||
uint16_t envAtk, envDcy, envStn, envRls;
|
|
||||||
|
|
||||||
private:
|
double sampleRate;
|
||||||
|
uint16_t masterPitch; // sum of bend and LFO, plus any other pitch-setting value
|
||||||
|
// protected:
|
||||||
|
uint16_t envAtk, envDcy, envStn, envRls;
|
||||||
|
int16_t portaCoeff;
|
||||||
|
double pitchTable[104];
|
||||||
|
|
||||||
|
|
||||||
|
//private:
|
||||||
|
int16_t lfoPitch;
|
||||||
|
int16_t bendPitch;
|
||||||
Voice voices[NUM_VOICES];
|
Voice voices[NUM_VOICES];
|
||||||
|
|
||||||
void runLfo();
|
void runLfo();
|
||||||
void runEnvelope(Voice voice);
|
void basePitch();
|
||||||
};
|
};
|
||||||
|
|
||||||
// global
|
// global
|
||||||
extern Synth s;
|
extern Synth ic29;
|
||||||
|
@ -23,28 +23,25 @@
|
|||||||
|
|
||||||
START_NAMESPACE_DISTRHO
|
START_NAMESPACE_DISTRHO
|
||||||
|
|
||||||
Assigner ic1;
|
|
||||||
|
|
||||||
Peacock::Peacock() : Plugin(paramCount, 0, 0), sampleRate(getSampleRate()) {
|
Peacock::Peacock() : Plugin(paramCount, 0, 0), sampleRate(getSampleRate()) {
|
||||||
s.run();
|
printf("peacock constructor\n");
|
||||||
|
ic29.buildTables(getSampleRate());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Peacock::runMidi(const MidiEvent *ev, uint32_t count, uint32_t timeLimit) {
|
void Peacock::runMidi(const MidiEvent *ev, uint32_t count, uint32_t timeLimit) {
|
||||||
// handle MIDI events, starting at lastEvent and continuing until timeLimit
|
// handle MIDI events, starting at lastEvent and continuing until timeLimit
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
if (count == 0) return; // no events to do, at all
|
if (count == 0) return; // no events to do, at all
|
||||||
|
|
||||||
for (uint32_t i = lastEvent; i < count; i++) {
|
for (i = lastEvent; i < count; i++) {
|
||||||
if (ev[i].frame > timeLimit) break; // exceeded the time limit
|
if (ev[i].frame > timeLimit) break; // exceeded the time limit
|
||||||
ic1.handleMidi((const MidiEvent *)&ev[i]);
|
ic1.handleMidi((const MidiEvent *)&ev[i]);
|
||||||
}
|
}
|
||||||
|
lastEvent = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Peacock::run(const float **, float **outputs, uint32_t frames, const MidiEvent *midiEvents, uint32_t midiEventCount) {
|
void Peacock::run(const float **, float **outputs, uint32_t frames, const MidiEvent *midiEvents, uint32_t midiEventCount) {
|
||||||
// no content yet
|
|
||||||
// dispose of parameters
|
|
||||||
(void)outputs;
|
|
||||||
|
|
||||||
// calculate an entire jack period's worth of samples
|
// calculate an entire jack period's worth of samples
|
||||||
// harder than it sounds because for short jack periods there may be many
|
// harder than it sounds because for short jack periods there may be many
|
||||||
// such calls between 4.3ms control updates, or there may be many updates
|
// such calls between 4.3ms control updates, or there may be many updates
|
||||||
@ -63,22 +60,30 @@ void Peacock::run(const float **, float **outputs, uint32_t frames, const MidiEv
|
|||||||
lastEvent = 0;
|
lastEvent = 0;
|
||||||
runMidi(midiEvents, midiEventCount, blockLeft);
|
runMidi(midiEvents, midiEventCount, blockLeft);
|
||||||
|
|
||||||
|
// generate a buffer's worth of samples
|
||||||
|
memset(outputs[0], 0, sizeof(float) * frames);
|
||||||
|
|
||||||
while (framePos < frames) {
|
while (framePos < frames) {
|
||||||
if (blockLeft == 0) {
|
if (blockLeft == 0) {
|
||||||
blockLeft = (int)(getSampleRate() * 0.0043); // how many samples per 4.3ms block?
|
blockLeft = (int)(getSampleRate() * 0.0043); // how many samples per 4.3ms block?
|
||||||
|
|
||||||
// handle all MIDI events for this block, up to the end of the block and frame
|
// handle all MIDI events for this block, up to the end of the block and frame
|
||||||
runMidi(midiEvents, midiEventCount, framePos + blockLeft);
|
runMidi(midiEvents, midiEventCount, framePos + blockLeft);
|
||||||
s.run();
|
ic29.run();
|
||||||
}
|
}
|
||||||
sizeThisTime = (framesLeft < blockLeft) ? framesLeft : blockLeft;
|
sizeThisTime = (framesLeft < blockLeft) ? framesLeft : blockLeft;
|
||||||
|
|
||||||
// run every synth voice into the buffer here FIXME
|
// run every synth voice into the buffer here FIXME
|
||||||
|
for (uint8_t i = 0; i < NUM_VOICES; i++) {
|
||||||
|
ic29.voices[i].run(outputs[0] + framePos, sizeThisTime);
|
||||||
|
}
|
||||||
|
|
||||||
framePos += sizeThisTime; // move along the frame
|
framePos += sizeThisTime; // move along the frame
|
||||||
framesLeft -= sizeThisTime;
|
framesLeft -= sizeThisTime;
|
||||||
blockLeft -= sizeThisTime;
|
blockLeft -= sizeThisTime;
|
||||||
}
|
}
|
||||||
|
// output processing goes here
|
||||||
|
memcpy(outputs[1], outputs[0], sizeof(float) * frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
Plugin *createPlugin() { return new Peacock(); }
|
Plugin *createPlugin() { return new Peacock(); }
|
||||||
|
@ -32,9 +32,9 @@ class Peacock : public Plugin {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Peacock();
|
Peacock();
|
||||||
|
float sampleRate;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float sampleRate;
|
|
||||||
|
|
||||||
const char *getLabel() const override { return "peacock-8"; }
|
const char *getLabel() const override { return "peacock-8"; }
|
||||||
const char *getDescription() const override {
|
const char *getDescription() const override {
|
||||||
|
Loading…
Reference in New Issue
Block a user