badline 0.6.1 → 0.8.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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +56 -0
  3. data/CLAUDE.md +3 -1
  4. data/README.md +132 -247
  5. data/doc/library.md +62 -0
  6. data/doc/media.md +69 -0
  7. data/doc/sid-player.md +132 -0
  8. data/doc/snapshots.md +69 -0
  9. data/exe/badline-ruby +9 -1
  10. data/lib/badline/address_bus/extra_sids.rb +30 -0
  11. data/lib/badline/address_bus/sid_slots.rb +42 -0
  12. data/lib/badline/address_bus.rb +5 -0
  13. data/lib/badline/audio/aiff.rb +2 -2
  14. data/lib/badline/audio/bare_player.rb +23 -12
  15. data/lib/badline/audio/cli.rb +153 -58
  16. data/lib/badline/audio/jukebox.rb +121 -36
  17. data/lib/badline/audio/machine_player.rb +25 -10
  18. data/lib/badline/audio/pcm_writer.rb +10 -6
  19. data/lib/badline/audio/playback.rb +6 -5
  20. data/lib/badline/audio/queued_tune.rb +89 -0
  21. data/lib/badline/audio/renderer.rb +57 -10
  22. data/lib/badline/audio/stereo.rb +97 -0
  23. data/lib/badline/audio/terminal.rb +39 -6
  24. data/lib/badline/audio/wav.rb +1 -1
  25. data/lib/badline/audio.rb +2 -0
  26. data/lib/badline/cartridge/freezer.rb +2 -0
  27. data/lib/badline/cartridge.rb +3 -0
  28. data/lib/badline/frontend/app.rb +38 -35
  29. data/lib/badline/frontend/audio_sink.rb +6 -5
  30. data/lib/badline/frontend/boot.rb +9 -2
  31. data/lib/badline/frontend/buttons.rb +184 -0
  32. data/lib/badline/frontend/confirmation.rb +50 -0
  33. data/lib/badline/frontend/controls.rb +44 -32
  34. data/lib/badline/frontend/file_browser.rb +225 -0
  35. data/lib/badline/frontend/filter_view.rb +96 -0
  36. data/lib/badline/frontend/frame_report.rb +52 -0
  37. data/lib/badline/frontend/info_view.rb +120 -0
  38. data/lib/badline/frontend/menu_dialogs.rb +122 -0
  39. data/lib/badline/frontend/menu_media.rb +128 -0
  40. data/lib/badline/frontend/menu_pages.rb +198 -0
  41. data/lib/badline/frontend/painter.rb +185 -0
  42. data/lib/badline/frontend/pause_menu.rb +246 -0
  43. data/lib/badline/frontend/player_commands.rb +33 -0
  44. data/lib/badline/frontend/player_footer.rb +86 -0
  45. data/lib/badline/frontend/player_header.rb +60 -0
  46. data/lib/badline/frontend/player_screen.rb +124 -0
  47. data/lib/badline/frontend/player_state.rb +67 -0
  48. data/lib/badline/frontend/player_window.rb +228 -0
  49. data/lib/badline/frontend/scope.rb +42 -0
  50. data/lib/badline/frontend/sid_history.rb +175 -0
  51. data/lib/badline/frontend/sid_view.rb +140 -0
  52. data/lib/badline/frontend/snapshots.rb +1 -1
  53. data/lib/badline/frontend/sound.rb +0 -1
  54. data/lib/badline/frontend/timeline.rb +5 -1
  55. data/lib/badline/frontend/visualizer_view.rb +101 -0
  56. data/lib/badline/frontend.rb +21 -0
  57. data/lib/badline/media/disk_set.rb +108 -0
  58. data/lib/badline/media/queue.rb +158 -0
  59. data/lib/badline/media.rb +14 -8
  60. data/lib/badline/options/help.rb +34 -5
  61. data/lib/badline/options/option.rb +1 -1
  62. data/lib/badline/options/table.rb +5 -3
  63. data/lib/badline/options/validation.rb +54 -0
  64. data/lib/badline/options.rb +65 -46
  65. data/lib/badline/sdl.rb +16 -6
  66. data/lib/badline/sid/catch_up.rb +11 -1
  67. data/lib/badline/sid/filter.rb +9 -0
  68. data/lib/badline/sid/voice.rb +6 -0
  69. data/lib/badline/sid/waveform.rb +20 -5
  70. data/lib/badline/sid.rb +35 -3
  71. data/lib/badline/storage/hvsc.rb +41 -0
  72. data/lib/badline/storage/sid_file.rb +45 -25
  73. data/lib/badline/storage/song_lengths.rb +6 -29
  74. data/lib/badline/storage/stil/credit.rb +50 -0
  75. data/lib/badline/storage/stil.rb +126 -0
  76. data/lib/badline/storage.rb +8 -0
  77. data/lib/badline/version.rb +1 -1
  78. metadata +36 -1
