Created
September 26, 2019 05:16
-
-
Save Frank-Buss/4a6fd7f7357a400e84e6ffd9478d9d05 to your computer and use it in GitHub Desktop.
Commander X16 YM2151 player
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ym2151 basic player by Barry Yost - sep 25, 2019 | |
// original original tune "Stardust" from C64 game "Lazy Jones" | |
// ported to C by Frank Buss | |
#include <stdint.h> | |
#include <6502.h> | |
struct YM2151_t { | |
uint8_t reg; | |
uint8_t data; | |
}; | |
static uint8_t ofs; | |
static uint8_t b; | |
static uint8_t bp; | |
static uint8_t delay; | |
static uint8_t patch[] = { | |
0x20, 0xe4, | |
0x38, 0x00, | |
// patches for operator 0 | |
0x40, 0x31, | |
0x60, 0x07, | |
0x80, 0x1f, | |
0xa0, 0x09, | |
0xc0, 0x00, | |
0xe0, 0xff, | |
// patches for operator 1 | |
0x48, 0x31, | |
0x68, 0x11, | |
0x88, 0x1f, | |
0xa8, 0x09, | |
0xc8, 0x00, | |
0xe8, 0xff, | |
// patches for operator 2 | |
0x50, 0x31, | |
0x70, 0x08, | |
0x90, 0x1f, | |
0xb0, 0x09, | |
0xd0, 0x00, | |
0xf0, 0xff, | |
// patches for operator 3 | |
0x58, 0x30, | |
0x78, 0x24, | |
0x98, 0x1f, | |
0xb8, 0x09, | |
0xd8, 0x00, | |
0xf8 ,0xff, | |
0 | |
}; | |
uint8_t notes[] = { | |
0xff, 0xff, 0xff, 0xff, 0xff, | |
0x2d, 0x31, 0x34, 0x36, 0x2d, 0xff, 0xff, 0xff, | |
0x2d, 0x31, 0x34, 0x36, 0x38, 0x36, 0x31, 0x34, 0xff, 0xff, 0xff, | |
0x31, 0xff, 0x36, 0x2d, | |
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | |
0 | |
}; | |
#define YM2151 (*(volatile struct YM2151_t*) 0x9fe0) | |
static void setReg(uint8_t adr, uint8_t value) | |
{ | |
YM2151.reg = adr; | |
YM2151.data = value; | |
} | |
static void loadPatch(uint8_t ch) | |
{ | |
uint8_t i = 0; | |
while (1) { | |
if (patch[i] == 0) break; | |
setReg(patch[i] + ch, patch[i + 1]); | |
i += 2; | |
} | |
} | |
static unsigned char irq() | |
{ | |
uint8_t n; | |
if (delay++ < 9) return IRQ_HANDLED; | |
delay = 0; | |
// play a note | |
n = notes[ofs++]; | |
if (n == 0) { | |
ofs = 0; | |
bp = 1; | |
} else { | |
if (n < 0xfe) setReg(0x28, n); | |
if (n != 0xff) { | |
setReg(8, 0); | |
if (n != 0xfe) setReg(8, 0x78); | |
} | |
b = (b + 1) & 1; | |
if ((ofs == 21) || (ofs == 25)) bp += 2; | |
if (ofs == 29) bp = 1; | |
setReg(8, b + bp); | |
setReg(8, 0x78 + b + bp); | |
} | |
// return from interrupt | |
return IRQ_HANDLED; | |
} | |
static void main2() | |
{ | |
int i; | |
uint8_t l, r; | |
uint8_t ch; | |
uint8_t n; | |
// init ym2151 | |
for (i = 0; i <= 256; i++) setReg(i, 0); | |
// load the patch into all voices | |
for (i = 0; i <= 7; i++) loadPatch(i); | |
// set up bass notes on channels 1-6 | |
l = 0xe4 - 0xc0 + 0x40; | |
r = 0xe4 - 0xc0 + 0x80; | |
// settings for left/right audio only | |
for (ch = 1; ch <= 5; ch += 2) { | |
if (ch == 1) n = 0x0d; | |
if (ch == 3) n = 0x14; | |
if (ch == 5) n = 0x16; | |
setReg(0x20 + ch, l); | |
setReg(0x20 + ch + 1, r); | |
setReg(0x28 + ch, n); | |
setReg(0x28 + ch + 1, n + 0x10); | |
} | |
ofs = 0; | |
bp = 1; | |
b = 1; | |
delay = 0; | |
// set new interrupt function | |
// needs different local stack from 0xa000 to 0xa7ff, because the stack functions are not reentrant | |
set_irq(irq, (void*) 0xa800, 0x0800); | |
while (1); | |
} | |
int main(void) | |
{ | |
// switch back to uppercase character set | |
__asm__("lda #$8e"); | |
__asm__("jsr BSOUT"); | |
// bad hack: redefine CC65 stack to 0x0xa800-0xafff, should be a proper x16 custom target | |
*((uint16_t*) 0x02) = 0xb000; | |
// call new main function, because local variables are not valid anymore after the stack change | |
main2(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment