jsbeeb 1.1.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.
- package/.editorconfig +15 -0
- package/.git-blame-ignore-revs +3 -0
- package/.github/copilot-instructions.md +94 -0
- package/.github/workflows/claude-issue-triage.yml +105 -0
- package/.github/workflows/claude.yml +63 -0
- package/.github/workflows/release-please.yml +75 -0
- package/.github/workflows/test-and-deploy.yml +86 -0
- package/.gitmodules +6 -0
- package/.husky/pre-commit +1 -0
- package/.idea/codeStyleSettings.xml +9 -0
- package/.idea/codeStyles/Project.xml +62 -0
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/compiler.xml +22 -0
- package/.idea/copyright/profiles_settings.xml +3 -0
- package/.idea/encodings.xml +6 -0
- package/.idea/inspectionProfiles/Project_Default.xml +7 -0
- package/.idea/jsLibraryMappings.xml +6 -0
- package/.idea/jsLinters/jshint.xml +85 -0
- package/.idea/jsLinters/jslint.xml +15 -0
- package/.idea/jsbeeb.iml +11 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/prettier.xml +7 -0
- package/.idea/runConfigurations/Debug.xml +5 -0
- package/.idea/scopes/scope_settings.xml +5 -0
- package/.idea/vcs.xml +8 -0
- package/.prettierignore +4 -0
- package/.prettierrc.json +1 -0
- package/.release-please-manifest.json +3 -0
- package/.vscode/launch.json +14 -0
- package/.vscode/settings.json +6 -0
- package/CHANGELOG.md +32 -0
- package/CLAUDE.md +136 -0
- package/COPYING +674 -0
- package/Dockerfile +22 -0
- package/Makefile +30 -0
- package/README.md +259 -0
- package/docker/nginx-default.conf +10 -0
- package/docs/pal-comb-filter-research.md +129 -0
- package/docs/pal-simulation-design.md +368 -0
- package/eslint.config.js +35 -0
- package/index.html +954 -0
- package/jsconfig.json +10 -0
- package/package.json +102 -0
- package/public/discs/README.Irq-Timing +3 -0
- package/public/discs/README.bcdtest +5 -0
- package/public/discs/README.elite +6 -0
- package/public/discs/README.eng_test +3 -0
- package/public/discs/README.protection +7 -0
- package/public/favicon.ico +0 -0
- package/public/images/botbar.png +0 -0
- package/public/images/cub-monitor.png +0 -0
- package/public/images/jsbeeb-example.png +0 -0
- package/public/images/placeholder.png +0 -0
- package/public/images/red-off-16.png +0 -0
- package/public/images/red-on-16.png +0 -0
- package/public/images/sb/CD-left.jpg +0 -0
- package/public/images/sb/CD-right.jpg +0 -0
- package/public/images/sidebar.png +0 -0
- package/public/images/tv.png +0 -0
- package/public/images/yellow-off-16.png +0 -0
- package/public/images/yellow-on-16.png +0 -0
- package/public/jsbeeb-icon.png +0 -0
- package/public/robots.txt +3 -0
- package/public/roms/ADFS1-53.rom +0 -0
- package/public/roms/BASIC.ROM +0 -0
- package/public/roms/README +4 -0
- package/public/roms/a01/BASIC1.rom +0 -0
- package/public/roms/ample.rom +0 -0
- package/public/roms/ats-3.0.rom +0 -0
- package/public/roms/b/DFS-0.9.rom +0 -0
- package/public/roms/b/DFS-1.2.rom +0 -0
- package/public/roms/b1770/dfs1770.rom +0 -0
- package/public/roms/b1770/zADFS.ROM +0 -0
- package/public/roms/bp/dfs.rom +0 -0
- package/public/roms/bp/zADFS.ROM +0 -0
- package/public/roms/bpos.rom +0 -0
- package/public/roms/compact/adfs210.rom +0 -0
- package/public/roms/compact/basic48.rom +0 -0
- package/public/roms/compact/basic486.rom +0 -0
- package/public/roms/compact/os51.rom +0 -0
- package/public/roms/compact/utils.rom +0 -0
- package/public/roms/deos.rom +0 -0
- package/public/roms/master/anfs-4.25.rom +0 -0
- package/public/roms/master/mos.txt +68819 -0
- package/public/roms/master/mos3.20 +0 -0
- package/public/roms/os.rom +0 -0
- package/public/roms/os01.rom +0 -0
- package/public/roms/tube/6502Tube.rom +0 -0
- package/public/roms/tube/ARMeval_100.rom +0 -0
- package/public/roms/tube/BIOS.ROM +0 -0
- package/public/roms/tube/ReCo6502ROM_816 +0 -0
- package/public/roms/tube/Z80_120.rom +0 -0
- package/public/roms/us/USBASIC.rom +0 -0
- package/public/roms/us/USDNFS.rom +0 -0
- package/public/roms/usmos.rom +0 -0
- package/public/sounds/disc525/motor.wav +0 -0
- package/public/sounds/disc525/motoroff.wav +0 -0
- package/public/sounds/disc525/motoron.wav +0 -0
- package/public/sounds/disc525/seek.wav +0 -0
- package/public/sounds/disc525/seek2.wav +0 -0
- package/public/sounds/disc525/seek3.wav +0 -0
- package/public/sounds/disc525/step.wav +0 -0
- package/public/teletext/txt0.dat +0 -0
- package/public/teletext/txt1.dat +0 -0
- package/public/teletext/txt2.dat +0 -0
- package/public/teletext/txt3.dat +0 -0
- package/release-please-config.json +13 -0
- package/run-container.sh +92 -0
- package/src/6502.js +1347 -0
- package/src/6502.opcodes.js +1411 -0
- package/src/acia.js +261 -0
- package/src/adc.js +149 -0
- package/src/analogue-source.js +21 -0
- package/src/app/app.js +175 -0
- package/src/app/electron.js +20 -0
- package/src/app/preload.js +8 -0
- package/src/app-bench.js +33 -0
- package/src/basic/multiline-tetris +9 -0
- package/src/basic-tokenise.js +104 -0
- package/src/canvas.js +177 -0
- package/src/cmos.js +141 -0
- package/src/config.js +165 -0
- package/src/ddnoise.js +138 -0
- package/src/disc-drive.js +371 -0
- package/src/disc-hfe.js +396 -0
- package/src/disc.js +997 -0
- package/src/econet/L3FS.dat +0 -0
- package/src/econet/scsi.dat +0 -0
- package/src/econet.js +714 -0
- package/src/fake6502.js +32 -0
- package/src/fdc.js +248 -0
- package/src/filestore.js +666 -0
- package/src/gamepad-source.js +59 -0
- package/src/gamepads.js +268 -0
- package/src/google-drive.js +160 -0
- package/src/intel-fdc.js +1717 -0
- package/src/jsbeeb.css +363 -0
- package/src/keyboard.js +411 -0
- package/src/lib/README +1 -0
- package/src/lib/webgl-debug.js +911 -0
- package/src/main.js +1759 -0
- package/src/microphone-input.js +149 -0
- package/src/models.js +200 -0
- package/src/mouse-joystick-source.js +107 -0
- package/src/music5000-worklet.js +43 -0
- package/src/music5000.js +207 -0
- package/src/scheduler.js +148 -0
- package/src/serial.js +31 -0
- package/src/soundchip.js +314 -0
- package/src/sth.js +59 -0
- package/src/tapes.js +265 -0
- package/src/teletext.js +348 -0
- package/src/teletext_adaptor.js +172 -0
- package/src/teletext_data.js +1064 -0
- package/src/touchscreen.js +86 -0
- package/src/tube.js +349 -0
- package/src/url-params.js +256 -0
- package/src/utils.js +1090 -0
- package/src/via.js +702 -0
- package/src/video-filters/pal-composite.js +94 -0
- package/src/video-filters/passthrough-filter.js +70 -0
- package/src/video-filters/shaders/pal-composite.frag.glsl +147 -0
- package/src/video-filters/shaders/pal-composite.vert.glsl +8 -0
- package/src/video-filters/shaders/passthrough.frag.glsl +6 -0
- package/src/video-filters/shaders/passthrough.vert.glsl +7 -0
- package/src/video.js +794 -0
- package/src/wd-fdc.js +1344 -0
- package/src/web/audio-handler.js +146 -0
- package/src/web/audio-renderer.js +115 -0
- package/src/web/debug.js +529 -0
- package/tests/integration/RmwX.asm +47 -0
- package/tests/integration/TestInstructionsSource +27 -0
- package/tests/integration/TestTimingsResults +27 -0
- package/tests/integration/TestTimingsSource +61 -0
- package/tests/integration/bcd.js +23 -0
- package/tests/integration/dormann.js +101 -0
- package/tests/integration/dp111timing.js +42 -0
- package/tests/integration/ensure-submodules.js +25 -0
- package/tests/integration/nops.bas +119 -0
- package/tests/integration/nops.js +24 -0
- package/tests/integration/protection.js +26 -0
- package/tests/integration/rmw.js +69 -0
- package/tests/integration/teletext/expected_bug_469.png +0 -0
- package/tests/integration/teletext/expected_flash_0.png +0 -0
- package/tests/integration/teletext/expected_flash_1.png +0 -0
- package/tests/integration/teletext/expected_hoglet_held_char.png +0 -0
- package/tests/integration/teletext/expected_reveal_flash_0.png +0 -0
- package/tests/integration/teletext/expected_reveal_flash_1.png +0 -0
- package/tests/integration/teletext.js +126 -0
- package/tests/integration/timings.js +56 -0
- package/tests/integration/via.js +1125 -0
- package/tests/suite/README.md +7 -0
- package/tests/suite/Test Suite 2.15.txt +373 -0
- package/tests/suite/bin/ start +0 -0
- package/tests/suite/bin/adca +0 -0
- package/tests/suite/bin/adcax +0 -0
- package/tests/suite/bin/adcay +0 -0
- package/tests/suite/bin/adcb +0 -0
- package/tests/suite/bin/adcix +0 -0
- package/tests/suite/bin/adciy +0 -0
- package/tests/suite/bin/adcz +0 -0
- package/tests/suite/bin/adczx +0 -0
- package/tests/suite/bin/alrb +0 -0
- package/tests/suite/bin/ancb +0 -0
- package/tests/suite/bin/anda +0 -0
- package/tests/suite/bin/andax +0 -0
- package/tests/suite/bin/anday +0 -0
- package/tests/suite/bin/andb +0 -0
- package/tests/suite/bin/andix +0 -0
- package/tests/suite/bin/andiy +0 -0
- package/tests/suite/bin/andz +0 -0
- package/tests/suite/bin/andzx +0 -0
- package/tests/suite/bin/aneb +0 -0
- package/tests/suite/bin/arrb +0 -0
- package/tests/suite/bin/asla +0 -0
- package/tests/suite/bin/aslax +0 -0
- package/tests/suite/bin/asln +0 -0
- package/tests/suite/bin/aslz +0 -0
- package/tests/suite/bin/aslzx +0 -0
- package/tests/suite/bin/asoa +0 -0
- package/tests/suite/bin/asoax +0 -0
- package/tests/suite/bin/asoay +0 -0
- package/tests/suite/bin/asoix +0 -0
- package/tests/suite/bin/asoiy +0 -0
- package/tests/suite/bin/asoz +0 -0
- package/tests/suite/bin/asozx +0 -0
- package/tests/suite/bin/axsa +0 -0
- package/tests/suite/bin/axsix +0 -0
- package/tests/suite/bin/axsz +0 -0
- package/tests/suite/bin/axszy +0 -0
- package/tests/suite/bin/bccr +0 -0
- package/tests/suite/bin/bcsr +0 -0
- package/tests/suite/bin/beqr +0 -0
- package/tests/suite/bin/bita +0 -0
- package/tests/suite/bin/bitz +0 -0
- package/tests/suite/bin/bmir +0 -0
- package/tests/suite/bin/bner +0 -0
- package/tests/suite/bin/bplr +0 -0
- package/tests/suite/bin/branchwrap +0 -0
- package/tests/suite/bin/brkn +0 -0
- package/tests/suite/bin/bvcr +0 -0
- package/tests/suite/bin/bvsr +0 -0
- package/tests/suite/bin/cia1pb6 +0 -0
- package/tests/suite/bin/cia1pb7 +0 -0
- package/tests/suite/bin/cia1ta +0 -0
- package/tests/suite/bin/cia1tab +0 -0
- package/tests/suite/bin/cia1tb +0 -0
- package/tests/suite/bin/cia1tb123 +0 -0
- package/tests/suite/bin/cia2pb6 +0 -0
- package/tests/suite/bin/cia2pb7 +0 -0
- package/tests/suite/bin/cia2ta +0 -0
- package/tests/suite/bin/cia2tb +0 -0
- package/tests/suite/bin/cia2tb123 +0 -0
- package/tests/suite/bin/clcn +0 -0
- package/tests/suite/bin/cldn +0 -0
- package/tests/suite/bin/clin +0 -0
- package/tests/suite/bin/clvn +0 -0
- package/tests/suite/bin/cmpa +0 -0
- package/tests/suite/bin/cmpax +0 -0
- package/tests/suite/bin/cmpay +0 -0
- package/tests/suite/bin/cmpb +0 -0
- package/tests/suite/bin/cmpix +0 -0
- package/tests/suite/bin/cmpiy +0 -0
- package/tests/suite/bin/cmpz +0 -0
- package/tests/suite/bin/cmpzx +0 -0
- package/tests/suite/bin/cntdef +0 -0
- package/tests/suite/bin/cnto2 +0 -0
- package/tests/suite/bin/cpuport +0 -0
- package/tests/suite/bin/cputiming +0 -0
- package/tests/suite/bin/cpxa +0 -0
- package/tests/suite/bin/cpxb +0 -0
- package/tests/suite/bin/cpxz +0 -0
- package/tests/suite/bin/cpya +0 -0
- package/tests/suite/bin/cpyb +0 -0
- package/tests/suite/bin/cpyz +0 -0
- package/tests/suite/bin/dcma +0 -0
- package/tests/suite/bin/dcmax +0 -0
- package/tests/suite/bin/dcmay +0 -0
- package/tests/suite/bin/dcmix +0 -0
- package/tests/suite/bin/dcmiy +0 -0
- package/tests/suite/bin/dcmz +0 -0
- package/tests/suite/bin/dcmzx +0 -0
- package/tests/suite/bin/deca +0 -0
- package/tests/suite/bin/decax +0 -0
- package/tests/suite/bin/decz +0 -0
- package/tests/suite/bin/deczx +0 -0
- package/tests/suite/bin/dexn +0 -0
- package/tests/suite/bin/deyn +0 -0
- package/tests/suite/bin/eora +0 -0
- package/tests/suite/bin/eorax +0 -0
- package/tests/suite/bin/eoray +0 -0
- package/tests/suite/bin/eorb +0 -0
- package/tests/suite/bin/eorix +0 -0
- package/tests/suite/bin/eoriy +0 -0
- package/tests/suite/bin/eorz +0 -0
- package/tests/suite/bin/eorzx +0 -0
- package/tests/suite/bin/finish +0 -0
- package/tests/suite/bin/flipos +0 -0
- package/tests/suite/bin/icr01 +0 -0
- package/tests/suite/bin/imr +0 -0
- package/tests/suite/bin/inca +0 -0
- package/tests/suite/bin/incax +0 -0
- package/tests/suite/bin/incz +0 -0
- package/tests/suite/bin/inczx +0 -0
- package/tests/suite/bin/insa +0 -0
- package/tests/suite/bin/insax +0 -0
- package/tests/suite/bin/insay +0 -0
- package/tests/suite/bin/insix +0 -0
- package/tests/suite/bin/insiy +0 -0
- package/tests/suite/bin/insz +0 -0
- package/tests/suite/bin/inszx +0 -0
- package/tests/suite/bin/inxn +0 -0
- package/tests/suite/bin/inyn +0 -0
- package/tests/suite/bin/irq +0 -0
- package/tests/suite/bin/jmpi +0 -0
- package/tests/suite/bin/jmpw +0 -0
- package/tests/suite/bin/jsrw +0 -0
- package/tests/suite/bin/lasay +0 -0
- package/tests/suite/bin/laxa +0 -0
- package/tests/suite/bin/laxay +0 -0
- package/tests/suite/bin/laxix +0 -0
- package/tests/suite/bin/laxiy +0 -0
- package/tests/suite/bin/laxz +0 -0
- package/tests/suite/bin/laxzy +0 -0
- package/tests/suite/bin/ldaa +0 -0
- package/tests/suite/bin/ldaax +0 -0
- package/tests/suite/bin/ldaay +0 -0
- package/tests/suite/bin/ldab +0 -0
- package/tests/suite/bin/ldaix +0 -0
- package/tests/suite/bin/ldaiy +0 -0
- package/tests/suite/bin/ldaz +0 -0
- package/tests/suite/bin/ldazx +0 -0
- package/tests/suite/bin/ldxa +0 -0
- package/tests/suite/bin/ldxay +0 -0
- package/tests/suite/bin/ldxb +0 -0
- package/tests/suite/bin/ldxz +0 -0
- package/tests/suite/bin/ldxzy +0 -0
- package/tests/suite/bin/ldya +0 -0
- package/tests/suite/bin/ldyax +0 -0
- package/tests/suite/bin/ldyb +0 -0
- package/tests/suite/bin/ldyz +0 -0
- package/tests/suite/bin/ldyzx +0 -0
- package/tests/suite/bin/loadth +0 -0
- package/tests/suite/bin/lsea +0 -0
- package/tests/suite/bin/lseax +0 -0
- package/tests/suite/bin/lseay +0 -0
- package/tests/suite/bin/lseix +0 -0
- package/tests/suite/bin/lseiy +0 -0
- package/tests/suite/bin/lsez +0 -0
- package/tests/suite/bin/lsezx +0 -0
- package/tests/suite/bin/lsra +0 -0
- package/tests/suite/bin/lsrax +0 -0
- package/tests/suite/bin/lsrn +0 -0
- package/tests/suite/bin/lsrz +0 -0
- package/tests/suite/bin/lsrzx +0 -0
- package/tests/suite/bin/lxab +0 -0
- package/tests/suite/bin/mmu +0 -0
- package/tests/suite/bin/mmufetch +0 -0
- package/tests/suite/bin/nmi +0 -0
- package/tests/suite/bin/nopa +0 -0
- package/tests/suite/bin/nopax +0 -0
- package/tests/suite/bin/nopb +0 -0
- package/tests/suite/bin/nopn +0 -0
- package/tests/suite/bin/nopz +0 -0
- package/tests/suite/bin/nopzx +0 -0
- package/tests/suite/bin/oneshot +0 -0
- package/tests/suite/bin/oraa +0 -0
- package/tests/suite/bin/oraax +0 -0
- package/tests/suite/bin/oraay +0 -0
- package/tests/suite/bin/orab +0 -0
- package/tests/suite/bin/oraix +0 -0
- package/tests/suite/bin/oraiy +0 -0
- package/tests/suite/bin/oraz +0 -0
- package/tests/suite/bin/orazx +0 -0
- package/tests/suite/bin/phan +0 -0
- package/tests/suite/bin/phpn +0 -0
- package/tests/suite/bin/plan +0 -0
- package/tests/suite/bin/plpn +0 -0
- package/tests/suite/bin/rlaa +0 -0
- package/tests/suite/bin/rlaax +0 -0
- package/tests/suite/bin/rlaay +0 -0
- package/tests/suite/bin/rlaix +0 -0
- package/tests/suite/bin/rlaiy +0 -0
- package/tests/suite/bin/rlaz +0 -0
- package/tests/suite/bin/rlazx +0 -0
- package/tests/suite/bin/rola +0 -0
- package/tests/suite/bin/rolax +0 -0
- package/tests/suite/bin/roln +0 -0
- package/tests/suite/bin/rolz +0 -0
- package/tests/suite/bin/rolzx +0 -0
- package/tests/suite/bin/rora +0 -0
- package/tests/suite/bin/rorax +0 -0
- package/tests/suite/bin/rorn +0 -0
- package/tests/suite/bin/rorz +0 -0
- package/tests/suite/bin/rorzx +0 -0
- package/tests/suite/bin/rraa +0 -0
- package/tests/suite/bin/rraax +0 -0
- package/tests/suite/bin/rraay +0 -0
- package/tests/suite/bin/rraix +0 -0
- package/tests/suite/bin/rraiy +0 -0
- package/tests/suite/bin/rraz +0 -0
- package/tests/suite/bin/rrazx +0 -0
- package/tests/suite/bin/rtin +0 -0
- package/tests/suite/bin/rtsn +0 -0
- package/tests/suite/bin/sbca +0 -0
- package/tests/suite/bin/sbcax +0 -0
- package/tests/suite/bin/sbcay +0 -0
- package/tests/suite/bin/sbcb +0 -0
- package/tests/suite/bin/sbcb(eb) +0 -0
- package/tests/suite/bin/sbcix +0 -0
- package/tests/suite/bin/sbciy +0 -0
- package/tests/suite/bin/sbcz +0 -0
- package/tests/suite/bin/sbczx +0 -0
- package/tests/suite/bin/sbxb +0 -0
- package/tests/suite/bin/secn +0 -0
- package/tests/suite/bin/sedn +0 -0
- package/tests/suite/bin/sein +0 -0
- package/tests/suite/bin/shaay +0 -0
- package/tests/suite/bin/shaiy +0 -0
- package/tests/suite/bin/shsay +0 -0
- package/tests/suite/bin/shxay +0 -0
- package/tests/suite/bin/shyax +0 -0
- package/tests/suite/bin/staa +0 -0
- package/tests/suite/bin/staax +0 -0
- package/tests/suite/bin/staay +0 -0
- package/tests/suite/bin/staix +0 -0
- package/tests/suite/bin/staiy +0 -0
- package/tests/suite/bin/staz +0 -0
- package/tests/suite/bin/stazx +0 -0
- package/tests/suite/bin/stxa +0 -0
- package/tests/suite/bin/stxz +0 -0
- package/tests/suite/bin/stxzy +0 -0
- package/tests/suite/bin/stya +0 -0
- package/tests/suite/bin/styz +0 -0
- package/tests/suite/bin/styzx +0 -0
- package/tests/suite/bin/taxn +0 -0
- package/tests/suite/bin/tayn +0 -0
- package/tests/suite/bin/trap1 +0 -0
- package/tests/suite/bin/trap10 +0 -0
- package/tests/suite/bin/trap11 +0 -0
- package/tests/suite/bin/trap12 +0 -0
- package/tests/suite/bin/trap13 +0 -0
- package/tests/suite/bin/trap14 +0 -0
- package/tests/suite/bin/trap15 +0 -0
- package/tests/suite/bin/trap16 +0 -0
- package/tests/suite/bin/trap17 +0 -0
- package/tests/suite/bin/trap2 +0 -0
- package/tests/suite/bin/trap3 +0 -0
- package/tests/suite/bin/trap4 +0 -0
- package/tests/suite/bin/trap5 +0 -0
- package/tests/suite/bin/trap6 +0 -0
- package/tests/suite/bin/trap7 +0 -0
- package/tests/suite/bin/trap8 +0 -0
- package/tests/suite/bin/trap9 +0 -0
- package/tests/suite/bin/tsxn +0 -0
- package/tests/suite/bin/txan +0 -0
- package/tests/suite/bin/txsn +0 -0
- package/tests/suite/bin/tyan +0 -0
- package/tests/suite/cbm-hackers-post.html +178 -0
- package/tests/suite/cbm-hackers-post.md +78 -0
- package/tests/test-machine.js +288 -0
- package/tests/test-suite.js +147 -0
- package/tests/test.css +7 -0
- package/tests/unit/gzip/test-1 +0 -0
- package/tests/unit/gzip/test-1.gz +0 -0
- package/tests/unit/gzip/test-2 +0 -0
- package/tests/unit/gzip/test-2.gz +0 -0
- package/tests/unit/gzip/test-3 +0 -0
- package/tests/unit/gzip/test-3.gz +0 -0
- package/tests/unit/gzip/test-4 +0 -0
- package/tests/unit/gzip/test-4.gz +0 -0
- package/tests/unit/test-adc.js +307 -0
- package/tests/unit/test-bcd.js +30 -0
- package/tests/unit/test-cmos.js +266 -0
- package/tests/unit/test-disc-drive.js +85 -0
- package/tests/unit/test-disc-hfe.js +347 -0
- package/tests/unit/test-disc.js +232 -0
- package/tests/unit/test-fifo.js +35 -0
- package/tests/unit/test-gamepad-source.js +67 -0
- package/tests/unit/test-gzip.js +22 -0
- package/tests/unit/test-intel-fdc.js +93 -0
- package/tests/unit/test-keyboard.js +410 -0
- package/tests/unit/test-mouse-joystick-source.js +128 -0
- package/tests/unit/test-scheduler.js +190 -0
- package/tests/unit/test-serial.js +154 -0
- package/tests/unit/test-teletext-adaptor.js +359 -0
- package/tests/unit/test-tokenise.js +65 -0
- package/tests/unit/test-url-params.js +398 -0
- package/tests/unit/test-utils.js +276 -0
- package/tests/unit/test-video.js +498 -0
- package/tests/unit/test-zip.js +56 -0
- package/tests/unit/zip/test-mixed.zip +0 -0
- package/tests/unit/zip/test-rom.zip +0 -0
- package/tests/unit/zip/test-ssd.zip +0 -0
- package/tools/fir-generator.js +80 -0
- package/tools/vite-plugin-fir-shader.js +131 -0
- package/vite.config.js +34 -0
package/Dockerfile
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# NOTE: We create a temporary Docker container to build the webapp in, then copy
|
|
2
|
+
# the generated distributable files to the final Docker image. This keeps the
|
|
3
|
+
# final image tidy (since it doesn't contain any generated temporary artifacts),
|
|
4
|
+
# and its size to a minimum.
|
|
5
|
+
# NOTE: The version of Node must be kept in sync with what's in package.json.
|
|
6
|
+
FROM node:22-alpine AS build
|
|
7
|
+
|
|
8
|
+
# build the webapp
|
|
9
|
+
WORKDIR /app/
|
|
10
|
+
COPY package.json .
|
|
11
|
+
RUN npm install
|
|
12
|
+
COPY . .
|
|
13
|
+
RUN npm run build
|
|
14
|
+
|
|
15
|
+
# create the final Docker image
|
|
16
|
+
# NOTE: The webapp is just a bunch of static files, so all we need is something to serve them.
|
|
17
|
+
FROM nginx:1.27-alpine
|
|
18
|
+
COPY docker/nginx-default.conf /etc/nginx/conf.d/default.conf
|
|
19
|
+
COPY --from=build /app/dist /app
|
|
20
|
+
|
|
21
|
+
EXPOSE 80
|
|
22
|
+
CMD [ "nginx", "-g", "daemon off;" ]
|
package/Makefile
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
NPM_UP_TO_DATE:=.npm-up-to-date
|
|
2
|
+
NODE=node
|
|
3
|
+
NPM=npm
|
|
4
|
+
|
|
5
|
+
.PHONY: all
|
|
6
|
+
all: test
|
|
7
|
+
|
|
8
|
+
npm: $(NPM_UP_TO_DATE)
|
|
9
|
+
|
|
10
|
+
.PHONY: npm
|
|
11
|
+
test: npm
|
|
12
|
+
$(NPM) test
|
|
13
|
+
|
|
14
|
+
$(NPM_UP_TO_DATE): package.json
|
|
15
|
+
$(NPM) install
|
|
16
|
+
touch $(NPM_UP_TO_DATE)
|
|
17
|
+
|
|
18
|
+
HASH := $(shell git rev-parse HEAD)
|
|
19
|
+
|
|
20
|
+
.PHONY: dist
|
|
21
|
+
dist: npm
|
|
22
|
+
npm run build
|
|
23
|
+
|
|
24
|
+
.PHONY: clean
|
|
25
|
+
clean:
|
|
26
|
+
@rm -rf dist out
|
|
27
|
+
|
|
28
|
+
.PHONY: spotless
|
|
29
|
+
spotless: clean
|
|
30
|
+
@rm -f $(NPM_UP_TO_DATE)
|
package/README.md
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
[](https://github.com/mattgodbolt/jsbeeb/actions/workflows/test-and-deploy.yml)
|
|
2
|
+
|
|
3
|
+
# jsbeeb - JavaScript BBC Micro Emulator
|
|
4
|
+
|
|
5
|
+
[](https://bbc.xania.org/)
|
|
6
|
+
|
|
7
|
+
A BBC Micro emulator written in JavaScript and running in modern browsers. Emulates a 32K BBC B (with sideways RAM)
|
|
8
|
+
and a 128K BBC Master, along with a number of different peripherals.
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
|
|
12
|
+
- [Keyboard Mappings](#keyboard-mappings)
|
|
13
|
+
- [Getting Set Up to Run Locally](#getting-set-up-to-run-locally)
|
|
14
|
+
- [Running as a Desktop Application](#running-as-a-desktop-application)
|
|
15
|
+
- [URL Parameters](#url-parameters)
|
|
16
|
+
- [Patches](#patches)
|
|
17
|
+
- [Loading BASIC Files from GitHub Gists](#loading-basic-files-from-github-gists)
|
|
18
|
+
- [Things Left to Do](#things-left-to-do)
|
|
19
|
+
- [Tests](#tests)
|
|
20
|
+
- [Thanks](#thanks)
|
|
21
|
+
- [More Information](#more-information)
|
|
22
|
+
- [License](#license)
|
|
23
|
+
- [Contact](#contact)
|
|
24
|
+
|
|
25
|
+
## Keyboard Mappings
|
|
26
|
+
|
|
27
|
+
The BBC had a somewhat different-looking keyboard to a modern PC, and so it's useful to know some of the mappings:
|
|
28
|
+
|
|
29
|
+
- BBC `F0` is `F10`
|
|
30
|
+
- BBC `Break` key is `F12`
|
|
31
|
+
- BBC `*` is on `"` (if it doesn't work for you try shift-2)
|
|
32
|
+
|
|
33
|
+
To play right now, visit [https://bbc.xania.org/](https://bbc.xania.org/). To load the default disc image (Elite in this
|
|
34
|
+
case), press shift-F12 (which is shift-Break on the BBC).
|
|
35
|
+
|
|
36
|
+
### Joystick Support
|
|
37
|
+
|
|
38
|
+
jsbeeb supports both USB/Bluetooth gamepads and mouse-based analogue joystick emulation. Note that BBC Micro joysticks use inverted axes:
|
|
39
|
+
|
|
40
|
+
- X-axis: Left = 65535, Right = 0
|
|
41
|
+
- Y-axis: Up = 65535, Down = 0
|
|
42
|
+
|
|
43
|
+
## Getting Set Up to Run Locally
|
|
44
|
+
|
|
45
|
+
### Prerequisites
|
|
46
|
+
|
|
47
|
+
- Node.js (https://nodejs.org/)
|
|
48
|
+
- npm (comes with Node.js)
|
|
49
|
+
|
|
50
|
+
### Installation
|
|
51
|
+
|
|
52
|
+
1. Clone the repository:
|
|
53
|
+
```sh
|
|
54
|
+
git clone https://github.com/mattgodbolt/jsbeeb.git
|
|
55
|
+
cd jsbeeb
|
|
56
|
+
```
|
|
57
|
+
2. Install dependencies:
|
|
58
|
+
```sh
|
|
59
|
+
npm install
|
|
60
|
+
```
|
|
61
|
+
3. Start the local webserver:
|
|
62
|
+
```sh
|
|
63
|
+
npm start
|
|
64
|
+
```
|
|
65
|
+
4. Visit `http://localhost:5173/` in your browser.
|
|
66
|
+
|
|
67
|
+
jsbeeb uses Node.js and vite to afford simple and standard web development tooling and third-party library access
|
|
68
|
+
without lots of painful copy/paste or wheel-reinventing, as well as the ability to better run tests, and "pack" up the
|
|
69
|
+
site to make it smaller and faster to load when it's deployed to [https://bbc.xania.org](https://bbc.xania.org).
|
|
70
|
+
|
|
71
|
+
## Running as a Desktop Application
|
|
72
|
+
|
|
73
|
+
jsbeeb can also run as a standalone desktop application using Electron:
|
|
74
|
+
|
|
75
|
+
### Running in Development
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
npm run electron
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
This automatically builds the latest code before launching Electron.
|
|
82
|
+
|
|
83
|
+
### Building Distributable Packages
|
|
84
|
+
|
|
85
|
+
To build packages for Linux distribution:
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
npm run build
|
|
89
|
+
npm run electron:build
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
This creates two package formats in `out/dist/`:
|
|
93
|
+
|
|
94
|
+
- **Debian/Ubuntu**: `.deb` package
|
|
95
|
+
- **Fedora/RHEL**: `.rpm` package
|
|
96
|
+
|
|
97
|
+
**Why no Snap packages?** electron-builder's snap support uses the outdated `gnome-3-28-1804` platform (Ubuntu 18.04), which causes GPU driver incompatibilities on modern systems, resulting in MESA loader failures and segfaults. While we were able to work around the initial Wayland issues (electron-builder sets `DISABLE_WAYLAND=1` by default, fixed with `allowNativeWayland: true`), the GPU problems proved insurmountable. The snap builder hasn't been updated to support modern bases like `core22` or `core24`. The `.deb` package works perfectly on all Debian-based systems.
|
|
98
|
+
|
|
99
|
+
**Note for Ubuntu/Debian users:** If you encounter RPM build errors, you may need to use the system FPM package manager instead of electron-builder's bundled version. First, install the required dependencies:
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
sudo apt-get install ruby rubygems build-essential
|
|
103
|
+
sudo gem install fpm
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Then build with:
|
|
107
|
+
|
|
108
|
+
```sh
|
|
109
|
+
USE_SYSTEM_FPM=true npm run electron:build
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Installing the Packaged Application
|
|
113
|
+
|
|
114
|
+
**Debian/Ubuntu:**
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
sudo apt install ./out/dist/jsbeeb_1.0.1_amd64.deb
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Fedora/RHEL/CentOS:**
|
|
121
|
+
|
|
122
|
+
```sh
|
|
123
|
+
sudo rpm -i out/dist/jsbeeb-1.0.1.x86_64.rpm
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Note:** Electron support was re-enabled in November 2024 after being disabled during the ESM migration in 2021. It now works with Electron 28+ which added full ES Modules support.
|
|
127
|
+
|
|
128
|
+
## URL Parameters
|
|
129
|
+
|
|
130
|
+
- `autoboot` - fakes a shift break
|
|
131
|
+
- `disc1=XXX` - loads disc XXX (from the `discs/` directory) into drive 1
|
|
132
|
+
- `disc2=XXX` - as above
|
|
133
|
+
- `disc1=local:YYY` - creates a local disk YYY which will be kept in browser local storage
|
|
134
|
+
- `disc1=sth:ZZZ` - loads disc ZZZ from the Stairway to Hell archive
|
|
135
|
+
- `tape=XXX` - loads tape XXX (from the `tapes/` directory)
|
|
136
|
+
- `tape=sth:ZZZ` - loads tape ZZZ from the Stairway to Hell archive
|
|
137
|
+
- `patch=P` - applies a memory patch `P`. See below.
|
|
138
|
+
- `loadBasic=X` - loads 'X' (a resource on the webserver) as text, tokenises it and puts it in `PAGE` as if you'd typed
|
|
139
|
+
it in to the emulator
|
|
140
|
+
- `embedBasic=X` - loads 'X' (a URI-encoded string) as text, tokenises it and puts it in `PAGE` as if you'd typed it in
|
|
141
|
+
to the emulator
|
|
142
|
+
- `autorun` - types `*TAPE` then `*/` to run from tape. In conjunction with `loadBasic` it types `RUN`.
|
|
143
|
+
- `autochain` - types `*TAPE` then `CH.""` to run from tape.
|
|
144
|
+
- `autotype` - types whatever you put after. e.g. `&autotype=PRINT"Matt is cool"%0a` (return is URI escaped to `%0a`)
|
|
145
|
+
- `embed` - Remove the margins around the screen, hide most navigation entries and make the page background
|
|
146
|
+
transparent (intended for use when running within an iframe in a third-party site).
|
|
147
|
+
- `cpuMultiplier=X` speeds up the CPU by a factor of `X`. May be fractional or below one to slow the CPU down. NB disc
|
|
148
|
+
loads become unreliable with a too-slow CPU, and running too fast might cause the browser to hang.
|
|
149
|
+
- `sbLeft` / `sbRight` / `sbBottom` - a URL to place left of, right of, or below the cub monitor. The left and right
|
|
150
|
+
should be around 648 high and the bottom image should be around 896 wide. Left and right wider than 300 will run into
|
|
151
|
+
problems on smaller screens; bottom taller than 100 or so similarly.
|
|
152
|
+
- `videoCyclesBatch` - the number of video cycles to batch up before running the video emulation. Defaults to zero:
|
|
153
|
+
anything higher leads to emulation inaccuracies. Useful for showing why accuracy is important, even if less efficient.
|
|
154
|
+
- `rom` - load the given URL or path as an extra ROM. If a URL is provided, that URL must allow cross-site requests.
|
|
155
|
+
Doesn't support the sth: pseudo URL unlike `disc` and `tape`, but if given a ZIP file will attempt to use the `.rom`
|
|
156
|
+
file assumed to be within.
|
|
157
|
+
- (mostly internal use) `logFdcCommands`, `logFdcStateChanges` - turn on logging in the disc controller.
|
|
158
|
+
- `audioDebug=true` turns on some audio debug graphs.
|
|
159
|
+
|
|
160
|
+
## Patches
|
|
161
|
+
|
|
162
|
+
Patches can be applied by making a `patch=P` URL parameter. `P` is a sequence of semicolon-separated patches of the form
|
|
163
|
+
`@XXXX,YYYY:ZZZZZ,...` where the `@XXXX` specifies a PC address to breakpoint, the `YYYY` is the address to patch and
|
|
164
|
+
the `ZZZZ` is the data to write at address `YYYY`. The `@` part is optional, but is handy to ensure the code you want to
|
|
165
|
+
patch has actually loaded. For example: `patch=@31a6,0769:6e4c4d48465a` which is a patch for the default Elite image.
|
|
166
|
+
Once the PC has reached `$31a6`, the bytes at `0769` are replaced with `6e4c4d48465a`.
|
|
167
|
+
|
|
168
|
+
## Loading BASIC Files from GitHub Gists
|
|
169
|
+
|
|
170
|
+
1. Create a gist with your code. https://gist.github.com/ - here's
|
|
171
|
+
an [example](https://gist.github.com/mattgodbolt/fc8d6f3d6e5e015dce399013719c8341)
|
|
172
|
+
2. Get the "Raw" link by clicking "raw" and copying the URL. In the case above
|
|
173
|
+
that's: https://gist.githubusercontent.com/mattgodbolt/fc8d6f3d6e5e015dce399013719c8341/raw/bd5cb4314bfc3ee4330783ecf82cb329a36b915c/foo.bas
|
|
174
|
+
3. Add that after "https://bbc.xania.org/?autorun&loadBasic=" or similar, for
|
|
175
|
+
example, [this link](https://bbc.xania.org/?loadBasic=https://gist.githubusercontent.com/mattgodbolt/fc8d6f3d6e5e015dce399013719c8341/raw/bd5cb4314bfc3ee4330783ecf82cb329a36b915c/foo.bas&autorun)
|
|
176
|
+
|
|
177
|
+
Note that every update you make means you need to make a new raw link.
|
|
178
|
+
|
|
179
|
+
## Things Left to Do
|
|
180
|
+
|
|
181
|
+
If you're looking to help:
|
|
182
|
+
|
|
183
|
+
- Testing
|
|
184
|
+
- Play lots of games and report issues either on [GitHub](https://github.com/mattgodbolt/jsbeeb/issues) or by email (
|
|
185
|
+
matt@godbolt.org).
|
|
186
|
+
- Core
|
|
187
|
+
- Save state ability
|
|
188
|
+
- Once we have this I'd love to get some "reverse step" debugging support
|
|
189
|
+
- Get the "boo" of the boot "boo-beep" working (disabled currently as the JavaScript startup makes the sound
|
|
190
|
+
dreadfully choppy on Chrome at least).
|
|
191
|
+
- Save disc support
|
|
192
|
+
- Local discs need to be made more workable and need an "export" feature
|
|
193
|
+
- Multiple discs need a UI
|
|
194
|
+
- `git grep -i todo`
|
|
195
|
+
- Optimisation
|
|
196
|
+
- While every attempt to make things fast has been made, I'm sure there's some more clever things that can be done
|
|
197
|
+
without compromising emulation accuracy
|
|
198
|
+
|
|
199
|
+
## Tests
|
|
200
|
+
|
|
201
|
+
For general correctness, there are several tests in the `tests` directory, including:
|
|
202
|
+
|
|
203
|
+
- Klaus Dormann's exhaustive [test of all documented opcodes](https://github.com/Klaus2m5/6502_65C02_functional_tests)
|
|
204
|
+
for 6502 and 65C12. This is brought in as a git submodule from a forked version of Klaus's original as it needed a few
|
|
205
|
+
tweaks to get 65C12 working.
|
|
206
|
+
- hoglet's Binary Coded Decimal tests.
|
|
207
|
+
- @dp111's [timing tests](https://github.com/dp111/6502Timing). Also brought in as a git submodule.
|
|
208
|
+
- A public domain Commodore 64 6502 test suite which tests every 6502 opcode (documented or otherwise) for every
|
|
209
|
+
possible input and flags condition.
|
|
210
|
+
- Some tests by @scarybeasts testing VIA and 65C12 functionality.
|
|
211
|
+
|
|
212
|
+
For timing correctness, we have:
|
|
213
|
+
|
|
214
|
+
- A timing test program written by Rich. It has been run on a real live BBC B and the results are in the directory. An
|
|
215
|
+
SSD of the same tests is in the `discs/` directory.
|
|
216
|
+
- Some of Kevin Edwards' protection systems (stripped of the games themselves). These are extremely timing- and
|
|
217
|
+
correctness-sensitive when it comes to the timers and interrupts of the BBC.
|
|
218
|
+
- Some 65C12-specific read-modify-write tests written by Ed Spittles.
|
|
219
|
+
|
|
220
|
+
Tests can be run automatically if you have `node` installed - just run `make` and it'll ensure the relevant libraries
|
|
221
|
+
are installed, then it'll run the tests. Please note it can take a while to run the whole test suite.
|
|
222
|
+
|
|
223
|
+
## Thanks
|
|
224
|
+
|
|
225
|
+
jsbeeb was heavily based on Sarah Walker's C [B-Em emulator](https://github.com/stardot/b-em) -- thanks to her for her
|
|
226
|
+
hard work and for open sourcing her code. B-em is now being maintained by a group of enthusiasts - thanks to them too!
|
|
227
|
+
|
|
228
|
+
Huge thanks to Richard Talbot-Watkins for his advice and help along the way in fathoming out the instruction timings,
|
|
229
|
+
interrupt fun, video code rewrite and for being such a good pal all these many years!
|
|
230
|
+
|
|
231
|
+
Thanks to [Michael Borcherds](https://twitter.com/mike_geogebra) for his help; improving the keyboard layouts and
|
|
232
|
+
handling in JavaScript, reporting issues, chasing down game bugs and much more.
|
|
233
|
+
|
|
234
|
+
Thanks to [David Banks](https://github.com/hoglet67) (hoglet) for his help in testing the gnarly BCD flag behaviour on
|
|
235
|
+
real live BBCs.
|
|
236
|
+
|
|
237
|
+
Cheers to [Ed Spittles](https://github.com/BigEd) for testing various interrupt timing code on a real BBC.
|
|
238
|
+
|
|
239
|
+
Thanks to Chris Jordan for his thorough testing, bug reports, ideas and help.
|
|
240
|
+
|
|
241
|
+
A lot of the early development used the amazing [Visual 6502](http://visual6502.org/) as reference for intra-instruction
|
|
242
|
+
timings. Amazing stuff.
|
|
243
|
+
|
|
244
|
+
Special shout out to the users of the [6502 Forums](http://forum.6502.org/)
|
|
245
|
+
|
|
246
|
+
## More Information
|
|
247
|
+
|
|
248
|
+
I've written a lot about how the innards work on [my blog](http://xania.org) in
|
|
249
|
+
the [emulation](http://xania.org/Emulation-archive) section. I gave a presentation on how it all fits together at work,
|
|
250
|
+
and posted the [video up on YouTube](https://www.youtube.com/watch?v=37jyHQT7fXQ). I have another presentation at
|
|
251
|
+
[ABug](https://www.youtube.com/watch?v=ABmwJXMLzYM).
|
|
252
|
+
|
|
253
|
+
## License
|
|
254
|
+
|
|
255
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
256
|
+
|
|
257
|
+
## Contact
|
|
258
|
+
|
|
259
|
+
For support or questions, please contact Matt Godbolt at matt@godbolt.org.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Authentic PAL TV Comb Filter Research
|
|
2
|
+
|
|
3
|
+
## Sources
|
|
4
|
+
|
|
5
|
+
1. **Watkinson "Engineer's Guide to Decoding & Encoding"** (pages 37-39)
|
|
6
|
+
2. **Jim Easterbrook PAL Decoder Page** (https://www.jim-easterbrook.me.uk/pal/)
|
|
7
|
+
3. **Web search**: PAL television patents and implementations from 1980s
|
|
8
|
+
|
|
9
|
+
## What Real PAL TVs Used
|
|
10
|
+
|
|
11
|
+
### 2H Delay Line Comb Filters
|
|
12
|
+
|
|
13
|
+
**Implementation:**
|
|
14
|
+
|
|
15
|
+
- Used "64 microsecond quartz delay line" (2 line periods for PAL)
|
|
16
|
+
- Delays of **2H** (two horizontal line periods) for PAL
|
|
17
|
+
- Contrast with NTSC which uses 1H delays
|
|
18
|
+
|
|
19
|
+
**Why 2H for PAL?**
|
|
20
|
+
|
|
21
|
+
- PAL subcarrier: 283.75 cycles per line (fractional 0.75)
|
|
22
|
+
- 2H spacing = 1.5 cycles = 540° = **180° phase shift** (mod 360°)
|
|
23
|
+
- This ensures chroma signals are in opposite phase and cancel when added
|
|
24
|
+
- V-switch state is SAME on lines N and N±2 (both inverted or both non-inverted)
|
|
25
|
+
|
|
26
|
+
**From Watkinson (page 38):**
|
|
27
|
+
|
|
28
|
+
> "The delays needed are of one line period [for NTSC]. The configuration for PAL is shown in b) in which the delays need to be of two line periods."
|
|
29
|
+
|
|
30
|
+
### Complementary Decoder Approach
|
|
31
|
+
|
|
32
|
+
**From Jim Easterbrook:**
|
|
33
|
+
|
|
34
|
+
> "Some form of filter is used to extract the modulated chrominance from a PAL signal. Subtracting this chrominance from a suitably delayed PAL signal then yields luminance"
|
|
35
|
+
|
|
36
|
+
This is the **complementary decoder** principle:
|
|
37
|
+
|
|
38
|
+
1. Extract chroma from composite using a filter
|
|
39
|
+
2. Subtract extracted chroma from **delayed** composite to get luma
|
|
40
|
+
3. The decoder is "complementary" because chroma + luma = original PAL signal
|
|
41
|
+
|
|
42
|
+
**Important Note:**
|
|
43
|
+
|
|
44
|
+
> "Decoders like this are not widely used, as better subjective results can be obtained by using separate filters for chrominance and luminance, each optimised to give the best looking signals."
|
|
45
|
+
|
|
46
|
+
**This explains our findings!**
|
|
47
|
+
|
|
48
|
+
- Notch filter (complementary approach) is simpler but not what most TVs used
|
|
49
|
+
- Real TVs used separate optimized filters for chroma and luma
|
|
50
|
+
|
|
51
|
+
### Simple Line Comb for Luma (Most Common Approach)
|
|
52
|
+
|
|
53
|
+
**From Watkinson Figure 3.4.2b:**
|
|
54
|
+
|
|
55
|
+
- PAL comb uses 2H delays
|
|
56
|
+
- **Simple averaging:** Add current line + line delayed by 2H
|
|
57
|
+
- This is a LOWPASS filter for luma
|
|
58
|
+
- Chroma cancels due to 180° phase inversion
|
|
59
|
+
- Luma adds (in phase)
|
|
60
|
+
|
|
61
|
+
**Coefficients:**
|
|
62
|
+
|
|
63
|
+
- Simplest form: `luma = 0.5 * current + 0.5 * delayed_2H`
|
|
64
|
+
- 3-tap variation: `luma = 0.25 * prev_2H + 0.5 * current + 0.25 * next_2H`
|
|
65
|
+
|
|
66
|
+
### Tradeoffs and Limitations
|
|
67
|
+
|
|
68
|
+
**From Watkinson (page 38-39):**
|
|
69
|
+
|
|
70
|
+
> "Quite a lot of vertical luminance resolution is being lost, and becoming cross luminance, particularly in PAL."
|
|
71
|
+
|
|
72
|
+
**The fundamental tradeoff:**
|
|
73
|
+
|
|
74
|
+
- **More averaging** (comb filter) → Less cross-color, more vertical blur
|
|
75
|
+
- **Less averaging** (notch filter) → Sharper, but more cross-color/cross-luma artifacts
|
|
76
|
+
|
|
77
|
+
**Bandpass Comb Variation:**
|
|
78
|
+
|
|
79
|
+
> "Some of this resolution loss can be overcome by restricting the combing to a bandpass region"
|
|
80
|
+
|
|
81
|
+
This means applying the comb filter only to mid-frequencies where chroma lives, preserving low-frequency luma detail. However:
|
|
82
|
+
|
|
83
|
+
> "Although the full luminance bandwidth is available, this is restricted to picture detail having vertical edges. Man-made subjects such as buildings give good results, but more natural scenes containing diagonal edges are less successful."
|
|
84
|
+
|
|
85
|
+
### BBC Transform Decoder (Advanced)
|
|
86
|
+
|
|
87
|
+
**Not a comb filter!** Uses Fourier transforms:
|
|
88
|
+
|
|
89
|
+
> "Each frequency in the block is compared with its reflection about the colour sub-carrier frequency, and if the magnitudes are too dissimilar the pair of frequencies is rejected."
|
|
90
|
+
|
|
91
|
+
This is much more sophisticated than simple comb filters and not what consumer TVs used.
|
|
92
|
+
|
|
93
|
+
## Summary for Implementation
|
|
94
|
+
|
|
95
|
+
### What Consumer PAL TVs Actually Did:
|
|
96
|
+
|
|
97
|
+
1. **Most common:** Simple 2H comb filter for luma
|
|
98
|
+
- Average current line with line ±2H away
|
|
99
|
+
- Coefficients: 0.5 + 0.5 (or 0.25 + 0.5 + 0.25 for 3-tap)
|
|
100
|
+
- Accept vertical blur as tradeoff for reduced color artifacts
|
|
101
|
+
|
|
102
|
+
2. **Some higher-end:** Separate optimized filters
|
|
103
|
+
- Not pure complementary decoder
|
|
104
|
+
- Custom filters for chroma and luma
|
|
105
|
+
- Try to balance sharpness vs artifacts
|
|
106
|
+
|
|
107
|
+
3. **Not common:** Pure notch/complementary decoders
|
|
108
|
+
- Simpler but gave worse subjective results
|
|
109
|
+
- Used in some early/cheap implementations
|
|
110
|
+
|
|
111
|
+
### What We Should Simulate:
|
|
112
|
+
|
|
113
|
+
**Option 1: Authentic simple comb (most TVs)**
|
|
114
|
+
|
|
115
|
+
- Use 2H comb with equal weighting: `luma = 0.5 * current + 0.5 * delayed_2H`
|
|
116
|
+
- Accept some vertical blur (that's what real TVs had!)
|
|
117
|
+
- Minimal checkerboard/cross-color
|
|
118
|
+
|
|
119
|
+
**Option 2: Notch filter (current implementation)**
|
|
120
|
+
|
|
121
|
+
- Sharper than real TVs
|
|
122
|
+
- But with FIR_GAIN = 2.0, no checkerboard
|
|
123
|
+
- Arguably "better" than real hardware, but less authentic
|
|
124
|
+
|
|
125
|
+
**Recommendation:**
|
|
126
|
+
Implement the simple 2H comb as an option so users can choose between:
|
|
127
|
+
|
|
128
|
+
- "Sharp mode" (notch filter - better than real hardware)
|
|
129
|
+
- "Authentic mode" (2H comb - what TVs actually did, with appropriate blur)
|