@@ -16,7 +16,7 @@ module Badline
16
16
  # BASIC's RUN handler, where a BASIC tune starts.
17
17
  BASIC_RUN = 0xa871
18
18
 
19
- # The 6502 stub that starts a tune: call init with the song number,
19
+ # The 6502 stub that starts a tune: call init with the subtune number,
20
20
  # point the KERNAL's IRQ vector at a raster handler that calls play,
21
21
  # and spin. Both calls are wrapped in the `$01` save, bank and restore
22
22
  # that puts the tune's own RAM under the CPU.
@@ -41,7 +41,7 @@ module Badline
41
41
  # pha
42
42
  # lda #iomap
43
43
  # sta $01
44
- # lda #song
44
+ # lda #subtune
45
45
  # jsr init
46
46
  # pla
47
47
  # sta $01
@@ -70,9 +70,9 @@ module Badline
70
70
  CIA1_ICR = 0xdc0d
71
71
  RASTER_IRQ_STATUS = 0xd019
72
72
 
73
- def initialize(tune, song:, base:)
73
+ def initialize(tune, subtune:, base:)
74
74
  @tune = tune
75
- @song = song
75
+ @subtune = subtune
76
76
  @base = base
77
77
  end
78
78
 
@@ -96,7 +96,7 @@ module Badline
96
96
 
97
97
  def boot
98
98
  start = [0x78] +
99
- banked(@tune.init_address, lda_imm(@song) + jsr(@tune.init_address)) +
99
+ banked(@tune.init_address, lda_imm(@subtune) + jsr(@tune.init_address)) +
100
100
  raster_irq + [0x58]
101
101
  start + jmp(boot_address + start.length)
102
102
  end
@@ -153,14 +153,13 @@ module Badline
153
153
  raise FormatError, "Truncated header" if truncated?
154
154
  raise FormatError, "No tune data" if data.empty?
155
155
  raise FormatError, "Sidplayer MUS data, which needs a MUS player" if mus?
156
- raise FormatError, "Written for #{sids} SIDs; only one is emulated" if sids > 1
157
156
  end
158
157
 
159
158
  def version = word(0x04)
160
159
  def data_offset = word(0x06)
161
160
  def play_address = word(0x0c)
162
- def songs = [word(0x0e), 1].max
163
- def start_song = word(0x10).clamp(1, songs)
161
+ def subtunes = [word(0x0e), 1].max
162
+ def start_subtune = word(0x10).clamp(1, subtunes)
164
163
  def speed = (word(0x12) << 16) + word(0x14)
165
164
  def name = text(0x16)
166
165
  def author = text(0x36)
@@ -181,22 +180,38 @@ module Badline
181
180
  # A v3 header can place a second SID at `$Dxx0` and a v4 header a
182
181
  # third, each given by its middle byte: even, and in `$d420-$d7e0` or
183
182
  # `$de00-$dfe0`. Anything else means the SID isn't there.
