LFO delay code
This commit is contained in:
parent
6bf1cc1da1
commit
88ca7a5037
@ -25,7 +25,6 @@ Chassis::Chassis() : Plugin(parameterCount, 0, 0), sampleRate(getSampleRate()) {
|
|||||||
|
|
||||||
// Initialisation functions
|
// Initialisation functions
|
||||||
|
|
||||||
|
|
||||||
void Chassis::initAudioPort(bool input, uint32_t index, AudioPort &port) {
|
void Chassis::initAudioPort(bool input, uint32_t index, AudioPort &port) {
|
||||||
port.groupId = kPortGroupStereo;
|
port.groupId = kPortGroupStereo;
|
||||||
Plugin::initAudioPort(input, index, port);
|
Plugin::initAudioPort(input, index, port);
|
||||||
@ -49,6 +48,7 @@ void Chassis::deactivate() {
|
|||||||
|
|
||||||
void Chassis::noteOn(uint8_t note) {
|
void Chassis::noteOn(uint8_t note) {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
s.keyon = true;
|
||||||
for (i = 0; i < NUM_VOICES; i++) {
|
for (i = 0; i < NUM_VOICES; i++) {
|
||||||
vPtr++;
|
vPtr++;
|
||||||
if (vPtr == NUM_VOICES) vPtr = 0;
|
if (vPtr == NUM_VOICES) vPtr = 0;
|
||||||
@ -70,6 +70,7 @@ void Chassis::noteOn(uint8_t note) {
|
|||||||
|
|
||||||
void Chassis::noteOff(uint8_t note) {
|
void Chassis::noteOff(uint8_t note) {
|
||||||
// printf("noteoff %d\n", note);
|
// printf("noteoff %d\n", note);
|
||||||
|
s.keyon = false;
|
||||||
for (uint32_t i = 0; i < NUM_VOICES; i++) {
|
for (uint32_t i = 0; i < NUM_VOICES; i++) {
|
||||||
if (s.voice[i].note == note && !s.voice[i].isFree()) {
|
if (s.voice[i].note == note && !s.voice[i].isFree()) {
|
||||||
s.voice[i].off();
|
s.voice[i].off();
|
||||||
@ -121,7 +122,8 @@ void Chassis::run(const float **, float **outputs, uint32_t frames, const MidiEv
|
|||||||
doMidi(midiEvents, midiEventCount, framePos + s.blockLeft);
|
doMidi(midiEvents, midiEventCount, framePos + s.blockLeft);
|
||||||
|
|
||||||
// printf("compute params and reset block size\n");
|
// printf("compute params and reset block size\n");
|
||||||
s.runLFO();
|
s.lfoDelay();
|
||||||
|
s.runLFO();
|
||||||
|
|
||||||
for (uint32_t i = 0; i < NUM_VOICES; i++) {
|
for (uint32_t i = 0; i < NUM_VOICES; i++) {
|
||||||
s.voice[i].gate(s);
|
s.voice[i].gate(s);
|
||||||
|
@ -128,6 +128,137 @@ h0590:
|
|||||||
// printf("%04x %d %d %d %d %d \n", ea, ff07, ff08, ff10, ff11, ff33);
|
// printf("%04x %d %d %d %d %d \n", ea, ff07, ff08, ff10, ff11, ff33);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Synth::lfoDelay() {
|
||||||
|
// compute LFO delay
|
||||||
|
|
||||||
|
uint16_t a, bc, d, de, ea, tos;
|
||||||
|
|
||||||
|
// 030d
|
||||||
|
if (!keyon /* ff11 */) goto h036b; // skip ahead if no notes are pressed
|
||||||
|
|
||||||
|
// 0312
|
||||||
|
if (!(ff1e & 0x08)) goto h0323; // a note is running, don't reset
|
||||||
|
|
||||||
|
// 0315 no note is running, reset it all
|
||||||
|
bc = 0;
|
||||||
|
ff56 = 0; // delay envelope
|
||||||
|
ff5a = 0; // holdoff timer
|
||||||
|
ff1e &= 0xf1; // mask bits in flag byte
|
||||||
|
|
||||||
|
h0323:
|
||||||
|
if (!(ff1e & 0x02)) goto h0370; // compute delay envelope
|
||||||
|
if (!(ff1e & 0x04)) goto h0388; // compute holdoff timer
|
||||||
|
|
||||||
|
// 032b
|
||||||
|
bc |= 0xff00; // initial scaling value?
|
||||||
|
|
||||||
|
//printf("0323 ");
|
||||||
|
|
||||||
|
h032d:
|
||||||
|
tos = bc; // push bc
|
||||||
|
|
||||||
|
// 032e
|
||||||
|
a = lfoDepthTable[patchRam.vcoLfo];
|
||||||
|
|
||||||
|
// MUL B; MOV A, EAH
|
||||||
|
a = (a * (bc >> 8)) >> 8;
|
||||||
|
|
||||||
|
// 0333 ADDNCW $0064; MVI A, $FF
|
||||||
|
a += ff64;
|
||||||
|
if (a > 0xff) a = 0xff;
|
||||||
|
|
||||||
|
// 0338 sets up HL to store computed pitch LFO output
|
||||||
|
|
||||||
|
// 33b
|
||||||
|
bc = ff4d; // current LFO output
|
||||||
|
|
||||||
|
// printf("-----------------------%02x %04x\n", a, bc);
|
||||||
|
|
||||||
|
// 033f
|
||||||
|
ea = (bc & 0xff) * a; // MUL C
|
||||||
|
d = a; // MOV D,A
|
||||||
|
a = (ea >> 8); // MOV A,EAH
|
||||||
|
bc &= 0xff00; bc |= a; // MOV C,A
|
||||||
|
a = d; // MOV A,D
|
||||||
|
|
||||||
|
// 0345
|
||||||
|
ea = (bc >> 8) * a; // MUL B
|
||||||
|
ea += (bc & 0xff); // EADD EA, C
|
||||||
|
|
||||||
|
// 0349
|
||||||
|
ea >>= 3; // divide by eight
|
||||||
|
|
||||||
|
// 034f
|
||||||
|
ff51 = ea; // save scaled pitch LFO
|
||||||
|
|
||||||
|
bc = tos; // pop BC, contains scaling amount
|
||||||
|
a = patchRam.vcfLfo << 1; // amount is doubled and stored at ff48
|
||||||
|
|
||||||
|
// 0354
|
||||||
|
ea = (bc >> 8) * a; // MUL B
|
||||||
|
a = ea >> 8; // MOV A, EAH
|
||||||
|
bc = ff4d; // current LFO output
|
||||||
|
|
||||||
|
// 035b
|
||||||
|
ea = (bc & 0xff) * a; // MUL C
|
||||||
|
d = a; // MOV D,A
|
||||||
|
a = ea >> 8; // MOV A, EAH
|
||||||
|
bc &= 0xff00; bc |= a; // MOV C,A
|
||||||
|
a = d; // MOV A,D
|
||||||
|
ea = (bc >> 8) * a; // MUL B
|
||||||
|
ea += (bc & 0xff); // EADD EA,C
|
||||||
|
ea >>= 1; // DSLR A
|
||||||
|
ff53 = ea; // save scaled VCF LFO
|
||||||
|
goto h03a1;
|
||||||
|
|
||||||
|
h036b:
|
||||||
|
ff1e |= 0x08; // set LFO flag
|
||||||
|
goto h0323;
|
||||||
|
|
||||||
|
h0370: // calculate holdoff time
|
||||||
|
//printf("0370 ");
|
||||||
|
ea = ff56; // holdoff time
|
||||||
|
bc = attackTable[patchRam.lfoDelay]; // stored at ff58
|
||||||
|
// 0379
|
||||||
|
ea += bc; // DADD EA,BC
|
||||||
|
ff56 = ea; // STEAX (DE) which still holds ff56 from 0x370
|
||||||
|
|
||||||
|
a = ea >> 8; // MOV A, EAH
|
||||||
|
if (a & 0xc0) goto h0385; // OFFI A, $C0
|
||||||
|
bc &= 0xff; // MOV B, 0
|
||||||
|
goto h032d;
|
||||||
|
h0385:
|
||||||
|
ff1e |= 0x02; // stop predelay flag
|
||||||
|
|
||||||
|
h0388:
|
||||||
|
//printf("0388 ");
|
||||||
|
ea = ff5a; // envelope speed
|
||||||
|
|
||||||
|
// 038d
|
||||||
|
bc = lfoDelayTable[patchRam.lfoDelay >> 4]; // delay setting divided by 8 and saved at ff6c
|
||||||
|
|
||||||
|
//printf("---------------------------------------- %04x %04x\n", ea, bc);
|
||||||
|
|
||||||
|
// 0391 DADDNC EA, BC
|
||||||
|
if ((ea + bc) > 0xffff) goto h039a;
|
||||||
|
ea += bc;
|
||||||
|
|
||||||
|
// 394
|
||||||
|
ff5a = ea; // STEAX (HL) hl still contains ff5a
|
||||||
|
|
||||||
|
bc |= (ea & 0xff00); // MOV A, EAH; MOV B, A
|
||||||
|
goto h032d;
|
||||||
|
|
||||||
|
h039a:
|
||||||
|
ff1e |= 0x04;
|
||||||
|
bc |= 0xff; // MVI B, $ff
|
||||||
|
goto h032d;
|
||||||
|
|
||||||
|
h03a1:
|
||||||
|
//printf("LFO=%04x VCF=%04x flags=%02x holdoff=%04x envelope=%04x\n", ff51, ff53, ff1e, ff56, ff5a);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void Synth::runLFO() {
|
void Synth::runLFO() {
|
||||||
// compute a loop's worth of LFO
|
// compute a loop's worth of LFO
|
||||||
|
|
||||||
@ -187,13 +318,13 @@ h078b:
|
|||||||
goto h075f; // store in LFO output variable
|
goto h075f; // store in LFO output variable
|
||||||
|
|
||||||
h079a:
|
h079a:
|
||||||
ea = 0; // output is close (enough) to zero, clamp
|
ea = 0; // output is close (enough) to zero, clamp
|
||||||
ff4a++; // increment the flags
|
ff4a++; // increment the flags
|
||||||
goto h075f; // store in LFO output variable
|
goto h075f; // store in LFO output variable
|
||||||
|
|
||||||
h07a2: // LFO output is positive
|
h07a2: // LFO output is positive
|
||||||
ea += 0x2000; // add on 0x2000 to scale PWM to 0 - 0x3fff
|
ea += 0x2000; // add on 0x2000 to scale PWM to 0 - 0x3fff
|
||||||
goto h076b; // jump back to scale LFO amount
|
goto h076b; // jump back to scale LFO amount
|
||||||
|
|
||||||
h07a9:
|
h07a9:
|
||||||
return;
|
return;
|
||||||
|
@ -26,8 +26,7 @@ class Synth;
|
|||||||
|
|
||||||
class Voice {
|
class Voice {
|
||||||
public:
|
public:
|
||||||
// uint8_t note = 72;
|
uint8_t note = 60; // per-voice note, set to middle C at 02b1h
|
||||||
uint8_t note = 60;
|
|
||||||
|
|
||||||
void on(uint32_t key, bool reset);
|
void on(uint32_t key, bool reset);
|
||||||
|
|
||||||
@ -107,15 +106,19 @@ class Synth {
|
|||||||
uint32_t blockLeft;
|
uint32_t blockLeft;
|
||||||
uint32_t framesLeft = 0;
|
uint32_t framesLeft = 0;
|
||||||
|
|
||||||
uint8_t ff1e;
|
bool keyon;
|
||||||
uint8_t ff4a; // LFO flags
|
|
||||||
|
// RAM from ff00h to ffffh is cleared to zero
|
||||||
|
// this is in the startup routine at 0280h
|
||||||
|
uint8_t ff1e = 0;
|
||||||
|
uint8_t ff4a = 0; // LFO flags
|
||||||
uint16_t ff4d = 0; // LFO output value
|
uint16_t ff4d = 0; // LFO output value
|
||||||
uint16_t ff4f; // computed PWM LFO
|
uint16_t ff4f = 0; // computed PWM LFO
|
||||||
uint16_t ff51; // computed pitch LFO
|
uint16_t ff51 = 0; // computed pitch LFO
|
||||||
uint16_t ff53; // computed VCF LFO
|
uint16_t ff53 = 0; // computed VCF LFO
|
||||||
uint16_t ff56; // LFO Delay envelope
|
uint16_t ff56 = 0; // LFO Delay envelope
|
||||||
uint16_t ff5a; // LFO Delay holdoff
|
uint16_t ff5a = 0; // LFO Delay holdoff
|
||||||
uint8_t ff64; // LFO mod sens amount
|
uint8_t ff64 = 0; // LFO mod sens amount
|
||||||
|
|
||||||
// okay, not the greatest, this right here
|
// okay, not the greatest, this right here
|
||||||
// this struct contains the bytes that make up a Juno 106 patch in
|
// this struct contains the bytes that make up a Juno 106 patch in
|
||||||
@ -124,13 +127,16 @@ class Synth {
|
|||||||
// the horrifying implication here is that we can just shunt this
|
// the horrifying implication here is that we can just shunt this
|
||||||
// around and memcpy() values from sysex on top of it
|
// around and memcpy() values from sysex on top of it
|
||||||
|
|
||||||
|
// this is set to a "sensible" patch
|
||||||
|
// the comments indicate what the defaults are set to
|
||||||
|
// in the routine at 02c2h, in case they're important
|
||||||
struct {
|
struct {
|
||||||
uint8_t lfoRate = 57;
|
uint8_t lfoRate = 57; // lookup value defaults to 0x0200
|
||||||
uint8_t lfoDelay = 45;
|
uint8_t lfoDelay = 45;
|
||||||
uint8_t vcoLfo = 0;
|
uint8_t vcoLfo = 0;
|
||||||
uint8_t pwmLfo = 55;
|
uint8_t pwmLfo = 55;
|
||||||
uint8_t noise = 0;
|
uint8_t noise = 0;
|
||||||
uint8_t vcfFreq = 85;
|
uint8_t vcfFreq = 85; // 0x3f80
|
||||||
uint8_t vcfReso = 0;
|
uint8_t vcfReso = 0;
|
||||||
uint8_t vcfEnv = 0;
|
uint8_t vcfEnv = 0;
|
||||||
uint8_t vcfLfo = 0;
|
uint8_t vcfLfo = 0;
|
||||||
@ -138,7 +144,7 @@ class Synth {
|
|||||||
uint8_t vca = 52;
|
uint8_t vca = 52;
|
||||||
uint8_t env_a = 59;
|
uint8_t env_a = 59;
|
||||||
uint8_t env_d = 32;
|
uint8_t env_d = 32;
|
||||||
uint8_t env_s = 86;
|
uint8_t env_s = 86; // 0x3f80
|
||||||
uint8_t env_r = 40;
|
uint8_t env_r = 40;
|
||||||
uint8_t sub = 0;
|
uint8_t sub = 0;
|
||||||
uint8_t switch1 = 26;
|
uint8_t switch1 = 26;
|
||||||
@ -174,5 +180,26 @@ class Synth {
|
|||||||
0x0b18, 0x0b7c, 0x0be0, 0x0c58, 0x0cd0, 0x0d48, 0x0dde, 0x0e74, 0x0f0a,
|
0x0b18, 0x0b7c, 0x0be0, 0x0c58, 0x0cd0, 0x0d48, 0x0dde, 0x0e74, 0x0f0a,
|
||||||
0x0fa0, 0x1000};
|
0x0fa0, 0x1000};
|
||||||
|
|
||||||
|
uint16_t attackTable[128] = {
|
||||||
|
0x4000, 0x2000, 0x1000, 0x0aaa, 0x0800, 0x0666, 0x0555, 0x0492, 0x0400,
|
||||||
|
0x038e, 0x0333, 0x02e9, 0x02ab, 0x0276, 0x0249, 0x0222, 0x0200, 0x01e2,
|
||||||
|
0x01c7, 0x01af, 0x0199, 0x0186, 0x0174, 0x0164, 0x0155, 0x0148, 0x013b,
|
||||||
|
0x012f, 0x0124, 0x011a, 0x0111, 0x0108, 0x0100, 0x00f8, 0x00f1, 0x00ea,
|
||||||
|
0x00e4, 0x00dd, 0x00d8, 0x00d2, 0x00cd, 0x00c8, 0x00c3, 0x00bf, 0x00ba,
|
||||||
|
0x00b6, 0x00b2, 0x00ae, 0x00ab, 0x00a7, 0x00a4, 0x00a1, 0x009e, 0x009b,
|
||||||
|
0x0098, 0x0095, 0x0092, 0x0090, 0x008d, 0x008b, 0x0089, 0x0086, 0x0084,
|
||||||
|
0x0082, 0x007f, 0x007d, 0x007a, 0x0077, 0x0074, 0x0072, 0x006f, 0x006c,
|
||||||
|
0x0069, 0x0067, 0x0064, 0x0061, 0x005e, 0x005c, 0x0059, 0x0056, 0x0053,
|
||||||
|
0x0050, 0x004e, 0x004b, 0x0048, 0x0045, 0x0042, 0x0040, 0x003f, 0x003d,
|
||||||
|
0x003c, 0x003a, 0x0039, 0x0037, 0x0036, 0x0034, 0x0033, 0x0031, 0x0030,
|
||||||
|
0x002e, 0x002d, 0x002b, 0x002a, 0x0028, 0x0027, 0x0025, 0x0024, 0x0022,
|
||||||
|
0x0021, 0x0021, 0x0020, 0x0020, 0x001f, 0x001f, 0x001e, 0x001e, 0x001d,
|
||||||
|
0x001d, 0x001c, 0x001c, 0x001b, 0x001b, 0x001a, 0x0019, 0x0018, 0x0017,
|
||||||
|
0x0016, 0x0015};
|
||||||
|
|
||||||
|
uint16_t lfoDelayTable[8] = {
|
||||||
|
0xffff, 0x0419, 0x020c, 0x015e, 0x0100, 0x0100, 0x0100, 0x0100};
|
||||||
|
|
||||||
void runLFO();
|
void runLFO();
|
||||||
|
void lfoDelay();
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user