badline 0.2.1 → 0.4.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.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/hooks/session-start.sh +57 -0
  3. data/.claude/settings.json +14 -0
  4. data/CHANGELOG.md +107 -0
  5. data/CLAUDE.md +51 -16
  6. data/CONTRIBUTING.md +95 -3
  7. data/README.md +119 -51
  8. data/SECURITY.md +9 -0
  9. data/doc/pinned-behaviour.md +293 -39
  10. data/exe/badline-ruby +59 -0
  11. data/lib/badline/address_bus.rb +28 -14
  12. data/lib/badline/addressable.rb +1 -1
  13. data/lib/badline/audio/aiff.rb +8 -3
  14. data/lib/badline/audio/bare_player.rb +20 -3
  15. data/lib/badline/audio/cli.rb +17 -12
  16. data/lib/badline/audio/console.rb +12 -58
  17. data/lib/badline/audio/machine_player.rb +9 -6
  18. data/lib/badline/audio/playback.rb +3 -0
  19. data/lib/badline/audio/renderer.rb +3 -3
  20. data/lib/badline/audio/sdl_sink.rb +20 -52
  21. data/lib/badline/audio/stream.rb +117 -0
  22. data/lib/badline/audio/terminal.rb +90 -0
  23. data/lib/badline/audio.rb +3 -2
  24. data/lib/badline/cartridge/easy_flash.rb +6 -2
  25. data/lib/badline/cartridge/epyx_fastload.rb +1 -1
  26. data/lib/badline/cartridge/geo_ram.rb +63 -0
  27. data/lib/badline/cartridge/mach5.rb +1 -1
  28. data/lib/badline/cartridge/magic_desk.rb +5 -1
  29. data/lib/badline/cartridge/ocean.rb +5 -2
  30. data/lib/badline/cartridge/rex_utility.rb +1 -1
  31. data/lib/badline/cartridge/rgcd.rb +1 -1
  32. data/lib/badline/cartridge/simons_basic.rb +2 -2
  33. data/lib/badline/cartridge/westermann.rb +2 -2
  34. data/lib/badline/cartridge.rb +9 -0
  35. data/lib/badline/checkpoint.rb +98 -0
  36. data/lib/badline/cia/interrupt_register.rb +34 -10
  37. data/lib/badline/cia.rb +19 -10
  38. data/lib/badline/color_memory.rb +2 -2
  39. data/lib/badline/computer.rb +34 -14
  40. data/lib/badline/cpu.rb +2 -2
  41. data/lib/badline/gui/application.rb +70 -26
  42. data/lib/badline/gui/gamepads.rb +22 -22
  43. data/lib/badline/gui/joy_map.rb +1 -1
  44. data/lib/badline/gui/key_map.rb +6 -1
  45. data/lib/badline/gui/pane.rb +7 -6
  46. data/lib/badline/gui/screen_pane.rb +9 -13
  47. data/lib/badline/gui/window.rb +35 -20
  48. data/lib/badline/gui.rb +1 -1
  49. data/lib/badline/input/mouse1351.rb +21 -6
  50. data/lib/badline/input/paddles.rb +11 -6
  51. data/lib/badline/kernal_trap/channel.rb +102 -7
  52. data/lib/badline/kernal_trap/drive/block_commands.rb +108 -0
  53. data/lib/badline/kernal_trap/drive/channels.rb +53 -0
  54. data/lib/badline/kernal_trap/drive/memory.rb +109 -0
  55. data/lib/badline/kernal_trap/drive/parameters.rb +28 -0
  56. data/lib/badline/kernal_trap/drive/status.rb +3 -0
  57. data/lib/badline/kernal_trap/drive/write_file.rb +41 -0
  58. data/lib/badline/kernal_trap/drive/writes.rb +92 -0
  59. data/lib/badline/kernal_trap/drive.rb +109 -131
  60. data/lib/badline/kernal_trap/file.rb +6 -14
  61. data/lib/badline/kernal_trap/load.rb +6 -0
  62. data/lib/badline/kernal_trap/save.rb +13 -7
  63. data/lib/badline/keyboard.rb +19 -3
  64. data/lib/badline/media.rb +44 -13
  65. data/lib/badline/memory.rb +2 -2
  66. data/lib/badline/options.rb +209 -0
  67. data/lib/badline/ram_expansion/banking.rb +30 -0
  68. data/lib/badline/ram_expansion/plus256k.rb +38 -0
  69. data/lib/badline/ram_expansion/plus60k.rb +31 -0
  70. data/lib/badline/ram_expansion/unexpanded.rb +22 -0
  71. data/lib/badline/ram_expansion.rb +21 -0
  72. data/lib/badline/region.rb +51 -0
  73. data/lib/badline/rom.rb +14 -5
  74. data/lib/badline/sdl/events.rb +47 -0
  75. data/lib/badline/sdl/functions.rb +73 -0
  76. data/lib/badline/sdl.rb +67 -0
  77. data/lib/badline/sid/catch_up.rb +110 -0
  78. data/lib/badline/sid/decimator.rb +6 -1
  79. data/lib/badline/sid/filter.rb +5 -5
  80. data/lib/badline/sid/waveform/fast_forward.rb +10 -10
  81. data/lib/badline/sid/waveform/noise_writeback.rb +32 -14
  82. data/lib/badline/sid/waveform.rb +8 -8
  83. data/lib/badline/sid.rb +19 -93
  84. data/lib/badline/storage/d64_image.rb +10 -0
  85. data/lib/badline/storage/d71_image.rb +12 -0
  86. data/lib/badline/storage/d81_image.rb +9 -0
  87. data/lib/badline/storage/disk_image/bam.rb +111 -0
  88. data/lib/badline/storage/disk_image/directory.rb +79 -0
  89. data/lib/badline/storage/disk_image/writing.rb +110 -0
  90. data/lib/badline/storage/disk_image.rb +49 -4
  91. data/lib/badline/storage/host_directory.rb +17 -4
  92. data/lib/badline/storage/sid_file.rb +36 -2
  93. data/lib/badline/storage.rb +18 -1
  94. data/lib/badline/time_of_day.rb +11 -2
  95. data/lib/badline/version.rb +1 -1
  96. data/lib/badline/via/control_lines.rb +104 -0
  97. data/lib/badline/via/interrupt_register.rb +58 -0
  98. data/lib/badline/via/shift_register.rb +135 -0
  99. data/lib/badline/via/timer1.rb +82 -0
  100. data/lib/badline/via/timer2.rb +84 -0
  101. data/lib/badline/via.rb +262 -0
  102. data/lib/badline/vic/bank.rb +4 -3
  103. data/lib/badline/vic/color_patches.rb +6 -3
  104. data/lib/badline/vic/display_state.rb +4 -0
  105. data/lib/badline/vic/graphics_shifter.rb +49 -8
  106. data/lib/badline/vic/registers.rb +19 -27
  107. data/lib/badline/vic/sequencer.rb +18 -18
  108. data/lib/badline/vic/sequencer_output.rb +4 -4
  109. data/lib/badline/vic/sprite/internal_bus.rb +4 -0
  110. data/lib/badline/vic/sprite/shifter.rb +25 -3
  111. data/lib/badline/vic/sprite.rb +5 -4
  112. data/lib/badline/vic/sprites.rb +8 -3
  113. data/lib/badline/vic.rb +98 -46
  114. data/lib/badline.rb +5 -0
  115. data/packaging/homebrew/badline.rb +34 -0
  116. metadata +37 -20
  117. data/exe/badline +0 -75
  118. data/exe/badline-sid +0 -34
  119. data/lib/badline/audio/options.rb +0 -137