184
- def sids
185
- 1 + [0x7a, 0x7b].first([version - 2, 0].max).count do |offset|
183
+ def sids = 1 + sid_addresses.size
184
+
185
+ # Where the second and third SIDs sit, those the header places.
186
+ def sid_addresses
187
+ addresses = []
188
+ [0x7a, 0x7b].first([version - 2, 0].max).each do |offset|
186
189
  page = @bytes[offset].to_i
187
- page.even? && ((0x42..0x7e).cover?(page) || (0xe0..0xfe).cover?(page))
190
+ next unless page.even? && ((0x42..0x7e).cover?(page) || (0xe0..0xfe).cover?(page))
191
+
192
+ addresses << (0xd000 | (page << 4))
188
193
  end
194
+ addresses
189
195
  end
190
196
 
191
197
  # Flag bits 4-5 name the SID the tune was written for: 01 the 6581,
192
198
  # 10 the 8580, 11 either and 00 unknown. Only an 8580-only tune gets one.
193
199
  def sid_model = flags[4, 2] == 0b10 ? :mos8580 : :mos6581
194
200
 
201
+ # Each SID's model, SID 1's first. Bits 6-7 name the second SID's and
202
+ # bits 8-9 the third's the same way, and one the header leaves unknown
203
+ # or open takes SID 1's.
204
+ def sid_models
205
+ models = [sid_model]
206
+ sid_addresses.size.times { |extra| models << model_named(flags[6 + (extra * 2), 2]) }
207
+ models
208
+ end
209
+
195
210
  # Flag bits 2-3 name the video standard the same way: 01 PAL, 10 NTSC,
196
211
  # 11 either and 00 unknown. Only an NTSC-only tune gets NTSC.
197
212
  def ntsc? = flags[2, 2] == 0b10
198
213
 
199
- # HVSC keys its song length database on the whole file, header and all.
214
+ # HVSC keys its subtune length database on the whole file, header and all.
200
215
  def md5 = @md5 ||= Digest::MD5.hexdigest(@bytes.pack("C*"))
201
216
 
202
217
  # The `$01` value a routine at `address` has to run under, following
@@ -227,8 +242,8 @@ module Badline
227
242
  # A set speed bit asks for CIA timer pacing instead of a raster IRQ.
228
243
  # The bare player honours it; the machine driver paces everything off
229
244
  # the raster either way.
230
- def cia_timed?(song = start_song)
231
- speed[[song - 1, 31].min] == 1
245
+ def cia_timed?(subtune = start_subtune)
246
+ speed[[subtune - 1, 31].min] == 1
232
247
  end
233
248
 
234
249
  def driver_address
@@ -236,20 +251,20 @@ module Badline
236
251
  raise(FormatError, "No free RAM for the player")
237
252
  end
238
253
 
239
- def driver(song: start_song)
240
- Driver.new(self, song: song.clamp(1, songs) - 1, base: driver_address).bytes
254
+ def driver(subtune: start_subtune)
255
+ Driver.new(self, subtune: subtune.clamp(1, subtunes) - 1, base: driver_address).bytes
241
256
  end
242
257
 
243
258
  # What a booted machine needs in RAM besides the image before
244
259
  # `boot_command` starts the tune, as address => bytes. A BASIC tune
245
260
  # gets the end of its program in VARTAB, as LOAD leaves it, and the
246
- # song in the A, X and Y that SYS loads from `$030c-$030e`, where the
261
+ # subtune in the A, X and Y that SYS loads from `$030c-$030e`, where the
247
262
  # tune reads it with PEEK(780).
248
- def boot_memory(song: start_song)
249
- return { driver_address => driver(song:) } unless basic?
263
+ def boot_memory(subtune: start_subtune)
264
+ return { driver_address => driver(subtune:) } unless basic?
250
265
 
251
266
  { 0x2d => [low_byte(end_address), high_byte(end_address)],
252
- 0x030c => [song.clamp(1, songs) - 1] * 3 }
267
+ 0x030c => [subtune.clamp(1, subtunes) - 1] * 3 }
253
268
  end
254
269
 
255
270
  def boot_command = basic? ? "run\r" : "sys#{driver_address}\r"
