pitch computation
This commit is contained in:
parent
88ca7a5037
commit
af49dcf7b6
@ -38,6 +38,10 @@ void Chassis::initAudioPort(bool input, uint32_t index, AudioPort &port) {
|
|||||||
void Chassis::activate() {
|
void Chassis::activate() {
|
||||||
// calculate filter coefficients and stuff
|
// calculate filter coefficients and stuff
|
||||||
printf("called activate()\n");
|
printf("called activate()\n");
|
||||||
|
|
||||||
|
for (uint8_t i=0; i<104; i++) {
|
||||||
|
s.pitchCV[i] = (261.63 * powf(2, (i-24) / 12.0f)) / sampleRate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Chassis::deactivate() {
|
void Chassis::deactivate() {
|
||||||
@ -126,6 +130,15 @@ void Chassis::run(const float **, float **outputs, uint32_t frames, const MidiEv
|
|||||||
s.runLFO();
|
s.runLFO();
|
||||||
|
|
||||||
for (uint32_t i = 0; i < NUM_VOICES; i++) {
|
for (uint32_t i = 0; i < NUM_VOICES; i++) {
|
||||||
|
s.voice[i].calcPitch(s);
|
||||||
|
|
||||||
|
switch(s.patchRam.switch1 & 0x03) {
|
||||||
|
case 1: s.voice[i].omega /= 4; break;
|
||||||
|
case 2: s.voice[i].omega /= 2;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("voice %d note = %02x ff71 = %04x\n",i, s.voice[i].note, s.voice[i].ff71 );
|
||||||
s.voice[i].gate(s);
|
s.voice[i].gate(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,119 @@ bool Voice::isFree() {
|
|||||||
return ff10 == false;
|
return ff10 == false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Voice::calcPitch(Synth &s) {
|
||||||
|
uint32_t bc, de, ea, a;
|
||||||
|
|
||||||
|
// 03ad
|
||||||
|
ea = 0x1818;
|
||||||
|
|
||||||
|
// add in tuning value from ff61, not implemented
|
||||||
|
|
||||||
|
// 03ba
|
||||||
|
bc = s.ff51; // computed pitch LFO
|
||||||
|
if (s.ff4a & 0x02) {
|
||||||
|
ea -= bc;
|
||||||
|
} else {
|
||||||
|
ea += bc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 03c6
|
||||||
|
// add in bender from ff68
|
||||||
|
|
||||||
|
// 03d2
|
||||||
|
s.ff6f = ea;
|
||||||
|
|
||||||
|
ea = ff71;
|
||||||
|
a = note;
|
||||||
|
|
||||||
|
// 03e3
|
||||||
|
bc = a << 8;
|
||||||
|
|
||||||
|
// 03e6
|
||||||
|
a = 0; // set from porta coefficient ff7d
|
||||||
|
|
||||||
|
if (a != 0) goto h03f5;
|
||||||
|
|
||||||
|
// 3eb
|
||||||
|
ea = bc;
|
||||||
|
h03ec:
|
||||||
|
ff71 = ea; // STEAX (DE++)
|
||||||
|
|
||||||
|
// we're not looping so we can ignore until
|
||||||
|
// 03ee inrw ff0f voice counter
|
||||||
|
// 03f0 eqiw ff0f, 06
|
||||||
|
// 03f3 jr 03e0
|
||||||
|
|
||||||
|
goto h0407;
|
||||||
|
|
||||||
|
h03f5:
|
||||||
|
if (ea == bc) goto h03ec; // DNE EA, BC; JR 03EC store value
|
||||||
|
if (!(ea > bc)) goto h0401; // DGT EA, BC; JR 0401
|
||||||
|
ea -= a;
|
||||||
|
if (!(ea > bc)) ea = bc;
|
||||||
|
goto h03ec;
|
||||||
|
h0401:
|
||||||
|
ea += a;
|
||||||
|
if (!(ea < bc)) ea = bc;
|
||||||
|
goto h03ec;
|
||||||
|
|
||||||
|
h0407:
|
||||||
|
// this outputs the Sub Osc CV
|
||||||
|
// ignore until
|
||||||
|
// 0413 mviw ff0f, 0 reset voice counter
|
||||||
|
s.ff34 = 1; // unsure what this is used for
|
||||||
|
|
||||||
|
// 0419
|
||||||
|
ea = ff71; // pitch + fraction per voice
|
||||||
|
bc = s.ff6f; // tune + lfo + bend
|
||||||
|
ea += bc;
|
||||||
|
// 0424
|
||||||
|
s.ff6e = ea & 0xff; // MOV A, EAL; STAW 006e
|
||||||
|
a = ea >> 8; // mov a, EAH
|
||||||
|
|
||||||
|
// 0428
|
||||||
|
if (a <= 0x2f) goto h04a5; // GTI A,$2F; JRE $04A5
|
||||||
|
if (a >= 0x97) goto h04ac; // LTI A,$97; JRE $04AC
|
||||||
|
|
||||||
|
a -= 0x30;
|
||||||
|
|
||||||
|
h0432:
|
||||||
|
// printf("setting omega for note %d \n", a);
|
||||||
|
omega = ((s.pitchCV[a + 1] - s.pitchCV[a]) * (s.ff6e / 256.0)) + s.pitchCV[a];
|
||||||
|
// 0432 onwards calculates the address for the CV
|
||||||
|
// table at E60 and stacks it
|
||||||
|
// 043a onwards fetches the value from the divider
|
||||||
|
// table and computes a linear interpolation with the next one up
|
||||||
|
// using the fractional value stored in ff6e
|
||||||
|
|
||||||
|
// 045a onwards decides which divider to program
|
||||||
|
|
||||||
|
// 0471 unstacks the CV table address and calculates a linear
|
||||||
|
// interpolation of this and the next CV value using ff6e
|
||||||
|
// 048b onwards sends it to the correct DAC
|
||||||
|
|
||||||
|
// 0496 onwards works out which vocie to do next and loops
|
||||||
|
|
||||||
|
// 04a3
|
||||||
|
goto h04d5;
|
||||||
|
|
||||||
|
h04a5: // pitch too low
|
||||||
|
s.ff6e = 0;
|
||||||
|
a = 0;
|
||||||
|
goto h0432;
|
||||||
|
|
||||||
|
h04ac: // pitch too high
|
||||||
|
s.ff6e = 0;
|
||||||
|
a = 0x66;
|
||||||
|
goto h0432;
|
||||||
|
|
||||||
|
// 04b3 programs the dividers somehow
|
||||||
|
// ignore until 04d5
|
||||||
|
|
||||||
|
h04d5:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void Voice::on(uint32_t key, bool reset = 0) {
|
void Voice::on(uint32_t key, bool reset = 0) {
|
||||||
// what's with the crazy private variables and all the gotos with crazy labels?
|
// what's with the crazy private variables and all the gotos with crazy labels?
|
||||||
// this code emulates the 78C11 code directly (probably inefficiently)
|
// this code emulates the 78C11 code directly (probably inefficiently)
|
||||||
@ -37,6 +150,8 @@ void Voice::on(uint32_t key, bool reset = 0) {
|
|||||||
// this current implementation doesn't reset the voice
|
// this current implementation doesn't reset the voice
|
||||||
(void)reset;
|
(void)reset;
|
||||||
|
|
||||||
|
// printf("called with key=%d\n", note);
|
||||||
|
|
||||||
ff10 = true; // note held from keyboard
|
ff10 = true; // note held from keyboard
|
||||||
ff07 = true; // attack phase
|
ff07 = true; // attack phase
|
||||||
if (note == key) goto h0144;
|
if (note == key) goto h0144;
|
||||||
@ -57,7 +172,9 @@ h0144:
|
|||||||
h0149:
|
h0149:
|
||||||
// this is in the wrong place really but is the equivalent of programming the counter
|
// this is in the wrong place really but is the equivalent of programming the counter
|
||||||
// and VCO ramp DAC
|
// and VCO ramp DAC
|
||||||
omega = (261.63 * powf(2, (note - 60) / 12.0f)) / 48000.0f;
|
// omega = (261.63 * powf(2, (note - 60) / 12.0f)) / 48000.0f;
|
||||||
|
// printf("note, key = %d, %d\n", note, key);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Voice::off() {
|
void Voice::off() {
|
||||||
@ -178,7 +295,8 @@ h032d:
|
|||||||
ea = (bc & 0xff) * a; // MUL C
|
ea = (bc & 0xff) * a; // MUL C
|
||||||
d = a; // MOV D,A
|
d = a; // MOV D,A
|
||||||
a = (ea >> 8); // MOV A,EAH
|
a = (ea >> 8); // MOV A,EAH
|
||||||
bc &= 0xff00; bc |= a; // MOV C,A
|
bc &= 0xff00;
|
||||||
|
bc |= a; // MOV C,A
|
||||||
a = d; // MOV A,D
|
a = d; // MOV A,D
|
||||||
|
|
||||||
// 0345
|
// 0345
|
||||||
@ -203,7 +321,8 @@ h032d:
|
|||||||
ea = (bc & 0xff) * a; // MUL C
|
ea = (bc & 0xff) * a; // MUL C
|
||||||
d = a; // MOV D,A
|
d = a; // MOV D,A
|
||||||
a = ea >> 8; // MOV A, EAH
|
a = ea >> 8; // MOV A, EAH
|
||||||
bc &= 0xff00; bc |= a; // MOV C,A
|
bc &= 0xff00;
|
||||||
|
bc |= a; // MOV C,A
|
||||||
a = d; // MOV A,D
|
a = d; // MOV A,D
|
||||||
ea = (bc >> 8) * a; // MUL B
|
ea = (bc >> 8) * a; // MUL B
|
||||||
ea += (bc & 0xff); // EADD EA,C
|
ea += (bc & 0xff); // EADD EA,C
|
||||||
|
@ -19,10 +19,11 @@
|
|||||||
// contains the actual sound generation code
|
// contains the actual sound generation code
|
||||||
|
|
||||||
#include "voice.hpp"
|
#include "voice.hpp"
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
static inline float poly3blep0(float t) {
|
static inline float poly3blep0(float t) {
|
||||||
float t2 = t * t;
|
float t2 = t * t;
|
||||||
return 2 * (t * t2 - 0.5f * t2 * t2);
|
return 2 * (t * t2 - 0.5f * t2 * t2);
|
||||||
@ -40,7 +41,6 @@ void Voice::run(Synth &s, float *buffer, uint32_t samples) {
|
|||||||
// there's a resistor on the panel board to sprag the range
|
// there's a resistor on the panel board to sprag the range
|
||||||
float pw = s.ff4f / 32768.0f;
|
float pw = s.ff4f / 32768.0f;
|
||||||
|
|
||||||
|
|
||||||
float sqr = 0.175;
|
float sqr = 0.175;
|
||||||
float saw = (s.patchRam.switch1 & 0x10) ? 0.220 : 0;
|
float saw = (s.patchRam.switch1 & 0x10) ? 0.220 : 0;
|
||||||
float sub = (s.patchRam.sub / 127.0f) * 0.275;
|
float sub = (s.patchRam.sub / 127.0f) * 0.275;
|
||||||
|
@ -29,14 +29,14 @@ class Voice {
|
|||||||
uint8_t note = 60; // per-voice note, set to middle C at 02b1h
|
uint8_t note = 60; // per-voice note, set to middle C at 02b1h
|
||||||
|
|
||||||
void on(uint32_t key, bool reset);
|
void on(uint32_t key, bool reset);
|
||||||
|
|
||||||
void off();
|
void off();
|
||||||
|
|
||||||
bool isFree();
|
bool isFree();
|
||||||
|
|
||||||
void run(Synth &s, float *buffer, uint32_t samples);
|
void run(Synth &s, float *buffer, uint32_t samples);
|
||||||
|
|
||||||
void gate(Synth &s);
|
void gate(Synth &s);
|
||||||
|
void calcPitch(Synth &s);
|
||||||
|
uint16_t ff71 = 0; // stores pitch + fraction
|
||||||
|
|
||||||
|
float omega;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum { ATTACK,
|
enum { ATTACK,
|
||||||
@ -57,7 +57,7 @@ class Voice {
|
|||||||
|
|
||||||
uint16_t env;
|
uint16_t env;
|
||||||
|
|
||||||
float phase = 0, omega = 260 / 48000.0, subosc = 1;
|
float phase = 0, subosc = 1;
|
||||||
// float env, target;
|
// float env, target;
|
||||||
float delay;
|
float delay;
|
||||||
uint8_t pulseStage = 0;
|
uint8_t pulseStage = 0;
|
||||||
@ -111,6 +111,7 @@ class Synth {
|
|||||||
// RAM from ff00h to ffffh is cleared to zero
|
// RAM from ff00h to ffffh is cleared to zero
|
||||||
// this is in the startup routine at 0280h
|
// this is in the startup routine at 0280h
|
||||||
uint8_t ff1e = 0;
|
uint8_t ff1e = 0;
|
||||||
|
uint8_t ff34 = 0;
|
||||||
uint8_t ff4a = 0; // LFO flags
|
uint8_t ff4a = 0; // LFO flags
|
||||||
uint16_t ff4d = 0; // LFO output value
|
uint16_t ff4d = 0; // LFO output value
|
||||||
uint16_t ff4f = 0; // computed PWM LFO
|
uint16_t ff4f = 0; // computed PWM LFO
|
||||||
@ -119,6 +120,9 @@ class Synth {
|
|||||||
uint16_t ff56 = 0; // LFO Delay envelope
|
uint16_t ff56 = 0; // LFO Delay envelope
|
||||||
uint16_t ff5a = 0; // LFO Delay holdoff
|
uint16_t ff5a = 0; // LFO Delay holdoff
|
||||||
uint8_t ff64 = 0; // LFO mod sens amount
|
uint8_t ff64 = 0; // LFO mod sens amount
|
||||||
|
uint8_t ff6e = 0; // fractional pitch temp
|
||||||
|
uint16_t ff6f = 0; // computed pitch amount
|
||||||
|
//uint16_t ff71 = 0; // unsure, to do with pitch
|
||||||
|
|
||||||
// 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
|
||||||
@ -200,6 +204,8 @@ class Synth {
|
|||||||
uint16_t lfoDelayTable[8] = {
|
uint16_t lfoDelayTable[8] = {
|
||||||
0xffff, 0x0419, 0x020c, 0x015e, 0x0100, 0x0100, 0x0100, 0x0100};
|
0xffff, 0x0419, 0x020c, 0x015e, 0x0100, 0x0100, 0x0100, 0x0100};
|
||||||
|
|
||||||
|
float pitchCV[104];
|
||||||
|
|
||||||
void runLFO();
|
void runLFO();
|
||||||
void lfoDelay();
|
void lfoDelay();
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user