badline 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/CLAUDE.md +59 -31
- data/README.md +1 -1
- data/doc/library.md +9 -9
- data/doc/pinned-behaviour.md +105 -105
- data/doc/snapshots.md +1 -4
- data/lib/badline/audio/bare_player.rb +4 -4
- data/lib/badline/audio/cli.rb +6 -6
- data/lib/badline/audio/jukebox.rb +2 -2
- data/lib/badline/audio/machine_player.rb +2 -2
- data/lib/badline/{media → audio}/queue.rb +1 -1
- data/lib/badline/audio/queued_tune.rb +6 -6
- data/lib/badline/audio/renderer.rb +5 -5
- data/lib/badline/audio/stereo.rb +1 -1
- data/lib/badline/c128/{bus_state.rb → bus/saved_state.rb} +6 -6
- data/lib/badline/c128/bus.rb +30 -51
- data/lib/badline/c128/color_lines.rb +2 -2
- data/lib/badline/c128/cpu.rb +1 -1
- data/lib/badline/c128/drives.rb +10 -11
- data/lib/badline/c128/fast_serial.rb +5 -5
- data/lib/badline/c128/mmu_pages.rb +1 -1
- data/lib/badline/c128/modes.rb +2 -2
- data/lib/badline/c128/saved_state.rb +21 -47
- data/lib/badline/c128/z80.rb +2 -2
- data/lib/badline/c128.rb +18 -72
- data/lib/badline/{computer → c64}/attachments.rb +16 -47
- data/lib/badline/c64/banked_ram/banking.rb +32 -0
- data/lib/badline/c64/banked_ram/plus256k.rb +56 -0
- data/lib/badline/c64/banked_ram/plus60k.rb +45 -0
- data/lib/badline/c64/banked_ram/unexpanded.rb +30 -0
- data/lib/badline/c64/banked_ram.rb +23 -0
- data/lib/badline/c64/bus/extra_sids.rb +32 -0
- data/lib/badline/c64/bus/fittings.rb +40 -0
- data/lib/badline/c64/bus/pla.rb +149 -0
- data/lib/badline/c64/bus/roms.rb +41 -0
- data/lib/badline/c64/bus/saved_state.rb +68 -0
- data/lib/badline/c64/bus/sid_slots.rb +44 -0
- data/lib/badline/c64/bus.rb +218 -0
- data/lib/badline/c64/cartridge/action_replay.rb +128 -0
- data/lib/badline/c64/cartridge/atomic_power.rb +26 -0
- data/lib/badline/c64/cartridge/bank.rb +83 -0
- data/lib/badline/c64/cartridge/comal80.rb +52 -0
- data/lib/badline/c64/cartridge/dinamic.rb +36 -0
- data/lib/badline/c64/cartridge/easy_flash.rb +147 -0
- data/lib/badline/c64/cartridge/epyx_fastload.rb +81 -0
- data/lib/badline/c64/cartridge/final_cartridge3.rb +91 -0
- data/lib/badline/c64/cartridge/flash/saved_state.rb +40 -0
- data/lib/badline/c64/cartridge/flash.rb +279 -0
- data/lib/badline/c64/cartridge/freezer.rb +35 -0
- data/lib/badline/c64/cartridge/fun_play.rb +40 -0
- data/lib/badline/c64/cartridge/g_mod2.rb +76 -0
- data/lib/badline/c64/cartridge/game_system.rb +42 -0
- data/lib/badline/c64/cartridge/geo_ram.rb +81 -0
- data/lib/badline/c64/cartridge/kcs_power.rb +77 -0
- data/lib/badline/c64/cartridge/mach5.rb +34 -0
- data/lib/badline/c64/cartridge/magic_desk.rb +32 -0
- data/lib/badline/c64/cartridge/ocean.rb +37 -0
- data/lib/badline/c64/cartridge/pagefox.rb +70 -0
- data/lib/badline/c64/cartridge/retro_replay/saved_state.rb +47 -0
- data/lib/badline/c64/cartridge/retro_replay.rb +286 -0
- data/lib/badline/c64/cartridge/rex_utility.rb +31 -0
- data/lib/badline/c64/cartridge/rgcd.rb +60 -0
- data/lib/badline/c64/cartridge/saved_state.rb +63 -0
- data/lib/badline/c64/cartridge/simons_basic.rb +37 -0
- data/lib/badline/c64/cartridge/standard.rb +17 -0
- data/lib/badline/c64/cartridge/super_games.rb +50 -0
- data/lib/badline/c64/cartridge/westermann.rb +32 -0
- data/lib/badline/c64/cartridge/zaxxon.rb +68 -0
- data/lib/badline/c64/cartridge.rb +258 -0
- data/lib/badline/c64/color_memory.rb +27 -0
- data/lib/badline/c64/common.rb +34 -0
- data/lib/badline/c64/kernal_traps.rb +89 -0
- data/lib/badline/c64/reu/dma/saved_state.rb +52 -0
- data/lib/badline/c64/reu/dma.rb +275 -0
- data/lib/badline/c64/reu/ram.rb +109 -0
- data/lib/badline/c64/reu/saved_state.rb +55 -0
- data/lib/badline/c64/reu/trigger.rb +34 -0
- data/lib/badline/c64/reu.rb +291 -0
- data/lib/badline/{computer → c64}/saved_state.rb +13 -18
- data/lib/badline/{computer → c64}/true_drives.rb +20 -31
- data/lib/badline/{computer.rb → c64.rb} +22 -80
- data/lib/badline/chips/cia/fast_forward.rb +62 -0
- data/lib/badline/chips/cia/interrupt_register.rb +145 -0
- data/lib/badline/chips/cia/saved_state.rb +49 -0
- data/lib/badline/chips/cia/serial/saved_state.rb +45 -0
- data/lib/badline/chips/cia/serial.rb +250 -0
- data/lib/badline/chips/cia/time_of_day.rb +232 -0
- data/lib/badline/chips/cia/timer.rb +208 -0
- data/lib/badline/chips/cia.rb +281 -0
- data/lib/badline/chips/cpu/addressing.rb +133 -0
- data/lib/badline/chips/cpu/boundary.rb +56 -0
- data/lib/badline/chips/cpu/core.rb +167 -0
- data/lib/badline/chips/cpu/instruction.rb +338 -0
- data/lib/badline/chips/cpu/instruction_set/arithmetic.rb +118 -0
- data/lib/badline/chips/cpu/instruction_set/bitwise.rb +130 -0
- data/lib/badline/chips/cpu/instruction_set/branch.rb +83 -0
- data/lib/badline/chips/cpu/instruction_set/flag.rb +67 -0
- data/lib/badline/chips/cpu/instruction_set/illegal.rb +274 -0
- data/lib/badline/chips/cpu/instruction_set/inc_dec.rb +73 -0
- data/lib/badline/chips/cpu/instruction_set/stack.rb +56 -0
- data/lib/badline/chips/cpu/instruction_set/transfer.rb +141 -0
- data/lib/badline/chips/cpu/instruction_set.rb +59 -0
- data/lib/badline/chips/cpu/interrupts.rb +108 -0
- data/lib/badline/chips/cpu/microcode.rb +179 -0
- data/lib/badline/chips/cpu/operations.rb +90 -0
- data/lib/badline/chips/cpu/port.rb +116 -0
- data/lib/badline/chips/cpu/saved_state.rb +117 -0
- data/lib/badline/chips/cpu/stack_operations.rb +84 -0
- data/lib/badline/chips/cpu/traps.rb +23 -0
- data/lib/badline/chips/cpu.rb +12 -0
- data/lib/badline/chips/sid/catch_up.rb +122 -0
- data/lib/badline/chips/sid/decimator.rb +66 -0
- data/lib/badline/chips/sid/envelope/saved_state.rb +70 -0
- data/lib/badline/chips/sid/envelope.rb +241 -0
- data/lib/badline/chips/sid/filter/saved_state.rb +42 -0
- data/lib/badline/chips/sid/filter.rb +241 -0
- data/lib/badline/chips/sid/saved_state.rb +52 -0
- data/lib/badline/chips/sid/voice.rb +79 -0
- data/lib/badline/chips/sid/waveform/combined.rb +128 -0
- data/lib/badline/chips/sid/waveform/fast_forward.rb +107 -0
- data/lib/badline/chips/sid/waveform/noise_writeback.rb +124 -0
- data/lib/badline/chips/sid/waveform/saved_state.rb +68 -0
- data/lib/badline/chips/sid/waveform.rb +307 -0
- data/lib/badline/chips/sid.rb +265 -0
- data/lib/badline/{c128 → chips}/vdc/memory.rb +1 -1
- data/lib/badline/{c128 → chips}/vdc/painter.rb +1 -1
- data/lib/badline/{c128 → chips}/vdc/raster.rb +1 -1
- data/lib/badline/chips/vdc/saved_state.rb +36 -0
- data/lib/badline/{c128 → chips}/vdc/window.rb +1 -1
- data/lib/badline/{c128 → chips}/vdc.rb +7 -31
- data/lib/badline/chips/via/control_lines.rb +124 -0
- data/lib/badline/chips/via/fast_forward.rb +55 -0
- data/lib/badline/chips/via/interrupt_register.rb +69 -0
- data/lib/badline/chips/via/saved_state.rb +44 -0
- data/lib/badline/chips/via/shift_register.rb +182 -0
- data/lib/badline/chips/via/timer1.rb +133 -0
- data/lib/badline/chips/via/timer2.rb +135 -0
- data/lib/badline/chips/via.rb +268 -0
- data/lib/badline/chips/vic/bank.rb +135 -0
- data/lib/badline/chips/vic/border_mask.rb +88 -0
- data/lib/badline/chips/vic/collisions.rb +117 -0
- data/lib/badline/chips/vic/color_patches.rb +49 -0
- data/lib/badline/chips/vic/display_state.rb +187 -0
- data/lib/badline/chips/vic/graphics_mode.rb +166 -0
- data/lib/badline/chips/vic/graphics_shifter/saved_state.rb +40 -0
- data/lib/badline/chips/vic/graphics_shifter.rb +187 -0
- data/lib/badline/chips/vic/register_log.rb +83 -0
- data/lib/badline/chips/vic/registers.rb +197 -0
- data/lib/badline/chips/vic/saved_state.rb +82 -0
- data/lib/badline/chips/vic/sequencer/saved_state.rb +91 -0
- data/lib/badline/chips/vic/sequencer.rb +277 -0
- data/lib/badline/chips/vic/sequencer_output.rb +118 -0
- data/lib/badline/chips/vic/sprite/internal_bus.rb +70 -0
- data/lib/badline/chips/vic/sprite/saved_state.rb +66 -0
- data/lib/badline/chips/vic/sprite/shifter.rb +148 -0
- data/lib/badline/chips/vic/sprite/timing.rb +58 -0
- data/lib/badline/chips/vic/sprite.rb +339 -0
- data/lib/badline/chips/vic/sprites/saved_state.rb +59 -0
- data/lib/badline/chips/vic/sprites.rb +284 -0
- data/lib/badline/chips/vic.rb +783 -0
- data/lib/badline/chips/vic_i/painter/saved_state.rb +40 -0
- data/lib/badline/{vic20/vic → chips/vic_i}/painter.rb +6 -30
- data/lib/badline/{vic20/vic → chips/vic_i}/saved_state.rb +2 -2
- data/lib/badline/chips/vic_i/sound/output.rb +85 -0
- data/lib/badline/chips/vic_i/sound.rb +235 -0
- data/lib/badline/{vic20/vic → chips/vic_i}/text_window.rb +2 -2
- data/lib/badline/{vic20/vic.rb → chips/vic_i.rb} +5 -5
- data/lib/badline/chips/z80/arithmetic.rb +119 -0
- data/lib/badline/chips/z80/bit_page.rb +57 -0
- data/lib/badline/chips/z80/block_io.rb +60 -0
- data/lib/badline/chips/z80/block_transfers.rb +61 -0
- data/lib/badline/chips/z80/bus_cycles.rb +113 -0
- data/lib/badline/chips/z80/core.rb +115 -0
- data/lib/badline/chips/z80/exchanges.rb +52 -0
- data/lib/badline/chips/z80/extended_page.rb +91 -0
- data/lib/badline/chips/z80/flags.rb +39 -0
- data/lib/badline/chips/z80/interrupt_acceptance.rb +48 -0
- data/lib/badline/chips/z80/jumps.rb +84 -0
- data/lib/badline/chips/z80/loads.rb +100 -0
- data/lib/badline/chips/z80/main_page.rb +136 -0
- data/lib/badline/chips/z80/registers.rb +122 -0
- data/lib/badline/chips/z80/saved_state.rb +71 -0
- data/lib/badline/chips/z80/shifts.rb +66 -0
- data/lib/badline/chips/z80.rb +13 -0
- data/lib/badline/core.rb +27 -29
- data/lib/badline/drives/datasette/saved_state.rb +37 -0
- data/lib/badline/drives/datasette.rb +140 -0
- data/lib/badline/drives/engine/core.rb +149 -0
- data/lib/badline/drives/engine/fast_serial.rb +75 -0
- data/lib/badline/drives/engine/idle.rb +127 -0
- data/lib/badline/drives/engine/idle_cpu.rb +30 -0
- data/lib/badline/drives/engine/orbit.rb +81 -0
- data/lib/badline/drives/engine/serial_lines.rb +75 -0
- data/lib/badline/drives/engine/sleep.rb +114 -0
- data/lib/badline/drives/engine/vias.rb +86 -0
- data/lib/badline/drives/engine/watch.rb +152 -0
- data/lib/badline/drives/engine.rb +11 -0
- data/lib/badline/drives/model1541/bus.rb +88 -0
- data/lib/badline/drives/model1541/byte_ready.rb +50 -0
- data/lib/badline/drives/model1541/cpu.rb +13 -0
- data/lib/badline/drives/model1541/disk/saved_state.rb +88 -0
- data/lib/badline/drives/model1541/disk.rb +317 -0
- data/lib/badline/drives/model1541/disk_via.rb +38 -0
- data/lib/badline/drives/model1541/gcr.rb +59 -0
- data/lib/badline/drives/model1541/mechanism/saved_state.rb +72 -0
- data/lib/badline/drives/model1541/mechanism.rb +315 -0
- data/lib/badline/drives/model1541/rotation.rb +123 -0
- data/lib/badline/drives/model1541/saved_state.rb +44 -0
- data/lib/badline/drives/model1541/sector_reader.rb +78 -0
- data/lib/badline/drives/model1541/serial_port.rb +20 -0
- data/lib/badline/drives/model1541/track.rb +100 -0
- data/lib/badline/drives/model1541.rb +81 -0
- data/lib/badline/drives/model1571/bus.rb +113 -0
- data/lib/badline/drives/model1571/cpu.rb +13 -0
- data/lib/badline/drives/model1571/saved_state.rb +47 -0
- data/lib/badline/drives/model1571/serial_port.rb +39 -0
- data/lib/badline/drives/model1571/serial_via.rb +27 -0
- data/lib/badline/drives/model1571/wd1770.rb +122 -0
- data/lib/badline/drives/model1571.rb +142 -0
- data/lib/badline/drives/model1581/bus.rb +139 -0
- data/lib/badline/drives/model1581/cpu.rb +13 -0
- data/lib/badline/drives/model1581/disk/saved_state.rb +89 -0
- data/lib/badline/drives/model1581/disk.rb +137 -0
- data/lib/badline/drives/model1581/mechanism.rb +119 -0
- data/lib/badline/drives/model1581/saved_state.rb +42 -0
- data/lib/badline/drives/model1581/serial_port.rb +54 -0
- data/lib/badline/drives/model1581/slot.rb +79 -0
- data/lib/badline/drives/model1581/track.rb +102 -0
- data/lib/badline/drives/model1581/track_bytes.rb +77 -0
- data/lib/badline/drives/model1581/wd1772/registers.rb +91 -0
- data/lib/badline/drives/model1581/wd1772/saved_state.rb +68 -0
- data/lib/badline/drives/model1581/wd1772/sector_writes.rb +75 -0
- data/lib/badline/drives/model1581/wd1772/sectors.rb +152 -0
- data/lib/badline/drives/model1581/wd1772/stepping.rb +111 -0
- data/lib/badline/drives/model1581/wd1772/tracks.rb +127 -0
- data/lib/badline/drives/model1581/wd1772/turn.rb +75 -0
- data/lib/badline/drives/model1581/wd1772.rb +218 -0
- data/lib/badline/drives/model1581.rb +206 -0
- data/lib/badline/drives/serial_bus.rb +161 -0
- data/lib/badline/frontend/boot.rb +10 -61
- data/lib/badline/frontend/machine_window.rb +3 -1
- data/lib/badline/frontend/player/filter_view.rb +1 -1
- data/lib/badline/frontend/player/player_controller.rb +2 -2
- data/lib/badline/frontend/player/player_screen.rb +1 -0
- data/lib/badline/frontend/player/theme.rb +7 -7
- data/lib/badline/frontend/timeline.rb +3 -3
- data/lib/badline/input/control_ports.rb +78 -0
- data/lib/badline/input/joystick.rb +27 -0
- data/lib/badline/input/keyboard.rb +114 -0
- data/lib/badline/input.rb +3 -0
- data/lib/badline/kernal_trap/{drive → dos}/block_commands.rb +1 -1
- data/lib/badline/kernal_trap/dos/channel.rb +183 -0
- data/lib/badline/kernal_trap/{drive → dos}/channels.rb +1 -1
- data/lib/badline/kernal_trap/{drive → dos}/memory.rb +1 -1
- data/lib/badline/kernal_trap/{drive → dos}/parameters.rb +1 -1
- data/lib/badline/kernal_trap/{drive → dos}/status.rb +1 -1
- data/lib/badline/kernal_trap/{drive → dos}/write_file.rb +1 -1
- data/lib/badline/kernal_trap/{drive → dos}/writes.rb +1 -1
- data/lib/badline/kernal_trap/{drive.rb → dos.rb} +11 -10
- data/lib/badline/kernal_trap/{file.rb → file_routine.rb} +1 -1
- data/lib/badline/kernal_trap/load.rb +6 -6
- data/lib/badline/kernal_trap/save.rb +5 -5
- data/lib/badline/kernal_trap/serial.rb +7 -7
- data/lib/badline/kernal_trap.rb +2 -3
- data/lib/badline/machine/clocking.rb +50 -0
- data/lib/badline/machine.rb +63 -7
- data/lib/badline/media/boot_disk.rb +2 -2
- data/lib/badline/media/disk_list.rb +3 -3
- data/lib/badline/media/disk_set.rb +1 -1
- data/lib/badline/media/extensions.rb +33 -0
- data/lib/badline/media/program.rb +28 -0
- data/lib/badline/media/true_drive.rb +4 -3
- data/lib/badline/media/tune.rb +35 -0
- data/lib/badline/media/vic20_cartridge.rb +1 -7
- data/lib/badline/media/vic20_media.rb +38 -80
- data/lib/badline/media.rb +84 -81
- data/lib/badline/model.rb +1 -1
- data/lib/badline/options/event.rb +3 -1
- data/lib/badline/roms/README +6 -6
- data/lib/badline/sdl.rb +1 -0
- data/lib/badline/{storage/sid_file.rb → sid_tune/file.rb} +3 -3
- data/lib/badline/{storage → sid_tune}/hvsc.rb +7 -7
- data/lib/badline/{storage → sid_tune}/song_lengths.rb +2 -2
- data/lib/badline/{storage → sid_tune}/stil/credit.rb +1 -1
- data/lib/badline/{storage → sid_tune}/stil.rb +3 -3
- data/lib/badline/sid_tune.rb +6 -0
- data/lib/badline/snapshot/c128_setup.rb +43 -0
- data/lib/badline/snapshot/c64_setup.rb +79 -0
- data/lib/badline/snapshot/image.rb +5 -25
- data/lib/badline/snapshot/machine_state.rb +10 -2
- data/lib/badline/snapshot/setup.rb +22 -66
- data/lib/badline/snapshot/state.rb +8 -17
- data/lib/badline/snapshot/storage_setup.rb +68 -0
- data/lib/badline/snapshot/vic20_setup.rb +37 -0
- data/lib/badline/snapshot/vice/c64_mem.rb +1 -1
- data/lib/badline/snapshot/vice/restore.rb +1 -1
- data/lib/badline/snapshot/vice/reu1764.rb +1 -1
- data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
- data/lib/badline/snapshot/vice.rb +7 -5
- data/lib/badline/snapshot.rb +13 -12
- data/lib/badline/storage/d64_image.rb +15 -9
- data/lib/badline/storage/d71_image.rb +0 -2
- data/lib/badline/storage/d81_image.rb +0 -2
- data/lib/badline/storage/disk_image/writing.rb +2 -2
- data/lib/badline/storage/disk_image.rb +3 -6
- data/lib/badline/storage/g64_image.rb +2 -2
- data/lib/badline/storage/host_directory.rb +0 -5
- data/lib/badline/storage/t64.rb +2 -8
- data/lib/badline/storage/unavailable.rb +1 -1
- data/lib/badline/storage.rb +0 -37
- data/lib/badline/support/c128_checkpoint.rb +39 -0
- data/lib/badline/support/checkpoint.rb +108 -0
- data/lib/badline/support/vic20_checkpoint.rb +38 -0
- data/lib/badline/support.rb +5 -0
- data/lib/badline/version.rb +1 -1
- data/lib/badline/vic20/attachments.rb +11 -81
- data/lib/badline/vic20/bus/saved_state.rb +35 -0
- data/lib/badline/vic20/bus.rb +3 -25
- data/lib/badline/vic20/cpu.rb +1 -1
- data/lib/badline/vic20/port_wiring.rb +4 -4
- data/lib/badline/vic20/saved_state.rb +16 -60
- data/lib/badline/vic20/user_via_ports.rb +2 -2
- data/lib/badline/vic20.rb +20 -51
- metadata +250 -221
- data/lib/badline/address_bus/extra_sids.rb +0 -30
- data/lib/badline/address_bus/fittings.rb +0 -38
- data/lib/badline/address_bus/pla.rb +0 -147
- data/lib/badline/address_bus/roms.rb +0 -39
- data/lib/badline/address_bus/saved_state.rb +0 -72
- data/lib/badline/address_bus/sid_slots.rb +0 -42
- data/lib/badline/address_bus.rb +0 -235
- data/lib/badline/cartridge/action_replay.rb +0 -126
- data/lib/badline/cartridge/atomic_power.rb +0 -24
- data/lib/badline/cartridge/bank.rb +0 -81
- data/lib/badline/cartridge/comal80.rb +0 -50
- data/lib/badline/cartridge/dinamic.rb +0 -34
- data/lib/badline/cartridge/easy_flash.rb +0 -145
- data/lib/badline/cartridge/epyx_fastload.rb +0 -79
- data/lib/badline/cartridge/final_cartridge3.rb +0 -89
- data/lib/badline/cartridge/flash.rb +0 -306
- data/lib/badline/cartridge/freezer.rb +0 -33
- data/lib/badline/cartridge/fun_play.rb +0 -38
- data/lib/badline/cartridge/g_mod2.rb +0 -74
- data/lib/badline/cartridge/game_system.rb +0 -40
- data/lib/badline/cartridge/geo_ram.rb +0 -79
- data/lib/badline/cartridge/kcs_power.rb +0 -75
- data/lib/badline/cartridge/mach5.rb +0 -32
- data/lib/badline/cartridge/magic_desk.rb +0 -30
- data/lib/badline/cartridge/ocean.rb +0 -35
- data/lib/badline/cartridge/pagefox.rb +0 -68
- data/lib/badline/cartridge/retro_replay.rb +0 -320
- data/lib/badline/cartridge/rex_utility.rb +0 -29
- data/lib/badline/cartridge/rgcd.rb +0 -58
- data/lib/badline/cartridge/simons_basic.rb +0 -35
- data/lib/badline/cartridge/standard.rb +0 -15
- data/lib/badline/cartridge/super_games.rb +0 -48
- data/lib/badline/cartridge/westermann.rb +0 -30
- data/lib/badline/cartridge/zaxxon.rb +0 -66
- data/lib/badline/cartridge.rb +0 -303
- data/lib/badline/checkpoint.rb +0 -98
- data/lib/badline/cia/fast_forward.rb +0 -60
- data/lib/badline/cia/interrupt_register.rb +0 -143
- data/lib/badline/cia/serial.rb +0 -275
- data/lib/badline/cia/state.rb +0 -47
- data/lib/badline/cia/timer.rb +0 -206
- data/lib/badline/cia.rb +0 -279
- data/lib/badline/color_memory.rb +0 -25
- data/lib/badline/computer/kernal_traps.rb +0 -29
- data/lib/badline/control_ports.rb +0 -76
- data/lib/badline/cpu/addressing.rb +0 -131
- data/lib/badline/cpu/boundary.rb +0 -54
- data/lib/badline/cpu/core.rb +0 -165
- data/lib/badline/cpu/microcode.rb +0 -177
- data/lib/badline/cpu/operations.rb +0 -88
- data/lib/badline/cpu/saved_state.rb +0 -115
- data/lib/badline/cpu/stack_operations.rb +0 -82
- data/lib/badline/cpu.rb +0 -10
- data/lib/badline/cycleable.rb +0 -38
- data/lib/badline/datasette.rb +0 -161
- data/lib/badline/drive/core.rb +0 -147
- data/lib/badline/drive/fast_serial.rb +0 -73
- data/lib/badline/drive/idle.rb +0 -125
- data/lib/badline/drive/idle_cpu.rb +0 -28
- data/lib/badline/drive/orbit.rb +0 -79
- data/lib/badline/drive/serial_lines.rb +0 -73
- data/lib/badline/drive/sleep.rb +0 -112
- data/lib/badline/drive/vias.rb +0 -84
- data/lib/badline/drive/watch.rb +0 -150
- data/lib/badline/drive.rb +0 -11
- data/lib/badline/drive1541/bus.rb +0 -86
- data/lib/badline/drive1541/byte_ready.rb +0 -48
- data/lib/badline/drive1541/cpu.rb +0 -11
- data/lib/badline/drive1541/disk.rb +0 -318
- data/lib/badline/drive1541/disk_state.rb +0 -94
- data/lib/badline/drive1541/disk_via.rb +0 -36
- data/lib/badline/drive1541/gcr.rb +0 -57
- data/lib/badline/drive1541/mechanism.rb +0 -313
- data/lib/badline/drive1541/mechanism_state.rb +0 -68
- data/lib/badline/drive1541/rotation.rb +0 -121
- data/lib/badline/drive1541/sector_reader.rb +0 -76
- data/lib/badline/drive1541/serial_port.rb +0 -18
- data/lib/badline/drive1541/track.rb +0 -98
- data/lib/badline/drive1541.rb +0 -111
- data/lib/badline/drive1571/bus.rb +0 -111
- data/lib/badline/drive1571/cpu.rb +0 -11
- data/lib/badline/drive1571/serial_port.rb +0 -37
- data/lib/badline/drive1571/serial_via.rb +0 -25
- data/lib/badline/drive1571/wd1770.rb +0 -120
- data/lib/badline/drive1571.rb +0 -175
- data/lib/badline/drive1581/bus.rb +0 -137
- data/lib/badline/drive1581/cpu.rb +0 -11
- data/lib/badline/drive1581/disk.rb +0 -135
- data/lib/badline/drive1581/disk_state.rb +0 -87
- data/lib/badline/drive1581/mechanism.rb +0 -117
- data/lib/badline/drive1581/serial_port.rb +0 -52
- data/lib/badline/drive1581/slot.rb +0 -78
- data/lib/badline/drive1581/track.rb +0 -100
- data/lib/badline/drive1581/track_bytes.rb +0 -75
- data/lib/badline/drive1581/wd1772/registers.rb +0 -89
- data/lib/badline/drive1581/wd1772/sector_writes.rb +0 -73
- data/lib/badline/drive1581/wd1772/sectors.rb +0 -150
- data/lib/badline/drive1581/wd1772/state.rb +0 -66
- data/lib/badline/drive1581/wd1772/stepping.rb +0 -109
- data/lib/badline/drive1581/wd1772/tracks.rb +0 -125
- data/lib/badline/drive1581/wd1772/turn.rb +0 -73
- data/lib/badline/drive1581/wd1772.rb +0 -216
- data/lib/badline/drive1581.rb +0 -233
- data/lib/badline/iec_bus.rb +0 -159
- data/lib/badline/instruction.rb +0 -334
- data/lib/badline/instruction_set/arithmetic.rb +0 -114
- data/lib/badline/instruction_set/bitwise.rb +0 -126
- data/lib/badline/instruction_set/branch.rb +0 -79
- data/lib/badline/instruction_set/flag.rb +0 -63
- data/lib/badline/instruction_set/illegal.rb +0 -270
- data/lib/badline/instruction_set/inc_dec.rb +0 -69
- data/lib/badline/instruction_set/stack.rb +0 -52
- data/lib/badline/instruction_set/transfer.rb +0 -137
- data/lib/badline/instruction_set.rb +0 -55
- data/lib/badline/interrupts.rb +0 -104
- data/lib/badline/joystick.rb +0 -25
- data/lib/badline/kernal_trap/channel.rb +0 -181
- data/lib/badline/keyboard.rb +0 -112
- data/lib/badline/ram_expansion/banking.rb +0 -30
- data/lib/badline/ram_expansion/plus256k.rb +0 -54
- data/lib/badline/ram_expansion/plus60k.rb +0 -43
- data/lib/badline/ram_expansion/unexpanded.rb +0 -28
- data/lib/badline/ram_expansion.rb +0 -21
- data/lib/badline/reu/dma/saved_state.rb +0 -50
- data/lib/badline/reu/dma.rb +0 -273
- data/lib/badline/reu/ram.rb +0 -107
- data/lib/badline/reu/saved_state.rb +0 -80
- data/lib/badline/reu/trigger.rb +0 -32
- data/lib/badline/reu.rb +0 -289
- data/lib/badline/sid/catch_up.rb +0 -120
- data/lib/badline/sid/decimator.rb +0 -64
- data/lib/badline/sid/envelope/state.rb +0 -68
- data/lib/badline/sid/envelope.rb +0 -239
- data/lib/badline/sid/filter.rb +0 -263
- data/lib/badline/sid/voice.rb +0 -77
- data/lib/badline/sid/waveform/combined.rb +0 -126
- data/lib/badline/sid/waveform/fast_forward.rb +0 -105
- data/lib/badline/sid/waveform/noise_writeback.rb +0 -122
- data/lib/badline/sid/waveform/state.rb +0 -66
- data/lib/badline/sid/waveform.rb +0 -305
- data/lib/badline/sid.rb +0 -303
- data/lib/badline/time_of_day.rb +0 -228
- data/lib/badline/traps.rb +0 -19
- data/lib/badline/via/control_lines.rb +0 -122
- data/lib/badline/via/fast_forward.rb +0 -53
- data/lib/badline/via/interrupt_register.rb +0 -67
- data/lib/badline/via/shift_register.rb +0 -180
- data/lib/badline/via/state.rb +0 -42
- data/lib/badline/via/timer1.rb +0 -131
- data/lib/badline/via/timer2.rb +0 -133
- data/lib/badline/via.rb +0 -266
- data/lib/badline/vic/bank.rb +0 -133
- data/lib/badline/vic/border_mask.rb +0 -86
- data/lib/badline/vic/collisions.rb +0 -115
- data/lib/badline/vic/color_patches.rb +0 -47
- data/lib/badline/vic/display_state.rb +0 -185
- data/lib/badline/vic/graphics_mode.rb +0 -164
- data/lib/badline/vic/graphics_shifter.rb +0 -207
- data/lib/badline/vic/register_log.rb +0 -81
- data/lib/badline/vic/registers.rb +0 -195
- data/lib/badline/vic/sequencer.rb +0 -275
- data/lib/badline/vic/sequencer_output.rb +0 -116
- data/lib/badline/vic/sequencer_state.rb +0 -89
- data/lib/badline/vic/sprite/internal_bus.rb +0 -68
- data/lib/badline/vic/sprite/saved_state.rb +0 -64
- data/lib/badline/vic/sprite/shifter.rb +0 -146
- data/lib/badline/vic/sprite/timing.rb +0 -56
- data/lib/badline/vic/sprite.rb +0 -337
- data/lib/badline/vic/sprites.rb +0 -282
- data/lib/badline/vic/sprites_state.rb +0 -57
- data/lib/badline/vic.rb +0 -852
- data/lib/badline/vic20/sound/output.rb +0 -83
- data/lib/badline/vic20/sound.rb +0 -233
- data/lib/badline/z80/arithmetic.rb +0 -117
- data/lib/badline/z80/bit_page.rb +0 -55
- data/lib/badline/z80/block_io.rb +0 -58
- data/lib/badline/z80/block_transfers.rb +0 -59
- data/lib/badline/z80/bus_cycles.rb +0 -111
- data/lib/badline/z80/core.rb +0 -113
- data/lib/badline/z80/exchanges.rb +0 -50
- data/lib/badline/z80/extended_page.rb +0 -89
- data/lib/badline/z80/flags.rb +0 -37
- data/lib/badline/z80/interrupt_acceptance.rb +0 -46
- data/lib/badline/z80/jumps.rb +0 -82
- data/lib/badline/z80/loads.rb +0 -98
- data/lib/badline/z80/main_page.rb +0 -134
- data/lib/badline/z80/registers.rb +0 -120
- data/lib/badline/z80/saved_state.rb +0 -69
- data/lib/badline/z80/shifts.rb +0 -64
- data/lib/badline/z80.rb +0 -11
- /data/lib/badline/snapshot/{fields.rb → vice/fields.rb} +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class CPU
|
|
6
|
+
module Traps
|
|
7
|
+
def install_trap(addr, &handler)
|
|
8
|
+
(@traps ||= {})[addr] = handler
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def remove_trap(addr)
|
|
12
|
+
@traps&.delete(addr)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def run_traps
|
|
18
|
+
@traps[@program_counter]&.call if @traps
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class SID
|
|
6
|
+
# Running the DSP over the cycles that have passed since it last caught
|
|
7
|
+
# up, in spans that fast-forward the voices and end on a whole cycle.
|
|
8
|
+
module CatchUp
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
# Runs the cycles that have passed, landing each queued write on the
|
|
12
|
+
# cycle the CPU wrote it on.
|
|
13
|
+
def catch_up
|
|
14
|
+
replayed = 0
|
|
15
|
+
i = 0
|
|
16
|
+
while i < @deferred_writes.length
|
|
17
|
+
cycle = @deferred_writes[i]
|
|
18
|
+
run(cycle - replayed)
|
|
19
|
+
replayed = cycle
|
|
20
|
+
apply_write(@deferred_writes[i + 1], @deferred_writes[i + 2])
|
|
21
|
+
i += 3
|
|
22
|
+
end
|
|
23
|
+
run(@pending_cycles - replayed)
|
|
24
|
+
@deferred_writes.clear
|
|
25
|
+
@pending_cycles = 0
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def run(cycles)
|
|
29
|
+
while cycles != 0
|
|
30
|
+
span = span(cycles)
|
|
31
|
+
fast_forward(span - 1) if span > 1
|
|
32
|
+
clock!(span)
|
|
33
|
+
cycles -= span
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# The longest stretch that can be fast-forwarded. A combined waveform
|
|
38
|
+
# feeding back into its own oscillator steps cycle by cycle, and a span
|
|
39
|
+
# never runs past an MSB rise that hard-syncs the next voice, so both
|
|
40
|
+
# land on a whole cycle.
|
|
41
|
+
def span(cycles)
|
|
42
|
+
return 1 if @stepped
|
|
43
|
+
|
|
44
|
+
span = @synthesizing ? synthesis_span(cycles) : cycles
|
|
45
|
+
return span unless @synced
|
|
46
|
+
|
|
47
|
+
span = sync_span(@waveform1, span)
|
|
48
|
+
span = sync_span(@waveform2, span)
|
|
49
|
+
sync_span(@waveform3, span)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# The filter steps at most @filter_chunk cycles at a time, and never
|
|
53
|
+
# across the end of a recorded sample.
|
|
54
|
+
def synthesis_span(cycles)
|
|
55
|
+
span = [cycles, @filter_chunk].min
|
|
56
|
+
return span unless @decimator
|
|
57
|
+
|
|
58
|
+
[@decimator.cycles_to_close, span].min
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Whether a span has to step, or watch for hard sync, only changes with
|
|
62
|
+
# a voice's control register.
|
|
63
|
+
def update_span_rules
|
|
64
|
+
@stepped = @voices.any? { |voice| voice.waveform.stepped?(@synthesizing) }
|
|
65
|
+
@synced = @voices.any? { |voice| voice.waveform.sync? }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def sync_span(waveform, span)
|
|
69
|
+
return span unless waveform.sync_dest.sync?
|
|
70
|
+
|
|
71
|
+
rise = waveform.cycles_to_msb_rise
|
|
72
|
+
rise && rise < span ? rise : span
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Unrolled over the three voices: the per-cycle block calls cost
|
|
76
|
+
# measurably on the synthesis path.
|
|
77
|
+
def fast_forward(cycles)
|
|
78
|
+
@voice1.fast_forward(cycles)
|
|
79
|
+
@voice2.fast_forward(cycles)
|
|
80
|
+
@voice3.fast_forward(cycles)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# The last cycle of a span, run whole. The filter integrates the span
|
|
84
|
+
# from the voices' output at its end.
|
|
85
|
+
def clock!(span)
|
|
86
|
+
@voice1.cycle!
|
|
87
|
+
@voice2.cycle!
|
|
88
|
+
@voice3.cycle!
|
|
89
|
+
@waveform1.synchronize!
|
|
90
|
+
@waveform2.synchronize!
|
|
91
|
+
@waveform3.synchronize!
|
|
92
|
+
return unless @synthesizing
|
|
93
|
+
|
|
94
|
+
@filter.cycle!(@voices, span)
|
|
95
|
+
record_sample(span) if @decimator
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def record_sample(span)
|
|
99
|
+
sample = @decimator.push(current_sample, span)
|
|
100
|
+
return unless sample
|
|
101
|
+
|
|
102
|
+
@samples << sample
|
|
103
|
+
record_voices if @voice_samples
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def record_voices
|
|
107
|
+
voice_samples = @voice_samples
|
|
108
|
+
voice_samples << (@voice1.output >> 7)
|
|
109
|
+
voice_samples << (@voice2.output >> 7)
|
|
110
|
+
voice_samples << (@voice3.output >> 7)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def current_sample
|
|
114
|
+
sample = @filter.output / SAMPLE_DIVISOR
|
|
115
|
+
return sample unless sample < -0x8000 || sample > 0x7fff
|
|
116
|
+
|
|
117
|
+
sample.clamp(-0x8000, 0x7fff)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class SID
|
|
6
|
+
# Reduces the SID's one-sample-per-cycle stream to an audio rate by
|
|
7
|
+
# averaging each window. Point sampling would be cheaper, but the pulse
|
|
8
|
+
# and noise waveforms carry enough energy above the output Nyquist to
|
|
9
|
+
# alias audibly.
|
|
10
|
+
#
|
|
11
|
+
# A sample can stand for several cycles at once, when the DSP has run
|
|
12
|
+
# them as one step.
|
|
13
|
+
class Decimator
|
|
14
|
+
def initialize(clock_hz:, rate:)
|
|
15
|
+
@clock_hz = clock_hz
|
|
16
|
+
@rate = rate
|
|
17
|
+
@phase = 0
|
|
18
|
+
@sum = 0
|
|
19
|
+
@count = 0
|
|
20
|
+
@cycles_to_close = window_cycles
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Cycles until the current window closes, counting the next one as 1.
|
|
24
|
+
attr_reader :cycles_to_close
|
|
25
|
+
|
|
26
|
+
# How far the current window has got. The clock and the rate are the
|
|
27
|
+
# host's.
|
|
28
|
+
def save_state(out)
|
|
29
|
+
out.int(@phase).int(@sum).int(@count).int(@cycles_to_close)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def load_state(input)
|
|
33
|
+
@phase = input.int
|
|
34
|
+
@sum = input.int
|
|
35
|
+
@count = input.int
|
|
36
|
+
@cycles_to_close = input.int
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Returns the averaged sample when these cycles close a window, and
|
|
40
|
+
# nil otherwise. They must not run past the window's end.
|
|
41
|
+
def push(sample, cycles = 1)
|
|
42
|
+
@sum += sample * cycles
|
|
43
|
+
@count += cycles
|
|
44
|
+
@phase += @rate * cycles
|
|
45
|
+
@cycles_to_close -= cycles
|
|
46
|
+
return unless @phase >= @clock_hz
|
|
47
|
+
|
|
48
|
+
@phase -= @clock_hz
|
|
49
|
+
@cycles_to_close = window_cycles
|
|
50
|
+
average
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def window_cycles = (@clock_hz - @phase + @rate - 1) / @rate
|
|
56
|
+
|
|
57
|
+
def average
|
|
58
|
+
value = @sum.fdiv(@count).round
|
|
59
|
+
@sum = 0
|
|
60
|
+
@count = 0
|
|
61
|
+
value
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class SID
|
|
6
|
+
class Envelope
|
|
7
|
+
# A snapshot of an envelope: its rates, the gate, the state and the
|
|
8
|
+
# counters and pipelines between them, and the same fields as reSID
|
|
9
|
+
# keeps them, for VICE's SIDEXTENDED module.
|
|
10
|
+
module SavedState
|
|
11
|
+
# The fields reSID keeps for an envelope between cycles: the rate and
|
|
12
|
+
# exponential counters, the level, the state as an index into STATES,
|
|
13
|
+
# whether it holds at zero, the two periods and the pipeline.
|
|
14
|
+
def resid_fields
|
|
15
|
+
[@rate_counter, @exponential_counter, @counter, STATES.index(@state).to_i, @hold_zero ? 1 : 0,
|
|
16
|
+
@rate_period, @exponential_period, @envelope_pipeline]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Takes the fields resid_fields gives from `fields`, from `at` on.
|
|
20
|
+
def restore_resid_fields(fields, at)
|
|
21
|
+
@rate_counter = fields[at]
|
|
22
|
+
@exponential_counter = fields[at + 1]
|
|
23
|
+
@counter = @env3 = fields[at + 2]
|
|
24
|
+
state = fields[at + 3]
|
|
25
|
+
@state = @next_state = STATES.fetch(state.clamp(0, STATES.length - 1)).to_sym
|
|
26
|
+
@hold_zero = fields[at + 4] != 0
|
|
27
|
+
@rate_period = fields[at + 5]
|
|
28
|
+
@exponential_period = fields[at + 6]
|
|
29
|
+
@envelope_pipeline = fields[at + 7]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def save_state(out)
|
|
33
|
+
[@attack, @decay, @sustain, @release].each { |rate| out.int(rate) }
|
|
34
|
+
out.boolean(@gate).int(STATES.index(@state)).int(STATES.index(@next_state))
|
|
35
|
+
out.int(@counter).int(@env3).int(@rate_counter).int(@rate_period).boolean(@reset_rate_counter)
|
|
36
|
+
out.int(@exponential_counter).int(@exponential_period)
|
|
37
|
+
out.int(@state_pipeline).int(@envelope_pipeline).int(@exponential_pipeline).boolean(@hold_zero)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def load_state(input)
|
|
41
|
+
@attack = input.int
|
|
42
|
+
@decay = input.int
|
|
43
|
+
@sustain = input.int
|
|
44
|
+
@release = input.int
|
|
45
|
+
@gate = input.boolean?
|
|
46
|
+
@state = STATES.fetch(input.int).to_sym
|
|
47
|
+
@next_state = STATES.fetch(input.int).to_sym
|
|
48
|
+
load_counters(input)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def load_counters(input)
|
|
54
|
+
@counter = input.int
|
|
55
|
+
@env3 = input.int
|
|
56
|
+
@rate_counter = input.int
|
|
57
|
+
@rate_period = input.int
|
|
58
|
+
@reset_rate_counter = input.boolean?
|
|
59
|
+
@exponential_counter = input.int
|
|
60
|
+
@exponential_period = input.int
|
|
61
|
+
@state_pipeline = input.int
|
|
62
|
+
@envelope_pipeline = input.int
|
|
63
|
+
@exponential_pipeline = input.int
|
|
64
|
+
@hold_zero = input.boolean?
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "badline/chips/sid/envelope/saved_state"
|
|
4
|
+
|
|
5
|
+
module Badline
|
|
6
|
+
module Chips
|
|
7
|
+
class SID
|
|
8
|
+
# ADSR envelope generator.
|
|
9
|
+
#
|
|
10
|
+
# A 15-bit rate counter divides the 1 MHz clock down to one envelope step
|
|
11
|
+
# per period. Attack steps linearly; decay and release run through a
|
|
12
|
+
# second, level-dependent divider that approximates an exponential
|
|
13
|
+
# curve.
|
|
14
|
+
#
|
|
15
|
+
# Each stage runs a cycle or more behind the one feeding it, after
|
|
16
|
+
# reSID 1.0's single-cycle pipeline: the rate counter resets the cycle
|
|
17
|
+
# after it matches, the envelope counter steps two cycles after that,
|
|
18
|
+
# and a gate edge only switches the rate over on its second cycle.
|
|
19
|
+
class Envelope
|
|
20
|
+
# Rate counter comparison values for each ADSR nibble. The counter
|
|
21
|
+
# takes a cycle to reset, so the period is one cycle longer (2ms to
|
|
22
|
+
# 8s over the attack range).
|
|
23
|
+
PERIODS = [8, 31, 62, 94, 148, 219, 266, 312,
|
|
24
|
+
391, 976, 1953, 3125, 3906, 11_719, 19_531, 31_250].freeze
|
|
25
|
+
|
|
26
|
+
# Envelope levels where the exponential divider changes, and the
|
|
27
|
+
# divider it changes to.
|
|
28
|
+
EXPONENTIAL_PERIODS = { 0xff => 1, 0x5d => 2, 0x36 => 4, 0x1a => 8,
|
|
29
|
+
0x0e => 16, 0x06 => 30, 0x00 => 1 }.freeze
|
|
30
|
+
|
|
31
|
+
# The states a snapshot names by index.
|
|
32
|
+
STATES = %i[attack decay_sustain release].freeze
|
|
33
|
+
|
|
34
|
+
include SavedState
|
|
35
|
+
|
|
36
|
+
attr_reader :state, :counter, :env3
|
|
37
|
+
|
|
38
|
+
def initialize
|
|
39
|
+
@attack = @decay = @sustain = @release = 0x0
|
|
40
|
+
@gate = false
|
|
41
|
+
@state = @next_state = :release
|
|
42
|
+
@counter = @env3 = 0x00
|
|
43
|
+
@rate_counter = 0
|
|
44
|
+
@rate_period = PERIODS[0]
|
|
45
|
+
@reset_rate_counter = false
|
|
46
|
+
@exponential_counter = 0
|
|
47
|
+
@exponential_period = 1
|
|
48
|
+
@state_pipeline = @envelope_pipeline = @exponential_pipeline = 0
|
|
49
|
+
@hold_zero = true
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def output = @counter
|
|
53
|
+
|
|
54
|
+
# The gate edge switches the state over two cycles. Rising, it runs
|
|
55
|
+
# the decay rate for the first of them. The rate counter is left
|
|
56
|
+
# running, so the first step lands somewhere inside the current
|
|
57
|
+
# period.
|
|
58
|
+
def control=(value)
|
|
59
|
+
gate = value.anybits?(0x01)
|
|
60
|
+
return if gate == @gate
|
|
61
|
+
|
|
62
|
+
@gate = gate
|
|
63
|
+
gate ? gate_on : gate_off
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def attack_decay=(value)
|
|
67
|
+
@attack = (value >> 4) & 0x0f
|
|
68
|
+
@decay = value & 0x0f
|
|
69
|
+
@rate_period = PERIODS[@attack] if @state == :attack
|
|
70
|
+
@rate_period = PERIODS[@decay] if @state == :decay_sustain
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def sustain_release=(value)
|
|
74
|
+
@sustain = (value >> 4) & 0x0f
|
|
75
|
+
@release = value & 0x0f
|
|
76
|
+
@rate_period = PERIODS[@release] if @state == :release
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# ENV3 reads the counter as it stood at the start of the cycle.
|
|
80
|
+
#
|
|
81
|
+
# Lowering the rate period below the current counter sends it the long
|
|
82
|
+
# way round through 2^15 before the envelope can step, the ADSR delay
|
|
83
|
+
# bug that hard restarts rely on. Counting from 0x7fff wraps to 1.
|
|
84
|
+
def cycle!
|
|
85
|
+
@env3 = @counter
|
|
86
|
+
run_pipeline if pipelined?
|
|
87
|
+
return @reset_rate_counter = true if @rate_counter == @rate_period
|
|
88
|
+
|
|
89
|
+
@rate_counter += 1
|
|
90
|
+
@rate_counter = 1 if @rate_counter == 0x8000
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Runs `cycles` cycles as #cycle! would. Between steps only the rate
|
|
94
|
+
# counter moves, so it jumps from one match to the next and the cycles
|
|
95
|
+
# around each step run whole. Frozen at zero, a period changes
|
|
96
|
+
# nothing, so whole periods are counted off at once.
|
|
97
|
+
def fast_forward(cycles)
|
|
98
|
+
while cycles.positive?
|
|
99
|
+
if pipelined?
|
|
100
|
+
cycle!
|
|
101
|
+
cycles -= 1
|
|
102
|
+
next
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
@env3 = @counter
|
|
106
|
+
idle = cycles_to_match
|
|
107
|
+
return advance_rate_counter(cycles) if cycles < idle
|
|
108
|
+
|
|
109
|
+
advance_rate_counter(idle)
|
|
110
|
+
cycles = skip_frozen_periods(cycles - idle)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
private
|
|
115
|
+
|
|
116
|
+
def land_step
|
|
117
|
+
@envelope_pipeline -= 1
|
|
118
|
+
step if @envelope_pipeline.zero? && !@hold_zero
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def gate_on
|
|
122
|
+
@next_state = :attack
|
|
123
|
+
@state = :decay_sustain
|
|
124
|
+
@rate_period = PERIODS[@decay]
|
|
125
|
+
@state_pipeline = 2
|
|
126
|
+
if @reset_rate_counter || @exponential_pipeline == 2
|
|
127
|
+
@envelope_pipeline = @exponential_period == 1 || @exponential_pipeline == 2 ? 2 : 4
|
|
128
|
+
elsif @exponential_pipeline == 1
|
|
129
|
+
@state_pipeline = 3
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def gate_off
|
|
134
|
+
@next_state = :release
|
|
135
|
+
@state_pipeline = @envelope_pipeline.positive? ? 3 : 2
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def state_change
|
|
139
|
+
@state_pipeline -= 1
|
|
140
|
+
if @next_state == :attack
|
|
141
|
+
enter_attack if @state_pipeline.zero?
|
|
142
|
+
elsif (@state == :attack && @state_pipeline.zero?) ||
|
|
143
|
+
(@state == :decay_sustain && @state_pipeline == 1)
|
|
144
|
+
@state = :release
|
|
145
|
+
@rate_period = PERIODS[@release]
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def enter_attack
|
|
150
|
+
@state = :attack
|
|
151
|
+
@rate_period = PERIODS[@attack]
|
|
152
|
+
@hold_zero = false
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# The first attack step also resets the exponential divider.
|
|
156
|
+
def reset_rate_counter
|
|
157
|
+
@rate_counter = 0
|
|
158
|
+
@reset_rate_counter = false
|
|
159
|
+
if @state == :attack
|
|
160
|
+
@exponential_counter = 0
|
|
161
|
+
@envelope_pipeline = 2
|
|
162
|
+
elsif !@hold_zero && (@exponential_counter += 1) == @exponential_period
|
|
163
|
+
@exponential_pipeline = @exponential_period == 1 ? 1 : 2
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def exponential_step
|
|
168
|
+
@exponential_counter = 0
|
|
169
|
+
return unless @state == :release || (@state == :decay_sustain && @counter != sustain_level)
|
|
170
|
+
|
|
171
|
+
@envelope_pipeline = 1
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def pipelined?
|
|
175
|
+
@reset_rate_counter || (@state_pipeline | @envelope_pipeline | @exponential_pipeline) != 0
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def run_pipeline
|
|
179
|
+
state_change if @state_pipeline.positive?
|
|
180
|
+
land_step if @envelope_pipeline.positive?
|
|
181
|
+
if @exponential_pipeline.positive? && (@exponential_pipeline -= 1).zero?
|
|
182
|
+
exponential_step
|
|
183
|
+
elsif @reset_rate_counter
|
|
184
|
+
reset_rate_counter
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Cycles that only count before the rate counter matches its period.
|
|
189
|
+
def cycles_to_match
|
|
190
|
+
return @rate_period - @rate_counter if @rate_counter <= @rate_period
|
|
191
|
+
|
|
192
|
+
0x7fff - @rate_counter + @rate_period
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def advance_rate_counter(cycles)
|
|
196
|
+
@rate_counter += cycles
|
|
197
|
+
@rate_counter -= 0x7fff if @rate_counter > 0x7fff
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# With the counter on its period, a frozen envelope comes back to the
|
|
201
|
+
# same state every period plus one cycles. Otherwise the next cycle
|
|
202
|
+
# starts a step.
|
|
203
|
+
def skip_frozen_periods(cycles)
|
|
204
|
+
cycles %= @rate_period + 1 if @hold_zero && @state != :attack
|
|
205
|
+
return cycles unless cycles.positive?
|
|
206
|
+
|
|
207
|
+
cycle!
|
|
208
|
+
cycles - 1
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def step
|
|
212
|
+
if @state == :attack
|
|
213
|
+
attack_step
|
|
214
|
+
else
|
|
215
|
+
@counter = (@counter - 1) & 0xff
|
|
216
|
+
end
|
|
217
|
+
set_exponential_period
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def attack_step
|
|
221
|
+
@counter = (@counter + 1) & 0xff
|
|
222
|
+
return unless @counter == 0xff
|
|
223
|
+
|
|
224
|
+
@state = :decay_sustain
|
|
225
|
+
@rate_period = PERIODS[@decay]
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def sustain_level = (@sustain << 4) | @sustain
|
|
229
|
+
|
|
230
|
+
# Reaching zero freezes the envelope until the gate is raised again.
|
|
231
|
+
def set_exponential_period
|
|
232
|
+
period = EXPONENTIAL_PERIODS[@counter]
|
|
233
|
+
return unless period
|
|
234
|
+
|
|
235
|
+
@exponential_period = period
|
|
236
|
+
@hold_zero = true if @counter.zero?
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class SID
|
|
6
|
+
class Filter
|
|
7
|
+
# The filter's state for a snapshot.
|
|
8
|
+
module SavedState
|
|
9
|
+
# The registers as the filter decoded them and its integrators. The
|
|
10
|
+
# W0 table is the model's.
|
|
11
|
+
def save_state(out)
|
|
12
|
+
out.int(@cutoff).int(@routing).int(@mode).int(@volume).boolean(@voice3_off).int(@w0).int(@resonance)
|
|
13
|
+
[@highpass, @bandpass, @lowpass, @unfiltered, @input].each { |value| out.int(value) }
|
|
14
|
+
@external.save_state(out)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def load_state(input)
|
|
18
|
+
@cutoff = input.int
|
|
19
|
+
@routing = input.int
|
|
20
|
+
@mode = input.int
|
|
21
|
+
@volume = input.int
|
|
22
|
+
@voice3_off = input.boolean?
|
|
23
|
+
@w0 = input.int
|
|
24
|
+
@resonance = input.int
|
|
25
|
+
load_integrators(input)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def load_integrators(input)
|
|
31
|
+
@highpass = input.int
|
|
32
|
+
@bandpass = input.int
|
|
33
|
+
@lowpass = input.int
|
|
34
|
+
@unfiltered = input.int
|
|
35
|
+
@input = input.int
|
|
36
|
+
@external.load_state(input)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|