@@ -289,14 +304,19 @@ module Badline
289
304
  end
290
305
 
291
306
  def driver_size
292
- @driver_size ||= Driver.new(self, song: 0, base: 0).bytes.length
307
+ @driver_size ||= Driver.new(self, subtune: 0, base: 0).bytes.length
308
+ end
309
+
310
+ def model_named(bits)
311
+ case bits
312
+ when 0b01 then :mos6581
313
+ when 0b10 then :mos8580
314
+ else sid_model
315
+ end
293
316
  end
294
317
 
295
318
  def text(offset)
296
- @bytes[offset, 32].take_while(&:positive?)
297
- .pack("C*")
298
- .force_encoding(Encoding::ISO_8859_1)
299
- .encode(Encoding::UTF_8)
319
+ Storage.latin1(@bytes[offset, 32].take_while(&:positive?))
300
320
  end
301
321
 
302
322
  # Header fields are big-endian, unlike everything else the 6502 sees.
@@ -2,9 +2,9 @@
2
2
 
3
3
  module Badline
4
4
  module Storage
5
- # HVSC's song length database. Each tune gets a comment naming its path
5
+ # HVSC's subtune length database. Each tune gets a comment naming its path
6
6
  # and a line keyed by the MD5 of the whole `.sid` file, holding one
7
- # `m:ss` time per song, optionally down to milliseconds:
7
+ # `m:ss` time per subtune, optionally down to milliseconds:
8
8
  #
9
9
  # ; /DEMOS/0-9/12th_Sector_Music.sid
10
10
  # c7c299ce06ec5ccffb2261fb11b42a73=4:33.108
@@ -12,38 +12,15 @@ module Badline
12
12
  # The file runs to well over a hundred thousand entries, so a lookup
13
13
  # scans for its one key rather than building a table.
14
14
  class SongLengths
15
- class << self
16
- # The database lives in the DOCUMENTS directory of an HVSC
17
- # collection, so look for one above the tune, then wherever
18
- # `$HVSC_BASE` points.
19
- def locate(tune_path)
20
- candidates(tune_path).find { |path| File.file?(path) }
21
- end
22
-
23
- private
24
-
25
- def candidates(tune_path)
26
- ancestors(File.dirname(File.expand_path(tune_path)))
27
- .push(ENV.fetch("HVSC_BASE", nil))
28
- .compact
29
- .map { |dir| File.join(dir, "DOCUMENTS", "Songlengths.md5") }
30
- end
31
-
32
- def ancestors(dir)
33
- dirs = []
34
- until dirs.last == dir
35
- dirs << dir
36
- dir = File.dirname(dir)
37
- end
38
- dirs
39
- end
40
- end
15
+ # The database lives in the DOCUMENTS directory of an HVSC
16
+ # collection.
17
+ def self.locate(tune_path) = HVSC.document(tune_path, "Songlengths.md5")
41
18
 
42
19
  def initialize(path)
43
20
  @path = path
44
21
  end
45
22
 
46
- # The tune's per-song lengths in seconds, or nil when it isn't listed.
23
+ # The tune's per-subtune lengths in seconds, or nil when it isn't listed.
47
24
  def lengths(md5)
48
25
  prefix = "#{md5.downcase}="
