0xf, # white -> intense white
]
-# see ribbit.bas
+# see /ribbit/ribbit.bas
# hrcg is loaded at DOS addr - $801 = $9600 - $801 = $8dff
RBOOT_ENTRY = 0x208
HRCG_START = 0x8dff # initialization with banner
HRCG_ENTRY = HRCG_START + 3 # initialization without banner
-# see lemonade_tone.lst
+# see /lemonade/lemonade_tone.lst
LEMONADE_TONE_PERIOD = 0x300
LEMONADE_TONE_DUR = 0x301
-LEMONADE_TONE_ENTRY = 0x302
+LEMONADE_TONE_START = 0x302
+LEMONADE_TONE_END = 0x317
+LEMONADE_TONE_DATA = [
+ 0xAD, 0x30, 0xC0,
+ 0x88,
+ 0xD0, 0x05,
+ 0xCE, 0x01, 0x03,
+ 0xF0, 0x09,
+ 0xCA,
+ 0xD0, 0xF5,
+ 0xAE, 0x00, 0x03,
+ 0x4C, 0x02, 0x03,
+ 0x60,
+]
+
+# see /ribbit/ribbit_tone.lst
+# it is the same as lemonade_tone except for some context save/restore
+LEMONADE_TONE_END2 = 0x31d
+LEMONADE_TONE_DATA2 = [
+ 0x20, 0x4A, 0xFF,
+ 0xAD, 0x30, 0xC0,
+ 0x88,
+ 0xD0, 0x05,
+ 0xCE, 0x01, 0x03,
+ 0xF0, 0x09,
+ 0xCA,
+ 0xD0, 0xF5,
+ 0xAE, 0x00, 0x03,
+ 0x4C, 0x05, 0x03,
+ 0x20, 0x3F, 0xFF,
+ 0x60,
+]
-# see little_brick_out_tone.lst
+# see /little_brick_out/little_brick_out_tone.lst
LITTLE_BRICK_OUT_TONE_PERIOD = 6
LITTLE_BRICK_OUT_TONE_DUR = 7
-LITTLE_BRICK_OUT_TONE_ENTRY = 0x300
+LITTLE_BRICK_OUT_TONE_START = 0x300
+LITTLE_BRICK_OUT_TONE_END = 0x313
+LITTLE_BRICK_OUT_TONE_DATA = [
+ 0xAD, 0x30, 0xC0,
+ 0x88,
+ 0xD0, 0x04,
+ 0xC6, 0x07,
+ 0xF0, 0x08,
+ 0xCA,
+ 0xD0, 0xF6,
+ 0xA6, 0x06,
+ 0x4C, 0x00, 0x03,
+ 0x60,
+]
# see tone.lst
TONE_REST = 0x300
TONE_FREQH = 0x314
# see lemonade_flash_patched.lst
-FLASH_INIT = 0x3600
-FLASH_INIT_PATCHED = 0x95ef
-FLASH_EXECUTE = 0x3603
-FLASH_EXECUTE_PATCHED = 0x9586
-flash_color0 = 0
+LEMONADE_FLASH_INIT = 0x3600
+LEMONADE_FLASH_INIT_PATCHED = 0x95ef
+LEMONADE_FLASH_EXECUTE = 0x3603
+LEMONADE_FLASH_EXECUTE_PATCHED = 0x9586
+lemonade_flash_color0 = 0
# command line
BEEP_STYLE_ALSA = 0
else:
mem[addr] = data
-def call(addr):
- global flash_color0
+# often-used tone routines that are installed by POKEing to addresses 768+:
+def lemonade_tone():
+ # for lemonade or ribbit, see /test/lemonade_tone.py
+ period_count = ((low_mem[LEMONADE_TONE_PERIOD] - 1) & 0xff) + 1
+ duration_count = ((low_mem[LEMONADE_TONE_DUR] - 1) & 0xff) + 1
+ cycles = 1.37788799e-02 + duration_count * (
+ -4.21513128e-06 + 1.27999925e+02 / period_count
+ )
+ duration = 1.27361219e-05 + duration_count * (
+ 2.50702246e-03 + 2.50310997e-03 / period_count
+ )
+ tone(cycles / duration, duration)
+
+def little_brick_out_tone():
+ # for little brick out, see /test/little_brick_out_tone.py
+ period_count = ((low_mem[LITTLE_BRICK_OUT_TONE_PERIOD] - 1) & 0xff) + 1
+ duration_count = ((low_mem[LITTLE_BRICK_OUT_TONE_DUR] - 1) & 0xff) + 1
+ cycles = 1.37788799e-02 + duration_count * (
+ -4.21513128e-06 + 1.27999925e+02 / period_count
+ )
+ duration = 1.27091766e-05 + duration_count * (
+ 2.50897802e-03 + 2.25279897e-03 / period_count
+ )
+ tone(cycles / duration, duration)
+
+# my tone routine
+# - uses 16-bit duration, for longer maximum duration
+# - uses 16-bit frequency, for improved tuning accuracy
+# - allows zero frequency, for a "rest" or accurate delay
+# however, duration and frequency constants in the application must be
+# pre-computed, as code is simplified by not equalizing execution paths
+def tone_tone():
+ frequency_incr = low_mem[TONE_FREQL] + (low_mem[TONE_FREQH] << 8)
+ duration_count = -(low_mem[TONE_DURL] + (low_mem[TONE_DURH] << 8))
+ duration_count = ((duration_count - 1) & 0xffff) + 1
+ duration = 3.58309497e-10 + duration_count * (
+ 2.34821712e-05 + frequency_incr * 4.47591203e-11
+ )
+ if frequency_incr:
+ period = 0x1fffe * (2.34821712e-05 / frequency_incr + 4.47591203e-11)
+ tone(1. / period, duration)
+ else:
+ time.sleep(duration)
+# the following pair of machine language subroutines for lemonade allow
+# application to quickly replace one colour on the GR screen with another
+def lemonade_flash_init():
+ global lemonade_flash_color0
+ lemonade_flash_color0 = low_mem[ZP_COLOR] & 0xf
+
+def lemonade_flash_execute():
+ global lemonade_flash_color0
+
+ time.sleep(.02)
+ color1 = low_mem[ZP_COLOR] & 0xf
+ for i in range(20):
+ x0 = 40
+ x1 = 0
+ addr = bascalc(i)
+ for j in range(40):
+ if (low_mem[addr + j] & 0xf) == lemonade_flash_color0:
+ low_mem[addr + j] = (low_mem[addr + j] & 0xf0) | color1
+ if j < x0:
+ x0 = j
+ x1 = j + 1
+ if (low_mem[addr + j] >> 4) == lemonade_flash_color0:
+ low_mem[addr + j] = (low_mem[addr + j] & 0xf) | (color1 << 4)
+ if j < x0:
+ x0 = j
+ x1 = j + 1
+ if x1 > x0:
+ gr_update(x0, i, x1, i + 1)
+ lemonade_flash_color0 = color1
+
+def call(addr):
addr &= 0xffff
if addr == RBOOT_ENTRY or addr == HRCG_START or addr == HRCG_ENTRY:
+ # these do not do anything locally, as they run in the terminal instead
pass
- elif addr == LITTLE_BRICK_OUT_TONE_ENTRY:
- # for little brick out, see test/little_brick_out_tone.py
- period_count = ((low_mem[LITTLE_BRICK_OUT_TONE_PERIOD] - 1) & 0xff) + 1
- duration_count = ((low_mem[LITTLE_BRICK_OUT_TONE_DUR] - 1) & 0xff) + 1
- cycles = 1.37788799e-02 + duration_count * (
- -4.21513128e-06 + 1.27999925e+02 / period_count
- )
- duration = 1.27091766e-05 + duration_count * (
- 2.50897802e-03 + 2.25279897e-03 / period_count
+ elif (
+ addr == LEMONADE_TONE_START and (
+ low_mem[LEMONADE_TONE_START:LEMONADE_TONE_END] == LEMONADE_TONE_DATA or
+ low_mem[LEMONADE_TONE_START:LEMONADE_TONE_END2] == LEMONADE_TONE_DATA2
)
- tone(cycles / duration, duration)
+ ):
+ lemonade_tone()
+ elif (
+ addr == LITTLE_BRICK_OUT_TONE_START and
+ low_mem[LITTLE_BRICK_OUT_TONE_START:LITTLE_BRICK_OUT_TONE_END] ==
+ LITTLE_BRICK_OUT_TONE_DATA
+ ):
+ little_brick_out_tone()
+ elif addr == TONE_REST:
+ low_mem[TONE_FREQL] = 0
+ low_mem[TONE_FREQH] = 0
+ tone_tone()
elif addr == TONE_REST or addr == TONE_TONE:
- pass
- ## for lemonade_patched, see test/tone.py
- #if addr == TONE_REST:
- # low_mem[TONE_FREQL] = 0
- # low_mem[TONE_FREQH] = 0
- #frequency_incr = low_mem[TONE_FREQL] + (low_mem[TONE_FREQH] << 8)
- #duration_count = -(low_mem[TONE_DURL] + (low_mem[TONE_DURH] << 8))
- #duration_count = ((duration_count - 1) & 0xffff) + 1
- #duration = 3.58309497e-10 + duration_count * (
- # 2.34821712e-05 + frequency_incr * 4.47591203e-11
- #)
- #if frequency_incr:
- # period = 0x1fffe * (2.34821712e-05 / frequency_incr + 4.47591203e-11)
- # tone(1. / period, duration)
- #else:
- # time.sleep(duration)
- elif addr == LEMONADE_TONE_ENTRY:
- # for lemonade, see test/lemonade_tone.py
- period_count = ((low_mem[LEMONADE_TONE_PERIOD] - 1) & 0xff) + 1
- duration_count = ((low_mem[LEMONADE_TONE_DUR] - 1) & 0xff) + 1
- cycles = 1.37788799e-02 + duration_count * (
- -4.21513128e-06 + 1.27999925e+02 / period_count
- )
- duration = 1.27361219e-05 + duration_count * (
- 2.50702246e-03 + 2.50310997e-03 / period_count
- )
- tone(cycles / duration, duration)
- elif addr == FLASH_INIT or addr == FLASH_INIT_PATCHED:
- # for lemonade, lighting (init)
- flash_color0 = low_mem[ZP_COLOR] & 0xf
- elif addr == FLASH_EXECUTE or addr == FLASH_EXECUTE_PATCHED:
- # for lemonade, lightning (execute)
- time.sleep(.02)
- flash_color1 = low_mem[ZP_COLOR] & 0xf
- for i in range(20):
- x0 = 40
- x1 = 0
- addr = bascalc(i)
- for j in range(40):
- if (low_mem[addr + j] & 0xf) == flash_color0:
- low_mem[addr + j] = (low_mem[addr + j] & 0xf0) | flash_color1
- if j < x0:
- x0 = j
- x1 = j + 1
- if (low_mem[addr + j] >> 4) == flash_color0:
- low_mem[addr + j] = (low_mem[addr + j] & 0xf) | (flash_color1 << 4)
- if j < x0:
- x0 = j
- x1 = j + 1
- if x1 > x0:
- gr_update(x0, i, x1, i + 1)
- flash_color0 = flash_color1
+ # note: will be loaded with PRINT CHR$(4);"BLOAD TONE.OBJ" which we do not
+ # emulate and therefore it does not appear in low_mem[], it has to go last
+ # (after the above checks for specific tone routines) to avoid a conflict
+ tone_tone()
+ elif (
+ addr == LEMONADE_FLASH_INIT or
+ addr == LEMONADE_FLASH_INIT_PATCHED
+ ):
+ lemonade_flash_init()
+ elif (
+ addr == LEMONADE_FLASH_EXECUTE or
+ addr == LEMONADE_FLASH_EXECUTE_PATCHED
+ ):
+ lemonade_flash_execute()
elif addr == ROM_CLREOP:
clreop()
elif addr == ROM_BELL2:
tone(1000, 100) # 1 kHz for .1 sec
elif addr == ROM_HOME:
+ # note: was not in Applesoft 1 (cassette version) so can appear as CALL
home()
elif addr == ROM_CLEOL:
cleol()