From 3e16f5314f58713b59d8f10f7874862a37eadea0 Mon Sep 17 00:00:00 2001 From: Gordon JC Pearce Date: Tue, 17 Sep 2024 21:10:00 +0100 Subject: [PATCH] reworked assigner note on --- plugin/assigner.cpp | 354 ++++++++++++++++++++++++++------------------ plugin/chassis.cpp | 20 ++- plugin/cpuboard.hpp | 13 +- 3 files changed, 229 insertions(+), 158 deletions(-) diff --git a/plugin/assigner.cpp b/plugin/assigner.cpp index 3b8daf1..487bb7d 100644 --- a/plugin/assigner.cpp +++ b/plugin/assigner.cpp @@ -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; } diff --git a/plugin/chassis.cpp b/plugin/chassis.cpp index 44bb4ad..6e4e047 100644 --- a/plugin/chassis.cpp +++ b/plugin/chassis.cpp @@ -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) { diff --git a/plugin/cpuboard.hpp b/plugin/cpuboard.hpp index 51c16ba..43c5ce3 100644 --- a/plugin/cpuboard.hpp +++ b/plugin/cpuboard.hpp @@ -2,16 +2,23 @@ #include +#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}; }; \ No newline at end of file