49
26
  File.foreach(@path) do |line|
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Storage
5
+ class STIL
6
+ # A TITLE in a STIL entry, the tune a subtune covers, with the ARTIST
7
+ # after it, and the stretch of the subtune it covers when the title
8
+ # ends in one, such as `(0:53)` or `(1:16-1:32)`. A credit without an
9
+ # end lasts until the next one takes over.
10
+ class Credit
11
+ TIMES = /\s*\((\d+):(\d\d)(?:\.\d+)?(?:-(\d+):(\d\d)(?:\.\d+)?)?\)\s*\z/
12
+
13
+ attr_reader :text, :start, :finish
14
+
15
+ def initialize(title, artist)
16
+ match = TIMES.match(title)
17
+ @start = match ? (match[1].to_i * 60) + match[2].to_i : 0
18
+ @finish = match && match[3] ? (match[3].to_i * 60) + match[4].to_i : -1
19
+ name = match ? title[0, match.begin(0)] : title
20
+ @text = artist.empty? ? name : "#{name} - #{artist}"
21
+ end
22
+
23
+ # The credits in the fields, in the order STIL lists them.
24
+ def self.list(fields)
25
+ credits = []
26
+ fields.each_with_index do |field, index|
27
+ next unless field.name == "TITLE"
28
+
29
+ following = fields[index + 1]
30
+ artist = following && following.name == "ARTIST" ? following.text : ""
31
+ credits << new(field.text.tr("\n", " "), artist.tr("\n", " "))
32
+ end
33
+ credits
34
+ end
35
+
36
+ # The text of the credit covering `seconds` into the subtune, or ""
37
+ # when none does: the last one started by then that hasn't ended.
38
+ def self.at(credits, seconds)
39
+ text = ""
40
+ credits.each do |credit|
41
+ text = credit.text if credit.covers?(seconds)
42
+ end
43
+ text
44
+ end
45
+
46
+ def covers?(seconds) = seconds >= @start && (@finish.negative? || seconds <= @finish)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/storage/stil/credit"
4
+
5
+ module Badline
6
+ module Storage
7
+ # HVSC's SID Tune Information List, `DOCUMENTS/STIL.txt`: covers,
8
+ # subtune names and composers' comments, keyed by each tune's HVSC path.
9
+ # An entry holds fields for the whole file, then a block per subtune
10
+ # that has any:
11
+ #
12
+ # /MUSICIANS/C/Crowther_Anthony/From_Ratt_To_You.sid
13
+ # COMMENT: The tune names are listed, if they were given a name, the
14
+ # remaining tunes were just called Tune 35, Tune 27 etc.
15
+ # (#16)
16
+ # NAME: G-Bust
17
+ # TITLE: Ghostbusters [from the movie]
18
+ # ARTIST: Ray Parker, Jr.
19
+ #
20
+ # A comment runs on over lines indented by nine spaces, and a blank line
21
+ # ends the entry. The file is ISO-8859-1.
22
+ class STIL
23
+ # One of NAME, AUTHOR, TITLE, ARTIST or COMMENT, with its lines of
24
+ # text joined by newlines.
25
+ class Field
26
+ attr_reader :name, :text
27
+
28
+ def initialize(name, text)
29
+ @name = name
30
+ @text = text
31
+ end
32
+
33
+ def continue(line)
34
+ @text = "#{@text}\n#{line}"
35
+ end
36
+
37
+ # The field laid out as STIL.txt does.
38
+ def lines
39
+ @text.split("\n").each_with_index.map do |line, index|
40
+ label = index.zero? ? "#{@name}:" : ""
41
+ "#{label.rjust(8)} #{line}"
42
+ end
43
+ end
44
+ end
45
+
46
+ # A tune's fields for the whole file, and for each subtune by number.
47
+ class Entry
48
+ attr_reader :fields
49
+
50
+ def initialize
51
+ @fields = []
52
+ @subtunes = {}
53
+ @subtune = 0
54
+ end
55
+
56
+ def subtune(number) = @subtunes.fetch(number, [])
57
+
58
+ # Starts the block for a subtune, which the fields read after it
59
+ # go to.
60
+ def open_subtune(subtune)
61
+ @subtune = subtune
62
+ @subtunes[subtune] = []
63
+ end
64
+
65
+ def add(field)
66
+ if @subtune.zero?
67
+ @fields << field
68
+ else
69
+ @subtunes[@subtune] << field
70
+ end
71
+ end
72
+
73
+ # Adds a line to the last field read.
74
+ def continue(line)
75
+ last = @subtune.zero? ? @fields.last : @subtunes[@subtune].last
76
+ last&.continue(line)
77
+ end
78
+ end
79
+
80
+ # The list lives in the DOCUMENTS directory of an HVSC collection.
81
+ def self.locate(tune_path) = HVSC.document(tune_path, "STIL.txt")
82
+
83
+ def initialize(path)
84
+ @path = path
85
+ end
86
+
87
+ # The entry for a tune's HVSC path, or nil when the list has none. The
88
+ # first lookup reads the whole list.
89
+ def entry(hvsc_path) = entries[hvsc_path]
90
+
91
+ def entries
92
+ @entries ||= parse(Storage.latin1(File.binread(@path).bytes))
93
+ end
94
+
95
+ private
96
+
97
+ def parse(text)
98
+ entries = {}
99
+ entry = nil
100
+ text.split("\n").each do |line|
101
+ line = line.chomp
102
+ if line.start_with?("/")
103
+ entry = Entry.new
104
+ entries[line] = entry
105
+ elsif entry.nil? || line.empty? || line.start_with?("#")
106
+ entry = nil
107
+ else
108
+ read(entry, line)
109
+ end
110
+ end
111
+ entries
112
+ end
113
+
114
+ def read(entry, line)
115
+ if line.start_with?("(#")
116
+ entry.open_subtune(line[2..].to_i)
117
+ elsif line.start_with?(" ")
118
+ entry.continue(line[9..])
119
+ else
120
+ name, text = line.lstrip.split(": ", 2)
121
+ entry.add(Field.new(name, text.to_s)) if %w[NAME AUTHOR TITLE ARTIST COMMENT].include?(name)
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -12,7 +12,9 @@ require "badline/storage/t64"
12
12
  require "badline/storage/tap"
