diff --git a/applepy.py b/applepy.py index 479de65..5052474 100644 --- a/applepy.py +++ b/applepy.py @@ -9,6 +9,7 @@ import struct import subprocess import sys import time +import wave class Display: @@ -288,12 +289,33 @@ class Speaker: self.play() +class Cassette: + + def __init__(self, fn): + wav = wave.open(fn, "r") + self.raw = wav.readframes(wav.getnframes()) + self.start_cycle = 0 + self.start_offset = 0 + + for i, b in enumerate(self.raw): + if ord(b) > 0xA0: + self.start_offset = i + break + + def read_byte(self, cycle): + if self.start_cycle == 0: + self.start_cycle = cycle + offset = self.start_offset + (cycle - self.start_cycle) * 22000 / 1000000 + return ord(self.raw[offset]) if offset < len(self.raw) else 0x80 + + class SoftSwitches: - def __init__(self, display, speaker): + def __init__(self, display, speaker, cassette): self.kbd = 0x00 self.display = display self.speaker = speaker + self.cassette = cassette def read_byte(self, cycle, address): assert 0xC000 <= address <= 0xCFFF @@ -320,6 +342,9 @@ class SoftSwitches: self.display.lores() elif address == 0xC057: self.display.hires() + elif address == 0xC060: + if self.cassette: + return self.cassette.read_byte(cycle) else: pass # print "%04X" % address return 0x00 @@ -327,10 +352,10 @@ class SoftSwitches: class Apple2: - def __init__(self, options, display, speaker): + def __init__(self, options, display, speaker, cassette): self.display = display self.speaker = speaker - self.softswitches = SoftSwitches(display, speaker) + self.softswitches = SoftSwitches(display, speaker, cassette) args = [ sys.executable, @@ -391,6 +416,7 @@ def usage(): print >>sys.stderr print >>sys.stderr, "Usage: applepy.py [options]" print >>sys.stderr + print >>sys.stderr, " -c, --cassette Cassette wav file to load" print >>sys.stderr, " -R, --rom ROM file to use (default A2ROM.BIN)" print >>sys.stderr, " -r, --ram RAM file to load (default none)" print >>sys.stderr, " -q, --quiet Quiet mode, no sounds (default sounds)" @@ -400,6 +426,7 @@ def usage(): def get_options(): class Options: def __init__(self): + self.cassette = None self.rom = "A2ROM.BIN" self.ram = None self.quiet = False @@ -408,7 +435,10 @@ def get_options(): a = 1 while a < len(sys.argv): if sys.argv[a].startswith("-"): - if sys.argv[a] in ("-R", "--rom"): + if sys.argv[a] in ("-c", "--cassette"): + a += 1 + options.cassette = sys.argv[a] + elif sys.argv[a] in ("-R", "--rom"): a += 1 options.rom = sys.argv[a] elif sys.argv[a] in ("-r", "--ram"): @@ -429,6 +459,7 @@ if __name__ == "__main__": options = get_options() display = Display() speaker = None if options.quiet else Speaker() + cassette = Cassette(options.cassette) if options.cassette else None - apple = Apple2(options, display, speaker) + apple = Apple2(options, display, speaker, cassette) apple.run()