aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsik2017-03-05 20:57:11 -0300
committersik2017-03-05 20:57:11 -0300
commita679ba38190bfed6ae150a12e819ad7527c495d1 (patch)
treeea4b189bce2732032998027f5dbcb75a1c0eea1d
parent2ad500e6d8a24ca09cbfc6618aea9c1cd3cc0e93 (diff)
Upgrade!
-rw-r--r--LICENSE2
-rw-r--r--README11
-rw-r--r--built/old-builds/prog-z80-1.3.binbin0 -> 4864 bytes
-rw-r--r--built/prog-z80.binbin4864 -> 5120 bytes
-rw-r--r--c/echo.c139
-rw-r--r--c/echo.h6
-rw-r--r--c/echoblob.h518
-rw-r--r--doc/api-asm.68k47
-rw-r--r--doc/api-c.txt53
-rw-r--r--doc/esf.txt43
-rw-r--r--src-68k/echo.68k165
-rw-r--r--src-68k/esf.68k43
-rw-r--r--src-z80/build.z801
-rw-r--r--src-z80/core/bgm.z806
-rw-r--r--src-z80/core/direct.z8030
-rw-r--r--src-z80/core/main.z8035
-rw-r--r--src-z80/core/sfx.z8010
-rw-r--r--src-z80/core/vars.z806
-rw-r--r--src-z80/player/fm.z80179
-rw-r--r--src-z80/player/freq.z8010
-rw-r--r--src-z80/player/misc.z8044
-rw-r--r--src-z80/player/pcm.z8011
-rw-r--r--src-z80/player/psg.z803
23 files changed, 1045 insertions, 317 deletions
diff --git a/LICENSE b/LICENSE
index 798102d..0ae3745 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-© 2010-2013 Javier Degirolmo
+© 2010-2017 Javier Degirolmo
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
diff --git a/README b/README
index 0916d2b..e1b42b4 100644
--- a/README
+++ b/README
@@ -7,12 +7,12 @@
| | |_ |_ ___ | | | | | | | |
| |_______ |_ |___| _| | | | | |_ |_____| _|
|___________| |________| |___| |___| |_________|
- ___ ___ _ _ ___ __ ___ ___ ___ _ ___ ___ _ ___
- | _| | | | | \ | _| | _| | | _| | | |_ |
- | |_| | | | | | | | | | |_| | | |_| | | | |_ _ _ ___ ___ | | _| |
+ ___ ___ _ _ ___ __ ___ ___ ___ _ ___ ___ _ _ _
+ | _| | | | | \ | _| | _| | | _| | | | | |
+ | |_| | | | | | | | | | |_| | | |_| | | | |_ _ _ ___ ___ | | | | |
|_ | | | | | | | | | | _| | | | | | | | _| | | | __| _ \ | | |_ |
- _| | | | | | | | | | | |_| | | | | | | | |_ | | | __| /_ | |_ _| |
- |___|___|___|_|_|__/ |___|_|_|___|_|_|_|___| \_/|___|_|_\_| |_|_|___|
+ _| | | | | | | | | | | |_| | | | | | | | |_ | | | __| /_ | |_ | |
+ |___|___|___|_|_|__/ |___|_|_|___|_|_|_|___| \_/|___|_|_\_| |_|_| |_|
=============================================================================
@@ -93,6 +93,7 @@ THANKS FOR TESTING:
* John Springer (you heart his pizza)
* Flygon (sorry for your headphones :P)
* djcouchycouch (for using an API I didn't even check if it worked)
+ * BigEvilCorporation (helped with testing Echo 1.4)
OTHER THANKS:
diff --git a/built/old-builds/prog-z80-1.3.bin b/built/old-builds/prog-z80-1.3.bin
new file mode 100644
index 0000000..307ea44
--- /dev/null
+++ b/built/old-builds/prog-z80-1.3.bin
Binary files differ
diff --git a/built/prog-z80.bin b/built/prog-z80.bin
index 307ea44..bbb92e2 100644
--- a/built/prog-z80.bin
+++ b/built/prog-z80.bin
Binary files differ
diff --git a/c/echo.c b/c/echo.c
index b4368da..e488e33 100644
--- a/c/echo.c
+++ b/c/echo.c
@@ -15,9 +15,37 @@ static volatile uint16_t* const z80_reset = (uint16_t *) 0xA11200;
{ *z80_busreq = 0; }
#define Z80_RESET() \
{ *z80_reset = 0; \
- int16_t i; for (i = 8; i >= 0; i--); \
+ volatile int16_t i; for (i = 4; i >= 0; i--); \
*z80_reset = 0x100; }
+// Macro to add delays
+// Using volatile is needlessly ugly but at least portable
+// GCC is already awful at optimizing, so this isn't that bad...
+#define DELAY() \
+ { volatile int16_t i; for (i = 0xFF; i >= 0; i--); }
+
+// Look-up tables for echo_set_volume
+static const uint8_t fm_volumes[] = {
+ 0x7F,0x7B,0x77,0x73,0x70,0x6C,0x68,0x65,
+ 0x61,0x5E,0x5A,0x57,0x54,0x50,0x4D,0x4A,
+ 0x47,0x44,0x41,0x3F,0x3C,0x39,0x36,0x34,
+ 0x31,0x2F,0x2D,0x2A,0x28,0x26,0x24,0x22,
+ 0x20,0x1E,0x1C,0x1A,0x18,0x16,0x15,0x13,
+ 0x12,0x10,0x0F,0x0D,0x0C,0x0B,0x0A,0x09,
+ 0x08,0x07,0x06,0x05,0x04,0x04,0x03,0x02,
+ 0x02,0x01,0x01,0x01,0x00,0x00,0x00,0x00
+};
+static const uint8_t psg_volumes[] = {
+ 0x0F,0x0F,0x0E,0x0E,0x0D,0x0D,0x0C,0x0C,
+ 0x0B,0x0B,0x0B,0x0A,0x0A,0x0A,0x09,0x09,
+ 0x08,0x08,0x08,0x07,0x07,0x07,0x06,0x06,
+ 0x06,0x06,0x05,0x05,0x05,0x04,0x04,0x04,
+ 0x04,0x03,0x03,0x03,0x03,0x03,0x02,0x02,
+ 0x02,0x02,0x02,0x02,0x01,0x01,0x01,0x01,
+ 0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+
//***************************************************************************
// echo_init
// Initializes Echo and gets it running.
@@ -35,6 +63,9 @@ void echo_init(const void **list) {
// due to linker shenanigans)
z80_ram[0x1FFF] = 0x00;
+ // Direct stream is empty yet
+ z80_ram[0x1F00] = 0xFF;
+
// Load the instrument list manually, since thanks to linker shenanigans
// we can't implement the list properly in ROM :/
volatile uint8_t *dest = &z80_ram[0x1C00];
@@ -65,6 +96,13 @@ void echo_init(const void **list) {
while (count-- >= 0)
*dest++ = *src++;
+ // Set up global volume
+ int i;
+ for (i = 0; i < 12; i++)
+ z80_ram[0x1FE0+i] = 0;
+ z80_ram[0x1FEC] = 1;
+ z80_ram[0x1FF1] = 1;
+
// Let Echo start running!
Z80_RESET();
Z80_RELEASE();
@@ -84,8 +122,7 @@ void echo_send_command(uint8_t cmd) {
// Is Echo busy yet?
while (z80_ram[0x1FFF] != 0x00) {
Z80_RELEASE();
- int16_t i;
- for (i = 0x3FF; i >= 0; i--);
+ DELAY();
Z80_REQUEST();
}
@@ -116,8 +153,7 @@ void echo_send_command_addr(uint8_t cmd, const void *addr) {
// Is Echo busy yet?
while (z80_ram[0x1FFF] != 0x00) {
Z80_RELEASE();
- int16_t i;
- for (i = 0x3FF; i >= 0; i--);
+ DELAY();
Z80_REQUEST();
}
@@ -187,9 +223,11 @@ void echo_stop_bgm(void) {
// Resumes background music playback.
//***************************************************************************
+/*
void echo_resume_bgm(void) {
echo_send_command(ECHO_CMD_RESUMEBGM);
}
+*/
//***************************************************************************
// echo_play_sfx
@@ -212,6 +250,95 @@ void echo_stop_sfx(void) {
}
//***************************************************************************
+// echo_play_direct
+// Injects events into the BGM stream for the next tick.
+//---------------------------------------------------------------------------
+// param ptr: pointer to BGM stream
+//***************************************************************************
+
+void echo_play_direct(const void *ptr) {
+ // We need access to Z80 bus
+ Z80_REQUEST();
+
+ // Check where we can start writing events
+ volatile uint8_t *dest = &z80_ram[0x1F00];
+ while (*dest != 0xFF) dest++;
+
+ // Write the events
+ const uint8_t *src = (uint8_t*)(ptr);
+ for (;;) {
+ uint8_t byte = *src++;
+ *dest++ = byte;
+ if (byte == 0xFF) break;
+ }
+
+ // Done with the Z80
+ Z80_RELEASE();
+}
+
+//***************************************************************************
+// echo_set_volume
+// Changes the global volume for every channel.
+//---------------------------------------------------------------------------
+// param vol: new volume (0 = quietest, 255 = loudest)
+//***************************************************************************
+
+void echo_set_volume(uint8_t vol) {
+ // We need access to Z80 bus
+ Z80_REQUEST();
+
+ // Set FM volume values
+ uint8_t fm_vol = fm_volumes[vol >> 2];
+ z80_ram[0x1FE0] = fm_vol;
+ z80_ram[0x1FE1] = fm_vol;
+ z80_ram[0x1FE2] = fm_vol;
+ z80_ram[0x1FE3] = fm_vol;
+ z80_ram[0x1FE4] = fm_vol;
+ z80_ram[0x1FE5] = fm_vol;
+ z80_ram[0x1FE6] = fm_vol;
+ z80_ram[0x1FE7] = fm_vol;
+
+ // Set PSG volume values
+ uint8_t psg_vol = psg_volumes[vol >> 2];
+ z80_ram[0x1FE8] = psg_vol;
+ z80_ram[0x1FE9] = psg_vol;
+ z80_ram[0x1FEA] = psg_vol;
+ z80_ram[0x1FEB] = psg_vol;
+
+ // Determine whether to enable PCM
+ z80_ram[0x1FEC] = (vol >= 0x40) ? 1 : 0;
+
+ // Tell Echo to update all the volumes
+ z80_ram[0x1FF1] = 1;
+
+ // Done with the Z80
+ Z80_RELEASE();
+}
+
+//***************************************************************************
+// echo_set_volume_ex
+// Changes the global volume for each individual channel.
+//---------------------------------------------------------------------------
+// param ptr: pointer to array with volume values
+//***************************************************************************
+
+void echo_set_volume_ex(const uint8_t *ptr) {
+ // We need access to Z80 bus
+ Z80_REQUEST();
+
+ // Store the new volume values
+ int i;
+ for (i = 0; i < 13; i++)
+ z80_ram[0x1FE0+i] = ptr[i];
+
+ // Tell Echo to update all the volumes
+ z80_ram[0x1FF1] = 1;
+
+ // Done with the Z80
+ Z80_RELEASE();
+}
+
+//***************************************************************************
// echo_set_pcm_rate
// Changes the playback rate of PCM.
//---------------------------------------------------------------------------
@@ -238,6 +365,8 @@ uint16_t echo_get_status(void) {
status = z80_ram[0x1FF0];
if (z80_ram[0x1FFF] != 0)
status |= ECHO_STAT_BUSY;
+ if (z80_ram[0x1F00] != 0xFF)
+ status |= ECHO_STAT_DIRBUSY;
// Done with the Z80
Z80_RELEASE();
diff --git a/c/echo.h b/c/echo.h
index 086535e..56088b6 100644
--- a/c/echo.h
+++ b/c/echo.h
@@ -19,15 +19,19 @@ enum {
/* Echo status flags */
#define ECHO_STAT_BGM 0x0002 /* Background music is playing */
#define ECHO_STAT_SFX 0x0001 /* Sound effect is playing */
+#define ECHO_STAT_DIRBUSY 0x4000 /* Echo isn't done with direct events */
#define ECHO_STAT_BUSY 0x8000 /* Echo still didn't parse command */
/* Function prototypes */
void echo_init(const void **);
void echo_play_bgm(const void *);
void echo_stop_bgm(void);
-void echo_resume_bgm(void);
+/*void echo_resume_bgm(void);*/
void echo_play_sfx(const void *);
void echo_stop_sfx(void);
+void echo_play_direct(const void *);
+void echo_set_volume(uint8_t);
+void echo_set_volume_ex(const uint8_t *);
void echo_set_pcm_rate(uint8_t);
uint16_t echo_get_status(void);
void echo_send_command(uint8_t);
diff --git a/c/echoblob.h b/c/echoblob.h
index 1782524..827cc5b 100644
--- a/c/echoblob.h
+++ b/c/echoblob.h
@@ -1,6 +1,6 @@
static uint8_t echo_blob[] = {
- 49,240, 31,175, 50,240, 31, 33, 17,127, 54,159, 54,191, 54,223,
- 54,255,175, 50, 0, 18, 50, 16, 18, 50, 32, 18, 50, 48, 18, 33,
+ 49,224, 31,175, 50,240, 31, 33, 17,127, 54,159, 54,191, 54,223,
+ 54,255,175, 50, 0, 19, 50, 16, 19, 50, 32, 19, 50, 48, 19, 33,
0, 96,117,117,117,117,117,117,117,117,117,221, 33, 0, 64,253,
38, 64,217, 6, 0,217,221, 54, 0, 43,221, 54, 1, 0, 30,127,
62, 64, 6, 4,221,119, 0,221,115, 1,221,119, 2,221,115, 3,
@@ -11,253 +11,269 @@ static uint8_t echo_blob[] = {
2,181,221, 54, 3,192,221, 54, 2,182,221, 54, 3,192,221, 54,
0, 36,221, 54, 1,254,221, 54, 0, 37,221, 54, 1, 3,221, 54,
0, 38,221, 54, 1,201,221, 54, 0, 39,221, 54, 1, 63,195,239,
- 0, 61,202, 67, 1, 61,202, 83, 5, 61,202,125, 6, 61,202, 0,
- 3, 61,202,133, 4, 61,202, 81, 3, 61,202,222, 2, 58, 0, 64,
- 15,220, 13, 2,175, 50,255, 31, 58, 0, 64, 15,220, 13, 2, 58,
- 255, 31,183, 32,204, 58, 0, 64, 15,220, 13, 2, 58, 0, 64,203,
- 79, 32, 8,203, 71,196, 13, 2,195,239, 0,221,126, 0,203, 71,
- 196, 13, 2,221, 54, 0, 39,221, 54, 1, 47, 58, 0, 64, 15,220,
- 13, 2,195, 37, 1, 58, 0, 64, 15,220, 13, 2,195, 47, 1, 58,
- 0, 64, 15,220, 13, 2,195, 69, 12, 58, 0, 64, 15,220, 13, 2,
+ 0, 61,202, 83, 1, 61,202,109, 5, 61,202,156, 6, 61,202, 21,
+ 3, 61,202,159, 4, 61,202,102, 3, 61,202,243, 2, 58, 0, 64,
+ 15,220, 34, 2,175, 50,255, 31, 58, 0, 64, 15,220, 34, 2, 58,
+ 255, 31,183, 32,204, 58, 0, 64, 15,220, 34, 2, 58, 0, 64,203,
+ 79, 32, 8,203, 71,196, 34, 2,195,239, 0, 58, 0, 64, 15,220,
+ 34, 2,221, 54, 0, 39,221, 54, 1, 47, 58, 0, 64, 15,220, 34,
+ 2, 58,241, 31,183,196,227, 16,195, 43, 1, 58, 0, 64, 15,220,
+ 34, 2,205, 84, 7, 58, 0, 64, 15,220, 34, 2,195, 63, 1, 58,
+ 0, 64, 15,220, 34, 2,195, 4, 13, 58, 0, 64, 15,220, 34, 2,
195,239, 0, 33,252, 31, 78, 44, 94, 44, 86,235,175, 50,255, 31,
- 17, 0, 28,205,113, 1,120,183,202,110, 1, 18, 20,205,113, 1,
- 120, 18, 20,205,113, 1,120, 18, 21, 21, 28,195, 83, 1,195,239,
- 0, 58,140, 18,185,202,145, 1,121, 50,140, 18,229, 33, 0, 96,
+ 17, 0, 28,205,129, 1,120,183,202,126, 1, 18, 20,205,129, 1,
+ 120, 18, 20,205,129, 1,120, 18, 21, 21, 28,195, 99, 1,195,239,
+ 0, 58,152, 19,185,202,161, 1,121, 50,152, 19,229, 33, 0, 96,
119, 15,119, 15,119, 15,119, 15,119, 15,119, 15,119,116, 15,119,
- 225, 70, 44,194,157, 1, 36,194,157, 1, 38,128, 12,201,205,184,
- 1,195,204, 5, 58, 0, 64, 15,220, 13, 2, 58,134, 18,183,194,
- 106, 4,205,184, 1,195,174, 3,205,113, 1,120,217, 38, 28,111,
- 86, 36, 94, 36, 78, 33, 0, 96,121, 50,140, 18,119, 15,119, 15,
- 119, 15,119, 15,119, 15,119, 15,119,116, 15,119, 38, 18,123,246,
- 240,111, 69, 26,119, 28, 44,194,227, 1,104,123,183,194,247, 1,
- 20,194,247, 1, 22,128, 12,217,175, 50, 13, 2,221, 54, 0, 43,
- 221, 54, 1,128,221, 54, 0, 42,221, 54, 1,128,201,201,217,221,
- 54, 0, 39,221, 54, 1, 31,126, 60, 40, 12,221, 54, 0, 42,221,
- 119, 1, 44, 40, 22,217,201, 6, 0,221, 54, 0, 42,221, 54, 1,
- 128,221, 54, 0, 43,221, 54, 1, 0,217,201, 58,140, 18,185,202,
- 89, 2,121, 50,140, 18, 33, 0, 96,119, 15,119, 15,119, 15,119,
- 15,119, 15,119, 15,119,116, 15,119, 33,240, 18, 26,119, 44, 28,
- 26,119, 44, 28, 26,119, 44, 28, 26,119, 44, 28, 26,119, 44, 28,
- 26,119, 44, 28, 26,119, 44, 28, 26,119, 44, 28, 26,119, 44, 28,
- 26,119, 44, 28, 26,119, 44, 28, 26,119, 44, 28, 26,119, 44, 28,
- 26,119, 44, 28, 26,119, 44, 28, 26,119, 44, 28,194,166, 2, 20,
- 194,166, 2, 22,128, 12, 46,240,195, 15, 2,205,197, 2,195,204,
- 5, 58, 0, 64, 15,220, 13, 2, 58,134, 18,183,194,174, 3,205,
- 197, 2,195,174, 3, 62,201, 50, 13, 2,221, 54, 0, 43,221, 54,
- 1, 0,201, 62, 1, 50,134, 18,205,197, 2,195,204, 5, 58,252,
- 31, 47, 71,175, 50,255, 31,120,221, 54, 0, 36, 15, 15,246,192,
- 221,119, 1,120,221, 54, 0, 37,230, 3,221,119, 1,195,239, 0,
- 58, 0, 64, 15,220, 13, 2,205,179, 4, 58, 0, 64, 15,220, 13,
- 2, 58,240, 31,246, 2, 50,240, 31, 58, 0, 64, 15,220, 13, 2,
- 33,252, 31, 78, 44, 94, 44, 86, 58, 0, 64, 15,220, 13, 2,175,
- 50,255, 31, 33,141, 18, 54, 1, 44, 54, 1, 44,113, 44,115, 44,
- 114, 58, 0, 64, 15,220, 13, 2, 33,141, 3, 34, 45, 1,195,239,
- 0,175, 50,255, 31, 6, 8, 17,135, 18, 58, 0, 64, 15,220, 13,
- 2, 26,183,194,114, 3, 58, 0, 64, 15,220, 13, 2, 5,205, 14,
- 12, 4, 29, 5,194, 90, 3, 58,240, 31,246, 2, 50,240, 31, 33,
- 141, 18, 54, 1, 33,141, 3, 34, 45, 1,195,239, 0, 58, 0, 64,
- 15,220, 13, 2, 33,142, 18,126, 61,202,160, 3,119,195, 47, 1,
- 58, 0, 64, 15,220, 13, 2, 44, 78, 44, 94, 44, 86,235, 58, 0,
- 64, 15,220, 13, 2,205,113, 1, 58, 0, 64, 15,220, 13, 2,120,
- 254, 8,218, 59, 7,254, 11,218, 1, 13,202,133, 13,254, 12,202,
- 164, 1, 58, 0, 64, 15,220, 13, 2,120,254, 24,218,220, 7,254,
- 28,218,225, 13,202,177, 2, 58, 0, 64, 15,220, 13, 2,120,254,
- 254,202,231, 15,254,255,202,127, 4,254,252,202, 41, 5,254,253,
- 202, 62, 5, 58, 0, 64, 15,220, 13, 2,120,254, 40,218,195, 9,
- 254, 44,218, 62, 14, 58, 0, 64, 15,220, 13, 2,120,254, 56,218,
- 10, 8,254, 59,218, 82, 15,202,172, 15, 58, 0, 64, 15,220, 13,
- 2,120,254, 72,218,137, 8,254, 76,218,213, 14, 58, 0, 64, 15,
- 220, 13, 2,120,254,224,218,247, 15,254,248,218, 22, 11, 58, 0,
- 64, 15,220, 13, 2,195,127, 4, 58, 0, 64, 15,220, 13, 2, 44,
- 194,106, 4, 36,194,106, 4, 38,128, 12, 58, 0, 64, 15,220, 13,
- 2, 44,194,124, 4, 36,194,124, 4, 38,128, 12,195,174, 3,205,
- 143, 4,195, 47, 1,175, 50,255, 31,205,143, 4,195,239, 0, 58,
- 240, 31,230,253, 50,240, 31, 58, 0, 64, 15,220, 13, 2,205,179,
- 4, 58, 0, 64, 15,220, 13, 2,175, 50,141, 18, 33, 47, 1, 34,
- 45, 1,201, 58,134, 18,183,204,197, 2, 6, 4, 17, 63, 18, 33,
- 139, 18, 58, 0, 64, 15,220, 13, 2, 54, 0,123,214, 15, 95,126,
- 183, 32, 2,175, 18, 58, 0, 64, 15,220, 13, 2, 29, 45, 16,226,
- 6, 8, 17, 79, 18, 58, 0, 64, 15,220, 13, 2, 62,127, 18, 29,
- 58, 0, 64, 15,220, 13, 2,126,183,194, 26, 5, 5,120,205,157,
- 11, 58, 0, 64, 15,220, 13, 2,120,230, 4,253,111,120,230, 3,
- 198,180,253,119, 0,253, 54, 1,192, 4, 45, 16,200, 33, 80, 18,
- 62,192, 6, 8,119, 44, 16,252,201, 58, 0, 64, 15,220, 13, 2,
- 235, 44, 78, 44, 94, 44, 86, 45, 45, 45,235,195,174, 3, 58, 0,
- 64, 15,220, 13, 2,235, 44,113, 44,115, 44,114, 45, 45, 45,235,
- 195,174, 3, 58, 0, 64, 15,220, 13, 2,205,185, 6, 58, 0, 64,
- 15,220, 13, 2, 58,240, 31,246, 1, 50,240, 31, 58, 0, 64, 15,
- 220, 13, 2, 33,252, 31, 78, 44, 94, 44, 86, 58, 0, 64, 15,220,
- 13, 2,175, 50,255, 31, 33,149, 18, 54, 1, 44, 54, 1, 44,113,
- 44,115, 44,114, 58, 0, 64, 15,220, 13, 2, 33,171, 5, 34, 35,
- 1, 58, 0, 64, 15,220, 13, 2,195,239, 0, 58, 0, 64, 15,220,
- 13, 2, 33,150, 18,126, 61,202,190, 5,119,195, 37, 1, 58, 0,
- 64, 15,220, 13, 2, 44, 78, 44, 94, 44, 86,235, 58, 0, 64, 15,
- 220, 13, 2,205,113, 1, 58, 0, 64, 15,220, 13, 2,120,254, 8,
- 218, 53, 7,254, 11,218,251, 12,202,127, 13,254, 12,202,158, 1,
- 58, 0, 64, 15,220, 13, 2,120,254, 24,218,214, 7,254, 28,218,
- 219, 13,202,171, 2, 58, 0, 64, 15,220, 13, 2,120,254,254,202,
- 225, 15,254,255,202,119, 6, 58, 0, 64, 15,220, 13, 2,120,254,
- 40,218,189, 9,254, 44,218, 24, 14, 58, 0, 64, 15,220, 13, 2,
- 120,254, 56,218, 4, 8,254, 59,218, 76, 15,202,166, 15, 58, 0,
- 64, 15,220, 13, 2,120,254, 72,218,131, 8,254, 76,218,143, 14,
- 58, 0, 64, 15,220, 13, 2,120,254,224,218,237, 15,254,232,218,
- 107, 11,254,236,218,185, 15,202,211, 2, 58, 0, 64, 15,220, 13,
- 2,120,254,248,218,231, 10,205,135, 6,195, 37, 1,175, 50,255,
- 31,205,135, 6,195,239, 0, 58, 0, 64, 15,220, 13, 2, 58,240,
- 31,230,254, 50,240, 31, 58, 0, 64, 15,220, 13, 2,175, 50,149,
- 18, 33, 37, 1, 34, 35, 1, 58, 0, 64, 15,220, 13, 2,205,185,
- 6, 58, 0, 64, 15,220, 13, 2,201, 58,134, 18,183,196,197, 2,
- 6, 4, 17,139, 18, 58, 0, 64, 15,220, 13, 2, 26,183, 40, 64,
- 175, 18, 58, 0, 64, 15,220, 13, 2,120, 15, 15, 15, 15, 61, 38,
- 18,111, 78,214, 15,111,113, 58, 0, 64, 15,220, 13, 2,213,125,
- 198, 8,111,198, 4, 95, 84, 58, 0, 64, 15,220, 13, 2, 26,119,
- 44, 28, 26,119, 44, 28, 26,119,209, 58, 0, 64, 15,220, 13, 2,
- 29, 16,178, 6, 8, 58, 0, 64, 15,220, 13, 2, 26,183,202, 47,
- 7,175, 18, 58, 0, 64, 15,220, 13, 2, 5,205, 14, 12, 4, 29,
- 5,194, 21, 7,201,205, 89, 7,195,204, 5, 71, 58, 0, 64, 15,
- 220, 13, 2,229,120,230, 7, 33,128, 18,133,111,126,225,183,194,
- 106, 4,120,205, 89, 7,195,174, 3,230, 7,221, 54, 0, 40,221,
- 119, 1, 71, 8, 58, 0, 64, 15,220, 13, 2,120,230, 4, 15,253,
- 111, 58, 0, 64, 15,220, 13, 2,205,113, 1, 58, 0, 64, 15,220,
- 13, 2, 8,213,229, 87,230, 3,198,164, 95, 58, 0, 64, 15,220,
- 13, 2, 38, 17,120,230, 31,198,144,111, 58, 0, 64, 15,220, 13,
- 2,120,230,224, 15, 15, 71,126,176,253,115, 0,253,119, 1, 58,
- 0, 64, 15,220, 13, 2,123,214, 4, 95, 45,126,253,115, 0,253,
- 119, 1, 58, 0, 64, 15,220, 13, 2,122,246,240,221, 54, 0, 40,
- 221,119, 1,225,209,201,205,250, 7,195,204, 5, 71, 58, 0, 64,
- 15,220, 13, 2,120,229,230, 7, 33,128, 18,133,111,126,225,183,
- 194,174, 3,120,205,250, 7,195,174, 3,230, 7,221, 54, 0, 40,
- 221,119, 1,201,205, 40, 8,195,204, 5, 71, 58, 0, 64, 15,220,
- 13, 2,120,229,230, 7, 33,128, 18,133,111,126,225,183,194, 88,
- 4,120,205, 40, 8,195,174, 3,245, 71, 58, 0, 64, 15,220, 13,
- 2,120,230, 4, 15,253,111, 58, 0, 64, 15,220, 13, 2,205,113,
- 1, 58, 0, 64, 15,220, 13, 2,241,213,230, 7, 87,230, 3,198,
- 164, 95, 58, 0, 64, 15,220, 13, 2,253,115, 0,253,112, 1, 58,
- 0, 64, 15,220, 13, 2,205,113, 1, 58, 0, 64, 15,220, 13, 2,
- 123,214, 4, 95,253,115, 0,253,112, 1, 58, 0, 64, 15,220, 13,
- 2,209,201,205,235, 8,195,204, 5,230, 7, 71, 58, 0, 64, 15,
- 220, 13, 2,213,197,120, 17, 64, 18,131, 95, 58, 0, 64, 15,220,
- 13, 2,205,113, 1, 58, 0, 64, 15,220, 13, 2,120, 18,123,198,
- 8, 95,175, 18, 89,193, 75,209, 58, 0, 64, 15,220, 13, 2,229,
- 120, 38, 18,198,128,111,126,225,183,194,174, 3, 58, 0, 64, 15,
- 220, 13, 2,120,229, 33, 64, 18,133,111, 70,225, 8, 58, 0, 64,
- 15,220, 13, 2, 8,205, 0, 9,195,174, 3,230, 7, 8, 58, 0,
- 64, 15,220, 13, 2,205,113, 1, 58, 0, 64, 15,220, 13, 2, 8,
- 245,230, 4, 15,253,111, 58, 0, 64, 15,220, 13, 2,241,197,213,
- 229, 38, 28,104, 86, 36, 94, 36, 78,235,245, 58, 0, 64, 15,220,
- 13, 2, 6, 7, 17,154, 18,120, 8,205,113, 1,235,112,235, 28,
- 205,113, 1,235,112,235, 28,205,113, 1,235,112,235, 28,205,113,
- 1,235,112,235, 28, 8, 71, 16,222,205,113, 1,235,112,235, 58,
- 0, 64, 15,220, 13, 2,241, 71,205,157, 11,120, 17, 88, 18,230,
- 7,131, 95,245,230, 3,198,176, 33,154, 18, 8, 58, 0, 64, 15,
- 220, 13, 2, 8,253,119, 0, 70, 44,253,112, 1, 8,120, 18,123,
- 198, 8, 95, 58, 0, 64, 15,220, 13, 2, 8,214,128, 6, 28,253,
- 119, 0, 78,253,113, 1,198, 4, 44, 16,244, 58, 0, 64, 15,220,
- 13, 2,125,214, 24,111, 6, 4,126, 18,123,198, 8, 95, 44, 16,
- 247, 58, 0, 64, 15,220, 13, 2,241,225,209,193,201,205, 32, 10,
- 195,204, 5,230, 7, 71, 58, 0, 64, 15,220, 13, 2,213,197,120,
- 22, 18,198, 72, 95, 58, 0, 64, 15,220, 13, 2,205,113, 1, 58,
- 0, 64, 15,220, 13, 2,235,112,235, 89,193, 75,209, 58, 0, 64,
- 15,220, 13, 2,229,120, 33,128, 18,133,111,126,225,183,194,174,
- 3, 58, 0, 64, 15,220, 13, 2,120,229, 33, 72, 18,133,111, 70,
- 225,245, 58, 0, 64, 15,220, 13, 2,241,205, 51, 10,195,174, 3,
- 245, 58, 0, 64, 15,220, 13, 2,205,113, 1, 58, 0, 64, 15,220,
- 13, 2,241,197,213,229,230, 7,245, 38, 18,198, 88,111, 8, 58,
- 0, 64, 15,220, 13, 2, 8,230, 4, 15,253,111, 58, 0, 64, 15,
- 220, 13, 2,241,230, 3,198, 64, 79,126,230, 7, 95, 58, 0, 64,
- 15,220, 13, 2,125,198, 8,111,123,254, 7, 56, 14,253,113, 0,
- 126,128,254,127, 56, 2, 62,127,253,119, 1,121,198, 4, 79, 58,
- 0, 64, 15,220, 13, 2,125,198, 8,111,123,254, 5, 56, 14,253,
- 113, 0,126,128,254,127, 56, 2, 62,127,253,119, 1,121,198, 4,
- 79, 58, 0, 64, 15,220, 13, 2,125,198, 8,111,123,254, 4, 56,
- 14,253,113, 0,126,128,254,127, 56, 2, 62,127,253,119, 1,121,
- 198, 4, 79, 58, 0, 64, 15,220, 13, 2,125,198, 8,111,253,113,
- 0,126,128,254,127, 56, 2, 62,127,253,119, 1, 58, 0, 64, 15,
- 220, 13, 2,225,209,193,201, 71, 58, 0, 64, 15,220, 13, 2,120,
- 230, 4, 15,253,111,120, 8, 58, 0, 64, 15,220, 13, 2,205,113,
- 1, 58, 0, 64, 15,220, 13, 2, 8,230, 3,198,180,253,119, 0,
- 253,112, 1,195,204, 5, 71, 58, 0, 64, 15,220, 13, 2,120,230,
- 4, 15,253,111,120, 8, 58, 0, 64, 15,220, 13, 2,205,113, 1,
- 58, 0, 64, 15,220, 13, 2, 8,229,230, 7, 38, 18,198, 80,111,
- 112, 8, 58, 0, 64, 15,220, 13, 2, 8,230, 7,198,128,111, 8,
- 126,183,225,194,174, 3, 58, 0, 64, 15,220, 13, 2, 8,230, 3,
- 198,180,253,119, 0,253,112, 1,195,174, 3,230, 7, 71, 58, 0,
- 64, 15,220, 13, 2,229, 38, 18,120,198,128,111, 54, 1,225, 58,
- 0, 64, 15,220, 13, 2,120,230, 4, 15,253,111,120,230, 3,135,
- 135,198,180,253,119, 0,253, 54, 1,192,195,204, 5,230, 7,245,
- 213,229, 79,230, 4, 15,253,111,121,230, 3,198, 64, 14, 6, 33,
- 168, 17, 8, 58, 0, 64, 15,220, 13, 2, 8, 94,253,119, 0,198,
- 4,253,115, 1, 0,253,119, 0,198, 4,253,115, 1, 0,253,119,
- 0,198, 4,253,115, 1, 0,253,119, 0,198, 4,253,115, 1, 44,
- 13,194,178, 11,225,209, 58, 0, 64, 15,220, 13, 2,241, 79,246,
- 240,221, 54, 0, 40,221,113, 1,221, 54, 0, 40,221,119, 1,221,
- 54, 0, 40,221,113, 1, 58, 0, 64, 15,220, 13, 2,201,120, 38,
- 18,198, 64,111,197,120, 70,205, 0, 9,193, 58, 0, 64, 15,220,
- 13, 2,197,125,198, 8,111,120, 70,205, 51, 10,193,125,198, 8,
- 111,120,230, 3,198,180,253,119, 0,126,253,119, 1, 58, 0, 64,
- 15,220, 13, 2,201, 33, 48, 18, 6, 3,197,126,203,127, 32, 6,
- 6, 15, 44,195,170, 12,230,127, 71, 44,126,128, 71, 58, 0, 64,
- 15,220, 13, 2,197, 44, 78, 44, 94, 44, 86,235, 58, 0, 64, 15,
- 220, 13, 2,205,113, 1, 58, 0, 64, 15,220, 13, 2,120,254,254,
- 202,209, 12,254,255,202,230, 12,253,104, 58, 0, 64, 15,220, 13,
- 2,235,114, 45,115, 45,113, 45,193, 58, 0, 64, 15,220, 13, 2,
- 253,125,128, 71,254, 16, 56, 2, 6, 15, 58, 0, 64, 15,220, 13,
- 2,120, 7, 7, 7,193,176, 15, 15, 15,246,144, 50, 17,127,125,
- 214, 17,111, 58, 0, 64, 15,220, 13, 2, 5,242, 74, 12,195, 57,
- 1, 58, 0, 64, 15,220, 13, 2, 28,235,113, 44,115, 44,114,235,
- 29, 29, 29,195,108, 12, 58, 0, 64, 15,220, 13, 2, 28,235, 78,
- 44, 94, 44, 86,235, 29, 29, 29,195,108, 12,205, 31, 13,195,204,
- 5, 71, 58, 0, 64, 15,220, 13, 2,120,229,230, 3, 33,136, 18,
- 133,111,126,225,183,194,106, 4,120,205, 31, 13,195,174, 3,230,
- 3, 71, 8, 58, 0, 64, 15,220, 13, 2,229, 38, 18,120, 15, 15,
- 15, 15,111,126,246,128,119, 58, 0, 64, 15,220, 13, 2,213, 44,
- 44, 84,125,198, 6, 95, 58, 0, 64, 15,220, 13, 2, 26,119, 44,
- 28, 26,119, 44, 28, 26,119,209,225, 58, 0, 64, 15,220, 13, 2,
- 205,113, 1, 58, 0, 64, 15,220, 13, 2, 8,229,213, 38, 17,104,
- 17, 17,127, 15, 15, 15, 70,176, 18, 44,126, 18,209,225,201,205,
- 146, 13,195,204, 5, 58,139, 18,183,194,106, 4,205,146, 13,195,
- 174, 3, 58, 0, 64, 15,220, 13, 2,229, 33, 48, 18,126,246,128,
- 119, 58, 0, 64, 15,220, 13, 2,213, 44, 44, 84,125,198, 6, 95,
- 58, 0, 64, 15,220, 13, 2, 26,119, 44, 28, 26,119, 44, 28, 26,
- 119,209,225, 58, 0, 64, 15,220, 13, 2,205,113, 1, 58, 0, 64,
- 15,220, 13, 2, 62,224,176, 50, 17,127,201,205,255, 13,195,204,
- 5, 71, 58, 0, 64, 15,220, 13, 2,120,229,230, 3, 33,136, 18,
- 133,111,126,225,183,194,174, 3,120,205,255, 13,195,174, 3,230,
- 3, 71, 58, 0, 64, 15,220, 13, 2,229, 38, 18,120, 15, 15, 15,
- 15,111,126,230,127,119,225,201,230, 3, 8, 58, 0, 64, 15,220,
- 13, 2,205,113, 1, 58, 0, 64, 15,220, 13, 2, 8,229, 38, 18,
- 15, 15, 15, 15,111,126,230,128,176,119,225,195,204, 5,230, 3,
- 8, 58, 0, 64, 15,220, 13, 2,205,113, 1, 58, 0, 64, 15,220,
- 13, 2, 8,213,229,245, 17,136, 18,131, 95, 26, 95, 58, 0, 64,
- 15,220, 13, 2,241, 38, 18, 15, 15, 15, 15,198, 15,111,112, 58,
- 0, 64, 15,220, 13, 2,123,183, 32, 16,125,214, 15,111,126,230,
- 128,176,119, 58, 0, 64, 15,220, 13, 2,225,209,195,174, 3,230,
- 3, 8, 58, 0, 64, 15,220, 13, 2,205,113, 1, 58, 0, 64, 15,
- 220, 13, 2, 8,213,229, 22, 28, 88, 38, 18, 15, 15, 15, 15,198,
- 10,111, 58, 0, 64, 15,220, 13, 2, 26,119, 20, 45, 26,119, 20,
- 45, 26,119, 58, 0, 64, 15,220, 13, 2,125,214, 8,111, 54, 0,
- 225,209,195,204, 5,230, 3, 8, 58, 0, 64, 15,220, 13, 2,205,
- 113, 1, 58, 0, 64, 15,220, 13, 2, 8,213,229, 22, 28, 88, 33,
- 136, 18,245,133,111,241, 70, 38, 18, 15, 15, 15, 15,198, 15,111,
- 58, 0, 64, 15,220, 13, 2,119, 45, 26,119, 20, 45, 26,119, 20,
- 45, 26,119, 58, 0, 64, 15,220, 13, 2,120,183,202, 36, 15,225,
- 209,195,174, 3, 58, 0, 64, 15,220, 13, 2, 84,125,214, 4, 95,
- 126, 18, 44, 28,126, 18, 44, 28,126, 18, 58, 0, 64, 15,220, 13,
- 2,125,214, 8,111, 54, 0,225,209,195,174, 3,205,112, 15,195,
- 204, 5, 71, 58, 0, 64, 15,220, 13, 2,120,229,230, 15, 38, 18,
- 198,128,111,126,225,183,194, 88, 4,120,205,112, 15,195,174, 3,
- 230, 3, 8, 58, 0, 64, 15,220, 13, 2,205,113, 1, 58, 0, 64,
- 15,220, 13, 2, 8,213, 17, 17,127, 15, 15, 15,176,246,128, 18,
- 58, 0, 64, 15,220, 13, 2,205,113, 1, 58, 0, 64, 15,220, 13,
- 2,235,112,235,209,201,205,195, 13,195,204, 5, 58,139, 18,183,
- 194,106, 4,205,195, 13,195,174, 3,230, 3, 71, 58, 0, 64, 15,
- 220, 13, 2,229, 38, 18,120,198,136,111, 54, 1, 58, 0, 64, 15,
- 220, 13, 2,120, 15, 15, 15, 15,111, 38, 18, 54, 0,225,195,204,
- 5,205, 1, 16,195, 37, 1,205, 1, 16,195, 47, 1,230, 15, 60,
- 71,205, 18, 16,195, 37, 1,230, 15, 60, 71,205, 18, 16,195, 47,
- 1, 58, 0, 64, 15,220, 13, 2,205,113, 1, 58, 0, 64, 15,220,
- 13, 2,235,114, 45,115, 45,113, 58, 0, 64, 15,220, 13, 2, 45,
- 112,201,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 225, 70, 44,194,173, 1, 36,194,173, 1, 38,128, 12,201,205,200,
+ 1,195,230, 5, 58, 0, 64, 15,220, 34, 2, 58,142, 19,183,194,
+ 132, 4,205,200, 1,195,195, 3, 58,236, 31,183,200,205,129, 1,
+ 120,217, 38, 28,111, 86, 36, 94, 36, 78, 33, 0, 96,121, 50,152,
+ 19,119, 15,119, 15,119, 15,119, 15,119, 15,119, 15,119,116, 15,
+ 119, 38, 19,123,246,240,111, 69, 26,119, 28, 44,194,248, 1,104,
+ 123,183,194, 12, 2, 20,194, 12, 2, 22,128, 12,217,175, 50, 34,
+ 2,221, 54, 0, 43,221, 54, 1,128,221, 54, 0, 42,221, 54, 1,
+ 128,201,201,217,221, 54, 0, 39,221, 54, 1, 31,126, 60, 40, 12,
+ 221, 54, 0, 42,221,119, 1, 44, 40, 22,217,201, 6, 0,221, 54,
+ 0, 42,221, 54, 1,128,221, 54, 0, 43,221, 54, 1, 0,217,201,
+ 58,152, 19,185,202,110, 2,121, 50,152, 19, 33, 0, 96,119, 15,
+ 119, 15,119, 15,119, 15,119, 15,119, 15,119,116, 15,119, 33,240,
+ 19, 26,119, 44, 28, 26,119, 44, 28, 26,119, 44, 28, 26,119, 44,
+ 28, 26,119, 44, 28, 26,119, 44, 28, 26,119, 44, 28, 26,119, 44,
+ 28, 26,119, 44, 28, 26,119, 44, 28, 26,119, 44, 28, 26,119, 44,
+ 28, 26,119, 44, 28, 26,119, 44, 28, 26,119, 44, 28, 26,119, 44,
+ 28,194,187, 2, 20,194,187, 2, 22,128, 12, 46,240,195, 36, 2,
+ 205,218, 2,195,230, 5, 58, 0, 64, 15,220, 34, 2, 58,142, 19,
+ 183,194,195, 3,205,218, 2,195,195, 3, 62,201, 50, 34, 2,221,
+ 54, 0, 43,221, 54, 1, 0,201, 62, 1, 50,142, 19,205,218, 2,
+ 195,230, 5, 58,252, 31, 47, 71,175, 50,255, 31,120,221, 54, 0,
+ 36, 15, 15,246,192,221,119, 1,120,221, 54, 0, 37,230, 3,221,
+ 119, 1,195,239, 0, 58, 0, 64, 15,220, 34, 2,205,205, 4, 58,
+ 0, 64, 15,220, 34, 2, 58,240, 31,246, 2, 50,240, 31, 58, 0,
+ 64, 15,220, 34, 2, 33,252, 31, 78, 44, 94, 44, 86, 58, 0, 64,
+ 15,220, 34, 2,175, 50,255, 31, 33,153, 19, 54, 1, 44, 54, 1,
+ 44,113, 44,115, 44,114, 58, 0, 64, 15,220, 34, 2, 33,162, 3,
+ 34, 61, 1,195,239, 0,175, 50,255, 31, 6, 8, 17,143, 19, 58,
+ 0, 64, 15,220, 34, 2, 26,183,194,135, 3, 58, 0, 64, 15,220,
+ 34, 2, 5,205,205, 12, 4, 29, 5,194,111, 3, 58,240, 31,246,
+ 2, 50,240, 31, 33,153, 19, 54, 1, 33,162, 3, 34, 61, 1,195,
+ 239, 0, 58, 0, 64, 15,220, 34, 2, 33,154, 19,126, 61,202,181,
+ 3,119,195, 63, 1, 58, 0, 64, 15,220, 34, 2, 44, 78, 44, 94,
+ 44, 86,235, 58, 0, 64, 15,220, 34, 2,205,129, 1, 58, 0, 64,
+ 15,220, 34, 2,120,254, 8,218,130, 7,254, 11,218,194, 13,202,
+ 70, 14,254, 12,202,180, 1, 58, 0, 64, 15,220, 34, 2,120,254,
+ 24,218, 35, 8,254, 28,218,162, 14,202,198, 2, 58, 0, 64, 15,
+ 220, 34, 2,120,254,254,202,168, 16,254,255,202,153, 4,254,252,
+ 202, 67, 5,254,253,202, 88, 5, 58, 0, 64, 15,220, 34, 2,120,
+ 254, 40,218, 14, 10,254, 44,218,255, 14, 58, 0, 64, 15,220, 34,
+ 2,120,254, 56,218, 81, 8,254, 59,218, 19, 16,202,109, 16, 58,
+ 0, 64, 15,220, 34, 2,120,254, 72,218,208, 8,254, 76,218,150,
+ 15, 58, 0, 64, 15,220, 34, 2,120,254,224,218,184, 16,254,248,
+ 218,135, 11,254,250,218,226, 11, 58, 0, 64, 15,220, 34, 2,195,
+ 153, 4, 58, 0, 64, 15,220, 34, 2, 44,194,132, 4, 36,194,132,
+ 4, 38,128, 12, 58, 0, 64, 15,220, 34, 2, 44,194,150, 4, 36,
+ 194,150, 4, 38,128, 12,195,195, 3,205,169, 4,195, 63, 1,175,
+ 50,255, 31,205,169, 4,195,239, 0, 58,240, 31,230,253, 50,240,
+ 31, 58, 0, 64, 15,220, 34, 2,205,205, 4, 58, 0, 64, 15,220,
+ 34, 2,175, 50,153, 19, 33, 63, 1, 34, 61, 1,201, 58,142, 19,
+ 183,204,218, 2, 6, 4, 17, 63, 19, 33,147, 19, 58, 0, 64, 15,
+ 220, 34, 2, 54, 0,123,214, 15, 95,126,183, 32, 2,175, 18, 58,
+ 0, 64, 15,220, 34, 2, 29, 45, 16,226, 6, 8, 17, 79, 19, 58,
+ 0, 64, 15,220, 34, 2, 62,127, 18, 29, 58, 0, 64, 15,220, 34,
+ 2,126,183,194, 52, 5, 5,120,205, 68, 12, 58, 0, 64, 15,220,
+ 34, 2,120,230, 4,253,111,120,230, 3,198,180,253,119, 0,253,
+ 54, 1,192, 4, 45, 16,200, 33, 80, 19, 62,192, 6, 8,119, 44,
+ 16,252,201, 58, 0, 64, 15,220, 34, 2,235, 44, 78, 44, 94, 44,
+ 86, 45, 45, 45,235,195,195, 3, 58, 0, 64, 15,220, 34, 2,235,
+ 44,113, 44,115, 44,114, 45, 45, 45,235,195,195, 3, 58, 0, 64,
+ 15,220, 34, 2,205,216, 6, 58, 0, 64, 15,220, 34, 2, 58,240,
+ 31,246, 1, 50,240, 31, 58, 0, 64, 15,220, 34, 2, 33,252, 31,
+ 78, 44, 94, 44, 86, 58, 0, 64, 15,220, 34, 2,175, 50,255, 31,
+ 33,161, 19, 54, 1, 44, 54, 1, 44,113, 44,115, 44,114, 58, 0,
+ 64, 15,220, 34, 2, 33,197, 5, 34, 41, 1, 58, 0, 64, 15,220,
+ 34, 2,195,239, 0, 58, 0, 64, 15,220, 34, 2, 33,162, 19,126,
+ 61,202,216, 5,119,195, 43, 1, 58, 0, 64, 15,220, 34, 2, 44,
+ 78, 44, 94, 44, 86,235, 58, 0, 64, 15,220, 34, 2,205,129, 1,
+ 58, 0, 64, 15,220, 34, 2,120,254, 8,218,124, 7,254, 11,218,
+ 188, 13,202, 64, 14,254, 12,202,174, 1, 58, 0, 64, 15,220, 34,
+ 2,120,254, 24,218, 29, 8,254, 28,218,156, 14,202,192, 2, 58,
+ 0, 64, 15,220, 34, 2,120,254,254,202,162, 16,254,255,202,150,
+ 6, 58, 0, 64, 15,220, 34, 2,120,254, 40,218, 8, 10,254, 44,
+ 218,217, 14, 58, 0, 64, 15,220, 34, 2,120,254, 56,218, 75, 8,
+ 254, 59,218, 13, 16,202,103, 16, 58, 0, 64, 15,220, 34, 2,120,
+ 254, 72,218,202, 8,254, 76,218, 80, 15, 58, 0, 64, 15,220, 34,
+ 2,120,254,224,218,174, 16,254,232,218, 18, 12,254,236,218,122,
+ 16,202,232, 2, 58, 0, 64, 15,220, 34, 2,120,254,248,218, 88,
+ 11,254,250,218,220, 11,205,166, 6,195, 43, 1,175, 50,255, 31,
+ 205,166, 6,195,239, 0, 58, 0, 64, 15,220, 34, 2, 58,240, 31,
+ 230,254, 50,240, 31, 58, 0, 64, 15,220, 34, 2,175, 50,161, 19,
+ 33, 43, 1, 34, 41, 1, 58, 0, 64, 15,220, 34, 2,205,216, 6,
+ 58, 0, 64, 15,220, 34, 2,201, 58,142, 19,183,196,218, 2, 6,
+ 4, 17,147, 19, 58, 0, 64, 15,220, 34, 2, 26,183, 40, 64,175,
+ 18, 58, 0, 64, 15,220, 34, 2,120, 15, 15, 15, 15, 61, 38, 19,
+ 111, 78,214, 15,111,113, 58, 0, 64, 15,220, 34, 2,213,125,198,
+ 8,111,198, 4, 95, 84, 58, 0, 64, 15,220, 34, 2, 26,119, 44,
+ 28, 26,119, 44, 28, 26,119,209, 58, 0, 64, 15,220, 34, 2, 29,
+ 16,178, 6, 8, 58, 0, 64, 15,220, 34, 2, 26,183,202, 78, 7,
+ 175, 18, 58, 0, 64, 15,220, 34, 2, 5,205,205, 12, 4, 29, 5,
+ 194, 52, 7,201, 58, 0, 31, 60,200, 58, 0, 64, 15,220, 34, 2,
+ 33,112, 7, 34, 12, 4, 33, 0, 31, 58,152, 19, 79,195,195, 3,
+ 33,153, 4, 34, 12, 4, 62,255, 50, 0, 31,201,205,160, 7,195,
+ 230, 5, 71, 58, 0, 64, 15,220, 34, 2,229,120,230, 7, 33,136,
+ 19,133,111,126,225,183,194,132, 4,120,205,160, 7,195,195, 3,
+ 230, 7,221, 54, 0, 40,221,119, 1, 71, 8, 58, 0, 64, 15,220,
+ 34, 2,120,230, 4, 15,253,111, 58, 0, 64, 15,220, 34, 2,205,
+ 129, 1, 58, 0, 64, 15,220, 34, 2, 8,213,229, 87,230, 3,198,
+ 164, 95, 58, 0, 64, 15,220, 34, 2, 38, 18,120,230, 31,198,144,
+ 111, 58, 0, 64, 15,220, 34, 2,120,230,224, 15, 15, 71,126,176,
+ 253,115, 0,253,119, 1, 58, 0, 64, 15,220, 34, 2,123,214, 4,
+ 95, 45,126,253,115, 0,253,119, 1, 58, 0, 64, 15,220, 34, 2,
+ 122,246,240,221, 54, 0, 40,221,119, 1,225,209,201,205, 65, 8,
+ 195,230, 5, 71, 58, 0, 64, 15,220, 34, 2,120,229,230, 7, 33,
+ 136, 19,133,111,126,225,183,194,195, 3,120,205, 65, 8,195,195,
+ 3,230, 7,221, 54, 0, 40,221,119, 1,201,205,111, 8,195,230,
+ 5, 71, 58, 0, 64, 15,220, 34, 2,120,229,230, 7, 33,136, 19,
+ 133,111,126,225,183,194,114, 4,120,205,111, 8,195,195, 3,245,
+ 71, 58, 0, 64, 15,220, 34, 2,120,230, 4, 15,253,111, 58, 0,
+ 64, 15,220, 34, 2,205,129, 1, 58, 0, 64, 15,220, 34, 2,241,
+ 213,230, 7, 87,230, 3,198,164, 95, 58, 0, 64, 15,220, 34, 2,
+ 253,115, 0,253,112, 1, 58, 0, 64, 15,220, 34, 2,205,129, 1,
+ 58, 0, 64, 15,220, 34, 2,123,214, 4, 95,253,115, 0,253,112,
+ 1, 58, 0, 64, 15,220, 34, 2,209,201,205, 50, 9,195,230, 5,
+ 230, 7, 71, 58, 0, 64, 15,220, 34, 2,213,197,120, 17, 64, 19,
+ 131, 95, 58, 0, 64, 15,220, 34, 2,205,129, 1, 58, 0, 64, 15,
+ 220, 34, 2,120, 18,123,198, 8, 95,175, 18, 89,193, 75,209, 58,
+ 0, 64, 15,220, 34, 2,229,120, 38, 19,198,136,111,126,225,183,
+ 194,195, 3, 58, 0, 64, 15,220, 34, 2,120,229, 33, 64, 19,133,
+ 111, 70,225, 8, 58, 0, 64, 15,220, 34, 2, 8,205, 71, 9,195,
+ 195, 3,230, 7, 8, 58, 0, 64, 15,220, 34, 2,205,129, 1, 58,
+ 0, 64, 15,220, 34, 2, 8,245,230, 4, 15,253,111, 58, 0, 64,
+ 15,220, 34, 2,241,197,213,229, 38, 28,104, 86, 36, 94, 36, 78,
+ 235,245, 58, 0, 64, 15,220, 34, 2, 6, 7, 17,166, 19,120, 8,
+ 205,129, 1,235,112,235, 28,205,129, 1,235,112,235, 28,205,129,
+ 1,235,112,235, 28,205,129, 1,235,112,235, 28, 8, 71, 16,222,
+ 205,129, 1,235,112,235, 58, 0, 64, 15,220, 34, 2,241, 71,205,
+ 68, 12,120, 17, 96, 19,230, 7,131, 95,245,230, 3,198,176, 33,
+ 166, 19, 8, 58, 0, 64, 15,220, 34, 2, 8,253,119, 0, 70, 44,
+ 253,112, 1, 8,120, 18,123,198, 8, 95, 58, 0, 64, 15,220, 34,
+ 2, 8,214,128, 6, 28,253,119, 0, 78,253,113, 1,198, 4, 44,
+ 16,244, 58, 0, 64, 15,220, 34, 2,125,214, 24,111, 6, 4,126,
+ 18,123,198, 8, 95, 44, 16,247, 58, 0, 64, 15,220, 34, 2,241,
+ 225,209,193, 6, 0,195,126, 10,205,107, 10,195,230, 5,230, 7,
+ 71, 58, 0, 64, 15,220, 34, 2,213,197,120, 22, 19,198, 72, 95,
+ 58, 0, 64, 15,220, 34, 2,205,129, 1, 58, 0, 64, 15,220, 34,
+ 2,235,112,235, 89,193, 75,209, 58, 0, 64, 15,220, 34, 2,229,
+ 120, 33,136, 19,133,111,126,225,183,194,195, 3, 58, 0, 64, 15,
+ 220, 34, 2,120,229, 33, 72, 19,133,111, 70,225,245, 58, 0, 64,
+ 15,220, 34, 2,241,205,126, 10,195,195, 3,245, 58, 0, 64, 15,
+ 220, 34, 2,205,129, 1, 58, 0, 64, 15,220, 34, 2,241,197,213,
+ 229,230, 7,245, 38, 19,198, 88,111,112,241,245, 38, 19,198, 96,
+ 111, 8, 58, 0, 64, 15,220, 34, 2, 8,230, 7,246,224, 22, 31,
+ 95, 8, 26, 87, 58, 0, 64, 15,220, 34, 2, 8,230, 4, 15,253,
+ 111, 58, 0, 64, 15,220, 34, 2,241,230, 3,198, 64, 79,126,230,
+ 7, 95, 58, 0, 64, 15,220, 34, 2,125,198, 8,111,123,254, 7,
+ 56, 17,253,113, 0,126,130,250,222, 10,128,242,224, 10, 62,127,
+ 253,119, 1,121,198, 4, 79, 58, 0, 64, 15,220, 34, 2,125,198,
+ 8,111,123,254, 5, 56, 17,253,113, 0,126,130,250, 3, 11,128,
+ 242, 5, 11, 62,127,253,119, 1,121,198, 4, 79, 58, 0, 64, 15,
+ 220, 34, 2,125,198, 8,111,123,254, 4, 56, 17,253,113, 0,126,
+ 130,250, 40, 11,128,242, 42, 11, 62,127,253,119, 1,121,198, 4,
+ 79, 58, 0, 64, 15,220, 34, 2,125,198, 8,111,253,113, 0,126,
+ 130,250, 72, 11,128,242, 74, 11, 62,127,253,119, 1, 58, 0, 64,
+ 15,220, 34, 2,225,209,193,201, 71, 58, 0, 64, 15,220, 34, 2,
+ 120,230, 4, 15,253,111,120, 8, 58, 0, 64, 15,220, 34, 2,205,
+ 129, 1, 58, 0, 64, 15,220, 34, 2, 8,230, 3,198,180,253,119,
+ 0,253,112, 1,195,230, 5, 71, 58, 0, 64, 15,220, 34, 2,120,
+ 230, 4, 15,253,111,120, 8, 58, 0, 64, 15,220, 34, 2,205,129,
+ 1, 58, 0, 64, 15,220, 34, 2, 8,229,230, 7, 38, 19,198, 80,
+ 111,112, 8, 58, 0, 64, 15,220, 34, 2, 8,230, 7,198,136,111,
+ 8,126,183,225,194,195, 3, 58, 0, 64, 15,220, 34, 2, 8,230,
+ 3,198,180,253,119, 0,253,112, 1,195,195, 3,205,232, 11,195,
+ 230, 5,205,232, 11,195,195, 3,230, 1,135,253,111, 58, 0, 64,
+ 15,220, 34, 2,205,129, 1,197, 58, 0, 64, 15,220, 34, 2,205,
+ 129, 1, 58, 0, 64, 15,220, 34, 2,120,193,253,112, 0,253,119,
+ 1,201,230, 7, 71, 58, 0, 64, 15,220, 34, 2,229, 38, 19,120,
+ 198,136,111, 54, 1,225, 58, 0, 64, 15,220, 34, 2,120,230, 4,
+ 15,253,111,120,230, 3,135,135,198,180,253,119, 0,253, 54, 1,
+ 192,195,230, 5,230, 7,245,213,229, 79,230, 4, 15,253,111,121,
+ 230, 3,198, 64, 14, 6, 33,181, 18, 8, 58, 0, 64, 15,220, 34,
+ 2, 8, 94,253,119, 0,253,115, 1,198, 4, 8, 58, 0, 64, 15,
+ 220, 34, 2, 8,253,119, 0,253,115, 1,198, 4, 8, 58, 0, 64,
+ 15,220, 34, 2, 8,253,119, 0,253,115, 1,198, 4, 8, 58, 0,
+ 64, 15,220, 34, 2, 8,253,119, 0,253,115, 1,198, 4, 44, 13,
+ 194, 89, 12,225,209, 58, 0, 64, 15,220, 34, 2,241, 79,246,240,
+ 221, 54, 0, 40,221,113, 1,221, 54, 0, 40,221,119, 1,221, 54,
+ 0, 40,221,113, 1, 58, 0, 64, 15,220, 34, 2,201,120, 38, 19,
+ 198, 64,111,197,120, 70,205, 71, 9,193, 58, 0, 64, 15,220, 34,
+ 2,197,125,198, 8,111,120, 70,205,126, 10,193,125,198, 8,111,
+ 120,230, 3,198,180,253,119, 0,126,253,119, 1, 58, 0, 64, 15,
+ 220, 34, 2,201, 33, 48, 19, 6, 3,197,126,203,127, 32, 6, 6,
+ 15, 44,195,107, 13,230,127, 71, 44,126,128, 71, 58, 0, 64, 15,
+ 220, 34, 2,197, 44, 78, 44, 94, 44, 86,235, 58, 0, 64, 15,220,
+ 34, 2,205,129, 1, 58, 0, 64, 15,220, 34, 2,120,254,254,202,
+ 146, 13,254,255,202,167, 13,253,104, 58, 0, 64, 15,220, 34, 2,
+ 235,114, 45,115, 45,113, 45,193, 58, 0, 64, 15,220, 34, 2,253,
+ 125,230, 15,128, 71,254, 16, 56, 2, 6, 15, 58, 0, 64, 15,220,
+ 34, 2,120, 7, 7, 7,193,176, 15, 15, 15,246,144, 50, 17,127,
+ 125,214, 17,111, 58, 0, 64, 15,220, 34, 2, 5,242, 9, 13,195,
+ 73, 1, 58, 0, 64, 15,220, 34, 2, 28,235,113, 44,115, 44,114,
+ 235, 29, 29, 29,195, 43, 13, 58, 0, 64, 15,220, 34, 2, 28,235,
+ 78, 44, 94, 44, 86,235, 29, 29, 29,195, 43, 13,205,224, 13,195,
+ 230, 5, 71, 58, 0, 64, 15,220, 34, 2,120,229,230, 3, 33,144,
+ 19,133,111,126,225,183,194,132, 4,120,205,224, 13,195,195, 3,
+ 230, 3, 71, 8, 58, 0, 64, 15,220, 34, 2,229, 38, 19,120, 15,
+ 15, 15, 15,111,126,246,128,119, 58, 0, 64, 15,220, 34, 2,213,
+ 44, 44, 84,125,198, 6, 95, 58, 0, 64, 15,220, 34, 2, 26,119,
+ 44, 28, 26,119, 44, 28, 26,119,209,225, 58, 0, 64, 15,220, 34,
+ 2,205,129, 1, 58, 0, 64, 15,220, 34, 2, 8,229,213, 38, 18,
+ 104, 17, 17,127, 15, 15, 15, 70,176, 18, 44,126, 18,209,225,201,
+ 205, 83, 14,195,230, 5, 58,147, 19,183,194,132, 4,205, 83, 14,
+ 195,195, 3, 58, 0, 64, 15,220, 34, 2,229, 33, 48, 19,126,246,
+ 128,119, 58, 0, 64, 15,220, 34, 2,213, 44, 44, 84,125,198, 6,
+ 95, 58, 0, 64, 15,220, 34, 2, 26,119, 44, 28, 26,119, 44, 28,
+ 26,119,209,225, 58, 0, 64, 15,220, 34, 2,205,129, 1, 58, 0,
+ 64, 15,220, 34, 2, 62,224,176, 50, 17,127,201,205,192, 14,195,
+ 230, 5, 71, 58, 0, 64, 15,220, 34, 2,120,229,230, 3, 33,144,
+ 19,133,111,126,225,183,194,195, 3,120,205,192, 14,195,195, 3,
+ 230, 3, 71, 58, 0, 64, 15,220, 34, 2,229, 38, 19,120, 15, 15,
+ 15, 15,111,126,230,127,119,225,201,230, 3, 8, 58, 0, 64, 15,
+ 220, 34, 2,205,129, 1, 58, 0, 64, 15,220, 34, 2, 8,229, 38,
+ 19, 15, 15, 15, 15,111,126,230,128,176,119,225,195,230, 5,230,
+ 3, 8, 58, 0, 64, 15,220, 34, 2,205,129, 1, 58, 0, 64, 15,
+ 220, 34, 2, 8,213,229,245, 17,144, 19,131, 95, 26, 95, 58, 0,
+ 64, 15,220, 34, 2,241, 38, 19, 15, 15, 15, 15,198, 15,111,112,
+ 58, 0, 64, 15,220, 34, 2,123,183, 32, 16,125,214, 15,111,126,
+ 230,128,176,119, 58, 0, 64, 15,220, 34, 2,225,209,195,195, 3,
+ 230, 3, 8, 58, 0, 64, 15,220, 34, 2,205,129, 1, 58, 0, 64,
+ 15,220, 34, 2, 8,213,229, 22, 28, 88, 38, 19, 15, 15, 15, 15,
+ 198, 10,111, 58, 0, 64, 15,220, 34, 2, 26,119, 20, 45, 26,119,
+ 20, 45, 26,119, 58, 0, 64, 15,220, 34, 2,125,214, 8,111, 54,
+ 0,225,209,195,230, 5,230, 3, 8, 58, 0, 64, 15,220, 34, 2,
+ 205,129, 1, 58, 0, 64, 15,220, 34, 2, 8,213,229, 22, 28, 88,
+ 33,144, 19,245,133,111,241, 70, 38, 19, 15, 15, 15, 15,198, 15,
+ 111, 58, 0, 64, 15,220, 34, 2,119, 45, 26,119, 20, 45, 26,119,
+ 20, 45, 26,119, 58, 0, 64, 15,220, 34, 2,120,183,202,229, 15,
+ 225,209,195,195, 3, 58, 0, 64, 15,220, 34, 2, 84,125,214, 4,
+ 95,126, 18, 44, 28,126, 18, 44, 28,126, 18, 58, 0, 64, 15,220,
+ 34, 2,125,214, 8,111, 54, 0,225,209,195,195, 3,205, 49, 16,
+ 195,230, 5, 71, 58, 0, 64, 15,220, 34, 2,120,229,230, 15, 38,
+ 19,198,136,111,126,225,183,194,114, 4,120,205, 49, 16,195,195,
+ 3,230, 3, 8, 58, 0, 64, 15,220, 34, 2,205,129, 1, 58, 0,
+ 64, 15,220, 34, 2, 8,213, 17, 17,127, 15, 15, 15,176,246,128,
+ 18, 58, 0, 64, 15,220, 34, 2,205,129, 1, 58, 0, 64, 15,220,
+ 34, 2,235,112,235,209,201,205,132, 14,195,230, 5, 58,147, 19,
+ 183,194,132, 4,205,132, 14,195,195, 3,230, 3, 71, 58, 0, 64,
+ 15,220, 34, 2,229, 38, 19,120,198,144,111, 54, 1, 58, 0, 64,
+ 15,220, 34, 2,120, 15, 15, 15, 15,111, 38, 19, 54, 0,225,195,
+ 230, 5,205,194, 16,195, 43, 1,205,194, 16,195, 63, 1,230, 15,
+ 60, 71,205,211, 16,195, 43, 1,230, 15, 60, 71,205,211, 16,195,
+ 63, 1, 58, 0, 64, 15,220, 34, 2,205,129, 1, 58, 0, 64, 15,
+ 220, 34, 2,235,114, 45,115, 45,113, 58, 0, 64, 15,220, 34, 2,
+ 45,112,201, 33,240, 31, 17, 88, 19, 14, 8, 26, 70,128,242,243,
+ 16, 62,127, 71,125,205,126, 10, 44, 28, 13, 32,238, 33,232, 31,
+ 17, 1, 19, 1, 16, 4,126, 18, 44,123,129, 95, 58, 0, 64, 15,
+ 220, 34, 2, 16,241,175, 50,241, 31,201,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
@@ -281,8 +297,8 @@ static uint8_t echo_blob[] = {
129, 2,143, 1,141, 1,140, 1,138, 1,137, 1,135, 1,134, 1,
133, 1,131, 1,130, 1,129, 1,128, 1,143, 0,142, 0,142, 0,
132, 2,169, 2,210, 2,253, 2, 42, 3, 90, 3,142, 3,196, 3,
- 253, 3, 57, 4,122, 4,190, 4,127, 0, 31, 31,255, 0,255,255,
- 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 253, 3, 57, 4,122, 4,190, 4, 0, 2, 4, 6, 8, 10, 12,254,
+ 252,250,248,246,244,127, 0, 31, 31,255, 0,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
@@ -298,8 +314,8 @@ static uint8_t echo_blob[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255,255,255,255,255,
- 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
diff --git a/doc/api-asm.68k b/doc/api-asm.68k
index b6fa48b..8c0995c 100644
--- a/doc/api-asm.68k
+++ b/doc/api-asm.68k
@@ -51,11 +51,6 @@ Echo_StopBGM
Stops playback of background music. Used both to stop and to pause music
(the latter can be undone with Echo_ResumeBGM, see below).
-Echo_ResumeBGM
-
- Resumes playback of whatever background music was playing last time before
- Echo_StopBGM was called. Used when you want to unpause music.
-
=============================================================================
*** Sound effects ***
@@ -71,6 +66,28 @@ Echo_StopSFX
=============================================================================
+*** Direct events ***
+
+Echo_PlayDirect
+
+ Injects events to be played as part of the BGM the next tick. The register
+ a0 points to the ESF data to be injected.
+
+ The injected events are a small stream on their own. The last event must
+ be $FF (this will return back to the BGM). Do *not* issue $FC, $FD or $FE
+ events, as you'll just break everything instead.
+
+ The buffer is small, so don't go overboard. There's room for up to 128
+ bytes (though again, each event is just 2-3 bytes). If there were direct
+ events pending to play, the new events will be appended at the end, so
+ take this into account when it comes to the buffer usage. You can check
+ if there are pending events with Echo_GetStatus (see bit 14) if you're
+ worried about running out of space.
+
+ The buffer is only checked every tick.
+
+=============================================================================
+
*** Control ***
Echo_GetStatus
@@ -80,12 +97,32 @@ Echo_GetStatus
Bit 0 .... Sound effect is playing
Bit 1 .... Background music is playing
+ Bit 14 ... Echo isn't done parsing direct events
Bit 15 ... Echo is busy (can't take commands)
The API will automatically wait if you try to send a command while Echo is
busy, so the only reason to check for that is if you don't want to halt
the 68000 until Echo is ready to take more commands.
+Echo_SetVolume
+
+ Sets the global volume. Register d0 is a byte value ranging from 0
+ (quietest) to 255 (loudest), and every channel is affected immediately.
+ The scale of the volume in this case is *linear*.
+
+ Note that since PCM doesn't have volume, it gets toggled on/off depending
+ on the volume value (the cut off point is at 25%).
+
+Echo_SetVolumeEx
+
+ Sets the global volume for each channel separately. Register a0 points to
+ a list of 13 bytes (one for each Echo channel). Values for FM and PSG
+ channels are given in the same way as in events, that is: logarithmic
+ scale, 0..127 for FM, 0..15 for PSG, lower = louder.
+
+ The last byte (the one belonging to the PCM channel) is used to toggle
+ whether PCM plays, either 0 (disabled) or 1 (enabled).
+
=============================================================================
*** Settings ***
diff --git a/doc/api-c.txt b/doc/api-c.txt
index f0dd326..24c6312 100644
--- a/doc/api-c.txt
+++ b/doc/api-c.txt
@@ -55,11 +55,6 @@ void echo_stop_bgm()
Stops playback of background music. Used both to stop and to pause music
(the latter can be undone with echo_resume_bgm, see below).
-void echo_resume_bgm()
-
- Resumes playback of whatever background music was playing last time before
- echo_stop_bgm was called. Used when you want to unpause music.
-
=============================================================================
*** Sound effects ***
@@ -75,6 +70,28 @@ void echo_stop_sfx()
=============================================================================
+*** Direct events ***
+
+void echo_play_direct(const void *esf)
+
+ Injects events to be played as part of the BGM the next tick. The
+ parameter 'esf' points to the ESF data to be injected.
+
+ The injected events are a small stream on their own. The last event must
+ be $FF (this will return back to the BGM). Do *not* issue $FC, $FD or $FE
+ events, as you'll just break everything instead.
+
+ The buffer is small, so don't go overboard. There's room for up to 128
+ bytes (though again, each event is just 2-3 bytes). If there were direct
+ events pending to play, the new events will be appended at the end, so
+ take this into account when it comes to the buffer usage. You can check
+ if there are pending events with Echo_GetStatus (see ECHO_STAT_DIRBUSY)
+ if you're worried about running out of space.
+
+ The buffer is only checked every tick.
+
+=============================================================================
+
*** Control ***
uint16_t echo_get_status()
@@ -82,14 +99,34 @@ uint16_t echo_get_status()
Gets the current status of Echo. Returns an OR of the following flags,
as relevant:
- ECHO_STAT_BGM .... Background music is playing
- ECHO_STAT_SFX .... Sound effect is playing
- ECHO_STAT_BUSY ... Echo is busy (can't take commands)
+ ECHO_STAT_BGM ....... Background music is playing
+ ECHO_STAT_SFX ....... Sound effect is playing
+ ECHO_STAT_DIRBUSY ... Echo isn't done parsing direct events
+ ECHO_STAT_BUSY ...... Echo is busy (can't take commands)
The API will automatically wait if you try to send a command while Echo is
busy, so the only reason to check for that is if you don't want to halt
the 68000 until Echo is ready to take more commands.
+void echo_set_volume(uint8_t vol)
+
+ Sets the global volume. The value 'vol' ranges from 0 (quietest) to 255
+ (loudest), and every channel is affected immediately. The scale of the
+ volume in this case is *linear*.
+
+ Note that since PCM doesn't have volume, it gets toggled on/off depending
+ on the volume value (the cut off point is at 25%).
+
+void echo_set_volume_ex(const uint8_t *ptr)
+
+ Sets the global volume for each channel separately. The parameter 'ptr'
+ points to a list of 13 bytes (one for each Echo channel). Values for FM
+ and PSG channels are given in the same way as in events, that is:
+ logarithmic scale, 0..127 for FM, 0..15 for PSG, lower = louder.
+
+ The last byte (the one belonging to the PCM channel) is used to toggle
+ whether PCM plays, either 0 (disabled) or 1 (enabled).
+
=============================================================================
*** Settings ***
diff --git a/doc/esf.txt b/doc/esf.txt
index a7b833e..a96e35d 100644
--- a/doc/esf.txt
+++ b/doc/esf.txt
@@ -85,6 +85,8 @@ EVENT LIST
$4Ann ..... Set instrument PSG channel #3
$4Bnn ..... Set instrument PSG channel #4
+ $Dn ....... Delay ticks (short)
+
$E0 ....... [SFX] Lock FM channel #1
$E1 ....... [SFX] Lock FM channel #2
$E2 ....... [SFX] Lock FM channel #3
@@ -103,9 +105,12 @@ EVENT LIST
$F5nn ..... Set parameters FM channel #5
$F6nn ..... Set parameters FM channel #6
+ $F8rrnn ... Set FM register in bank 0
+ $F9rrnn ... Set FM register in bank 1
+
$FC ....... [BGM] Go to loop
$FD ....... [BGM] Set loop point
- $FEnn ..... Delay ticks
+ $FEnn ..... Delay ticks (long)
$FF ....... Stop playback
=============================================================================
@@ -288,6 +293,14 @@ $4Bnn: Set instrument PSG channel #4
=============================================================================
+$D0~$DF: Delay ticks (short)
+
+ Same as $FE01 to $FE10 ($D0 = $FE01, $D1 = $FE02, etc.). Just a shorter
+ variant of the event to reduce space usage for shorter delays (which are
+ the most common).
+
+=============================================================================
+
$E0: Lock FM channel #1 [SFX ONLY]
$E1: Lock FM channel #2 [SFX ONLY]
$E2: Lock FM channel #3 [SFX ONLY]
@@ -326,6 +339,34 @@ $F6: Set parameters FM channel #6
=============================================================================
+$F8rrnn: Set FM register in bank 0
+$F9rrnn: Set FM register in bank 1
+
+ These events are used to change the value of a YM2612 register directly.
+ The rr byte indicates the register, the nn byte is the value to be
+ written into it ($F8 writes to $4000/1, $F9 writes to $4002/3).
+
+ HERE BE DRAGONS, USE AT YOUR OWN RISK. The channel locking mechanism will
+ *not* take care of this event, and if a SFX locks the channel then the
+ register will *not* be restored properly once the SFX is over.
+
+ More specifically:
+
+ * If you use it on a BGM, don't let it touch any channels that may
+ get locked by SFXs.
+
+ * If you use it on a SFX for an effect on the SFX itself, use it only
+ for channels locked by that SFX.
+
+ * If you use it on a SFX to affect the music, use it only on channels
+ that are *not* locked by any SFX (same as first rule, actually).
+
+ * It's possible to touch the global registers ($22~$2B in bank 0).
+ Do it at your own risk. You may mess up with Echo's functionality,
+ so be careful about it and make sure you know what you're doing.
+
+=============================================================================
+
$FC: Go to loop [BGM ONLY]
$FD: Set loop point [BGM ONLY]
diff --git a/src-68k/echo.68k b/src-68k/echo.68k
index 9304247..f10695a 100644
--- a/src-68k/echo.68k
+++ b/src-68k/echo.68k
@@ -192,11 +192,40 @@ Echo_StopBGM:
; Resumes BGM playback
;****************************************************************************
-Echo_ResumeBGM:
- move.w d0, -(sp) ; Save register
- move.b #$06, d0 ; Command $06 = resume BGM
- bsr Echo_SendCommand ; Send command to Echo
- move.w (sp)+, d0 ; Restore register
+;Echo_ResumeBGM:
+; move.w d0, -(sp) ; Save register
+; move.b #$06, d0 ; Command $06 = resume BGM
+; bsr Echo_SendCommand ; Send command to Echo
+; move.w (sp)+, d0 ; Restore register
+; rts ; End of subroutine
+
+;****************************************************************************
+; Echo_PlayDirect
+; Injects events into the BGM stream for the next tick.
+;
+; input a0.l ... Pointer to stream data
+;****************************************************************************
+
+Echo_PlayDirect:
+ Echo_Z80Request ; We need the Z80 bus
+ movem.l d0-d1/a0-a1, -(sp) ; Save registers
+
+ lea ($A01F00), a1 ; Skip any pending events
+ moveq #-1, d1
+@Skip:
+ cmp.b (a1), d1
+ beq.s @Load
+ addq.w #1, a1
+ bra.s @Skip
+
+@Load: ; Copy stream into the direct buffer
+ move.b (a0)+, d0
+ move.b d0, (a1)+
+ cmp.b d1, d0
+ bne.s @Load
+
+ movem.l (sp)+, d0-d1/a0-a1 ; Restore registers
+ Echo_Z80Release ; We're done with the Z80 bus
rts ; End of subroutine
;****************************************************************************
@@ -215,12 +244,112 @@ Echo_SetPCMRate:
rts ; End of subroutine
;****************************************************************************
+; Echo_SetVolume
+; Changes the global volume for every channel.
+;
+; input d0.b ... New volume (0 = quietest, 255 = loudest)
+;****************************************************************************
+
+Echo_SetVolume:
+ Echo_Z80Request ; We need the Z80 bus
+ movem.l d0-d1/a0-a1, -(sp) ; Save registers
+
+ lea @FMTable(pc), a0 ; Determine FM volume
+ moveq #0, d1
+ move.b d0, d1
+ lsr.b #2, d1
+ move.b (a0,d1.w), d1
+
+ lea ($A01FE0), a1 ; Copy new FM volume values
+ move.b d1, (a1)+ ; FM channel 0
+ move.b d1, (a1)+ ; FM channel 1
+ move.b d1, (a1)+ ; FM channel 2
+ move.b d1, (a1)+ ; FM channel 3
+ move.b d1, (a1)+ ; FM channel 4
+ move.b d1, (a1)+ ; FM channel 5
+ move.b d1, (a1)+ ; FM channel 6
+ move.b d1, (a1)+ ; FM channel 7
+
+ lea @PSGTable(pc), a0 ; Determine PSG volume
+ moveq #0, d1
+ move.b d0, d1
+ lsr.b #2, d1
+ move.b (a0,d1.w), d1
+
+ ; Copy new PSG values
+ move.b d1, (a1)+ ; PSG channel 0
+ move.b d1, (a1)+ ; PSG channel 1
+ move.b d1, (a1)+ ; PSG channel 2
+ move.b d1, (a1)+ ; PSG channel 3
+
+ cmp.b #$40, d0 ; Determine whether PCM should be enabled
+ shs d1 ; (we do an heuristic for enabling PCM
+ and.b #1, d1 ; based on the volume value)
+ move.b d1, (a1)+
+
+ move.b #1, ($A01FF1) ; Tell Echo to update the volume levels
+
+ movem.l (sp)+, d0-d1/a0-a1 ; Restore registers
+ Echo_Z80Release ; We're done with the Z80 bus
+ rts ; End of subroutine
+
+;----------------------------------------------------------------------------
+
+@FMTable:
+ dc.b $7F,$7B,$77,$73,$70,$6C,$68,$65,$61,$5E,$5A,$57,$54,$50,$4D,$4A
+ dc.b $47,$44,$41,$3F,$3C,$39,$36,$34,$31,$2F,$2D,$2A,$28,$26,$24,$22
+ dc.b $20,$1E,$1C,$1A,$18,$16,$15,$13,$12,$10,$0F,$0D,$0C,$0B,$0A,$09
+ dc.b $08,$07,$06,$05,$04,$04,$03,$02,$02,$01,$01,$01,$00,$00,$00,$00
+
+@PSGTable:
+ dc.b $0F,$0F,$0E,$0E,$0D,$0D,$0C,$0C,$0B,$0B,$0B,$0A,$0A,$0A,$09,$09
+ dc.b $08,$08,$08,$07,$07,$07,$06,$06,$06,$06,$05,$05,$05,$04,$04,$04
+ dc.b $04,$03,$03,$03,$03,$03,$02,$02,$02,$02,$02,$02,$01,$01,$01,$01
+ dc.b $01,$01,$01,$01,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
+
+;****************************************************************************
+; Echo_SetVolumeEx
+; Changes the global volume for each individual channel.
+;
+; input a0.l ... Pointer to 13 bytes
+; 8 bytes with FM volumes (0..127)
+; 4 bytes with PSG volumes (0..15)
+; 1 byte with PCM toggle (0/1)
+;****************************************************************************
+
+Echo_SetVolumeEx:
+ Echo_Z80Request ; We need the Z80 bus
+ movem.l a0-a1, -(sp) ; Save registers
+
+ lea ($A01FE0), a1 ; Copy new volume values
+ move.b (a0)+, (a1)+ ; FM channel 0
+ move.b (a0)+, (a1)+ ; FM channel 1
+ move.b (a0)+, (a1)+ ; FM channel 2
+ move.b (a0)+, (a1)+ ; FM channel 3
+ move.b (a0)+, (a1)+ ; FM channel 4
+ move.b (a0)+, (a1)+ ; FM channel 5
+ move.b (a0)+, (a1)+ ; FM channel 6
+ move.b (a0)+, (a1)+ ; FM channel 7
+ move.b (a0)+, (a1)+ ; PSG channel 0
+ move.b (a0)+, (a1)+ ; PSG channel 1
+ move.b (a0)+, (a1)+ ; PSG channel 2
+ move.b (a0)+, (a1)+ ; PSG channel 3
+ move.b (a0)+, (a1)+ ; PCM channel toggle
+
+ move.b #1, ($A01FF1) ; Tell Echo to update the volume levels
+
+ movem.l (sp)+, a0-a1 ; Restore registers
+ Echo_Z80Release ; We're done with the Z80 bus
+ rts ; End of subroutine
+
+;****************************************************************************
; Echo_GetStatus
; Gets the current status of Echo
;
; output d0.w ... Echo status
; Bit #0: SFX is playing
; Bit #1: BGM is playing
+; Bit #14: direct events not played
; Bit #15: command still not parsed
;****************************************************************************
@@ -228,10 +357,17 @@ Echo_GetStatus:
moveq #0, d0
Echo_Z80Request ; We need the Z80 bus
move.b ($A01FF0), d0 ; Get the status flags
+
tst.b ($A01FFF) ; Check if command still has to be parsed
beq.s @NotBusy ; Any commands left to be parsed?
bset.l #15, d0 ; If so, set the relevant flag
@NotBusy:
+
+ cmpi.b #$FF, ($A01F00) ; Check if the direct buffer is empty
+ beq.s @DirectEmpty ; Any direct events still to be played?
+ bset.l #14, d0 ; If so, set the relevant flag
+@DirectEmpty:
+
Echo_Z80Release ; Let the Z80 go!
rts ; End of subroutine
@@ -292,6 +428,25 @@ Echo_Init:
move.b (a0)+, (a1)+ ; Copy byte into Z80 RAM
dbf d0, @LoadLoop ; Go for next byte
+ moveq #0, d0 ; Set default global volumes
+ lea ($A01FE0), a0
+ move.b d0, (a0)+
+ move.b d0, (a0)+
+ move.b d0, (a0)+
+ move.b d0, (a0)+
+ move.b d0, (a0)+
+ move.b d0, (a0)+
+ move.b d0, (a0)+
+ move.b d0, (a0)+
+ move.b d0, (a0)+
+ move.b d0, (a0)+
+ move.b d0, (a0)+
+ move.b d0, (a0)+
+ move.b #1, (a0)+
+ move.b d0, ($A01FF1)
+
+ move.b #$FF, ($A01F00) ; No direct events to execute
+
Echo_Z80Reset ; Now reset for real
Echo_Z80Release ; Let the Z80 go!
diff --git a/src-68k/esf.68k b/src-68k/esf.68k
index fdaa55e..fc8dacc 100644
--- a/src-68k/esf.68k
+++ b/src-68k/esf.68k
@@ -45,6 +45,15 @@ ESF_FMFREQ_10 equ ESF_FMFREQ_AS
ESF_FMFREQ_11 equ ESF_FMFREQ_B
;****************************************************************************
+; Panning values
+;****************************************************************************
+
+ESF_PAN_OFF: equ $00 ; Mute
+ESF_PAN_L: equ $80 ; Left speaker only
+ESF_PAN_R: equ $40 ; Right speaker only
+ESF_PAN_LR: equ $C0 ; Both speakers
+
+;****************************************************************************
; ESF_NoteOn
; Start playing a note.
;----------------------------------------------------------------------------
@@ -166,6 +175,40 @@ ESF_Lock macro
endm
;****************************************************************************
+; ESF_SetPan
+; Set the panning of a FM channel.
+;----------------------------------------------------------------------------
+; Format:
+; ESF_SetPan channel, panning
+;----------------------------------------------------------------------------
+; param channel ... channel to modify
+; param panning ... panning (see ESF_PAN_*)
+;****************************************************************************
+
+ESF_SetPan macro
+ dc.b $F0+(\1)
+ dc.b (\2)
+ endm
+
+;****************************************************************************
+; ESF_SetFMReg
+; Set a FM register directly.
+;----------------------------------------------------------------------------
+; Format:
+; ESF_SetFMReg bank, register, value
+;----------------------------------------------------------------------------
+; param bank ....... YM2612 bank (0 or 1)
+; param register ... register to modify
+; param value ...... value to write
+;****************************************************************************
+
+ESF_SetFMReg macro
+ dc.b $F8+(\1)
+ dc.b (\2)
+ dc.b (\3)
+ endm
+
+;****************************************************************************
; ESF_Delay
; Stop event.
;----------------------------------------------------------------------------
diff --git a/src-z80/build.z80 b/src-z80/build.z80
index 88932ac..1aaa709 100644
--- a/src-z80/build.z80
+++ b/src-z80/build.z80
@@ -2,6 +2,7 @@
include "src-z80/player/pcm.z80"
include "src-z80/core/bgm.z80"
include "src-z80/core/sfx.z80"
+ include "src-z80/core/direct.z80"
include "src-z80/player/fm.z80"
include "src-z80/player/psg.z80"
include "src-z80/player/misc.z80"
diff --git a/src-z80/core/bgm.z80 b/src-z80/core/bgm.z80
index 2f57a73..338a7a6 100644
--- a/src-z80/core/bgm.z80
+++ b/src-z80/core/bgm.z80
@@ -97,6 +97,8 @@ ResumeBGM:
;****************************************************************************
; ProcessBGM
; Processes a tick for a BGM
+;----------------------------------------------------------------------------
+; breaks: all
;****************************************************************************
ProcessBGM:
@@ -153,6 +155,7 @@ ProcessBGMSkip:
cp $FE
jp z, SetDelayBGM ; Event $FE: set delay
cp $FF
+ProcessBGMEventFF:
jp z, StopBGMEvent ; Event $FF: stop BGM
cp $FC
jp z, LoopBGM ; Event $FC: loop BGM
@@ -192,8 +195,11 @@ ProcessBGMSkip:
cp $F8 ; Events $F0-$F7: set FM parameters
jp c, SetFMParamBGM
+ cp $FA ; Events $F8-$F9: set FM register
+ jp c, SetFMRegBGM
PollPCM ; FFFFFFFFF bad event >:(
+ProcessBGMEnd:
jp StopBGMEvent ; End of subroutine
ProcessBGMSkip2: ; This is where we land after a locked event
diff --git a/src-z80/core/direct.z80 b/src-z80/core/direct.z80
new file mode 100644
index 0000000..d796ddf
--- /dev/null
+++ b/src-z80/core/direct.z80
@@ -0,0 +1,30 @@
+;****************************************************************************
+; ProcessDirect
+; Processes the direct event stream.
+;----------------------------------------------------------------------------
+; breaks: all
+;****************************************************************************
+
+ProcessDirect:
+ ld a, ($1F00) ; Are there even events to process?
+ inc a
+ ret z
+
+ PollPCM
+
+ ld hl, ProcessDirectEnd ; Override $FF event
+ ld (ProcessBGMEventFF+1), hl
+
+ ld hl, $1F00 ; Where event data is stored
+ ld a, (RAM_LastBank) ; To avoid wasting time with bank
+ ld c, a ; switching
+
+ jp ProcessBGMRun ; Start processing the event
+
+ProcessDirectEnd:
+ ld hl, StopBGMEvent ; Restore $FF event
+ ld (ProcessBGMEventFF+1), hl
+ ld a, $FF ; Reset the stream
+ ld ($1F00), a
+
+ ret ; Return to the main loop
diff --git a/src-z80/core/main.z80 b/src-z80/core/main.z80
index da323f4..4eb6e5a 100644
--- a/src-z80/core/main.z80
+++ b/src-z80/core/main.z80
@@ -90,6 +90,8 @@ EntryPoint:
;****************************************************************************
; PollPCM
; Used to update PCM while not idle
+;----------------------------------------------------------------------------
+; breaks: af
;****************************************************************************
PollPCM: macro
@@ -154,21 +156,31 @@ IdleLoop:
;****************************************************************************
DoTick:
- ld a, (ix+0)
- bit 0, a
- call nz, UpdatePCM
+; ld a, (ix+0)
+; bit 0, a
+; call nz, UpdatePCM
- ld (ix+0), $27
+ PollPCM
+
+ ld (ix+0), $27 ; Retrigger the timer
ld (ix+1), $2F
PollPCM
+
+ ld a, ($1FF1) ; Refresh volume if needed
+ or a
+ call nz, RefreshVolume
DoTick_SFX: ; Process SFXs
jp DoTick_SFXSkip
DoTick_SFXSkip:
PollPCM
+
+ call ProcessDirect ; Process direct events
+ PollPCM
+
DoTick_BGM: ; Process BGMs
jp DoTick_BGMSkip
DoTick_BGMSkip:
@@ -257,6 +269,19 @@ LoadList:
;****************************************************************************
; GetParam
; Subroutine for getting the parameter byte
+;----------------------------------------------------------------------------
+; input c .... current bank
+; input hl ... current address
+;----------------------------------------------------------------------------
+; output b .... value
+; output c .... new bank
+; output hl ... new address
+;----------------------------------------------------------------------------
+; breaks: af
+;----------------------------------------------------------------------------
+; note: the C value gets incremented *only* when HL hits $0000 (this is
+; relevant if you consider using it to fetch from Z80 RAM, which should
+; never result in HL becoming $0000).
;****************************************************************************
GetParam:
@@ -270,7 +295,7 @@ GetParam:
BankSwitch
pop hl
.noswitchp:
- ld b, (hl) ; Get volume
+ ld b, (hl) ; Get value
inc l ; Get next address
jp nz, .nonewbankp
diff --git a/src-z80/core/sfx.z80 b/src-z80/core/sfx.z80
index 1c62873..4bca4c7 100644
--- a/src-z80/core/sfx.z80
+++ b/src-z80/core/sfx.z80
@@ -1,6 +1,8 @@
;****************************************************************************
; PlaySFX [command $02]
; Plays a SFX
+;----------------------------------------------------------------------------
+; breaks: all
;****************************************************************************
PlaySFX:
@@ -48,6 +50,8 @@ PlaySFX:
;****************************************************************************
; ProcessSFX
; Processes a tick for a SFX
+;----------------------------------------------------------------------------
+; breaks: all
;****************************************************************************
ProcessSFX:
@@ -147,10 +151,14 @@ ProcessSFXRun:
cp $F8 ; Events $F0-$F7: set FM parameters
jp c, SetFMParamSFX
+ cp $FA ; Events $F8-$F9: set FM register
+ jp c, SetFMRegSFX
;****************************************************************************
; StopSFX* [command $03, event $FF]
; Stops SFX playback
+;----------------------------------------------------------------------------
+; breaks: all
;****************************************************************************
StopSFXEvent:
@@ -186,6 +194,8 @@ StopSFX:
;****************************************************************************
; ClearSFX
; Clears SFX resources
+;----------------------------------------------------------------------------
+; breaks: all
;****************************************************************************
ClearSFX:
diff --git a/src-z80/core/vars.z80 b/src-z80/core/vars.z80
index 959711b..cd7162d 100644
--- a/src-z80/core/vars.z80
+++ b/src-z80/core/vars.z80
@@ -17,6 +17,7 @@ RAM_BGMFMInstr: ds 8 ; FM instruments used by BGM
RAM_BGMFMVol: ds 8 ; FM volumes used by BGM
RAM_BGMFMPan: ds 8, $C0 ; FM panning used by BGM
+RAM_FMVol: ds 8 ; FM volume of each channel
RAM_FMData: ds 8*5 ; FM info (for volume handling)
; ds 8*1 ... Register $B0
; ds 8*1 ... Register $40
@@ -25,6 +26,7 @@ RAM_FMData: ds 8*5 ; FM info (for volume handling)
; ds 8*1 ... Register $4C
RAM_Locked: ds 12 ; Locked channels
+RAM_PSGNote: ds 4 ; Current PSG notes
RAM_LastBank: ds 1 ; Last accessed bank
@@ -64,9 +66,11 @@ RAM_PointerList: equ $1C00
; 68000 communication variables
;****************************************************************************
-RAM_Stack: equ $1FF0 ; Where stack starts
+RAM_Stack: equ $1FE0 ; Where stack starts
+RAM_GlobalVol: equ $1FE0 ; Global volume for all channels
RAM_Status: equ $1FF0 ; Current playback status
+RAM_RefreshVol: equ $1FF1 ; Set to refresh all volumes
RAM_Command: equ $1FFF ; Command type
RAM_ComAddr: equ $1FFD ; Command address parameter
RAM_ComBank: equ $1FFC ; Command bank parameter
diff --git a/src-z80/player/fm.z80 b/src-z80/player/fm.z80
index 558a01d..505e849 100644
--- a/src-z80/player/fm.z80
+++ b/src-z80/player/fm.z80
@@ -1,6 +1,12 @@
;****************************************************************************
-; NoteOnFM
+; NoteOnFM* [events $00~$07]
; Does a "note on" for a FM channel
+;----------------------------------------------------------------------------
+; input a .... FM channel (bottom 3 bits)
+; input c .... current bank
+; input hl ... current address
+;----------------------------------------------------------------------------
+; breaks: af, b
;****************************************************************************
NoteOnFMSFX:
@@ -95,8 +101,14 @@ NoteOnFM:
ret ; End of subroutine
;****************************************************************************
-; NoteOffFM
+; NoteOffFM [events $10~$17]
; Does a "note off" for a FM channel
+;----------------------------------------------------------------------------
+; input a .... FM channel (bottom 3 bits)
+; input c .... current bank
+; input hl ... current address
+;----------------------------------------------------------------------------
+; breaks: af, b
;****************************************************************************
NoteOffFMSFX:
@@ -129,8 +141,14 @@ NoteOffFM:
ret ; End of subroutine
;****************************************************************************
-; SetFMNote*
+; SetFMNote* [events $30~$37]
; Sets the note of a FM channel without "note on"
+;----------------------------------------------------------------------------
+; input a .... FM channel (bottom 3 bits)
+; input c .... current bank
+; input hl ... current address
+;----------------------------------------------------------------------------
+; breaks: af, b
;****************************************************************************
SetNoteFMSFX:
@@ -200,8 +218,14 @@ SetNoteFM:
ret ; End of subroutine
;****************************************************************************
-; LoadFM*
+; LoadFM* [events $40~$47]
; Loads a FM instrument
+;----------------------------------------------------------------------------
+; input a .... FM channel (bottom 3 bits)
+; input c .... current bank
+; input hl ... current address
+;----------------------------------------------------------------------------
+; breaks: af, b
;****************************************************************************
LoadFMSFX:
@@ -398,7 +422,9 @@ LoadFMDirect:
pop hl
pop de
pop bc
- ret
+
+ ld b, 0
+ jp SetFMVolLoad
;****************************************************************************
; SetFMVol*
@@ -475,6 +501,13 @@ SetFMVolLoad:
and $07 ; Get channel ID
+ push af ; Store new FM volume
+ ld h, RAM_FMVol>>8
+ add RAM_FMVol&$FF
+ ld l, a
+ ld (hl), b
+ pop af
+
push af
ld h, RAM_FMData>>8 ; Get address of FM data
add RAM_FMData&$FF
@@ -483,6 +516,17 @@ SetFMVolLoad:
ex af, af'
PollPCM
ex af, af'
+
+ and $07 ; Get global volume
+ or $E0
+ ld d, $1F
+ ld e, a
+ ex af, af'
+ ld a, (de)
+ ld d, a
+
+ PollPCM
+ ex af, af'
and $04 ; Determine which port to write
rrca
@@ -508,11 +552,13 @@ SetFMVolLoad:
jr c, .noop1
ld (iy+0), c
ld a, (hl)
+ add d
+ jp m, .tooquiet1
add b
- cp $7F
- jr c, .notooloud1
+ jp p, .notooquiet1
+.tooquiet1:
ld a, $7F
-.notooloud1:
+.notooquiet1:
ld (iy+1), a
.noop1:
ld a, c
@@ -529,11 +575,13 @@ SetFMVolLoad:
jr c, .noop2
ld (iy+0), c
ld a, (hl)
+ add d
+ jp m, .tooquiet2
add b
- cp $7F
- jr c, .notooloud2
+ jp p, .notooquiet2
+.tooquiet2:
ld a, $7F
-.notooloud2:
+.notooquiet2:
ld (iy+1), a
.noop2:
ld a, c
@@ -550,11 +598,13 @@ SetFMVolLoad:
jr c, .noop3
ld (iy+0), c
ld a, (hl)
+ add d
+ jp m, .tooquiet3
add b
- cp $7F
- jr c, .notooloud3
+ jp p, .notooquiet3
+.tooquiet3:
ld a, $7F
-.notooloud3:
+.notooquiet3:
ld (iy+1), a
.noop3:
ld a, c
@@ -568,11 +618,13 @@ SetFMVolLoad:
ld l, a
ld (iy+0), c
ld a, (hl) ; Process operator #4
+ add d
+ jp m, .tooquiet4
add b
- cp $7F
- jr c, .notooloud4
+ jp p, .notooquiet4
+.tooquiet4:
ld a, $7F
-.notooloud4:
+.notooquiet4:
ld (iy+1), a
PollPCM
@@ -583,8 +635,17 @@ SetFMVolLoad:
ret ; End of subroutine
;****************************************************************************
-; SetFMParam*
+; SetFMParam* [events $F0-$F7]
; Sets the different parameters of a FM channel
+;----------------------------------------------------------------------------
+; input c .... current bank
+; input hl ... current address
+;----------------------------------------------------------------------------
+; output b .... value
+; output c .... new bank
+; output hl ... new address
+;----------------------------------------------------------------------------
+; breaks: af, b
;****************************************************************************
SetFMParamSFX:
@@ -657,8 +718,62 @@ SetFMParamBGM:
jp ProcessBGMRun ; End of subroutine
;****************************************************************************
+; SetFMReg* [events $F8-$F9]
+; Changes a FM register
+;----------------------------------------------------------------------------
+; input a .... YM2612 register bank (0 or 1, in bit 0)
+; input c .... current bank
+; input hl ... current address
+;----------------------------------------------------------------------------
+; output b .... value
+; output c .... new bank
+; output hl ... new address
+;----------------------------------------------------------------------------
+; breaks: af, b
+;****************************************************************************
+
+SetFMRegSFX:
+ call SetFMReg ; We're just a wrapper
+ jp ProcessSFXRun
+
+SetFMRegBGM:
+ call SetFMReg ; We're just a wrapper
+ jp ProcessBGMRun
+
+;----------------------------------------------------------------------------
+
+SetFMReg:
+ and $01 ; Get port address
+ add a
+ ld iyl, a
+
+ PollPCM ; Get parameters
+ call GetParam
+ push bc
+ PollPCM
+ call GetParam
+ PollPCM
+ ld a, b
+ pop bc
+
+ ld (iy+0), b ; Write register
+ ld (iy+1), a
+
+ ret ; End of subroutine
+
+;****************************************************************************
; LockChannelFM [events $E0-$E7]
; Locks a FM channel
+;----------------------------------------------------------------------------
+; input a ... FM channel (0..7, in bottom 3 bits)
+; input c .... current bank
+; input hl ... current address
+;----------------------------------------------------------------------------
+; output b .... value
+; output c .... new bank
+; output hl ... new address
+;----------------------------------------------------------------------------
+; breaks: af, iy
;****************************************************************************
LockChannelFM:
@@ -694,6 +809,10 @@ LockChannelFM:
;****************************************************************************
; KillFM
; Kills a FM channel
+;----------------------------------------------------------------------------
+; input a ... FM channel (0..7, in bottom 3 bits)
+;----------------------------------------------------------------------------
+; breaks: af, c, iy
;****************************************************************************
KillFM:
@@ -720,20 +839,26 @@ KillFM:
ld e, (hl)
ld (iy+0), a
- add 4
ld (iy+1), e
- nop
- ld (iy+0), a
add 4
- ld (iy+1), e
- nop
+ ex af, af'
+ PollPCM
+ ex af, af'
ld (iy+0), a
- add 4
ld (iy+1), e
- nop
+ add 4
+ ex af, af'
+ PollPCM
+ ex af, af'
ld (iy+0), a
+ ld (iy+1), e
add 4
+ ex af, af'
+ PollPCM
+ ex af, af'
+ ld (iy+0), a
ld (iy+1), e
+ add 4
inc l
dec c
@@ -743,7 +868,7 @@ KillFM:
pop de
PollPCM
pop af
-
+
ld c, a ; Cause the ADSR to reset
or $F0
ld (ix+0), $28
@@ -752,7 +877,7 @@ KillFM:
ld (ix+1), a
ld (ix+0), $28
ld (ix+1), c
-
+
PollPCM
ret ; End of subroutine
diff --git a/src-z80/player/freq.z80 b/src-z80/player/freq.z80
index beb8702..7f963e5 100644
--- a/src-z80/player/freq.z80
+++ b/src-z80/player/freq.z80
@@ -89,6 +89,16 @@ FMFreqTable:
dw 1021, 1081, 1146, 1214
;****************************************************************************
+; PSGShiftTable
+; Semitone shifting table for PSG instruments
+;****************************************************************************
+
+PSGShiftTable:
+ db 0
+ db 2, 4, 6, 8, 10, 12
+ db -2, -4, -6, -8, -10, -12
+
+;****************************************************************************
; DummyFMInstr
; Dummy FM instrument to mute FM channels...
;
diff --git a/src-z80/player/misc.z80 b/src-z80/player/misc.z80
index 36be250..dee980e 100644
--- a/src-z80/player/misc.z80
+++ b/src-z80/player/misc.z80
@@ -44,3 +44,47 @@ SetDelayShort:
ld (hl), b
ret ; End of subroutine
+
+;****************************************************************************
+; RefreshVolume
+; Reloads the volume for all channels.
+;----------------------------------------------------------------------------
+; breaks: all
+;****************************************************************************
+
+RefreshVolume:
+ ld hl, $1FF0 ; Update FM volume
+ ld de, RAM_FMVol
+ ld c, 8
+.fixfmvol:
+ ld a, (de)
+ ld b, (hl)
+ add b
+ jp p, .fixfmvolok
+ ld a, $7F
+.fixfmvolok:
+ ld b, a
+ ld a, l
+ call SetFMVolLoad
+ inc l
+ inc e
+ dec c
+ jr nz, .fixfmvol
+
+ ld hl, $1FE8 ; Update PSG volume
+ ld de, RAM_PSGData+1
+ ld bc, $0410
+.fixpsgvol:
+ ld a, (hl)
+ ld (de), a
+ inc l
+ ld a, e
+ add a, c
+ ld e, a
+ PollPCM
+ djnz .fixpsgvol
+
+ xor a ; Mark that volume was refreshed
+ ld ($1FF1), a
+
+ ret ; End of subroutine
diff --git a/src-z80/player/pcm.z80 b/src-z80/player/pcm.z80
index 2a484d4..99feb6d 100644
--- a/src-z80/player/pcm.z80
+++ b/src-z80/player/pcm.z80
@@ -1,6 +1,11 @@
;****************************************************************************
-; PlayPCM*
+; PlayPCM* [event $0C]
; Plays a PCM sample
+;----------------------------------------------------------------------------
+; input c .... current bank
+; input hl ... current address
+;----------------------------------------------------------------------------
+; breaks: af, b
;****************************************************************************
PlayPCMSFX:
@@ -18,6 +23,10 @@ PlayPCMBGM:
jp ProcessBGMRun ; End of subroutine
PlayPCM:
+ ld a, (RAM_GlobalVol+$0C) ; Are we allowed to play PCM?
+ or a
+ ret z
+
call GetParam ; Get sample ID
ld a, b
diff --git a/src-z80/player/psg.z80 b/src-z80/player/psg.z80
index f0c5a76..b88978c 100644
--- a/src-z80/player/psg.z80
+++ b/src-z80/player/psg.z80
@@ -46,7 +46,7 @@ UpdatePSG:
cp $FF ; Loop envelope?
jp z, .envloop
- ld iyl, b ; Keep byte safe somewhere...
+ ld iyl, b ; Keep byte safe somewhere...
PollPCM
ex de, hl ; Store new address
@@ -61,6 +61,7 @@ UpdatePSG:
PollPCM
db $FD,$7D ; ld a, iyl ; Mix envelope with volume
+ and $0F
add b
ld b, a