reworked assigner note on

This commit is contained in:
Gordon JC Pearce 2024-09-17 21:10:00 +01:00
parent 72fa8a2aab
commit 3e16f5314f
3 changed files with 229 additions and 158 deletions

View File

@ -2,6 +2,8 @@
#include "cpuboard.hpp"
// startup needs to clear RAM etc
// 0xffbe = 0x0c; transpose = 12;
// Disassembly of assigner.bin, 8192 bytes [0x0 to 0x1fff]
// ; start
// 0000: 4e 9a JRE $009C
@ -20,7 +22,7 @@
// 000a: 04 08 10 LXI SP,$1008
// 000d: 20 40 INRW $0040
// 000f: 80 CALT ($0080)
//
// ; bit patterns used for Note Off
// ; ANDed with a flag byte to mask it off
// 0010: fe JR $000F
@ -30,7 +32,7 @@
// 0014: ef JR $0004
// 0015: df JR $0035
// 0016: bf 7f STAX (HL+$7F)
//
// ; timer/event
// 0018: 00 NOP
// 0019: 00 NOP
@ -873,7 +875,7 @@
// 0592: 11 EXX
// 0593: aa EI
// 0594: 62 RETI
//
// ; serial interrupt handler
// 0595: 10 EXA
// 0596: 11 EXX
@ -910,7 +912,7 @@
// 05d5: 75 a0 00 EQIW $00A0,$00
// 05d8: 71 a0 80 MVIW $00A0,$80
// 05db: d3 JR $05EF ; return from interrupt
//
// ; handle control change
// 05dc: 1b MOV C,A
// 05dd: 0a MOV A,B
@ -927,7 +929,7 @@
// 05f0: 11 EXX
// 05f1: aa EI
// 05f2: 62 RETI
//
// ; wasn't control or note
// 05f3: 67 c0 NEI A,$C0 ; program change?
// 05f5: c4 JR $05FA
@ -1050,142 +1052,200 @@
//
// ; handle note on/off?
// ; called with status in $ff4e, value in $ff3e and velocity in C
// 06ca: 01 3e LDAW $003E ; first byte
// 06cc: 27 17 GTI A,$17 ; greater than 23
// 06ce: 4e 36 JRE $0706 ; no, add an octave
// 06d0: 37 6d LTI A,$6D ; less than 108
// 06d2: 4e 36 JRE $070A ; no, subtract an octave
// 06d4: 74 e0 be SUBW $00BE ; subtract a value - transpose?
// 06d7: 1a MOV B,A ; save in b
// 06d8: 48 22 SLR B
// 06da: 48 22 SLR B
// 06dc: 48 22 SLR B ; divide by 8
// 06de: 07 07 ANI A,$07 ; lower three bits
// 06e0: 75 4e 90 EQIW $004E,$90 ; note on?
// 06e3: d5 JR $06F9 ; no, jump ahead
// 06e4: 74 6b 00 NEI C,$00 ; velocity 0
// 06e7: d1 JR $06F9 ; no, jump ahead
// ; otherwise fall through and handle Note On
// 06e8: 34 08 00 LXI HL,$0008 ; lookup table runs 01, 02, 04, 08, 10, 20, 40, 80
// ; inverse of the one at 0x0010
// 06eb: ac LDAX (HL+A) ; look up table based on note
// 06ec: 1b MOV C,A ; save
// 06ed: 34 40 ff LXI HL,$FF40 ; bit flags
// 06f0: ad LDAX (HL+B) ; byte pointed to by upper part
// 06f1: 60 9b ORA A,C ; or in whichever note is flagged
// 06f3: bd STAX (HL+B) ; save in flag
//
// ;
// 06f4: 71 3f 01 MVIW $003F,$01 ; expect two bytes
// 06f7: 4f 53 JRE $064C ; return
//
// ; note off?
// ; A contains lower three bits of note, B contains upper 4 bits
// 06f9: 34 10 00 LXI HL,$0010 ; lookup table runs fe, fd, fb, f7, ef, df, bf, 7f
// ; inverse of 0x0008
// 06fc: ac LDAX (HL+A) ; look up the table based on the note
// 06fd: 1b MOV C,A ; fetch value, store in C
// 06fe: 34 40 ff LXI HL,$FF40 ; table in RAM
// 0701: ad LDAX (HL+B) ; $FF40 + upper four bits as offset
// 0702: 60 8b ANA A,C ; mask off the bit for the note
// 0704: bd STAX (HL+B) ; store at $FF40 + offset
// 0705: ee JR $06F4
//
// ; add or subtract an octave to bring out-of-range notes in
// 0706: 46 0c ADI A,$0C ; add 12 to note value in A
// 0708: 4f c2 JRE $06CC ; jump back and test if it's in range yet
// 070a: 66 0c SUI A,$0C ; subtract 12 from note value in A
// 070c: 4f c2 JRE $06D0 ; jump back and test if it's in range yet
//
// ; store first value
// 070e: 63 3e STAW $003E
// 0710: 4f 3a JRE $064C ; return from interrupt
//
// ; control change?
// 0712: 01 3e LDAW $003E ; parameter?
// 0714: 27 7a GTI A,$7A ; all notes off, or higher?
// 0716: 4e 35 JRE $074D
// 0718: 45 4f 40 ONIW $004F,$40 ; flag variable
// 071b: 4f d7 JRE $06F4
// 071d: 67 7b NEI A,$7B ; all notes off?
// 071f: 4e 51 JRE $0772
// 0721: 47 02 ONI A,$02 ; mono/poly (but ignored according to the manual)
// 0723: c8 JR $072C
// 0724: 05 4f fd ANIW $004F,$FD ; flag variable
// 0727: 47 01 ONI A,$01 ; omni on
// 0729: 4e 4d JRE $0778 ; set omni off
// 072b: c8 JR $0734
// 072c: 05 4f fe ANIW $004F,$FE ; clear flag variable bit 0
// 072f: 47 01 ONI A,$01 ; if mono on?
// 0731: 15 4f 01 ORIW $004F,$01 ; set flag variable?
// 0734: 69 03 MVI A,$03
// 0736: 74 88 4f ANAW $004F
// 0739: 15 4f 20 ORIW $004F,$20
// 073c: 77 01 EQI A,$01
// 073e: 05 4f df ANIW $004F,$DF
// 0741: 6a 0d MVI B,$0D ; 14 values
// 0743: 69 00 MVI A,$00 ; zero out note flags
// 0745: 34 40 ff LXI HL,$FF40 ; table in RAM for note flags
// 0748: 3d STAX (HL+) ; store
// 0749: 52 DCR B
// 074a: fd JR $0748 ; loop
// 074b: 4f a7 JRE $06F4 ; expect two bytes
// 074d: 77 40 EQI A,$40 ; sustain
// 074f: ce JR $075E
// 0750: 74 6b 00 NEI C,$00 ; value is zero
// 0753: c5 JR $0759
// 0754: 15 b6 10 ORIW $00B6,$10 ; sustain on
// 0757: 4f 9b JRE $06F4
// 0759: 15 b6 08 ORIW $00B6,$08 ; sustain off
// 075c: 4f 96 JRE $06F4
// 075e: 77 01 EQI A,$01 ; mod wheel
// 0760: 4f 92 JRE $06F4 ; expect two bytes and return (running status)
// 0762: 55 a8 20 OFFIW $00A8,$20 ; midi mode 0
// 0765: c7 JR $076D ; continue
// 0766: 0b MOV A,C ; get byte
// 0767: 17 80 ORI A,$80 ; set bit?
// 0769: 63 a2 STAW $00A2 ; mod wheel value?
// 076b: 4f 87 JRE $06F4 ; expect two bytes and return (running status)
// 076d: 71 a2 80 MVIW $00A2,$80 ; mod wheel off?
// 0770: 4f 82 JRE $06F4 ; expect two bytes and return
//
// ; handle all notes off
// 0772: 5d 4f BIT 5,$004F ; all notes off?
// 0774: 4f 7e JRE $06F4 ; expect two bytes and return
// 0776: 4f c9 JRE $0741 ; wipe a table
// 0778: 74 7b 01 EQI C,$01
// 077b: 15 4f 02 ORIW $004F,$02
// 077e: 4f b4 JRE $0734
//
// ; program change
// 0780: 55 a8 20 OFFIW $00A8,$20 ; Midi mode 0?
// 0783: c5 JR $0789 ; skip ahead and do nothing
// 0784: 0b MOV A,C ; get prog
// 0785: 17 80 ORI A,$80 ; bit 7
// 0787: 63 a3 STAW $00A3 ; store
// 0789: 71 3f 00 MVIW $003F,$00 ; expect one byte (running status)
// 078c: 54 4c 06 JMP $064C ; return
//
// ; bend
// 078f: 55 a8 20 OFFIW $00A8,$20 ; midi mode 0?
// 0792: d7 JR $07AA ; clear and end
// 0793: 0b MOV A,C
// 0794: 18 MOV EAH,A ; EAH gets msb
// 0795: 01 3e LDAW $003E ; lsb
// 0797: 48 25 SLL A ; multiply by two
// 0799: 19 MOV EAL,A ; EA contains 14-bit bend multiplied by 2
// 079a: 48 a4 DSLL EA ; left aligned
// 079c: 08 MOV A,EAH
// 079d: 47 80 ONI A,$80 ; negative?
// 079f: c4 JR $07A4
// 07a0: 63 a1 STAW $00A1 ; save in ffa1
// 07a2: 4f 50 JRE $06F4 ; return, two byte running status
// 07a4: 16 ff XRI A,$FF ; invert
// 07a6: 63 a0 STAW $00A0 ; save in ffa0
// 07a8: 4f 4a JRE $06F4 ; return, two byte running status
// 07aa: 71 a1 80 MVIW $00A1,$80 ; reset bend?
// 07ad: 4f 45 JRE $06F4 ; return, two byte running status
//
void Assigner::noteOn(uint8_t c) {
// 06ca: 01 3e LDAW $003E ; first byte
a = ram[0x3e];
h06cc:
// 06cc: 27 17 GTI A,$17 ; greater than 23
// 06ce: 4e 36 JRE $0706 ; no, add an octave
if (a > 0x17) {
// skip
} else
goto h0706;
h06d0:
// 06d0: 37 6d LTI A,$6D ; less than 108
// 06d2: 4e 36 JRE $070A ; no, subtract an octave
if (a < 0x6d) {
// skip
} else
goto h070a;
// 06d4: 74 e0 be SUBW $00BE ; subtract a value - transpose?
a -= ram[0xbe];
// 06d7: 1a MOV B,A ; save in b
b = a;
// 06d8: 48 22 SLR B
// 06da: 48 22 SLR B
// 06dc: 48 22 SLR B ; divide by 8
b >>= 3;
// 06de: 07 07 ANI A,$07 ; lower three bits
a &= 0x07;
// 06e0: 75 4e 90 EQIW $004E,$90 ; note on?
// 06e3: d5 JR $06F9 ; no, jump ahead
if (ram[0x4e] == 0x90) {
// skip
} else
goto h06f9;
// 06e4: 74 6b 00 NEI C,$00 ; velocity 0
// 06e7: d1 JR $06F9 ; no, jump ahead
if (c != 0) {
// skip
} else
goto h06f9;
// ; otherwise fall through and handle Note On
// 06e8: 34 08 00 LXI HL,$0008 ; lookup table runs 01, 02, 04, 08, 10, 20, 40, 80
// ; inverse of the one at 0x0010
// 06eb: ac LDAX (HL+A) ; look up table based on note
hl = 0x08;
a = bitMask[hl + a]; // fetch bit corresponding to lower bits of note
// 06ec: 1b MOV C,A ; save
// 06ed: 34 40 ff LXI HL,$FF40 ; bit flags
// 06f0: ad LDAX (HL+B) ; byte pointed to by upper part
// 06f1: 60 9b ORA A,C ; or in whichever note is flagged
// 06f3: bd STAX (HL+B) ; save in flag
c = a; // save A for later
hl = 0x40; // MIDI key bitmap
a = ram[hl + b];
a |= c;
ram[hl + b] = a; // OR in the bit we saved and save it back
// ; this sets up the MIDI routine to expect a two-byte message again
// which allows for running status
// 06f4: 71 3f 01 MVIW $003F,$01 ; expect two bytes
// 06f7: 4f 53 JRE $064C ; return
return;
h06f9:
// ; note off?
// ; A contains lower three bits of note, B contains upper 4 bits
// 06f9: 34 10 00 LXI HL,$0010 ; lookup table runs fe, fd, fb, f7, ef, df, bf, 7f
// ; inverse of 0x0008
// 06fc: ac LDAX (HL+A) ; look up the table based on the note
hl = 0x10;
a = bitMask[hl + a];
// 06fd: 1b MOV C,A ; fetch value, store in C
// 06fe: 34 40 ff LXI HL,$FF40 ; table in RAM
// 0701: ad LDAX (HL+B) ; $FF40 + upper four bits as offset
// 0702: 60 8b ANA A,C ; mask off the bit for the note
// 0704: bd STAX (HL+B) ; store at $FF40 + offset
c = a;
hl = 0x40;
a = ram[hl + b];
a &= c;
ram[hl + b] = a;
return;
// jump back to set up for running status
// 0705: ee JR $06F4
h0706:
// ; add or subtract an octave to bring out-of-range notes in
// 0706: 46 0c ADI A,$0C ; add 12 to note value in A
// 0708: 4f c2 JRE $06CC ; jump back and test if it's in range yet
a += 12; // semitones
goto h06cc; // test again
h070a:
// 070a: 66 0c SUI A,$0C ; subtract 12 from note value in A
// 070c: 4f c2 JRE $06D0 ; jump back and test if it's in range yet
a -= 12; // semitones
goto h06d0;
// ; store first value
// 070e: 63 3e STAW $003E
// 0710: 4f 3a JRE $064C ; return from interrupt
//
// ; control change?
// 0712: 01 3e LDAW $003E ; parameter?
// 0714: 27 7a GTI A,$7A ; all notes off, or higher?
// 0716: 4e 35 JRE $074D
// 0718: 45 4f 40 ONIW $004F,$40 ; flag variable
// 071b: 4f d7 JRE $06F4
// 071d: 67 7b NEI A,$7B ; all notes off?
// 071f: 4e 51 JRE $0772
// 0721: 47 02 ONI A,$02 ; mono/poly (but ignored according to the manual)
// 0723: c8 JR $072C
// 0724: 05 4f fd ANIW $004F,$FD ; flag variable
// 0727: 47 01 ONI A,$01 ; omni on
// 0729: 4e 4d JRE $0778 ; set omni off
// 072b: c8 JR $0734
// 072c: 05 4f fe ANIW $004F,$FE ; clear flag variable bit 0
// 072f: 47 01 ONI A,$01 ; if mono on?
// 0731: 15 4f 01 ORIW $004F,$01 ; set flag variable?
// 0734: 69 03 MVI A,$03
// 0736: 74 88 4f ANAW $004F
// 0739: 15 4f 20 ORIW $004F,$20
// 073c: 77 01 EQI A,$01
// 073e: 05 4f df ANIW $004F,$DF
// 0741: 6a 0d MVI B,$0D ; 14 values
// 0743: 69 00 MVI A,$00 ; zero out note flags
// 0745: 34 40 ff LXI HL,$FF40 ; table in RAM for note flags
// 0748: 3d STAX (HL+) ; store
// 0749: 52 DCR B
// 074a: fd JR $0748 ; loop
// 074b: 4f a7 JRE $06F4 ; expect two bytes
// 074d: 77 40 EQI A,$40 ; sustain
// 074f: ce JR $075E
// 0750: 74 6b 00 NEI C,$00 ; value is zero
// 0753: c5 JR $0759
// 0754: 15 b6 10 ORIW $00B6,$10 ; sustain on
// 0757: 4f 9b JRE $06F4
// 0759: 15 b6 08 ORIW $00B6,$08 ; sustain off
// 075c: 4f 96 JRE $06F4
// 075e: 77 01 EQI A,$01 ; mod wheel
// 0760: 4f 92 JRE $06F4 ; expect two bytes and return (running status)
// 0762: 55 a8 20 OFFIW $00A8,$20 ; midi mode 0
// 0765: c7 JR $076D ; continue
// 0766: 0b MOV A,C ; get byte
// 0767: 17 80 ORI A,$80 ; set bit?
// 0769: 63 a2 STAW $00A2 ; mod wheel value?
// 076b: 4f 87 JRE $06F4 ; expect two bytes and return (running status)
// 076d: 71 a2 80 MVIW $00A2,$80 ; mod wheel off?
// 0770: 4f 82 JRE $06F4 ; expect two bytes and return
//
// ; handle all notes off
// 0772: 5d 4f BIT 5,$004F ; all notes off?
// 0774: 4f 7e JRE $06F4 ; expect two bytes and return
// 0776: 4f c9 JRE $0741 ; wipe a table
// 0778: 74 7b 01 EQI C,$01
// 077b: 15 4f 02 ORIW $004F,$02
// 077e: 4f b4 JRE $0734
//
// ; program change
// 0780: 55 a8 20 OFFIW $00A8,$20 ; Midi mode 0?
// 0783: c5 JR $0789 ; skip ahead and do nothing
// 0784: 0b MOV A,C ; get prog
// 0785: 17 80 ORI A,$80 ; bit 7
// 0787: 63 a3 STAW $00A3 ; store
// 0789: 71 3f 00 MVIW $003F,$00 ; expect one byte (running status)
// 078c: 54 4c 06 JMP $064C ; return
//
// ; bend
// 078f: 55 a8 20 OFFIW $00A8,$20 ; midi mode 0?
// 0792: d7 JR $07AA ; clear and end
// 0793: 0b MOV A,C
// 0794: 18 MOV EAH,A ; EAH gets msb
// 0795: 01 3e LDAW $003E ; lsb
// 0797: 48 25 SLL A ; multiply by two
// 0799: 19 MOV EAL,A ; EA contains 14-bit bend multiplied by 2
// 079a: 48 a4 DSLL EA ; left aligned
// 079c: 08 MOV A,EAH
// 079d: 47 80 ONI A,$80 ; negative?
// 079f: c4 JR $07A4
// 07a0: 63 a1 STAW $00A1 ; save in ffa1
// 07a2: 4f 50 JRE $06F4 ; return, two byte running status
// 07a4: 16 ff XRI A,$FF ; invert
// 07a6: 63 a0 STAW $00A0 ; save in ffa0
// 07a8: 4f 4a JRE $06F4 ; return, two byte running status
// 07aa: 71 a1 80 MVIW $00A1,$80 ; reset bend?
// 07ad: 4f 45 JRE $06F4 ; return, two byte running status
}
// ; handle TX interrupt
// 07af: 01 c1 LDAW $00C1 ; buffer pointers?
// 07b1: 74 f8 c2 EQAW $00C2
@ -1901,12 +1961,12 @@ void Assigner::resetVoices() {
b = 5; // five voices
// 0b86: 69 80 MVI A,$80
a = 0x80;
// 0b88: 3d STAX (HL+)
h0b88:
// 0b88: 3d STAX (HL+)
h0b88:
ram[hl++] = a;
// 0b89: 52 DCR B
// 0b8a: fd JR $0B88
if (b>0) {
if (b > 0) {
b--;
goto h0b88;
}
@ -1916,14 +1976,14 @@ void Assigner::resetVoices() {
b = 0x05;
// 0b90: 69 88 MVI A,$88
a = 0x88;
// 0b92: 3d STAX (HL+)
h0b92:
// 0b92: 3d STAX (HL+)
h0b92:
ram[hl++] = a;
// 0b93: 41 INR A
a++;
// 0b94: 52 DCR B
// 0b95: fc JR $0B92
if (b>0) {
if (b > 0) {
b--;
goto h0b92;
}

View File

@ -71,14 +71,16 @@ void Chassis::noteOn(uint8_t note) {
ic1.ram[0x4e] = 0x90;
ic1.ram[0x3e] = note;
ic1.noteOn();
ic1.noteOn(0x40);
/*
#ifdef D_MIDIBITMAP
printf("note on -> ");
for (uint8_t i = 0x40; i < 0x4f; i++) {
printf("%02x ", ic1.ram[i]);
}
printf("\n");
*/
#endif
s.keyon = true;
for (i = 0; i < NUM_VOICES; i++) {
vPtr++;
@ -98,16 +100,18 @@ void Chassis::noteOn(uint8_t note) {
}
void Chassis::noteOff(uint8_t note) {
ic1.ram[0x4e] = 0x80;
ic1.ram[0x4e] = 0x90;
ic1.ram[0x3e] = note;
ic1.noteOn();
ic1.noteOn(0);
/*
#ifdef D_MIDIBITMAP
printf("note off -> ");
for (uint8_t i = 0x40; i < 0x4f; i++) {
printf("%02x ", ic1.ram[i]);
}
printf("\n");
*/
#endif
s.keyon = false;
for (uint32_t i = 0; i < NUM_VOICES; i++) {
if (s.voice[i].note == note && !s.voice[i].isFree()) {
@ -133,7 +137,7 @@ void Chassis::doMidi(const MidiEvent *ev, uint32_t count, uint32_t timeLimit) {
}
lastEvent = i;
ic1.voiceOn();
//ic1.voiceOn();
}
void Chassis::run(const float **, float **outputs, uint32_t frames, const MidiEvent *midiEvents, uint32_t midiEventCount) {

View File

@ -2,16 +2,23 @@
#include <cstdint>
#define D_MIDIBITMAP
class Assigner {
public:
uint8_t ram[256];
uint16_t a = 0, b = 0, c = 0, eal = 0, eah = 0;
uint32_t bc, de, hl, ea = 0;
void noteOn();
void noteOn(uint8_t c);
void voiceOn();
void resetVoices();
// void clearNotes();
//void assignNote();
// void clearNotes();
// void assignNote();
private:
uint8_t bitMask[24] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f};
};