jsbeeb 1.12.0 → 1.13.1

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.
@@ -0,0 +1,508 @@
1
+ import { keyCodes, userKeymap } from "./utils.js";
2
+
3
+ // Detect keyboard layout locally — mirrors the logic in utils.js but avoids
4
+ // importing the non-exported isUKlayout. Should be replaced with an import
5
+ // if utils.js ever exports it.
6
+ function detectKeyboardLayout() {
7
+ if (typeof navigator === "undefined") return "UK";
8
+ if (typeof localStorage !== "undefined" && localStorage.keyboardLayout) {
9
+ return localStorage.keyboardLayout === "US" ? "US" : "UK";
10
+ }
11
+ if (navigator.language) {
12
+ if (navigator.language.toLowerCase() === "en-gb") return "UK";
13
+ if (navigator.language.toLowerCase() === "en-us") return "US";
14
+ }
15
+ return "UK";
16
+ }
17
+
18
+ const isUKlayout = detectKeyboardLayout() === "UK";
19
+
20
+ // ATOM
21
+
22
+ /*
23
+ Acorn Atom
24
+
25
+ &B001 - keyboard matrix column:
26
+ ~b0 : SPC [ \ ] ^ LCK <-> ^-v Lft Rgt
27
+ ~b1 : Dwn Up CLR ENT CPY DEL 0 1 2 3
28
+ ~b2 : 4 5 6 7 8 9 : ; < =
29
+ ~b3 : > ? @ A B C D E F G
30
+ ~b4 : H I J K L M N O P Q
31
+ ~b5 : R S T U V W X Y Z ESC
32
+ ~b6 : Ctrl
33
+ ~b7 : Shift
34
+ 9 8 7 6 5 4 3 2 1 0
35
+
36
+ &B002 - REPT key
37
+ ~b6 : Rept
38
+
39
+ */
40
+
41
+ export const ATOM = {
42
+ RIGHT: [0, 0],
43
+ LEFT: [1, 0],
44
+ UP_DOWN: [2, 0],
45
+ LEFT_RIGHT: [3, 0],
46
+ LOCK: [4, 0], //CAPSLOCK
47
+
48
+ UP_ARROW: [5, 0], // big uparrow next to break
49
+ RIGHT_SQUARE_BRACKET: [6, 0],
50
+ BACKSLASH: [7, 0],
51
+ LEFT_SQUARE_BRACKET: [8, 0],
52
+ SPACE: [9, 0],
53
+
54
+ K3: [0, 1],
55
+ K2: [1, 1],
56
+ K1: [2, 1],
57
+ K0: [3, 1],
58
+ DELETE: [4, 1],
59
+ COPY: [5, 1],
60
+ RETURN: [6, 1],
61
+ CLEAR: [7, 1],
62
+ UP: [8, 1],
63
+ DOWN: [9, 1],
64
+
65
+ MINUS_EQUALS: [0, 2],
66
+ COMMA_LESSTHAN: [1, 2],
67
+ SEMICOLON_PLUS: [2, 2],
68
+ COLON_STAR: [3, 2],
69
+ K9: [4, 2],
70
+ K8: [5, 2],
71
+ K7: [6, 2],
72
+ K6: [7, 2],
73
+ K5: [8, 2],
74
+ K4: [9, 2],
75
+
76
+ G: [0, 3],
77
+ F: [1, 3],
78
+ E: [2, 3],
79
+ D: [3, 3],
80
+ C: [4, 3],
81
+ B: [5, 3],
82
+ A: [6, 3],
83
+ AT: [7, 3],
84
+ SLASH_QUESTIONMARK: [8, 3], // AND QUESTION MARK
85
+ PERIOD_GREATERTHAN: [9, 3], // AND GREATER
86
+
87
+ Q: [0, 4],
88
+ P: [1, 4],
89
+ O: [2, 4],
90
+ N: [3, 4],
91
+ M: [4, 4],
92
+ L: [5, 4],
93
+ K: [6, 4],
94
+ J: [7, 4],
95
+ I: [8, 4],
96
+ H: [9, 4],
97
+
98
+ ESCAPE: [0, 5],
99
+ Z: [1, 5],
100
+ Y: [2, 5],
101
+ X: [3, 5],
102
+ W: [4, 5],
103
+ V: [5, 5],
104
+ U: [6, 5],
105
+ T: [7, 5],
106
+ S: [8, 5],
107
+ R: [9, 5],
108
+
109
+ // special codes
110
+ CTRL: [0, 6],
111
+ SHIFT: [0, 7],
112
+ REPT: [1, 6],
113
+ };
114
+
115
+ export function stringToATOMKeys(str) {
116
+ const array = [];
117
+ let shiftState = false;
118
+ let capsLockState = true;
119
+ for (let i = 0; i < str.length; ++i) {
120
+ const c = str.charCodeAt(i);
121
+ let charStr = str.charAt(i);
122
+ let atomKey = null;
123
+ let needsShift = false;
124
+ // Only letters care about caps lock state; non-letter characters
125
+ // leave it wherever it is to avoid unnecessary LOCK toggles.
126
+ let needsCapsLock = capsLockState;
127
+ if (c >= 65 && c <= 90) {
128
+ // A-Z
129
+ atomKey = ATOM[charStr];
130
+ needsCapsLock = true;
131
+ } else if (c >= 97 && c <= 122) {
132
+ // a-z (LOCK toggles the ROM's internal caps lock state)
133
+ charStr = String.fromCharCode(c - 32);
134
+ atomKey = ATOM[charStr];
135
+ needsCapsLock = false;
136
+ } else if (c >= 48 && c <= 57) {
137
+ // 0-9
138
+ atomKey = ATOM["K" + charStr];
139
+ } else if (c >= 33 && c <= 41) {
140
+ // ! to )
141
+ charStr = String.fromCharCode(c + 16);
142
+ atomKey = ATOM["K" + charStr];
143
+ needsShift = true;
144
+ } else {
145
+ switch (charStr) {
146
+ case "\n":
147
+ atomKey = ATOM.RETURN;
148
+ break;
149
+ case "\t":
150
+ atomKey = ATOM.SPACE; // Atom has no TAB key
151
+ break;
152
+ case " ":
153
+ atomKey = ATOM.SPACE;
154
+ break;
155
+ case "-":
156
+ atomKey = ATOM.MINUS_EQUALS;
157
+ break;
158
+ case "=":
159
+ atomKey = ATOM.MINUS_EQUALS;
160
+ needsShift = true;
161
+ break;
162
+ case "\\":
163
+ atomKey = ATOM.BACKSLASH;
164
+ break;
165
+ case "@":
166
+ atomKey = ATOM.AT;
167
+ break;
168
+ case "[":
169
+ atomKey = ATOM.LEFT_SQUARE_BRACKET;
170
+ break;
171
+ case ";":
172
+ atomKey = ATOM.SEMICOLON_PLUS;
173
+ break;
174
+ case "+":
175
+ atomKey = ATOM.SEMICOLON_PLUS;
176
+ needsShift = true;
177
+ break;
178
+ case ":":
179
+ atomKey = ATOM.COLON_STAR;
180
+ break;
181
+ case "*":
182
+ atomKey = ATOM.COLON_STAR;
183
+ needsShift = true;
184
+ break;
185
+ case "]":
186
+ atomKey = ATOM.RIGHT_SQUARE_BRACKET;
187
+ break;
188
+ case ",":
189
+ atomKey = ATOM.COMMA_LESSTHAN;
190
+ break;
191
+ case "<":
192
+ atomKey = ATOM.COMMA_LESSTHAN;
193
+ needsShift = true;
194
+ break;
195
+ case ".":
196
+ atomKey = ATOM.PERIOD_GREATERTHAN;
197
+ break;
198
+ case ">":
199
+ atomKey = ATOM.PERIOD_GREATERTHAN;
200
+ needsShift = true;
201
+ break;
202
+ case "/":
203
+ atomKey = ATOM.SLASH_QUESTIONMARK;
204
+ break;
205
+ case "?":
206
+ atomKey = ATOM.SLASH_QUESTIONMARK;
207
+ needsShift = true;
208
+ break;
209
+ }
210
+ }
211
+
212
+ if (!atomKey) continue;
213
+
214
+ if ((needsShift && !shiftState) || (!needsShift && shiftState)) {
215
+ array.push(ATOM.SHIFT);
216
+ shiftState = !shiftState;
217
+ }
218
+ if ((needsCapsLock && !capsLockState) || (!needsCapsLock && capsLockState)) {
219
+ array.push(ATOM.LOCK);
220
+ capsLockState = !capsLockState;
221
+ }
222
+ array.push(atomKey);
223
+ }
224
+
225
+ if (shiftState) array.push(ATOM.SHIFT);
226
+ if (!capsLockState) array.push(ATOM.LOCK);
227
+ return array;
228
+ }
229
+
230
+ export function getKeyMapAtom(keyLayout) {
231
+ const keys2 = [];
232
+
233
+ // shift pressed
234
+ keys2[true] = {};
235
+
236
+ // shift not pressed
237
+ keys2[false] = {};
238
+
239
+ // shiftDown MUST be true or false (not undefined)
240
+ function doMap(s, colRow, shiftDown) {
241
+ if (keys2[shiftDown][s] && keys2[shiftDown][s] !== colRow) {
242
+ console.log(
243
+ "Warning: duplicate binding for atom key",
244
+ (shiftDown ? "<SHIFT>" : "") + s,
245
+ colRow,
246
+ keys2[shiftDown][s],
247
+ );
248
+ }
249
+ keys2[shiftDown][s] = colRow;
250
+ }
251
+
252
+ // shiftDown undefined -> map both
253
+ function map(s, colRow, shiftDown) {
254
+ if ((!s && s !== 0) || !colRow) {
255
+ console.log("error binding key", s, colRow);
256
+ }
257
+ if (typeof s === "string") {
258
+ s = s.charCodeAt(0);
259
+ }
260
+
261
+ if (shiftDown === undefined) {
262
+ doMap(s, colRow, true);
263
+ doMap(s, colRow, false);
264
+ } else {
265
+ doMap(s, colRow, shiftDown);
266
+ }
267
+ }
268
+
269
+ map(keyCodes.Q, ATOM.Q);
270
+ map(keyCodes.W, ATOM.W);
271
+ map(keyCodes.E, ATOM.E);
272
+ map(keyCodes.R, ATOM.R);
273
+ map(keyCodes.T, ATOM.T);
274
+ map(keyCodes.Y, ATOM.Y);
275
+ map(keyCodes.U, ATOM.U);
276
+ map(keyCodes.I, ATOM.I);
277
+ map(keyCodes.O, ATOM.O);
278
+ map(keyCodes.P, ATOM.P);
279
+
280
+ map(keyCodes.A, ATOM.A);
281
+ map(keyCodes.S, ATOM.S);
282
+ map(keyCodes.D, ATOM.D);
283
+ map(keyCodes.F, ATOM.F);
284
+ map(keyCodes.G, ATOM.G);
285
+ map(keyCodes.H, ATOM.H);
286
+ map(keyCodes.J, ATOM.J);
287
+ map(keyCodes.K, ATOM.K);
288
+ map(keyCodes.L, ATOM.L);
289
+
290
+ map(keyCodes.Z, ATOM.Z);
291
+ map(keyCodes.X, ATOM.X);
292
+ map(keyCodes.C, ATOM.C);
293
+ map(keyCodes.V, ATOM.V);
294
+ map(keyCodes.B, ATOM.B);
295
+ map(keyCodes.N, ATOM.N);
296
+ map(keyCodes.M, ATOM.M);
297
+
298
+ // these keys are in the same place on PC/Mac and ATOM keyboards
299
+ // including shifted characters
300
+ // so can be the same for "natural" and "gaming"
301
+ map(keyCodes.COMMA, ATOM.COMMA_LESSTHAN);
302
+ map(keyCodes.PERIOD, ATOM.PERIOD_GREATERTHAN);
303
+ map(keyCodes.SLASH, ATOM.SLASH_QUESTIONMARK);
304
+ map(keyCodes.SPACE, ATOM.SPACE);
305
+ map(keyCodes.ENTER, ATOM.RETURN);
306
+
307
+ // other keys to map to these in "game" layout too
308
+ map(keyCodes.F9, ATOM.CLEAR); // not actually on an ATOM keyboard
309
+ map(keyCodes.LEFT, ATOM.LEFT); // arrow left
310
+ map(keyCodes.RIGHT, ATOM.LEFT_RIGHT); // arrow right
311
+ map(keyCodes.DOWN, ATOM.DOWN); // arrow down
312
+ map(keyCodes.UP, ATOM.UP_DOWN); // arrow up
313
+
314
+ map(keyCodes.BACKSPACE, ATOM.DELETE); // delete
315
+ map(keyCodes.DELETE, ATOM.DELETE); // delete
316
+
317
+ map(keyCodes.ESCAPE, ATOM.ESCAPE);
318
+ map(keyCodes.TAB, ATOM.COPY);
319
+
320
+ map(keyCodes.F10, ATOM.REPT);
321
+
322
+ map(keyCodes.F1, ATOM.LOCK); // which is better for ATOM.LOCK - use all of them?
323
+ map(keyCodes.WINDOWS, ATOM.LOCK);
324
+ map(keyCodes.ALT_LEFT, ATOM.LOCK);
325
+
326
+ if (keyLayout === "natural") {
327
+ // "natural" keyboard
328
+ // Like a PC/Mac keyboard
329
+
330
+ // US Keyboard: has Tilde on <Shift>BACK_QUOTE
331
+ map(keyCodes.BACK_QUOTE, ATOM.UP_ARROW); // ` on PC, § on Mac
332
+ map(keyCodes.APOSTROPHE, isUKlayout ? ATOM.AT : ATOM.K2, true);
333
+ map(keyCodes.K2, isUKlayout ? ATOM.K2 : ATOM.AT, true);
334
+
335
+ // 1st row
336
+ map(keyCodes.K3, ATOM.K3, true);
337
+ map(keyCodes.K6, ATOM.UP_ARROW, true);
338
+ map(keyCodes.K7, ATOM.K6, true);
339
+ map(keyCodes.K8, ATOM.COLON_STAR, true);
340
+ map(keyCodes.K9, ATOM.K8, true);
341
+ map(keyCodes.K0, ATOM.K9, true);
342
+
343
+ map(keyCodes.K2, ATOM.K2, false);
344
+ map(keyCodes.K3, ATOM.K3, false);
345
+ map(keyCodes.K6, ATOM.K6, false);
346
+ map(keyCodes.K7, ATOM.K7, false);
347
+ map(keyCodes.K8, ATOM.K8, false);
348
+ map(keyCodes.K9, ATOM.K9, false);
349
+ map(keyCodes.K0, ATOM.K0, false);
350
+
351
+ map(keyCodes.K1, ATOM.K1);
352
+ map(keyCodes.K4, ATOM.K4);
353
+ map(keyCodes.K5, ATOM.K5);
354
+
355
+ // 3rd row
356
+
357
+ map(keyCodes.HASH, ATOM.BACKSLASH); // Atom has no # key; map to nearest
358
+
359
+ map(keyCodes.MINUS, ATOM.MINUS_EQUALS);
360
+
361
+ // 2nd row
362
+ map(keyCodes.LEFT_SQUARE_BRACKET, ATOM.LEFT_SQUARE_BRACKET);
363
+
364
+ map(keyCodes.RIGHT_SQUARE_BRACKET, ATOM.RIGHT_SQUARE_BRACKET);
365
+
366
+ // 3rd row
367
+
368
+ map(keyCodes.SEMICOLON, ATOM.SEMICOLON_PLUS);
369
+
370
+ map(keyCodes.APOSTROPHE, ATOM.COLON_STAR, false);
371
+
372
+ map(keyCodes.EQUALS, ATOM.SEMICOLON_PLUS); // OK for <Shift> at least
373
+
374
+ map(keyCodes.END, ATOM.COPY);
375
+ map(keyCodes.F11, ATOM.COPY);
376
+
377
+ map(keyCodes.CTRL, ATOM.CTRL);
378
+ map(keyCodes.CTRL_LEFT, ATOM.CTRL);
379
+ map(keyCodes.CTRL_RIGHT, ATOM.CTRL);
380
+ map(keyCodes.SHIFT, ATOM.SHIFT);
381
+ map(keyCodes.SHIFT_LEFT, ATOM.SHIFT);
382
+ map(keyCodes.SHIFT_RIGHT, ATOM.SHIFT);
383
+
384
+ map(keyCodes.BACKSLASH, ATOM.BACKSLASH);
385
+ } else if (keyLayout === "gaming") {
386
+ // gaming keyboard
387
+
388
+ // 1st row
389
+ map(keyCodes.ESCAPE, ATOM.ESCAPE);
390
+
391
+ // 2nd row
392
+ map(keyCodes.BACK_QUOTE, ATOM.ESCAPE);
393
+ map(keyCodes.K1, ATOM.K1);
394
+ map(keyCodes.K2, ATOM.K2);
395
+ map(keyCodes.K3, ATOM.K3);
396
+ map(keyCodes.K4, ATOM.K4);
397
+ map(keyCodes.K5, ATOM.K5);
398
+ map(keyCodes.K6, ATOM.K6);
399
+ map(keyCodes.K7, ATOM.K7);
400
+ map(keyCodes.K8, ATOM.K8);
401
+ map(keyCodes.K9, ATOM.K9);
402
+ map(keyCodes.K0, ATOM.K0);
403
+ map(keyCodes.MINUS, ATOM.MINUS_EQUALS);
404
+ map(keyCodes.EQUALS, ATOM.UP_ARROW);
405
+ map(keyCodes.BACKSPACE, ATOM.BACKSLASH);
406
+ map(keyCodes.INSERT, ATOM.LEFT);
407
+ map(keyCodes.HOME, ATOM.RIGHT);
408
+
409
+ // 3rd row
410
+ map(keyCodes.LEFT_SQUARE_BRACKET, ATOM.AT);
411
+ map(keyCodes.RIGHT_SQUARE_BRACKET, ATOM.LEFT_SQUARE_BRACKET);
412
+ // no key for ATOM.UNDERSCORE_POUND in UK
413
+ // see 4th row for US mapping keyCodes.BACKSLASH
414
+ map(keyCodes.DELETE, ATOM.UP);
415
+ map(keyCodes.END, ATOM.DOWN);
416
+
417
+ // 4th row
418
+ // no key for ATOM.CAPSLOCK (mapped to CTRL_LEFT below)
419
+ map(keyCodes.CAPSLOCK, ATOM.CTRL);
420
+ map(keyCodes.SEMICOLON, ATOM.SEMICOLON_PLUS);
421
+ map(keyCodes.APOSTROPHE, ATOM.COLON_STAR);
422
+ // UK keyboard (key missing on US)
423
+ map(keyCodes.HASH, ATOM.RIGHT_SQUARE_BRACKET);
424
+
425
+ // UK has extra key \| for SHIFT
426
+ map(keyCodes.SHIFT_LEFT, isUKlayout ? ATOM.LOCK : ATOM.SHIFT);
427
+ // UK: key is between SHIFT and Z
428
+ // US: key is above ENTER
429
+ map(keyCodes.BACKSLASH, isUKlayout ? ATOM.SHIFT : ATOM.BACKSLASH);
430
+
431
+ // 5th row
432
+
433
+ // Atom uses CTRL as shift, so map PC Ctrl to Atom's LOCK key
434
+ map(keyCodes.CTRL_LEFT, ATOM.LOCK);
435
+ map(keyCodes.SHIFT, ATOM.CTRL);
436
+
437
+ // ATOM.DELETE is covered by the common mapping above
438
+ map(keyCodes.CTRL_RIGHT, ATOM.COPY);
439
+ } else {
440
+ // Physical, and default
441
+ // Like a real ATOM
442
+ // mainly the CTRL key is still CTRL (as CAPSLOCK locks on the MAC)
443
+ // UP/DOWN/LEFT/RIGHT are using arrow keys
444
+ // REPT is using RIGHT_SHIFT
445
+ // note: LOCK is on LEFT_ALT
446
+ map(keyCodes.K1, ATOM.K1);
447
+ map(keyCodes.K2, ATOM.K2);
448
+ map(keyCodes.K3, ATOM.K3);
449
+ map(keyCodes.K4, ATOM.K4);
450
+ map(keyCodes.K5, ATOM.K5);
451
+ map(keyCodes.K6, ATOM.K6);
452
+ map(keyCodes.K7, ATOM.K7);
453
+ map(keyCodes.K8, ATOM.K8);
454
+ map(keyCodes.K9, ATOM.K9);
455
+ map(keyCodes.K0, ATOM.K0);
456
+ map(keyCodes.MINUS, ATOM.MINUS_EQUALS); // - / _ becomes - / =
457
+ map(keyCodes.EQUALS, ATOM.COLON_STAR); // = / + becomes : / *
458
+ //BREAK is code in 'main.js' to F12
459
+
460
+ // Q-P normal
461
+ map(keyCodes.LEFT_SQUARE_BRACKET, ATOM.AT); // maps to @
462
+ map(keyCodes.RIGHT_SQUARE_BRACKET, ATOM.BACKSLASH); // maps to \
463
+
464
+ map(keyCodes.SHIFT, ATOM.CTRL);
465
+ map(keyCodes.SHIFT_LEFT, ATOM.CTRL); // using CAPSLOCK for CTRL doesn't work on MAC
466
+ map(keyCodes.CTRL, ATOM.SHIFT);
467
+ map(keyCodes.CTRL_LEFT, ATOM.SHIFT);
468
+
469
+ map(keyCodes.CTRL_RIGHT, ATOM.SHIFT);
470
+ map(keyCodes.SHIFT_RIGHT, ATOM.REPT);
471
+
472
+ // A-L normal
473
+ map(keyCodes.SEMICOLON, ATOM.SEMICOLON_PLUS); // ; / +
474
+ map(keyCodes.APOSTROPHE, ATOM.LEFT_SQUARE_BRACKET);
475
+ map(keyCodes.BACKSLASH, ATOM.RIGHT_SQUARE_BRACKET); // HASH is \| key on Mac
476
+
477
+ // Z - M normal
478
+ }
479
+
480
+ // user keymapping
481
+ // do last (to override defaults)
482
+ while (userKeymap.length > 0) {
483
+ const mapping = userKeymap.pop();
484
+ map(keyCodes[mapping.native], ATOM[mapping.atom]);
485
+ }
486
+
487
+ return keys2;
488
+ }
489
+
490
+ export function remapGamepad(gamepad) {
491
+ //mmcdefaults
492
+
493
+ // 3-key pressed left
494
+ // G-key pressed right
495
+ // Q-key pressed up
496
+ // =-key pressed down
497
+ // rightarrow-key pressed fire
498
+
499
+ gamepad.gamepadMapping[14] = ATOM.K3;
500
+ gamepad.gamepadMapping[15] = ATOM.G;
501
+ gamepad.gamepadMapping[13] = ATOM.MINUS_EQUALS;
502
+ gamepad.gamepadMapping[12] = ATOM.Q;
503
+
504
+ // button 0 = right arrow key (fire in many Atom games)
505
+ gamepad.gamepadMapping[0] = ATOM.RIGHT;
506
+ // "start" (often <Space> to start game)
507
+ gamepad.gamepadMapping[9] = ATOM.SPACE;
508
+ }
package/src/video.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import { Teletext } from "./teletext.js";
3
3
  import * as utils from "./utils.js";