13
13
  require "badline/storage/crt_file"
14
14
  require "badline/storage/sid_file"
15
+ require "badline/storage/hvsc"
15
16
  require "badline/storage/song_lengths"
17
+ require "badline/storage/stil"
16
18
  require "badline/storage/unavailable"
17
19
 
18
20
  module Badline
@@ -62,6 +64,12 @@ module Badline
62
64
  bytes.map { |b| b.between?(0xc1, 0xda) ? b - 0x80 : b }.pack("C*")
63
65
  end
64
66
 
67
+ # Decodes ISO-8859-1 bytes, the text of .sid headers and HVSC's
68
+ # documents, to UTF-8.
69
+ def latin1(bytes)
70
+ bytes.pack("U*").force_encoding(Encoding::UTF_8)
71
+ end
72
+
65
73
  # CBM DOS drive prefix: "0:NAME" selects a drive, "@0:NAME" is
66
74
  # save-with-replace
67
75
  def strip_drive_prefix(name)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- VERSION = "0.6.1"
4
+ VERSION = "0.8.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: badline
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Inge Jørgensen
@@ -41,11 +41,17 @@ files:
41
41
  - MIT-LICENSE
42
42
  - README.md
43
43
  - SECURITY.md
44
+ - doc/library.md
45
+ - doc/media.md
44
46
  - doc/pinned-behaviour.md
47
+ - doc/sid-player.md
48
+ - doc/snapshots.md
45
49
  - exe/badline-ruby
46
50
  - lib/badline.rb
47
51
  - lib/badline/address_bus.rb
52
+ - lib/badline/address_bus/extra_sids.rb
48
53
  - lib/badline/address_bus/saved_state.rb
54
+ - lib/badline/address_bus/sid_slots.rb
49
55
  - lib/badline/address_bus/ultimax_pages.rb
50
56
  - lib/badline/addressable.rb
51
57
  - lib/badline/audio.rb
@@ -57,7 +63,9 @@ files:
57
63
  - lib/badline/audio/machine_player.rb
58
64
  - lib/badline/audio/pcm_writer.rb
59
65
  - lib/badline/audio/playback.rb
66
+ - lib/badline/audio/queued_tune.rb
60
67
  - lib/badline/audio/renderer.rb
68
+ - lib/badline/audio/stereo.rb
61
69
  - lib/badline/audio/terminal.rb
62
70
  - lib/badline/audio/wav.rb