@@ -1,137 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "optparse"
4
-
5
- module Badline
6
- module Audio
7
- # The command line of `badline-sid`. It loads nothing else from badline,
8
- # so the executable can parse and reject its arguments before paying for
9
- # the emulator.
10
- class Options
11
- class Error < StandardError; end
12
-
13
- FALLBACK_SECONDS = 60.0
14
-
15
- DEFAULT_RATE = 44_100
16
-
17
- SID_MODELS = { "6581" => :mos6581, "8580" => :mos8580 }.freeze
18
-
19
- BANNER = <<~BANNER.freeze
20
- Usage: badline-sid [options] tune.sid [-o output]
21
-
22
- Plays a .sid tune on the host's audio device, or with an output file
23
- renders it to 16-bit PCM instead. The container follows the output
24
- file's extension, .wav or .aiff.
25
-
26
- A .sid file carries no length of its own. Without --seconds the tune is
27
- looked up by MD5 in HVSC's Songlengths.md5, taken from --songlengths, from
28
- the DOCUMENTS directory of an HVSC collection above the tune, or from
29
- $HVSC_BASE. Failing all of those it runs for #{FALLBACK_SECONDS.to_i} seconds.
30
-
31
- Played on a terminal, n or → skips to the next song, p or ← to the
32
- previous one, space pauses and q quits.
33
-
34
- PSID tunes run on a bare CPU and SID, faster than real time. RSID
35
- tunes boot the whole machine and run at about half real time, so
36
- they stutter when played. --filter-chunk 1 runs the filter cycle by
37
- cycle, which is exact but takes about twice as long.
38
-
39
- Options:
40
- BANNER
41
-
42
- attr_reader :tune_path, :output, :song, :seconds, :songlengths, :sid_model, :filter_chunk
43
-
44
- def self.parse(argv) = new.parse(argv)
45
-
46
- def initialize
47
- @jit = true
48
- @quiet = false
49
- @tui = true
50
- @help = false
51
- end
52
-
53
- def parse(argv)
54
- arguments = parser.parse(argv)
55
- @tune_path, positional_output, *extra = arguments
56
- raise Error, "unexpected argument: #{extra.first}" if extra.any?
57
-
58
- @output ||= positional_output
59
- validate unless help?
60
- self
61
- rescue OptionParser::ParseError => e
62
- raise Error, e.message
63
- end
64
-
65
- def render? = !output.nil?
66
-
67
- def rate = @rate || DEFAULT_RATE
68
-
69
- def rate_given? = !@rate.nil?
70
-
71
- def help = parser.help
72
-
73
- def help? = @help
74
-
75
- def quiet? = @quiet
76
-
77
- def tui? = @tui
78
-
79
- def jit? = @jit
80
-
81
- private
82
-
83
- def validate
84
- raise Error, "no tune given" unless tune_path
85
-
86
- validate_numbers
87
- validate_paths
88
- end
89
-
90
- def validate_numbers
91
- raise Error, "invalid argument: --song #{song}" if song&.< 1
92
- raise Error, "invalid argument: --seconds #{seconds}" unless seconds.nil? || seconds.positive?
93
- raise Error, "invalid argument: --rate #{rate}" unless rate.positive?
94
- raise Error, "invalid argument: --filter-chunk #{filter_chunk}" if filter_chunk&.< 1
95
- end
96
-
97
- def validate_paths
98
- [tune_path, songlengths].compact.each do |path|
99
- raise Error, "no such file: #{path}" unless File.exist?(path)
100
- end
101
- end
102
-
103
- def parser
104
- @parser ||= OptionParser.new do |opts|
105
- opts.banner = BANNER
106
- define_tune_options(opts)
107
- define_output_options(opts)
108
- define_run_options(opts)
109
- end
110
- end
111
-
112
- def define_tune_options(opts)
113
- opts.on("-s", "--song N", Integer, "Subtune to play, from 1 (default: the tune's own)") { |n| @song = n }
114
- opts.on("--seconds N", Float, "Length to play (default: the tune's own)") { |n| @seconds = n }
115
- opts.on("--songlengths PATH", "HVSC Songlengths.md5 to take the length from") { |path| @songlengths = path }
116
- opts.on("--sid MODEL", SID_MODELS,
117
- "SID to play on: 6581 or 8580 (default: the tune's own, else 6581)") { |model| @sid_model = model }
118
- end
119
-
120
- def define_output_options(opts)
121
- opts.on("-o", "--output PATH", "Render to a .wav or .aiff file instead of playing") { |path| @output = path }
122
- opts.on("--rate HZ", Integer,
123
- "Sample rate (default: #{DEFAULT_RATE}, or the audio device's own)") { |n| @rate = n }
124
- opts.on("--filter-chunk N", Integer, "Filter step in cycles, 1 is exact (default: 4)") do |n|
125
- @filter_chunk = n
126
- end
127
- end
128
-
129
- def define_run_options(opts)
130
- opts.on("--quiet", "Don't report progress") { @quiet = true }
131
- opts.on("--no-tui", "Play without the interactive display, even on a terminal") { @tui = false }
132
- opts.on("--disable-jit", "Run without enabling YJIT") { @jit = false }
133
- opts.on("-h", "--help", "Show this help") { @help = true }
134
- end
135
- end
136
- end
137
- end