4
4
  import { BbcDefaultPalette as NulaDefaultPalette } from "./bbc-palette.js";
5
+ import { Video6847 } from "./6847.js";
5
6
 
6
7
  export const VDISPENABLE = 1 << 0;
7
8
  export const HDISPENABLE = 1 << 1;
@@ -326,7 +327,7 @@ function table4bppOffset(ulamode, byte) {
326
327
  ////////////////////
327
328
  // The video class
328
329
  export class Video {
329
- constructor(isMaster, fb32_param, paint_ext_param) {
330
+ constructor(isMaster, fb32_param, paint_ext_param, { isAtom = false } = {}) {
330
331
  this.isMaster = isMaster;
331
332
  this.fb32 = utils.makeFast32(fb32_param);
332
333
  this.collook = utils.makeFast32(
@@ -422,6 +423,13 @@ export class Video {
422
423
  this.crtc = new Crtc(this);
423
424
  this.ula = new Ula(this);
424
425
 
426
+ // Atom: attach the MC6847 VDG and use its polltime
427
+ this.video6847 = null;
428
+ if (isAtom) {
429
+ this.video6847 = new Video6847(this);
430
+ this.polltime = this.video6847.polltimeFacade;
431
+ }
432
+
425
433
  this.reset(null);
426
434
  this.clearPaintBuffer();
427
435
  this.paint();
@@ -536,6 +544,9 @@ export class Video {
536
544
  this.cpu = cpu;
537
545
  this.sysvia = via;
538
546
  if (via) via.cb2changecallback = this.cb2changed.bind(this);
547
+ if (this.video6847 && cpu) {
548
+ this.video6847.reset(cpu, cpu.atomppia);
549
+ }
539
550
  }
540
551
 
541
552
  paint() {
@@ -1,4 +1,4 @@
1
- import { FakeSoundChip, SoundChip } from "../soundchip.js";
1
+ import { FakeSoundChip, SoundChip, AtomSoundChip } from "../soundchip.js";
2
2
  import { DdNoise, FakeDdNoise } from "../ddnoise.js";
3
3
  import { RelayNoise, FakeRelayNoise } from "../relaynoise.js";
4
4
  import { Music5000, FakeMusic5000 } from "../music5000.js";
@@ -11,7 +11,9 @@ const rendererUrl = new URL("./audio-renderer.js", import.meta.url).href;
11
11
  const music5000WorkletUrl = new URL("../music5000-worklet.js", import.meta.url).href;
12
12
 
13
13
  export class AudioHandler {
14
- constructor({ warningNode, statsNode, audioFilterFreq, audioFilterQ, noSeek } = {}) {
14
+ constructor({ warningNode, statsNode, audioFilterFreq, audioFilterQ, noSeek, cpuSpeed, isAtom } = {}) {
15
+ this.cpuSpeed = cpuSpeed;
16
+ this.isAtom = isAtom;
15
17
  this.warningNode = warningNode;
16
18
  toggle(this.warningNode, false);
17
19
  this.stats = {};
@@ -26,7 +28,10 @@ export class AudioHandler {
26
28
  this._jsAudioNode = null;
27
29
  if (this.audioContext && this.audioContext.audioWorklet) {
28
30
  this.audioContext.onstatechange = () => this.checkStatus();
29
- this.soundChip = new SoundChip((buffer, time) => this._onBuffer(buffer, time));
31
+ const onBuffer = (buffer, time) => this._onBuffer(buffer, time);
32
+ this.soundChip = this.isAtom
33
+ ? new AtomSoundChip(onBuffer, { cpuSpeed: this.cpuSpeed })
34
+ : new SoundChip(onBuffer);
30
35
  // Master gain node for all sample-based audio (disc, relay, etc.).
31
36
  this.masterGain = this.audioContext.createGain();
32
37
  this.masterGain.connect(this.audioContext.destination);