63
71
  - lib/badline/cartridge.rb
@@ -132,18 +140,39 @@ files:
132
140
  - lib/badline/frontend/app.rb
133
141
  - lib/badline/frontend/audio_sink.rb
134
142
  - lib/badline/frontend/boot.rb
143
+ - lib/badline/frontend/buttons.rb
144
+ - lib/badline/frontend/confirmation.rb
135
145
  - lib/badline/frontend/controls.rb
136
146
  - lib/badline/frontend/drive_led.rb
147
+ - lib/badline/frontend/file_browser.rb
148
+ - lib/badline/frontend/filter_view.rb
137
149
  - lib/badline/frontend/frame_rate.rb
150
+ - lib/badline/frontend/frame_report.rb
138
151
  - lib/badline/frontend/gamepads.rb
152
+ - lib/badline/frontend/info_view.rb
139
153
  - lib/badline/frontend/keys.rb
154
+ - lib/badline/frontend/menu_dialogs.rb
155
+ - lib/badline/frontend/menu_media.rb
156
+ - lib/badline/frontend/menu_pages.rb
140
157
  - lib/badline/frontend/pacer.rb
141
158
  - lib/badline/frontend/pad_port.rb
159
+ - lib/badline/frontend/painter.rb
160
+ - lib/badline/frontend/pause_menu.rb
161
+ - lib/badline/frontend/player_commands.rb
162
+ - lib/badline/frontend/player_footer.rb
163
+ - lib/badline/frontend/player_header.rb
164
+ - lib/badline/frontend/player_screen.rb
165
+ - lib/badline/frontend/player_state.rb
166
+ - lib/badline/frontend/player_window.rb
167
+ - lib/badline/frontend/scope.rb
142
168
  - lib/badline/frontend/screen.rb
143
169
  - lib/badline/frontend/screenshot.rb
170
+ - lib/badline/frontend/sid_history.rb
171
+ - lib/badline/frontend/sid_view.rb
144
172
  - lib/badline/frontend/snapshots.rb
145
173
  - lib/badline/frontend/sound.rb
146
174
  - lib/badline/frontend/timeline.rb
175
+ - lib/badline/frontend/visualizer_view.rb
147
176
  - lib/badline/iec_bus.rb
148
177
  - lib/badline/input.rb
149
178
  - lib/badline/input/mouse1351.rb
@@ -179,6 +208,8 @@ files:
179
208
  - lib/badline/keyboard.rb
180
209
  - lib/badline/keyboard_buffer.rb
181
210
  - lib/badline/media.rb
211
+ - lib/badline/media/disk_set.rb
212
+ - lib/badline/media/queue.rb
182
213
  - lib/badline/media/true_drive.rb
183
214
  - lib/badline/memory.rb
184
215
  - lib/badline/options.rb
@@ -186,6 +217,7 @@ files:
186
217
  - lib/badline/options/help.rb
187
218
  - lib/badline/options/option.rb
188
219
  - lib/badline/options/table.rb
220
+ - lib/badline/options/validation.rb
189
221
  - lib/badline/ram_expansion.rb
190
222
  - lib/badline/ram_expansion/banking.rb
191
223
  - lib/badline/ram_expansion/plus256k.rb
@@ -251,10 +283,13 @@ files:
251
283
  - lib/badline/storage/disk_image/writing.rb
252
284
  - lib/badline/storage/g64_image.rb
253
285
  - lib/badline/storage/host_directory.rb
286
+ - lib/badline/storage/hvsc.rb
254
287
  - lib/badline/storage/listing.rb
255
288
  - lib/badline/storage/p00.rb
256
289
  - lib/badline/storage/sid_file.rb
257
290
  - lib/badline/storage/song_lengths.rb
291
+ - lib/badline/storage/stil.rb
292
+ - lib/badline/storage/stil/credit.rb
258
293
  - lib/badline/storage/t64.rb
259
294
  - lib/badline/storage/tap.rb
260
295
  - lib/badline/storage/unavailable.rb