├── .editorconfig ├── .gitignore ├── .gitmodules ├── .npmignore ├── .travis.yml ├── API.md ├── README.md ├── exports.json ├── fixtures └── roms │ ├── 01-special.gb │ ├── 02-interrupts.gb │ ├── 03-op sp,hl.gb │ ├── 04-op r,imm.gb │ ├── 05-op rp.gb │ ├── 06-ld r,r.gb │ ├── 07-jr,jp,call,ret,rst.gb │ ├── 08-misc instrs.gb │ ├── 09-op r,r.gb │ ├── 10-bit ops.gb │ ├── 11-op a,(hl).gb │ ├── 5200 Menu (USA) (Proto).a52 │ ├── CMC80s.NES │ ├── CMCWavy.NES │ ├── Calc Plus (USA) (Program).bin │ ├── Checkers (USA).bin │ ├── Computer Golf (USA).bin │ ├── Dithering.NES │ ├── FDSPic.NES │ ├── Flame.nes │ ├── GENIE.NES │ ├── GameGenie.NES │ ├── Greys.NES │ ├── Interlace1.NES │ ├── Interlace2.NES │ ├── Interlace3.NES │ ├── Jump Bug (Europe).bin │ ├── LINUSMUS.NES │ ├── Mandelbrot.NES │ ├── Moby2.NES │ ├── Motion.NES │ ├── NESA.NES │ ├── NESA_TimesofLore.NES │ ├── Nigaoe Artist (Japan).bin │ ├── PALTEST.NES │ ├── Pachinko-UFO (Japan).bin │ ├── Pacman.bin │ ├── PolarPinwheel.NES │ ├── PolarPop.NES │ ├── PolarRot1.NES │ ├── PolarRot21.NES │ ├── PolarRot79.NES │ ├── PolarRot8.NES │ ├── RGB.NES │ ├── SCROLL.NES │ ├── SNDTEST.NES │ ├── SOUND.NES │ ├── Sango Fighter (Taiwan).bin │ ├── SolarWars.NES │ ├── SolarWarsSilent.NES │ ├── Space Force (USA, Europe).bin │ ├── Spongebob Schwammkopf - Der Tag des Schwamms (Germany) (Rev 2).bin │ ├── StarsSE.NES │ ├── Super Soccer (Europe).bin │ ├── Urban Champion (Germany).bin │ ├── cpu_instrs.gb │ ├── cpu_test.gbc │ ├── opus5.gb │ ├── testRom1.gb │ ├── testRom2.gb │ └── ttt.gb ├── mime.json ├── package.json ├── retro.idl ├── retro.js ├── runtime_exports.json ├── script ├── add-repo ├── bootstrap ├── build ├── build-core ├── clean ├── publish └── rm-repo ├── shell.js ├── test.js ├── test.json └── types.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.js] 8 | indent_style = space 9 | indent_size = 2 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.bc 2 | *.o 3 | node_modules 4 | npm-debug.log 5 | jspm_packages 6 | pkg 7 | config.js 8 | coverage 9 | .nyc_output 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | # 2 | # All of the following work fine. 3 | # 4 | [submodule "gambatte"] 5 | path = core/gambatte 6 | url = https://github.com/matthewbauer/gambatte-libretro.git 7 | branch = emscripten 8 | [submodule "snes9x-next"] 9 | path = core/snes9x-next 10 | url = https://github.com/matthewbauer/snes9x-next.git 11 | [submodule "vba-next"] 12 | path = core/vba-next 13 | url = https://github.com/matthewbauer/vba-next.git 14 | [submodule "vecx"] 15 | path = core/vecx 16 | url = https://github.com/matthewbauer/libretro-vecx.git 17 | [submodule "gw"] 18 | path = core/gw 19 | url = https://github.com/matthewbauer/gw-libretro.git 20 | [submodule "stella"] 21 | path = core/stella 22 | url = https://github.com/matthewbauer/stella-libretro.git 23 | [submodule "nestopia"] 24 | path = core/nestopia 25 | url = https://github.com/matthewbauer/nestopia.git 26 | branch = emscripten 27 | [submodule "mupen64plus"] 28 | path = core/mupen64plus 29 | url = https://github.com/matthewbauer/mupen64plus-libretro.git 30 | branch = emscripten 31 | [submodule "picodrive"] 32 | path = core/picodrive 33 | url = https://github.com/matthewbauer/picodrive.git 34 | branch = emscripten 35 | [submodule "virtualjaguar"] 36 | path = core/virtualjaguar 37 | url = https://github.com/matthewbauer/virtualjaguar-libretro.git 38 | [submodule "prosystem"] 39 | path = core/prosystem 40 | url = https://github.com/matthewbauer/prosystem-libretro.git 41 | branch = emscripten 42 | #[submodule "mame"] 43 | # path = core/mame 44 | # url = https://github.com/libretro/mame.git 45 | [submodule "fmsx"] 46 | path = core/fmsx 47 | url = https://github.com/libretro/fmsx-libretro.git 48 | [submodule "quicknes"] 49 | path = core/quicknes 50 | url = https://github.com/matthewbauer/QuickNES_Core.git 51 | branch = emscripten 52 | 53 | # 54 | # Maybe someday... 55 | # 56 | [submodule "dosbox"] 57 | path = core/dosbox 58 | url = https://github.com/matthewbauer/dosbox-libretro.git 59 | [submodule "desmume"] 60 | path = core/desmume 61 | url = https://github.com/matthewbauer/desmume.git 62 | [submodule "ppsspp"] 63 | path = core/ppsspp 64 | url = https://github.com/matthewbauer/libretro-ppsspp.git 65 | [submodule "pcsx1"] 66 | path = core/pcsx1 67 | url = https://github.com/matthewbauer/pcsx1-libretro.git 68 | [submodule "81"] 69 | path = core/81 70 | url = https://github.com/matthewbauer/81-libretro.git 71 | [submodule "tyrquake"] 72 | path = core/tyrquake 73 | url = https://github.com/matthewbauer/tyrquake.git 74 | [submodule "prboom"] 75 | path = core/prboom 76 | url = https://github.com/matthewbauer/libretro-prboom.git 77 | [submodule "handy"] 78 | path = core/handy 79 | url = https://github.com/matthewbauer/handy-libretro.git 80 | [submodule "4do"] 81 | path = core/4do 82 | url = https://github.com/matthewbauer/4do-libretro.git 83 | [submodule "fba"] 84 | path = core/fba 85 | url = https://github.com/matthewbauer/libretro-fba.git 86 | [submodule "o2em"] 87 | path = core/o2em 88 | url = https://github.com/matthewbauer/libretro-o2em.git 89 | #[submodule "wswan"] 90 | # path = core/wswan 91 | # url = https://github.com/libretro/beetle-wswan-libretro.git 92 | 93 | # 94 | # These emulate the same platforms as a working core 95 | # 96 | [submodule "catsfc"] 97 | path = core/catsfc 98 | url = https://github.com/matthewbauer/CATSFC-libretro.git 99 | [submodule "snes9x"] 100 | path = core/snes9x 101 | url = https://github.com/snes9xgit/snes9x.git 102 | [submodule "pocketsnes"] 103 | path = core/pocketsnes 104 | url = https://github.com/matthewbauer/pocketsnes-libretro.git 105 | [submodule "vbam"] 106 | path = core/vbam 107 | url = https://github.com/matthewbauer/vbam-libretro.git 108 | [submodule "bsnes"] 109 | path = core/bsnes 110 | url = https://github.com/matthewbauer/bsnes-libretro.git 111 | [submodule "bsnes-mercury"] 112 | path = core/bsnes-mercury 113 | url = https://github.com/matthewbauer/bsnes-mercury.git 114 | [submodule "meteor"] 115 | path = core/meteor 116 | url = https://github.com/matthewbauer/meteor-libretro.git 117 | [submodule "genesis-plus-gx"] 118 | path = core/genesis-plus-gx 119 | url = https://github.com/matthewbauer/Genesis-Plus-GX.git 120 | [submodule "blueMSX"] 121 | path = core/blueMSX 122 | url = https://github.com/matthewbauer/blueMSX-libretro.git 123 | [submodule "fceumm"] 124 | path = core/fceumm 125 | url = https://github.com/libretro/libretro-fceumm.git 126 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !retro.js 3 | !core.js 4 | !package.json 5 | !.npmignore 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: false 3 | node_js: 4 | - '5.0' 5 | env: 6 | matrix: 7 | - CORE=snes9x-next 8 | - CORE=vba-next 9 | - CORE=gambatte 10 | - CORE=nestopia 11 | - CORE=stella 12 | - CORE=prosystem 13 | global: 14 | secure: A12Crb+3gA2IIyHYUogzLXjfnBSigUGMnYqnuANkf8Qe6PHvk96Kda91NMX/hhyn9eeh1mptWlmjAaxcrBtgSSxHSHhAJdebkUcVDJyV0PmwcGuGMICEU4BC0FhhZQxLY6ig0Yk8laUZd95nX6K+UwoLEldb8JIOGHF5822bQEEBpIx6Z0v5Hg4BR7aK3C+ji5JYON+pzYFqIuB3Gn3dFnUe5uSGPMP3a9XfFx4QSuULucl2nbEGFR30YWn89wbZ9fiYTVbIQeqyGSOpxa5U42VFWLil76Yq8WeBc4t7QBEzIcPx2iTENyk6EO1Mp0daNKmTCWAXhP/yCzrWW1PM5IslLoVJq6flsmohdFl3EzSwZeY3kGvMJEFTrH8Mt2qt8MUeNjQ1GuhNpLET9ziz77e9e2oemtm40M+xRUM5r3wDaTOGisiuUBt+cnWsNJYSMcjieXxbKUCWXCr838C55zNNOUTntxLnbSDH3dYfhBv3wWJb2Jd4bvo2tgw7sBwmxqvZKDyNgIvrwOL2PDaC50+AT3njObhY21nVtM+LG5F1sFIiNEdxQZM0TPxCQ5LpsYKpmXPzFXZTERnlyECorkBVlNeU6Tg1YQEJCR19aJCKGyh6p/y+47jFmO2tu57xhn4a5wcH6R6B1KdLrsHIX3/w4jtwAYRcm9Xg6NKrLrw= 15 | addons: 16 | apt: 17 | sources: 18 | - ubuntu-toolchain-r-test 19 | packages: 20 | - cmake 21 | - g++-4.9 22 | git: 23 | submodules: false 24 | before_script: 25 | - git clone https://github.com/matthewbauer/emscripten-sdk.git && emscripten-sdk/emsdk 26 | activate --build=Release sdk-incoming-64bit && source emscripten-sdk/emsdk_env.sh 27 | && export EMSCRIPTEN_ROOT_PATH=$EMSCRIPTEN && export EMSCRIPTEN=1 28 | before_install: 29 | - git submodule update --init core/$CORE 30 | script: 31 | - sh ./script/build-core core/$CORE 32 | - npm test 33 | after_success: 34 | - npm run publish -- $CORE 35 | -------------------------------------------------------------------------------- /API.md: -------------------------------------------------------------------------------- 1 | # API 2 | 3 | This will document how a module can implement the RetroJS API. It is heavily based on the libretro API with some tweaks to get rid of pointers. 4 | 5 | ## Additional Info 6 | 7 | Please refer to the [libretro.h](https://github.com/libretro/RetroArch/blob/master/libretro.h) file for more info on this. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # retrojs 2 | 3 | This project compiles some libretro projects into nice CommonJS modules using Emscripten. 4 | 5 | ## Building 6 | To build, you will need to have Node and Emscripten installed and run the following: 7 | 8 | ```sh 9 | git clone --recursive https://github.com/matthewbauer/retrojs.git 10 | cd retrojs 11 | npm install 12 | npm run build 13 | ``` 14 | 15 | ## Testing 16 | To run the tests from node: 17 | ``` 18 | npm test 19 | ``` 20 | 21 | The test file test.html can be loaded in the browser to run after index.js files have been built. 22 | 23 | ## Cores 24 | These cores seem to work and are available from NPM: 25 | 26 | * snes9x-next 27 | * gambatte 28 | * vba-next 29 | * nestopia 30 | * gw 31 | * vecx 32 | * picodrive (still very broken) 33 | * virtualjaguar (still very broken) 34 | * mupen64plus (still very broken) 35 | 36 | ## API 37 | The API closely follows libretro.h with pointers converted into Javascript objects to abstract Emscripten memory. 38 | 39 | * init 40 | * deinit 41 | * api_version 42 | * reset 43 | * run 44 | * unload_game 45 | * get_region 46 | * cheat_reset 47 | * get_memory_size 48 | * serialize_size 49 | * set_controller_port_device 50 | * get_system_info 51 | * get_system_av_info 52 | * serialize 53 | * unserialize 54 | * load_game 55 | * load_game_special 56 | * get_memory_data 57 | * set_audio_sample_batch 58 | * set_video_refresh 59 | * set_audio_sample 60 | * set_environment 61 | * set_input_state 62 | * set_input_poll 63 | 64 | Constants are exporeted as well. They are currently set to the 65 | -------------------------------------------------------------------------------- /exports.json: -------------------------------------------------------------------------------- 1 | [ 2 | "_malloc", 3 | "_free", 4 | "_retro_api_version", 5 | "_retro_cheat_reset", 6 | "_retro_cheat_set", 7 | "_retro_deinit", 8 | "_retro_get_memory_data", 9 | "_retro_get_memory_size", 10 | "_retro_get_region", 11 | "_retro_get_system_av_info", 12 | "_retro_get_system_info", 13 | "_retro_init", 14 | "_retro_load_game_special", 15 | "_retro_load_game", 16 | "_retro_reset", 17 | "_retro_run", 18 | "_retro_serialize_size", 19 | "_retro_serialize", 20 | "_retro_set_audio_sample_batch", 21 | "_retro_set_audio_sample", 22 | "_retro_set_controller_port_device", 23 | "_retro_set_environment", 24 | "_retro_set_input_poll", 25 | "_retro_set_input_state", 26 | "_retro_set_video_refresh", 27 | "_retro_unload_game", 28 | "_retro_unserialize" 29 | ] 30 | -------------------------------------------------------------------------------- /fixtures/roms/01-special.gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/01-special.gb -------------------------------------------------------------------------------- /fixtures/roms/02-interrupts.gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/02-interrupts.gb -------------------------------------------------------------------------------- /fixtures/roms/03-op sp,hl.gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/03-op sp,hl.gb -------------------------------------------------------------------------------- /fixtures/roms/04-op r,imm.gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/04-op r,imm.gb -------------------------------------------------------------------------------- /fixtures/roms/05-op rp.gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/05-op rp.gb -------------------------------------------------------------------------------- /fixtures/roms/06-ld r,r.gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/06-ld r,r.gb -------------------------------------------------------------------------------- /fixtures/roms/07-jr,jp,call,ret,rst.gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/07-jr,jp,call,ret,rst.gb -------------------------------------------------------------------------------- /fixtures/roms/08-misc instrs.gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/08-misc instrs.gb -------------------------------------------------------------------------------- /fixtures/roms/09-op r,r.gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/09-op r,r.gb -------------------------------------------------------------------------------- /fixtures/roms/10-bit ops.gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/10-bit ops.gb -------------------------------------------------------------------------------- /fixtures/roms/11-op a,(hl).gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/11-op a,(hl).gb -------------------------------------------------------------------------------- /fixtures/roms/5200 Menu (USA) (Proto).a52: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/5200 Menu (USA) (Proto).a52 -------------------------------------------------------------------------------- /fixtures/roms/CMC80s.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/CMC80s.NES -------------------------------------------------------------------------------- /fixtures/roms/CMCWavy.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/CMCWavy.NES -------------------------------------------------------------------------------- /fixtures/roms/Calc Plus (USA) (Program).bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Calc Plus (USA) (Program).bin -------------------------------------------------------------------------------- /fixtures/roms/Checkers (USA).bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Checkers (USA).bin -------------------------------------------------------------------------------- /fixtures/roms/Computer Golf (USA).bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Computer Golf (USA).bin -------------------------------------------------------------------------------- /fixtures/roms/Dithering.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Dithering.NES -------------------------------------------------------------------------------- /fixtures/roms/FDSPic.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/FDSPic.NES -------------------------------------------------------------------------------- /fixtures/roms/Flame.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Flame.nes -------------------------------------------------------------------------------- /fixtures/roms/GENIE.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/GENIE.NES -------------------------------------------------------------------------------- /fixtures/roms/GameGenie.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/GameGenie.NES -------------------------------------------------------------------------------- /fixtures/roms/Greys.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Greys.NES -------------------------------------------------------------------------------- /fixtures/roms/Interlace1.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Interlace1.NES -------------------------------------------------------------------------------- /fixtures/roms/Interlace2.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Interlace2.NES -------------------------------------------------------------------------------- /fixtures/roms/Interlace3.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Interlace3.NES -------------------------------------------------------------------------------- /fixtures/roms/Jump Bug (Europe).bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Jump Bug (Europe).bin -------------------------------------------------------------------------------- /fixtures/roms/LINUSMUS.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/LINUSMUS.NES -------------------------------------------------------------------------------- /fixtures/roms/Mandelbrot.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Mandelbrot.NES -------------------------------------------------------------------------------- /fixtures/roms/Moby2.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Moby2.NES -------------------------------------------------------------------------------- /fixtures/roms/Motion.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Motion.NES -------------------------------------------------------------------------------- /fixtures/roms/NESA.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/NESA.NES -------------------------------------------------------------------------------- /fixtures/roms/NESA_TimesofLore.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/NESA_TimesofLore.NES -------------------------------------------------------------------------------- /fixtures/roms/Nigaoe Artist (Japan).bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Nigaoe Artist (Japan).bin -------------------------------------------------------------------------------- /fixtures/roms/PALTEST.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/PALTEST.NES -------------------------------------------------------------------------------- /fixtures/roms/Pachinko-UFO (Japan).bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Pachinko-UFO (Japan).bin -------------------------------------------------------------------------------- /fixtures/roms/Pacman.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Pacman.bin -------------------------------------------------------------------------------- /fixtures/roms/PolarPinwheel.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/PolarPinwheel.NES -------------------------------------------------------------------------------- /fixtures/roms/PolarPop.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/PolarPop.NES -------------------------------------------------------------------------------- /fixtures/roms/PolarRot1.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/PolarRot1.NES -------------------------------------------------------------------------------- /fixtures/roms/PolarRot21.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/PolarRot21.NES -------------------------------------------------------------------------------- /fixtures/roms/PolarRot79.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/PolarRot79.NES -------------------------------------------------------------------------------- /fixtures/roms/PolarRot8.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/PolarRot8.NES -------------------------------------------------------------------------------- /fixtures/roms/RGB.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/RGB.NES -------------------------------------------------------------------------------- /fixtures/roms/SCROLL.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/SCROLL.NES -------------------------------------------------------------------------------- /fixtures/roms/SNDTEST.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/SNDTEST.NES -------------------------------------------------------------------------------- /fixtures/roms/SOUND.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/SOUND.NES -------------------------------------------------------------------------------- /fixtures/roms/Sango Fighter (Taiwan).bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Sango Fighter (Taiwan).bin -------------------------------------------------------------------------------- /fixtures/roms/SolarWars.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/SolarWars.NES -------------------------------------------------------------------------------- /fixtures/roms/SolarWarsSilent.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/SolarWarsSilent.NES -------------------------------------------------------------------------------- /fixtures/roms/Space Force (USA, Europe).bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Space Force (USA, Europe).bin -------------------------------------------------------------------------------- /fixtures/roms/Spongebob Schwammkopf - Der Tag des Schwamms (Germany) (Rev 2).bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Spongebob Schwammkopf - Der Tag des Schwamms (Germany) (Rev 2).bin -------------------------------------------------------------------------------- /fixtures/roms/StarsSE.NES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/StarsSE.NES -------------------------------------------------------------------------------- /fixtures/roms/Super Soccer (Europe).bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Super Soccer (Europe).bin -------------------------------------------------------------------------------- /fixtures/roms/Urban Champion (Germany).bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/Urban Champion (Germany).bin -------------------------------------------------------------------------------- /fixtures/roms/cpu_instrs.gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/cpu_instrs.gb -------------------------------------------------------------------------------- /fixtures/roms/cpu_test.gbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/cpu_test.gbc -------------------------------------------------------------------------------- /fixtures/roms/opus5.gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/opus5.gb -------------------------------------------------------------------------------- /fixtures/roms/testRom1.gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/testRom1.gb -------------------------------------------------------------------------------- /fixtures/roms/testRom2.gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/testRom2.gb -------------------------------------------------------------------------------- /fixtures/roms/ttt.gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewbauer/retrojs/b2327d39c2a0344b368d3a809770bb6ffd226023/fixtures/roms/ttt.gb -------------------------------------------------------------------------------- /mime.json: -------------------------------------------------------------------------------- 1 | { 2 | "mx1": "application/vnd.microsoft.msx.rom", 3 | "mx2": "application/vnd.microsoft.msx2.rom", 4 | "cpc": "application/vnd.amstrad.cpc.rom", 5 | "nes": "application/vnd.nintendo.nes.rom", 6 | "fds": "application/vnd.nintendo.fds.rom", 7 | "gb": "application/vnd.nintendo.gameboy.rom", 8 | "gbc": "application/vnd.nintendo.gbc.rom", 9 | "mgw": "application/vnd.nintendo.gw.rom", 10 | "lnx": "application/vnd.atari.lynx.rom", 11 | "st": "application/vnd.atari.st.rom", 12 | "stx": "application/vnd.atari.st.rom", 13 | "gen": "application/vnd.sega.genesis.rom", 14 | "smd": "application/vnd.sega.megadrive.rom", 15 | "md": "application/vnd.sega.megadrive.rom", 16 | "sms": "application/vnd.sega.mastersystem.rom", 17 | "smc": "application/vnd.nintendo.snes.rom", 18 | "sfc": "application/vnd.nintendo.snes.rom", 19 | "swc": "application/vnd.nintendo.snes.rom", 20 | "nds": "application/vnd.nintendo.ds.rom", 21 | "uae": "application/vnd.commodore.amiga.rom", 22 | "adf": "application/vnd.commodore.amiga.rom", 23 | "ipf": "application/vnd.commodore.amiga.rom", 24 | "dms": "application/vnd.commodore.amiga.rom", 25 | "gba": "application/vnd.nintendo.gba.rom", 26 | "vec": "application/vnd.smith.vectrex.rom", 27 | "n64": "application/vnd.nintendo.64.rom", 28 | "z64": "application/vnd.nintendo.64.rom", 29 | "u64": "application/vnd.nintendo.64.rom", 30 | "v64": "application/vnd.nintendo.64.rom", 31 | "gcm": "application/vnd.nintendo.gamecube.rom", 32 | "wdf": "application/vnd.nintendo.wii.rom", 33 | "z80": "application/vnd.sinclair.zxspectrum.rom", 34 | "a26": "application/vnd.atari.2600.rom", 35 | "a52": "application/vnd.atari.5200.rom", 36 | "a78": "applicatoin/vnd.atari.7800.rom", 37 | "d64": "application/vnd.commodore.64.rom", 38 | "g64": "application/vnd.commodore.64.rom", 39 | "t64": "application/vnd.commodore.64.rom", 40 | "x64": "application/vnd.commodore.64.rom", 41 | "adf": "application/vnd.commodore.64.rom", 42 | "int": "application/vnd.matell.intellivision.rom", 43 | "ngp": "application/vnd.snk.neogeo.rom", 44 | "ngc": "application/vnd.snk.neogeo.rom" 45 | } 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "jspm": { 3 | "dependencies": { 4 | "chai": "npm:chai@^3.0.0", 5 | "fs": "github:jspm/nodelibs-fs@^0.1.2", 6 | "json": "github:systemjs/plugin-json@^0.1.0", 7 | "mocha": "npm:mocha@^2.2.5", 8 | "raw": "github:matthewbauer/plugin-raw@^0.3.1" 9 | }, 10 | "devDependencies": { 11 | "babel": "npm:babel-core@^5.8.24", 12 | "babel-runtime": "npm:babel-runtime@^5.8.24", 13 | "core-js": "npm:core-js@^1.1.4", 14 | "traceur": "github:jmcriffey/bower-traceur@0.0.91", 15 | "traceur-runtime": "github:jmcriffey/bower-traceur-runtime@0.0.91" 16 | } 17 | }, 18 | "devDependencies": { 19 | "ava": "*", 20 | "denodeify": "^1.2.1", 21 | "jspm": "^0.16.25", 22 | "npm": "^3.6.0", 23 | "nyc": "^5.5.0" 24 | }, 25 | "scripts": { 26 | "test": "nyc ava test.js", 27 | "build": "sh ./script/build", 28 | "publish": "node ./script/publish", 29 | "install": "jspm install -y" 30 | }, 31 | "nyc": { 32 | "exclude": [ 33 | "core/*/core.js" 34 | ] 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /retro.idl: -------------------------------------------------------------------------------- 1 | interface Core { 2 | void init(); 3 | void deinit(); 4 | void set_environment(callback cb); 5 | void set_video_refresh(video_refresh_t cb); 6 | void set_audio_sample(audio_sample_t arg); 7 | void set_audio_sample_batch(audio_sample_batch_t cb); 8 | void set_input_poll(input_poll_t cb); 9 | void set_input_state(input_state_t cb); 10 | unsigned long long api_version(); 11 | void get_system_info(system_info info); 12 | void get_system_av_info(system_av_info info); 13 | void set_controller_port_device(unsigned long device, unsigned long port); 14 | void reset(); 15 | void run(); 16 | unsigned long long serialize_size(); 17 | bool serialize(unsigned long size); 18 | bool unserialize(unsigned long size); 19 | void cheat_reset(); 20 | void cheat_set(char code, bool enabled, unsigned long index); 21 | bool load_game(game_info game); 22 | bool load_game_special(unsigned long num_info, game_info info, unsigned long game_type); 23 | void unload_game(); 24 | unsigned long long get_region(); 25 | void get_memory_data(unsigned long id); 26 | unsigned long long get_memory_size(unsigned long id); 27 | }; 28 | 29 | interface Language { 30 | const long LANGUAGE_CHINESE_SIMPLIFIED = 11; 31 | const long LANGUAGE_CHINESE_TRADITIONAL = 10; 32 | const long LANGUAGE_KOREAN = 9; 33 | const long LANGUAGE_RUSSIAN = 8; 34 | const long LANGUAGE_PORTUGUESE = 7; 35 | const long LANGUAGE_DUTCH = 6; 36 | const long LANGUAGE_ITALIAN = 5; 37 | const long LANGUAGE_GERMAN = 4; 38 | const long LANGUAGE_SPANISH = 3; 39 | const long LANGUAGE_FRENCH = 2; 40 | const long LANGUAGE_JAPANESE = 1; 41 | const long LANGUAGE_ENGLISH = 0; 42 | }; 43 | 44 | interface Key { 45 | const long K_UNDO = 322; 46 | const long K_EURO = 321; 47 | const long K_POWER = 320; 48 | const long K_MENU = 319; 49 | const long K_BREAK = 318; 50 | const long K_SYSREQ = 317; 51 | const long K_PRINT = 316; 52 | const long K_HELP = 315; 53 | const long K_COMPOSE = 314; 54 | const long K_MODE = 313; 55 | const long K_RSUPER = 312; 56 | const long K_LSUPER = 311; 57 | const long K_LMETA = 310; 58 | const long K_RMETA = 309; 59 | const long K_LALT = 308; 60 | const long K_RALT = 307; 61 | const long K_LCTRL = 306; 62 | const long K_RCTRL = 305; 63 | const long K_LSHIFT = 304; 64 | const long K_RSHIFT = 303; 65 | const long K_SCROLLOCK = 302; 66 | const long K_CAPSLOCK = 301; 67 | const long K_NUMLOCK = 300; 68 | const long K_F15 = 296; 69 | const long K_F14 = 295; 70 | const long K_F13 = 294; 71 | const long K_F12 = 293; 72 | const long K_F11 = 292; 73 | const long K_F10 = 291; 74 | const long K_F9 = 290; 75 | const long K_F8 = 289; 76 | const long K_F7 = 288; 77 | const long K_F6 = 287; 78 | const long K_F5 = 286; 79 | const long K_F4 = 285; 80 | const long K_F3 = 284; 81 | const long K_F2 = 283; 82 | const long K_F1 = 282; 83 | const long K_PAGEDOWN = 281; 84 | const long K_PAGEUP = 280; 85 | const long K_END = 279; 86 | const long K_HOME = 278; 87 | const long K_INSERT = 277; 88 | const long K_LEFT = 276; 89 | const long K_RIGHT = 275; 90 | const long K_DOWN = 274; 91 | const long K_UP = 273; 92 | const long K_KP_EQUALS = 272; 93 | const long K_KP_ENTER = 271; 94 | const long K_KP_PLUS = 270; 95 | const long K_KP_MINUS = 269; 96 | const long K_KP_MULTIPLY = 268; 97 | const long K_KP_DIVIDE = 267; 98 | const long K_KP_PERIOD = 266; 99 | const long K_KP9 = 265; 100 | const long K_KP8 = 264; 101 | const long K_KP7 = 263; 102 | const long K_KP6 = 262; 103 | const long K_KP5 = 261; 104 | const long K_KP4 = 260; 105 | const long K_KP3 = 259; 106 | const long K_KP2 = 258; 107 | const long K_KP1 = 257; 108 | const long K_KP0 = 256; 109 | const long K_DELETE = 127; 110 | const long K_z = 122; 111 | const long K_y = 121; 112 | const long K_x = 120; 113 | const long K_w = 119; 114 | const long K_v = 118; 115 | const long K_u = 117; 116 | const long K_t = 116; 117 | const long K_s = 115; 118 | const long K_r = 114; 119 | const long K_q = 113; 120 | const long K_p = 112; 121 | const long K_o = 111; 122 | const long K_n = 110; 123 | const long K_m = 109; 124 | const long K_l = 108; 125 | const long K_k = 107; 126 | const long K_j = 106; 127 | const long K_i = 105; 128 | const long K_h = 104; 129 | const long K_g = 103; 130 | const long K_f = 102; 131 | const long K_e = 101; 132 | const long K_d = 100; 133 | const long K_c = 99; 134 | const long K_b = 98; 135 | const long K_a = 97; 136 | const long K_BACKQUOTE = 96; 137 | const long K_UNDERSCORE = 95; 138 | const long K_CARET = 94; 139 | const long K_RIGHTBRACKET = 93; 140 | const long K_BACKSLASH = 92; 141 | const long K_LEFTBRACKET = 91; 142 | const long K_AT = 64; 143 | const long K_QUESTION = 63; 144 | const long K_GREATER = 62; 145 | const long K_EQUALS = 61; 146 | const long K_LESS = 60; 147 | const long K_SEMICOLON = 59; 148 | const long K_COLON = 58; 149 | const long K_9 = 57; 150 | const long K_8 = 56; 151 | const long K_7 = 55; 152 | const long K_6 = 54; 153 | const long K_5 = 53; 154 | const long K_4 = 52; 155 | const long K_3 = 51; 156 | const long K_2 = 50; 157 | const long K_1 = 49; 158 | const long K_0 = 48; 159 | const long K_SLASH = 47; 160 | const long K_PERIOD = 46; 161 | const long K_MINUS = 45; 162 | const long K_COMMA = 44; 163 | const long K_PLUS = 43; 164 | const long K_ASTERISK = 42; 165 | const long K_RIGHTPAREN = 41; 166 | const long K_LEFTPAREN = 40; 167 | const long K_QUOTE = 39; 168 | const long K_AMPERSAND = 38; 169 | const long K_DOLLAR = 36; 170 | const long K_HASH = 35; 171 | const long K_QUOTEDBL = 34; 172 | const long K_EXCLAIM = 33; 173 | const long K_SPACE = 32; 174 | const long K_ESCAPE = 27; 175 | const long K_PAUSE = 19; 176 | const long K_RETURN = 13; 177 | const long K_CLEAR = 12; 178 | const long K_TAB = 9; 179 | const long K_BACKSPACE = 8; 180 | const long K_UNKNOWN = 0; 181 | const long K_FIRST = 0; 182 | }; 183 | 184 | interface mod { 185 | const long KMOD_SCROLLOCK = 64; 186 | const long KMOD_CAPSLOCK = 32; 187 | const long KMOD_NUMLOCK = 16; 188 | const long KMOD_META = 8; 189 | const long KMOD_ALT = 4; 190 | const long KMOD_CTRL = 2; 191 | const long KMOD_SHIFT = 1; 192 | const long KMOD_NONE = 0; 193 | }; 194 | 195 | interface log_level { 196 | const long LOG_DEBUG = 0; 197 | const long LOG_INFO = 1; 198 | const long LOG_WARN = 2; 199 | const long LOG_ERROR = 3; 200 | }; 201 | 202 | interface sensor_action { 203 | const long SENSOR_ACCELEROMETER_ENABLE = 0; 204 | const long SENSOR_ACCELEROMETER_DISABLE = 1; 205 | }; 206 | 207 | interface camera_buffer { 208 | const long CAMERA_BUFFER_OPENGL_TEXTURE = 0; 209 | const long CAMERA_BUFFER_RAW_FRAMEBUFFER = 1; 210 | }; 211 | 212 | interface rumble_effect { 213 | const long RUMBLE_STRONG = 0; 214 | const long RUMBLE_WEAK = 1; 215 | }; 216 | 217 | interface hw_context_type { 218 | const long HW_CONTEXT_OPENGLES_VERSION = 5; 219 | const long HW_CONTEXT_OPENGLES3 = 4; 220 | const long HW_CONTEXT_OPENGL_CORE = 3; 221 | const long HW_CONTEXT_OPENGLES2 = 2; 222 | const long HW_CONTEXT_OPENGL = 1; 223 | const long HW_CONTEXT_NONE = 0; 224 | }; 225 | 226 | interface pixel_format { 227 | const long PIXEL_FORMAT_0RGB1555 = 0; 228 | const long PIXEL_FORMAT_XRGB8888 = 1; 229 | const long PIXEL_FORMAT_RGB565 = 2; 230 | }; 231 | 232 | callback environment_t = bool (unsigned long cmd); 233 | callback video_refresh_t = void (Uint8Array data, unsigned long width, unsigned long height, unsigned long pitch); 234 | callback audio_sample_t = void (unsigned long left, unsigned long right); 235 | callback audio_sample_batch_t = unsigned long (Int16Array data, unsigned long frames); 236 | callback input_poll_t = void (); 237 | callback input_state_t = long (unsigned long port, unsigned long device, unsigned long index, unsigned long id); 238 | 239 | typedef long int64_t; 240 | typedef unsigned long uint64_t; 241 | typedef uint64_t perf_tick_t; 242 | typedef int64_t time_t; 243 | -------------------------------------------------------------------------------- /retro.js: -------------------------------------------------------------------------------- 1 | 'format cjs' 2 | var core = require('./core') 3 | 4 | function addHelpers () { 5 | this.LANGUAGE_ENGLISH = 0 6 | this.LANGUAGE_JAPANESE = 1 7 | this.LANGUAGE_FRENCH = 2 8 | this.LANGUAGE_SPANISH = 3 9 | this.LANGUAGE_GERMAN = 4 10 | this.LANGUAGE_ITALIAN = 5 11 | this.LANGUAGE_DUTCH = 6 12 | this.LANGUAGE_PORTUGUESE = 7 13 | this.LANGUAGE_RUSSIAN = 8 14 | this.LANGUAGE_KOREAN = 9 15 | this.LANGUAGE_CHINESE_TRADITIONAL = 10 16 | this.LANGUAGE_CHINESE_SIMPLIFIED = 11 17 | this.K_UNDO = 322 18 | this.K_EURO = 321 19 | this.K_POWER = 320 20 | this.K_MENU = 319 21 | this.K_BREAK = 318 22 | this.K_SYSREQ = 317 23 | this.K_PRINT = 316 24 | this.K_HELP = 315 25 | this.K_COMPOSE = 314 26 | this.K_MODE = 313 27 | this.K_RSUPER = 312 28 | this.K_LSUPER = 311 29 | this.K_LMETA = 310 30 | this.K_RMETA = 309 31 | this.K_LALT = 308 32 | this.K_RALT = 307 33 | this.K_LCTRL = 306 34 | this.K_RCTRL = 305 35 | this.K_LSHIFT = 304 36 | this.K_RSHIFT = 303 37 | this.K_SCROLLOCK = 302 38 | this.K_CAPSLOCK = 301 39 | this.K_NUMLOCK = 300 40 | this.K_F15 = 296 41 | this.K_F14 = 295 42 | this.K_F13 = 294 43 | this.K_F12 = 293 44 | this.K_F11 = 292 45 | this.K_F10 = 291 46 | this.K_F9 = 290 47 | this.K_F8 = 289 48 | this.K_F7 = 288 49 | this.K_F6 = 287 50 | this.K_F5 = 286 51 | this.K_F4 = 285 52 | this.K_F3 = 284 53 | this.K_F2 = 283 54 | this.K_F1 = 282 55 | this.K_PAGEDOWN = 281 56 | this.K_PAGEUP = 280 57 | this.K_END = 279 58 | this.K_HOME = 278 59 | this.K_INSERT = 277 60 | this.K_LEFT = 276 61 | this.K_RIGHT = 275 62 | this.K_DOWN = 274 63 | this.K_UP = 273 64 | this.K_KP_EQUALS = 272 65 | this.K_KP_ENTER = 271 66 | this.K_KP_PLUS = 270 67 | this.K_KP_MINUS = 269 68 | this.K_KP_MULTIPLY = 268 69 | this.K_KP_DIVIDE = 267 70 | this.K_KP_PERIOD = 266 71 | this.K_KP9 = 265 72 | this.K_KP8 = 264 73 | this.K_KP7 = 263 74 | this.K_KP6 = 262 75 | this.K_KP5 = 261 76 | this.K_KP4 = 260 77 | this.K_KP3 = 259 78 | this.K_KP2 = 258 79 | this.K_KP1 = 257 80 | this.K_KP0 = 256 81 | this.K_DELETE = 127 82 | this.K_z = 122 83 | this.K_y = 121 84 | this.K_x = 120 85 | this.K_w = 119 86 | this.K_v = 118 87 | this.K_u = 117 88 | this.K_t = 116 89 | this.K_s = 115 90 | this.K_r = 114 91 | this.K_q = 113 92 | this.K_p = 112 93 | this.K_o = 111 94 | this.K_n = 110 95 | this.K_m = 109 96 | this.K_l = 108 97 | this.K_k = 107 98 | this.K_j = 106 99 | this.K_i = 105 100 | this.K_h = 104 101 | this.K_g = 103 102 | this.K_f = 102 103 | this.K_e = 101 104 | this.K_d = 100 105 | this.K_c = 99 106 | this.K_b = 98 107 | this.K_a = 97 108 | this.K_BACKQUOTE = 96 109 | this.K_UNDERSCORE = 95 110 | this.K_CARET = 94 111 | this.K_RIGHTBRACKET = 93 112 | this.K_BACKSLASH = 92 113 | this.K_LEFTBRACKET = 91 114 | this.K_AT = 64 115 | this.K_QUESTION = 63 116 | this.K_GREATER = 62 117 | this.K_EQUALS = 61 118 | this.K_LESS = 60 119 | this.K_SEMICOLON = 59 120 | this.K_COLON = 58 121 | this.K_9 = 57 122 | this.K_8 = 56 123 | this.K_7 = 55 124 | this.K_6 = 54 125 | this.K_5 = 53 126 | this.K_4 = 52 127 | this.K_3 = 51 128 | this.K_2 = 50 129 | this.K_1 = 49 130 | this.K_0 = 48 131 | this.K_SLASH = 47 132 | this.K_PERIOD = 46 133 | this.K_MINUS = 45 134 | this.K_COMMA = 44 135 | this.K_PLUS = 43 136 | this.K_ASTERISK = 42 137 | this.K_RIGHTPAREN = 41 138 | this.K_LEFTPAREN = 40 139 | this.K_QUOTE = 39 140 | this.K_AMPERSAND = 38 141 | this.K_DOLLAR = 36 142 | this.K_HASH = 35 143 | this.K_QUOTEDBL = 34 144 | this.K_EXCLAIM = 33 145 | this.K_SPACE = 32 146 | this.K_ESCAPE = 27 147 | this.K_PAUSE = 19 148 | this.K_RETURN = 13 149 | this.K_CLEAR = 12 150 | this.K_TAB = 9 151 | this.K_BACKSPACE = 8 152 | this.K_UNKNOWN = 0 153 | this.K_FIRST = 0 154 | this.KMOD_SCROLLOCK = 64 155 | this.KMOD_CAPSLOCK = 32 156 | this.KMOD_NUMLOCK = 16 157 | this.KMOD_META = 8 158 | this.KMOD_ALT = 4 159 | this.KMOD_CTRL = 2 160 | this.KMOD_SHIFT = 1 161 | this.KMOD_NONE = 0 162 | this.LOG_DEBUG = 0 163 | this.LOG_INFO = 1 164 | this.LOG_WARN = 2 165 | this.LOG_ERROR = 3 166 | this.SENSOR_ACCELEROMETER_ENABLE = 0 167 | this.SENSOR_ACCELEROMETER_DISABLE = 1 168 | this.CAMERA_BUFFER_OPENGL_TEXTURE = 0 169 | this.CAMERA_BUFFER_RAW_FRAMEBUFFER = 1 170 | this.RUMBLE_STRONG = 0 171 | this.RUMBLE_WEAK = 1 172 | this.HW_CONTEXT_OPENGLES_VERSION = 5 173 | this.HW_CONTEXT_OPENGLES3 = 4 174 | this.HW_CONTEXT_OPENGL_CORE = 3 175 | this.HW_CONTEXT_OPENGLES2 = 2 176 | this.HW_CONTEXT_OPENGL = 1 177 | this.HW_CONTEXT_NONE = 0 178 | this.PIXEL_FORMAT_RGB565 = 2 179 | this.PIXEL_FORMAT_XRGB8888 = 1 180 | this.PIXEL_FORMAT_0RGB1555 = 0 181 | this.API_VERSION = 1 182 | this.DEVICE_TYPE_SHIFT = 8 183 | this.DEVICE_NONE = 0 184 | this.DEVICE_JOYPAD = 1 185 | this.DEVICE_MOUSE = 2 186 | this.DEVICE_KEYBOARD = 3 187 | this.DEVICE_LIGHTGUN = 4 188 | this.DEVICE_ANALOG = 5 189 | this.DEVICE_POINTER = 6 190 | this.DEVICE_ID_JOYPAD_B = 0 191 | this.DEVICE_ID_JOYPAD_Y = 1 192 | this.DEVICE_ID_JOYPAD_SELECT = 2 193 | this.DEVICE_ID_JOYPAD_START = 3 194 | this.DEVICE_ID_JOYPAD_UP = 4 195 | this.DEVICE_ID_JOYPAD_DOWN = 5 196 | this.DEVICE_ID_JOYPAD_LEFT = 6 197 | this.DEVICE_ID_JOYPAD_RIGHT = 7 198 | this.DEVICE_ID_JOYPAD_A = 8 199 | this.DEVICE_ID_JOYPAD_X = 9 200 | this.DEVICE_ID_JOYPAD_L = 10 201 | this.DEVICE_ID_JOYPAD_R = 11 202 | this.DEVICE_ID_JOYPAD_L2 = 12 203 | this.DEVICE_ID_JOYPAD_R2 = 13 204 | this.DEVICE_ID_JOYPAD_L3 = 14 205 | this.DEVICE_ID_JOYPAD_R3 = 15 206 | this.DEVICE_INDEX_ANALOG_LEFT = 0 207 | this.DEVICE_INDEX_ANALOG_RIGHT = 1 208 | this.DEVICE_ID_ANALOG_X = 0 209 | this.DEVICE_ID_ANALOG_Y = 1 210 | this.DEVICE_ID_MOUSE_X = 0 211 | this.DEVICE_ID_MOUSE_Y = 1 212 | this.DEVICE_ID_MOUSE_LEFT = 2 213 | this.DEVICE_ID_MOUSE_RIGHT = 3 214 | this.DEVICE_ID_MOUSE_WHEELUP = 4 215 | this.DEVICE_ID_MOUSE_WHEELDOWN = 5 216 | this.DEVICE_ID_MOUSE_MIDDLE = 6 217 | this.DEVICE_ID_MOUSE_HORIZ_WHEELUP = 7 218 | this.DEVICE_ID_MOUSE_HORIZ_WHEELDOWN = 8 219 | this.DEVICE_ID_LIGHTGUN_X = 0 220 | this.DEVICE_ID_LIGHTGUN_Y = 1 221 | this.DEVICE_ID_LIGHTGUN_TRIGGER = 2 222 | this.DEVICE_ID_LIGHTGUN_CURSOR = 3 223 | this.DEVICE_ID_LIGHTGUN_TURBO = 4 224 | this.DEVICE_ID_LIGHTGUN_PAUSE = 5 225 | this.DEVICE_ID_LIGHTGUN_START = 6 226 | this.DEVICE_ID_POINTER_X = 0 227 | this.DEVICE_ID_POINTER_Y = 1 228 | this.DEVICE_ID_POINTER_PRESSED = 2 229 | this.REGION_NTSC = 0 230 | this.REGION_PAL = 1 231 | this.MEMORY_SAVE_RAM = 0 232 | this.MEMORY_RTC = 1 233 | this.MEMORY_SYSTEM_RAM = 2 234 | this.MEMORY_VIDEO_RAM = 3 235 | this.ENVIRONMENT_SET_ROTATION = 1 236 | this.ENVIRONMENT_GET_OVERSCAN = 2 237 | this.ENVIRONMENT_GET_CAN_DUPE = 3 238 | this.ENVIRONMENT_SET_MESSAGE = 6 239 | this.ENVIRONMENT_SHUTDOWN = 7 240 | this.ENVIRONMENT_SET_PERFORMANCE_LEVEL = 8 241 | this.ENVIRONMENT_GET_SYSTEM_DIRECTORY = 9 242 | this.ENVIRONMENT_SET_PIXEL_FORMAT = 10 243 | this.ENVIRONMENT_SET_INPUT_DESCRIPTORS = 11 244 | this.ENVIRONMENT_SET_KEYBOARD_CALLBACK = 12 245 | this.ENVIRONMENT_SET_DISK_CONTROL_INTERFACE = 13 246 | this.ENVIRONMENT_SET_HW_RENDER = 14 247 | this.ENVIRONMENT_GET_VARIABLE = 15 248 | this.ENVIRONMENT_SET_VARIABLES = 16 249 | this.ENVIRONMENT_GET_VARIABLE_UPDATE = 17 250 | this.ENVIRONMENT_SET_SUPPORT_NO_GAME = 18 251 | this.ENVIRONMENT_GET_LIBRETRO_PATH = 19 252 | this.ENVIRONMENT_SET_AUDIO_CALLBACK = 22 253 | this.ENVIRONMENT_SET_FRAME_TIME_CALLBACK = 21 254 | this.ENVIRONMENT_GET_RUMBLE_INTERFACE = 23 255 | this.ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES = 24 256 | this.ENVIRONMENT_GET_LOG_INTERFACE = 27 257 | this.ENVIRONMENT_GET_PERF_INTERFACE = 28 258 | this.ENVIRONMENT_GET_LOCATION_INTERFACE = 29 259 | this.ENVIRONMENT_GET_CONTENT_DIRECTORY = 30 260 | this.ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY = 30 261 | this.ENVIRONMENT_GET_SAVE_DIRECTORY = 31 262 | this.ENVIRONMENT_SET_SYSTEM_AV_INFO = 32 263 | this.ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK = 33 264 | this.ENVIRONMENT_SET_SUBSYSTEM_INFO = 34 265 | this.ENVIRONMENT_SET_CONTROLLER_INFO = 35 266 | this.ENVIRONMENT_SET_GEOMETRY = 37 267 | this.ENVIRONMENT_GET_USERNAME = 38 268 | this.ENVIRONMENT_GET_LANGUAGE = 39 269 | this.MEMDESC_CONST = 1 270 | this.MEMDESC_BIGENDIAN = 2 271 | this.MEMDESC_ALIGN_2 = 65536 272 | this.MEMDESC_ALIGN_4 = 131072 273 | this.MEMDESC_ALIGN_8 = 196608 274 | this.MEMDESC_MINSIZE_2 = 16777216 275 | this.MEMDESC_MINSIZE_4 = 33554432 276 | this.MEMDESC_MINSIZE_8 = 50331648 277 | this.SIMD_SSE = 1 278 | this.SIMD_SSE2 = 2 279 | this.SIMD_VMX = 4 280 | this.SIMD_VMX128 = 8 281 | this.SIMD_AVX = 16 282 | this.SIMD_NEON = 32 283 | this.SIMD_SSE3 = 64 284 | this.SIMD_SSSE3 = 128 285 | this.SIMD_MMX = 256 286 | this.SIMD_MMXEXT = 512 287 | this.SIMD_SSE4 = 1024 288 | this.SIMD_SSE42 = 2048 289 | this.SIMD_AVX2 = 4096 290 | this.SIMD_VFPU = 8192 291 | this.SIMD_PS = 16384 292 | this.SIMD_AES = 32768 293 | this.SIMD_VFPV3 = 65536 294 | this.SIMD_VFPV4 = 131072 295 | this.SENSOR_ACCELEROMETER_X = 1 296 | this.SENSOR_ACCELEROMETER_Y = 1 297 | this.SENSOR_ACCELEROMETER_Z = 2 298 | 299 | this._ptrs = [] 300 | this._funcs = [] 301 | 302 | this._unstringify = function (ptr, str) { 303 | var _str = this._malloc(str.length + 1) 304 | this._ptrs.push(_str) 305 | this.writeStringToMemory(str, _str) 306 | this.setValue(ptr, _str, '*') 307 | return ptr 308 | } 309 | 310 | this._addFunction = function (f) { 311 | var func = this.Runtime.addFunction(f) 312 | this._funcs.push(func) 313 | return func 314 | } 315 | 316 | this._stringify = function (ptr) { 317 | return this.Pointer_stringify(this.getValue(ptr, '*')) 318 | } 319 | 320 | this._get_variable = function (ptr) { 321 | return { 322 | key: this._stringify(ptr), 323 | value: this._stringify(ptr + 4) 324 | } 325 | } 326 | 327 | this._get_av_info = function (ptr) { 328 | return { 329 | geometry: { 330 | base_width: this.getValue(ptr, 'i32'), 331 | base_height: this.getValue(ptr + 4, 'i32'), 332 | max_width: this.getValue(ptr + 8, 'i32'), 333 | max_height: this.getValue(ptr + 12, 'i32'), 334 | aspect_ratio: this.getValue(ptr + 16, 'float') 335 | }, 336 | timing: { 337 | fps: this.getValue(ptr + 24, 'double'), 338 | sample_rate: this.getValue(ptr + 32, 'double') 339 | } 340 | } 341 | } 342 | 343 | this._set_info = function (ptr, data) { 344 | var _data = this._malloc(data.length) 345 | this._ptrs.push(_data) 346 | new Uint8Array(this.HEAP8.buffer, _data, data.length).set(data) 347 | this.setValue(ptr + 4, _data, '*') 348 | this.setValue(ptr + 8, data.length, 'i32') 349 | 350 | // need_fullpath = true support 351 | var path = '/dummy.raw' 352 | var stream = this.FS_open(path, 'w+') 353 | this.FS_write(stream, data, 0, data.length, 0) 354 | this.FS_close(stream) 355 | this._unstringify(ptr, path) 356 | } 357 | 358 | this.get_system_info = function () { 359 | var _data = this._malloc(20) 360 | this._retro_get_system_info(_data) 361 | var obj = { 362 | library_name: this._stringify(_data), 363 | library_version: this._stringify(_data + 4), 364 | valid_extensions: this._stringify(_data + 8), 365 | need_fullpath: this.getValue(_data + 12, 'i32') > 0, 366 | block_extract: this.getValue(_data + 16, 'i32') > 0 367 | } 368 | this._free(_data) 369 | return obj 370 | } 371 | 372 | this.get_system_av_info = function () { 373 | var _data = this._malloc(40) 374 | this._retro_get_system_av_info(_data) 375 | var info = this._get_av_info(_data) 376 | this._free(_data) 377 | return info 378 | } 379 | 380 | this.serialize = function () { 381 | var size = this._retro_serialize_size() 382 | var _data = this._malloc(size) 383 | var data = false 384 | if (this._retro_serialize(_data, size)) { 385 | data = new Uint8Array(this.HEAP8.buffer, _data, size) 386 | } 387 | this._free(_data) 388 | return data 389 | } 390 | 391 | this.unserialize = function (data) { 392 | var _data = this._malloc(data.length) 393 | new Uint8Array(this.HEAP8.buffer, _data, data.length).set(data) 394 | var result = this._retro_unserialize(_data, data.length) 395 | this._free(_data) 396 | return result 397 | } 398 | 399 | this.cheat_set = function (index, enabled, code) { 400 | var _code = this._malloc(code.length) 401 | this._ptrs.push(_code) 402 | this.writeStringToMemory(code, _code) 403 | this._retro_cheat_set(index, enabled, _code) 404 | } 405 | 406 | this.load_game = function (data) { 407 | var _info = this._malloc(16) 408 | this._ptrs.push(_info) 409 | this._set_info(_info, data) 410 | return this._retro_load_game(_info) 411 | } 412 | 413 | this.load_game_special = function (game_type, datas) { 414 | var _info = this._malloc(16 * datas.length) 415 | this._ptrs.push(_info) 416 | for (var data in datas) { 417 | this._set_info(_info + 16 * data, datas[data]) 418 | } 419 | return this._retro_load_game_special(game_type, _info, datas.length) 420 | } 421 | 422 | this.get_memory_data = function (id) { 423 | return new Uint8Array(this.HEAP8.buffer, this._retro_get_memory_data(id), this._retro_get_memory_size(id)) 424 | } 425 | 426 | this.set_environment = function (fn) { // complete libretro spec 427 | this._retro_set_environment(this._addFunction(function (fn, cmd, _data) { 428 | switch (cmd) { 429 | case this.ENVIRONMENT_SHUTDOWN: { 430 | return fn(cmd) 431 | } 432 | case this.ENVIRONMENT_SET_PERFORMANCE_LEVEL: 433 | case this.ENVIRONMENT_SET_PIXEL_FORMAT: 434 | case this.ENVIRONMENT_SET_ROTATION: 435 | case this.ENVIRONMENT_SET_SUPPORT_NO_GAME: { 436 | return fn(cmd, this.getValue(_data, 'i32')) 437 | } 438 | case this.ENVIRONMENT_SET_GEOMETRY: { 439 | return fn(cmd, { 440 | base_width: this.getValue(_data, 'i32'), 441 | base_height: this.getValue(_data + 4, 'i32'), 442 | max_width: this.getValue(_data + 8, 'i32'), 443 | max_height: this.getValue(_data + 12, 'i32'), 444 | aspect_ratio: this.getValue(_data + 16, 'float') 445 | }) 446 | } 447 | case this.ENVIRONMENT_SET_INPUT_DESCRIPTORS: { 448 | var descriptions = [] 449 | for (var ptr = _data; this.getValue(ptr + 16, '*'); ptr += 20) { 450 | descriptions.push({ 451 | port: this.getValue(ptr, 'i32'), 452 | device: this.getValue(ptr + 4, 'i32'), 453 | index: this.getValue(ptr + 8, 'i32'), 454 | id: this.getValue(ptr + 12, 'i32'), 455 | description: this._stringify(ptr + 16) 456 | }) 457 | } 458 | return fn(cmd, descriptions) 459 | } 460 | case this.ENVIRONMENT_SET_MESSAGE: { 461 | return fn(cmd, this._stringify(_data), this.getValue(_data + 4, 'i32')) 462 | } 463 | case this.ENVIRONMENT_SET_SYSTEM_AV_INFO: { 464 | return fn(cmd, this._get_av_info(_data)) 465 | } 466 | case this.ENVIRONMENT_SET_VARIABLES: { 467 | var variables = [] 468 | for (ptr = _data; this.getValue(ptr, '*'); ptr += 8) { 469 | variables.push(this._get_variable(ptr)) 470 | } 471 | return fn(cmd, variables) 472 | } 473 | case this.ENVIRONMENT_GET_CAN_DUPE: 474 | case this.ENVIRONMENT_GET_OVERSCAN: 475 | case this.ENVIRONMENT_GET_VARIABLE_UPDATE: { 476 | this.setValue(_data, fn(cmd), 'i16') 477 | return true 478 | } 479 | case this.ENVIRONMENT_GET_LANGUAGE: 480 | case this.ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES: { 481 | this.setValue(_data, fn(cmd), 'i32') 482 | return true 483 | } 484 | case this.ENVIRONMENT_GET_SYSTEM_DIRECTORY: 485 | case this.ENVIRONMENT_GET_LIBRETRO_PATH: 486 | case this.ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY: 487 | case this.ENVIRONMENT_GET_SAVE_DIRECTORY: 488 | case this.ENVIRONMENT_GET_USERNAME: { 489 | this._unstringify(_data, fn(cmd)) 490 | return true 491 | } 492 | case this.ENVIRONMENT_GET_VARIABLE: { 493 | this._unstringify(_data + 4, fn(cmd, this._get_variable(_data))) 494 | return true 495 | } 496 | case this.ENVIRONMENT_GET_LOG_INTERFACE: { 497 | var func = fn(cmd) 498 | this.setValue(_data, this._addFunction(function (func, level) { 499 | var args = [] 500 | var varargs = Array.prototype.slice.call(arguments, 3) 501 | for (var vararg in varargs) { 502 | args.push(this.Pointer_stringify(varargs[vararg])) 503 | } 504 | func.apply(null, [level].concat(args)) 505 | }.bind(this, func)), '*') 506 | return true 507 | } 508 | case this.ENVIRONMENT_GET_PERF_INTERFACE: { 509 | var perf = fn(cmd) 510 | this.setValue(_data, this._addFunction(perf.get_time_usec), '*') 511 | this.setValue(_data + 4, this._addFunction(perf.get_cpu_features), '*') 512 | this.setValue(_data + 8, this._addFunction(perf.get_perf_counter), '*') 513 | this.setValue(_data + 12, this._addFunction(perf.register), '*') 514 | this.setValue(_data + 16, this._addFunction(perf.start), '*') 515 | this.setValue(_data + 20, this._addFunction(perf.stop), '*') 516 | this.setValue(_data + 24, this._addFunction(perf.log), '*') 517 | return true 518 | } 519 | case this.ENVIRONMENT_GET_RUMBLE_INTERFACE: { 520 | this.setValue(_data, this._addFunction(fn(cmd)), '*') 521 | return true 522 | } 523 | default: { 524 | return fn(cmd, _data) 525 | } 526 | } 527 | }.bind(this, fn))) 528 | } 529 | 530 | this.set_video_refresh = function (fn) { 531 | this._retro_set_video_refresh(this._addFunction(function (fn, _data, width, height, pitch) { 532 | var data = new Uint16Array(this.HEAPU16.buffer, _data, height * pitch) 533 | fn(data, width, height, pitch) 534 | }.bind(this, fn))) 535 | } 536 | 537 | this.set_audio_sample_batch = function (fn) { 538 | this._retro_set_audio_sample_batch(this._addFunction(function (fn, _data, frames) { 539 | var left = new Float32Array(frames) 540 | var right = new Float32Array(frames) 541 | var data = new Int16Array(this.HEAP16.buffer, _data, frames * 4) 542 | for (var i = 0; i < frames; i++) { 543 | left[i] = data[i * 2] / 0x8000 544 | right[i] = data[i * 2 + 1] / 0x8000 545 | } 546 | return fn(left, right, frames) 547 | }.bind(this, fn))) 548 | } 549 | 550 | this.set_audio_sample = function (fn) { 551 | this._retro_set_audio_sample(this._addFunction(fn)) 552 | } 553 | 554 | this.set_input_poll = function (fn) { 555 | this._retro_set_input_poll(this._addFunction(fn)) 556 | } 557 | 558 | this.set_input_state = function (fn) { 559 | this._retro_set_input_state(this._addFunction(fn)) 560 | } 561 | 562 | this.init = function () { 563 | this._retro_init() 564 | } 565 | 566 | this.deinit = function () { 567 | this._retro_deinit() 568 | for (var func in this._funcs) { 569 | this.Runtime.removeFunction(this._funcs[func]) 570 | } 571 | this._funcs = [] 572 | } 573 | 574 | this.api_version = function () { 575 | return this._retro_api_version() 576 | } 577 | 578 | this.reset = function () { 579 | this._retro_reset() 580 | } 581 | 582 | this.run = function () { 583 | this._retro_run() 584 | } 585 | 586 | this.unload_game = function () { 587 | this._retro_unload_game() 588 | for (var ptr in this._ptrs) { 589 | this._free(this._ptrs[ptr]) 590 | } 591 | this._ptrs = [] 592 | } 593 | 594 | this.get_region = function () { 595 | return this._retro_get_region() 596 | } 597 | 598 | this.cheat_reset = function () { 599 | this._retro_cheat_reset() 600 | } 601 | 602 | this.set_controller_port_device = function (port, device) { 603 | this._retro_set_controller_port_device(port, device) 604 | } 605 | } 606 | 607 | addHelpers.call(core) 608 | 609 | module.exports = core 610 | -------------------------------------------------------------------------------- /runtime_exports.json: -------------------------------------------------------------------------------- 1 | [ 2 | "Runtime", 3 | "getValue", 4 | "setValue", 5 | "Pointer_stringify", 6 | "writeStringToMemory", 7 | "UTF8ToString", 8 | "FS_open", 9 | "FS_write", 10 | "FS_close" 11 | ] 12 | -------------------------------------------------------------------------------- /script/add-repo: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | git submodule add --force --name $1 https://github.com/libretro/$1-libretro.git core/$1 4 | -------------------------------------------------------------------------------- /script/bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | git submodule init 4 | git submodule update 5 | npm install 6 | -------------------------------------------------------------------------------- /script/build: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if test "$#" -gt 0; then 4 | cores=$@ 5 | else 6 | cores=core/* 7 | fi 8 | 9 | for core in $cores 10 | do 11 | ./script/build-core $core & 12 | done 13 | 14 | wait 15 | -------------------------------------------------------------------------------- /script/build-core: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | core=$1 4 | 5 | SHELL_FILE="'`pwd`/shell.js'" 6 | EXPORTS=`pwd`/exports.json 7 | DIR=`pwd` 8 | 9 | (cd $core && emmake make platform=emscripten) 10 | 11 | BC_FILE=`find $core -name '*.bc' -print` 12 | 13 | # nestopia: 16777216 14 | # stella: 16777216 15 | # vecx: 16777216 16 | # quicknes: 16777216 17 | # prosystem: 16777216 18 | # gambatte: 16777216 19 | # snes9x-next: 134217728 20 | # fmsx: 134217728 21 | # gw: 134217728 22 | # mupen64plus: 134217728 23 | # virtualjaguar: 134217728 24 | # vba-next: 134217728 25 | # picodrive: 134217728 26 | 27 | (cd `dirname $BC_FILE` && \ 28 | emcc `basename ${BC_FILE}` -o ${DIR}/${core}/core.js -O3 -Oz \ 29 | -s EMULATED_FUNCTION_POINTERS=2 \ 30 | -s TOTAL_MEMORY=${TOTAL_MEMORY-134217728} \ 31 | -s EXPORTED_FUNCTIONS=@${DIR}/exports.json \ 32 | -s EXPORTED_RUNTIME_METHODS=@${DIR}/runtime_exports.json \ 33 | -s SHELL_FILE=${SHELL_FILE} \ 34 | -s FORCE_FILESYSTEM=1 \ 35 | ) 36 | 37 | cp retro.js ${core}/index.js 38 | -------------------------------------------------------------------------------- /script/clean: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | source ~/emsdk_portable/emsdk_set_env.sh 4 | 5 | find . -name .DS_Store -delete 6 | 7 | for core in core/* 8 | do 9 | find $core -name '*.bc' -delete 10 | find $core -name '*.js' -delete 11 | find $core -name '*.o' -delete 12 | find $core -name '*.mem' -delete 13 | done 14 | -------------------------------------------------------------------------------- /script/publish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var denodeify = require('denodeify') 4 | var fs = require('fs') 5 | var npm = require('npm') 6 | function getDirs() { 7 | if (process.argv.length > 2) 8 | return Promise.resolve(process.argv.slice(2)) 9 | else 10 | return denodeify(fs.readdir)('core') 11 | } 12 | getDirs().then(function (cores) { 13 | return Promise.all(cores.map(function(core) { 14 | if (core[0] === '.') 15 | return 16 | return Promise.resolve().then(function() { 17 | return denodeify(npm.load)() 18 | }).then(function() { 19 | return denodeify(fs.writeFile)('core/' + core + '/package.json', JSON.stringify({ 20 | name: core, 21 | version: "1.0.5", 22 | main: 'index.js', 23 | homepage: 'https://github.com/matthewbauer/retrojs', 24 | files: ['index.js', 'core.js', 'core.js.mem'], 25 | dependencies: { 26 | } 27 | })) 28 | }).then(function() { 29 | return denodeify(npm.commands.publish)(['core/' + core]) 30 | }).then(function() { 31 | return denodeify(fs.unlink)('core/' + core + '/package.json') 32 | }) 33 | })) 34 | }).catch(console.error) 35 | -------------------------------------------------------------------------------- /script/rm-repo: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | git submodule deinit -f core/$1 4 | git rm -f --cached core/$1 5 | git submodule sync 6 | rm -r core/$1 7 | -------------------------------------------------------------------------------- /shell.js: -------------------------------------------------------------------------------- 1 | 'format global' 2 | 'exports Module' 3 | var ENVIRONMENT_IS_WEB = false 4 | var ENVIRONMENT_IS_NODE = false 5 | var ENVIRONMENT_IS_SHELL = false 6 | var Module = { 7 | print: function () {}, 8 | printErr: function () {}, 9 | noExitRuntime: true, 10 | noInitialRun: true, 11 | memoryInitializerRequest: { 12 | addEventListener: function(load, useRequest) { 13 | var data = require('fs').readFileSync(__dirname + '/core.js.mem') 14 | this.response = data 15 | useRequest() 16 | }, 17 | status: 200 18 | } 19 | } 20 | {{BODY}} 21 | if (typeof module !== 'undefined') 22 | module.exports = Module 23 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var test = require('ava') 2 | var fs = require('fs') 3 | var denodeify = require('denodeify') 4 | var _cores = require('./test.json') 5 | 6 | var cores = _cores.filter(function(core) { 7 | return !process.env.CORE || core.name === process.env.CORE 8 | }) 9 | 10 | function environment(cmd, _data) { 11 | if (cmd === this.ENVIRONMENT_GET_LOG_INTERFACE) { 12 | return function(data) {} 13 | } else if (cmd === this.ENVIRONMENT_GET_CAN_DUPE) { 14 | return true 15 | } else if (cmd === this.ENVIRONMENT_GET_OVERSCAN) { 16 | return true 17 | } else if (cmd === this.ENVIRONMENT_SET_PIXEL_FORMAT) { 18 | return true 19 | } else if (cmd === this.ENVIRONMENT_SET_PERFORMANCE_LEVEL) { 20 | return true 21 | } else if (cmd === this.ENVIRONMENT_SET_VARIABLES) { 22 | return true 23 | } else if (cmd === this.ENVIRONMENT_GET_VARIABLE_UPDATE) { 24 | return false 25 | } else if (cmd === this.ENVIRONMENT_GET_VARIABLE) { 26 | if (_data.key === 'mupen64-gfxplugin') { 27 | return 'angrylion' 28 | } else { 29 | return '' 30 | } 31 | } else if (cmd === this.ENVIRONMENT_GET_SYSTEM_DIRECTORY) { 32 | return '.' 33 | } else if (cmd === this.ENVIRONMENT_GET_PERF_INTERFACE) { 34 | return { 35 | get_time_usec: function() { 36 | return new Date().getTime() * 1000 37 | }, 38 | get_cpu_features: function() { 39 | return 0 40 | }, 41 | log: function() {}, 42 | stop: function() {}, 43 | start: function() {}, 44 | perf_register: function() {} 45 | } 46 | } else if (cmd === this.ENVIRONMENT_GET_RUMBLE_INTERFACE) { 47 | return function () { 48 | return true 49 | } 50 | } else { 51 | return true 52 | } 53 | } 54 | 55 | function loadCore(core) { 56 | var path = './core/' + core.name 57 | delete require.cache[require.resolve(path)] 58 | return require(path) 59 | } 60 | 61 | test.afterEach(function(t) { 62 | t.context.deinit() 63 | }) 64 | 65 | function testGame(test, core, rom) { 66 | test.serial(core.name + ' : ' + rom.name + ' : running for 100 frames', function(t) { 67 | return denodeify(fs.readFile)('./fixtures/roms/' + rom.name) 68 | .then(function(buffer) { 69 | t.context = loadCore(core) 70 | t.context.set_environment(environment.bind(t.context)) 71 | t.context.set_audio_sample(function(){}) 72 | t.context.set_audio_sample_batch(function(left, right, frames) { return frames }) 73 | t.context.set_input_state(function() { return 0 }) 74 | t.context.set_input_poll(function(){}) 75 | t.context.set_video_refresh(function(){}) 76 | t.context.init() 77 | t.context.load_game(new Uint8Array(buffer)) 78 | for (var i = 0; i < 100; i++) { 79 | t.context.run() 80 | } 81 | t.context.unload_game() 82 | }) 83 | }) 84 | test.serial(core.name + ' : ' + rom.name + ' : resetting game', function(t) { 85 | return denodeify(fs.readFile)('./fixtures/roms/' + rom.name) 86 | .then(function(buffer) { 87 | t.context = loadCore(core) 88 | t.context.set_environment(environment.bind(t.context)) 89 | t.context.set_audio_sample(function(){}) 90 | t.context.set_audio_sample_batch(function(left, right, frames) { return frames }) 91 | t.context.set_input_state(function() { return 0 }) 92 | t.context.set_input_poll(function(){}) 93 | t.context.set_video_refresh(function(){}) 94 | t.context.init() 95 | t.context.load_game(new Uint8Array(buffer)) 96 | for (var i = 0; i < 50; i++) { 97 | t.context.run() 98 | } 99 | t.context.reset() 100 | for (var i = 0; i < 50; i++) { 101 | t.context.run() 102 | } 103 | t.context.unload_game() 104 | }) 105 | }) 106 | test.serial(core.name + ' : ' + rom.name + ' : mashing buttons', function(t) { 107 | return denodeify(fs.readFile)('./fixtures/roms/' + rom.name) 108 | .then(function(buffer) { 109 | t.context = loadCore(core) 110 | t.context.set_environment(environment.bind(t.context)) 111 | t.context.set_audio_sample(function(){}) 112 | t.context.set_audio_sample_batch(function(left, right, frames) { return frames }) 113 | t.context.set_input_state(function() { 114 | return 1 115 | }) 116 | t.context.set_input_poll(function(){}) 117 | t.context.set_video_refresh(function(){}) 118 | t.context.init() 119 | t.context.load_game(new Uint8Array(buffer)) 120 | for (var i = 0; i < 100; i++) { 121 | t.context.run() 122 | } 123 | t.context.unload_game() 124 | }) 125 | }) 126 | // if (rom.hasFirstFrame) { 127 | // test(core.name + ': ' + rom.name + ' : checking first frame', function(t) { 128 | // return denodeify(fs.readFile)('./fixtures/roms/' + rom.name) 129 | // .then(function(buffer) { 130 | // return denodeify(fs.readFile)('./fixtures/frames/0/' + rom.name + '.dat') 131 | // .then(function(b) { 132 | // t.context = loadCore(core) 133 | // t.context.set_environment(environment.bind(t.context)) 134 | // t.context.set_audio_sample(function(){}) 135 | // t.context.set_audio_sample_batch(function(left, right, frames) { return frames }) 136 | // t.context.set_input_state(function() { return 0 }) 137 | // t.context.set_input_poll(function(){}) 138 | // t.context.set_video_refresh(function(frame) { 139 | // t.same(b, frame) 140 | // }) 141 | // t.context.init() 142 | // t.context.load_game(new Uint8Array(buffer)) 143 | // t.context.run() 144 | // }) 145 | // }) 146 | // }) 147 | // } else { 148 | // test('generating first frame...', function(t) { 149 | // return denodeify(fs.readFile)('./fixtures/roms/' + rom.name) 150 | // .then(function(buffer) { 151 | // t.context = loadCore(core) 152 | // t.context.set_environment(environment.bind(t.context)) 153 | // t.context.set_audio_sample(function(){}) 154 | // t.context.set_audio_sample_batch(function(left, right, frames) { return frames }) 155 | // t.context.set_input_state(function() { return 0 }) 156 | // t.context.set_input_poll(function(){}) 157 | // t.context.set_video_refresh(function(frame) { 158 | // fs.writeFileSync('./fixtures/frames/0/' + rom.name + '.dat', new Buffer(frame), 'binary') 159 | // rom.hasFirstFrame = true 160 | // }) 161 | // t.context.init() 162 | // t.context.load_game(new Uint8Array(buffer)) 163 | // t.context.run() 164 | // }) 165 | // }) 166 | // } 167 | // if (!rom.skipSave) { 168 | // test(core.name + ': ' + rom.name + ' : saving', function(t) { 169 | // return denodeify(fs.readFile)('./fixtures/roms/' + rom.name) 170 | // .then(function(buffer) { 171 | // t.context = loadCore(core) 172 | // t.context.set_environment(environment.bind(t.context)) 173 | // t.context.set_audio_sample(function(){}) 174 | // t.context.set_audio_sample_batch(function(left, right, frames) { return frames }) 175 | // t.context.set_input_state(function() { return 0 }) 176 | // t.context.set_input_poll(function(){}) 177 | // t.context.set_video_refresh(function(){}) 178 | // t.context.init() 179 | // t.context.load_game(new Uint8Array(buffer)) 180 | // var save = new Uint8Array(t.context.serialize()) 181 | // t.context.reset() 182 | // var notnewsave = new Uint8Array(t.context.serialize()) 183 | // t.same(notnewsave, save) 184 | // t.context.unserialize(save) 185 | // var newsave = new Uint8Array(t.context.serialize()) 186 | // t.same(newsave, save) 187 | // }) 188 | // }) 189 | // } 190 | } 191 | 192 | function testCore(test, core) { 193 | test.serial.cb(core.name + '.api_version()', function(t) { 194 | t.context = loadCore(core) 195 | t.is(t.context.api_version(), 1) 196 | t.is(t.context.api_version(), t.context.API_VERSION) 197 | t.end() 198 | }) 199 | test.serial.cb(core.name + '.get_region()', function(t) { 200 | t.context = loadCore(core) 201 | t.is(t.context.get_region(), t.context['REGION_' + core.region]) 202 | t.end() 203 | }) 204 | test.serial.cb(core.name + '.get_system_info()', function(t) { 205 | t.context = loadCore(core) 206 | var system_info = t.context.get_system_info() 207 | t.is(typeof system_info.library_name, 'string') 208 | t.is(typeof system_info.library_version, 'string') 209 | t.is(typeof system_info.valid_extensions, 'string') 210 | t.is(typeof system_info.need_fullpath, 'boolean') 211 | t.is(typeof system_info.block_extract, 'boolean') 212 | if (core.system_info) { 213 | t.same(system_info, core.system_info) 214 | } else { 215 | core.system_info = system_info 216 | } 217 | t.end() 218 | }) 219 | test.serial.cb(core.name + '.get_system_av_info()', function(t) { 220 | t.context = loadCore(core) 221 | var av_info = t.context.get_system_av_info() 222 | t.is(typeof av_info.geometry.base_width,'number') 223 | t.is(typeof av_info.geometry.base_height, 'number') 224 | t.is(typeof av_info.geometry.max_width, 'number') 225 | t.is(typeof av_info.geometry.max_height, 'number') 226 | t.is(typeof av_info.geometry.aspect_ratio, 'number') 227 | t.is(typeof av_info.timing.fps, 'number') 228 | t.is(typeof av_info.timing.sample_rate, 'number') 229 | if (core.av_info) { 230 | t.same(av_info, core.av_info) 231 | } else { 232 | core.av_info = av_info 233 | } 234 | t.end() 235 | }) 236 | test.serial.cb(core.name + '.set_controller_port_device()', function(t) { 237 | t.context = loadCore(core) 238 | t.context.set_controller_port_device(0, t.context.DEVICE_JOYPAD) 239 | t.end() 240 | }) 241 | test.serial.cb(core.name + '.cheat_reset()', function(t) { 242 | t.context = loadCore(core) 243 | t.context.cheat_reset() 244 | t.end() 245 | }) 246 | core.roms.forEach(function(rom) { 247 | testGame(test, core, rom) 248 | }) 249 | } 250 | 251 | cores.forEach(function(core) { testCore(test, core) }) 252 | 253 | test.after(function(t) { 254 | return denodeify(fs.writeFile)('./test.json', JSON.stringify(_cores, undefined, 2) + '\n') 255 | }) 256 | -------------------------------------------------------------------------------- /test.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "snes9x-next", 4 | "roms": [], 5 | "system_info": { 6 | "library_name": "Snes9X Next", 7 | "library_version": "v1.52.4", 8 | "valid_extensions": "smc|fig|sfc|gd3|gd7|dx2|bsx|swc", 9 | "need_fullpath": false, 10 | "block_extract": false 11 | }, 12 | "region": "NTSC", 13 | "av_info": { 14 | "geometry": { 15 | "base_width": 256, 16 | "base_height": 224, 17 | "max_width": 512, 18 | "max_height": 512, 19 | "aspect_ratio": 1.3333333730697632 20 | }, 21 | "timing": { 22 | "fps": 60.098811862348406, 23 | "sample_rate": 32040.5 24 | } 25 | } 26 | }, 27 | { 28 | "name": "gambatte", 29 | "roms": [], 30 | "region": "NTSC", 31 | "system_info": { 32 | "library_name": "Gambatte", 33 | "library_version": "v0.5.0", 34 | "valid_extensions": "gb|gbc|dmg", 35 | "need_fullpath": false, 36 | "block_extract": true 37 | }, 38 | "av_info": { 39 | "geometry": { 40 | "base_width": 160, 41 | "base_height": 144, 42 | "max_width": 160, 43 | "max_height": 144, 44 | "aspect_ratio": 0 45 | }, 46 | "timing": { 47 | "fps": 0, 48 | "sample_rate": 0 49 | } 50 | } 51 | }, 52 | { 53 | "name": "vba-next", 54 | "roms": [], 55 | "region": "NTSC", 56 | "system_info": { 57 | "library_name": "VBA Next", 58 | "library_version": "v1.0.2", 59 | "valid_extensions": "gba", 60 | "need_fullpath": false, 61 | "block_extract": false 62 | }, 63 | "av_info": { 64 | "geometry": { 65 | "base_width": 240, 66 | "base_height": 160, 67 | "max_width": 240, 68 | "max_height": 160, 69 | "aspect_ratio": 1.5 70 | }, 71 | "timing": { 72 | "fps": 59.72750056960583, 73 | "sample_rate": 32000 74 | } 75 | } 76 | }, 77 | { 78 | "name": "vecx", 79 | "roms": [], 80 | "region": "PAL", 81 | "system_info": { 82 | "library_name": "VecX", 83 | "library_version": "1.2", 84 | "valid_extensions": "bin|vec", 85 | "need_fullpath": false, 86 | "block_extract": false 87 | }, 88 | "av_info": { 89 | "geometry": { 90 | "base_width": 330, 91 | "base_height": 410, 92 | "max_width": 330, 93 | "max_height": 410, 94 | "aspect_ratio": 0 95 | }, 96 | "timing": { 97 | "fps": 50, 98 | "sample_rate": 44100 99 | } 100 | } 101 | }, 102 | { 103 | "name": "gw", 104 | "region": "NTSC", 105 | "roms": [], 106 | "system_info": { 107 | "library_name": "Game & Watch", 108 | "library_version": "1.0", 109 | "valid_extensions": "mgw", 110 | "need_fullpath": false, 111 | "block_extract": false 112 | }, 113 | "av_info": { 114 | "geometry": { 115 | "base_width": 0, 116 | "base_height": 0, 117 | "max_width": 0, 118 | "max_height": 0, 119 | "aspect_ratio": 0 120 | }, 121 | "timing": { 122 | "fps": 60, 123 | "sample_rate": 44100 124 | } 125 | } 126 | }, 127 | { 128 | "name": "stella", 129 | "roms": [], 130 | "region": "NTSC", 131 | "system_info": { 132 | "library_name": "Stella", 133 | "library_version": "3.9.3", 134 | "valid_extensions": "a26|bin", 135 | "need_fullpath": false, 136 | "block_extract": false 137 | }, 138 | "av_info": { 139 | "geometry": { 140 | "base_width": 320, 141 | "base_height": 0, 142 | "max_width": 320, 143 | "max_height": 256, 144 | "aspect_ratio": 1.3333333730697632 145 | }, 146 | "timing": { 147 | "fps": 4.154065219583061e-40, 148 | "sample_rate": 31400 149 | } 150 | } 151 | }, 152 | { 153 | "name": "nestopia", 154 | "roms": [ 155 | { 156 | "name": "Atomic.NES", 157 | "skipSave": true, 158 | "hasFirstFrame": true 159 | }, 160 | { 161 | "name": "CMC80s.NES", 162 | "skipSave": true 163 | }, 164 | { 165 | "name": "CMCWavy.NES", 166 | "skipSave": true 167 | }, 168 | { 169 | "name": "Dithering.NES", 170 | "skipSave": true 171 | }, 172 | { 173 | "name": "FDSPic.NES", 174 | "skipSave": true 175 | }, 176 | { 177 | "name": "Flame.nes", 178 | "skipSave": true 179 | }, 180 | { 181 | "name": "GENIE.NES", 182 | "skipSave": true 183 | }, 184 | { 185 | "name": "GameGenie.NES", 186 | "skipSave": true 187 | }, 188 | { 189 | "name": "Greys.NES", 190 | "skipSave": true 191 | }, 192 | { 193 | "name": "Interlace1.NES", 194 | "skipSave": true 195 | }, 196 | { 197 | "name": "Interlace2.NES", 198 | "skipSave": true 199 | }, 200 | { 201 | "name": "Interlace3.NES", 202 | "skipSave": true 203 | }, 204 | { 205 | "name": "Mandelbrot.NES", 206 | "skipSave": true 207 | }, 208 | { 209 | "name": "MegaManJet.nes", 210 | "skipSave": true 211 | }, 212 | { 213 | "name": "Moby2.NES", 214 | "skipSave": true 215 | }, 216 | { 217 | "name": "Motion.NES", 218 | "skipSave": true 219 | }, 220 | { 221 | "name": "NESA.NES", 222 | "skipSave": true 223 | }, 224 | { 225 | "name": "NESA_TimesofLore.NES", 226 | "skipSave": true 227 | }, 228 | { 229 | "name": "PALTEST.NES", 230 | "skipSave": true 231 | }, 232 | { 233 | "name": "PolarPinwheel.NES", 234 | "skipSave": true 235 | }, 236 | { 237 | "name": "PolarPop.NES", 238 | "skipSave": true 239 | }, 240 | { 241 | "name": "PolarRot1.NES", 242 | "skipSave": true 243 | }, 244 | { 245 | "name": "PolarRot21.NES", 246 | "skipSave": true 247 | }, 248 | { 249 | "name": "PolarRot79.NES", 250 | "skipSave": true 251 | }, 252 | { 253 | "name": "PolarRot8.NES", 254 | "skipSave": true 255 | }, 256 | { 257 | "name": "RGB.NES", 258 | "skipSave": true 259 | }, 260 | { 261 | "name": "SCROLL.NES" 262 | }, 263 | { 264 | "name": "SNDTEST.NES", 265 | "skipSave": true 266 | }, 267 | { 268 | "name": "SOUND.NES" 269 | }, 270 | { 271 | "name": "SolarWars.NES", 272 | "skipSave": true 273 | }, 274 | { 275 | "name": "SolarWarsSilent.NES", 276 | "skipSave": true 277 | }, 278 | { 279 | "name": "StarsSE.NES", 280 | "skipSave": true 281 | } 282 | ], 283 | "region": "NTSC", 284 | "system_info": { 285 | "library_name": "Nestopia", 286 | "library_version": "v1.47-WIP", 287 | "valid_extensions": "nes|fds", 288 | "need_fullpath": false, 289 | "block_extract": false 290 | }, 291 | "av_info": { 292 | "geometry": { 293 | "base_width": 256, 294 | "base_height": 240, 295 | "max_width": 602, 296 | "max_height": 240, 297 | "aspect_ratio": 1.3333333730697632 298 | }, 299 | "timing": { 300 | "fps": 60, 301 | "sample_rate": 44100 302 | } 303 | } 304 | }, 305 | { 306 | "name": "quicknes", 307 | "roms": [], 308 | "region": "NTSC", 309 | "system_info": { 310 | "library_name": "QuickNES", 311 | "library_version": "v1", 312 | "valid_extensions": "nes", 313 | "need_fullpath": false, 314 | "block_extract": false 315 | }, 316 | "av_info": { 317 | "geometry": { 318 | "base_width": 240, 319 | "base_height": 224, 320 | "max_width": 240, 321 | "max_height": 224, 322 | "aspect_ratio": 1.3333333730697632 323 | }, 324 | "timing": { 325 | "fps": 60, 326 | "sample_rate": 44100 327 | } 328 | } 329 | }, 330 | { 331 | "name": "picodrive", 332 | "region": "NTSC", 333 | "roms": [], 334 | "system_info": { 335 | "library_name": "PicoDrive", 336 | "library_version": "1.91", 337 | "valid_extensions": "bin|gen|smd|md|32x|cue|iso|sms", 338 | "need_fullpath": true, 339 | "block_extract": false 340 | }, 341 | "av_info": { 342 | "geometry": { 343 | "base_width": 320, 344 | "base_height": 0, 345 | "max_width": 320, 346 | "max_height": 240, 347 | "aspect_ratio": 1.3333333730697632 348 | }, 349 | "timing": { 350 | "fps": 60, 351 | "sample_rate": 44100 352 | } 353 | } 354 | }, 355 | { 356 | "name": "fmsx", 357 | "region": "NTSC", 358 | "roms": [], 359 | "system_info": { 360 | "library_name": "fMSX", 361 | "library_version": "3.9", 362 | "valid_extensions": "rom|mx1|mx2", 363 | "need_fullpath": true, 364 | "block_extract": false 365 | }, 366 | "av_info": { 367 | "geometry": { 368 | "base_width": 0, 369 | "base_height": 0, 370 | "max_width": 640, 371 | "max_height": 480, 372 | "aspect_ratio": 0 373 | }, 374 | "timing": { 375 | "fps": 60, 376 | "sample_rate": 48000 377 | } 378 | } 379 | }, 380 | { 381 | "name": "prosystem", 382 | "region": "NTSC", 383 | "roms": [], 384 | "system_info": { 385 | "library_name": "ProSystem", 386 | "library_version": "1.3e", 387 | "valid_extensions": "a78|bin", 388 | "need_fullpath": false, 389 | "block_extract": false 390 | }, 391 | "av_info": { 392 | "geometry": { 393 | "base_width": 320, 394 | "base_height": 240, 395 | "max_width": 320, 396 | "max_height": 292, 397 | "aspect_ratio": 1.3333333730697632 398 | }, 399 | "timing": { 400 | "fps": 60, 401 | "sample_rate": 48000 402 | } 403 | } 404 | } 405 | ] 406 | -------------------------------------------------------------------------------- /types.json: -------------------------------------------------------------------------------- 1 | { 2 | "ri": "bluemsx", 3 | "mx1": "bluemsx", 4 | "mx2": "bluemsx", 5 | "col": "bluemsx", 6 | "sg": "bluemsx", 7 | "sc": "bluemsx", 8 | "dsk": "cap32", 9 | "sna": "cap32", 10 | "cpc": "cap32", 11 | "com": "dosbox", 12 | "nes": "nestopia", 13 | "fds": "nestopia", 14 | "gb": "gambatte", 15 | "gbc": "gambatte", 16 | "mgw": "gw", 17 | "lnx": "handy", 18 | "st": "hatari", 19 | "stx": "hatari", 20 | "msa": "hatari", 21 | "gen": "picodrive", 22 | "smd": "picodrive", 23 | "md": "picodrive", 24 | "32x": "picodrive", 25 | "sms": "picodrive", 26 | "smc": "snes9x-next", 27 | "fig": "snes9x-next", 28 | "sfc": "snes9x-next", 29 | "swc": "snes9x-next", 30 | "uae": "uae", 31 | "adf": "uae", 32 | "fdi": "uae", 33 | "ipf": "uae", 34 | "dms": "uae", 35 | "gba": "vba-next", 36 | "vec": "vecx", 37 | "n64": "mupen64plus", 38 | "z64": "mupen64plus", 39 | "u64": "mupen64plus", 40 | "v64": "mupen64plus", 41 | "nds": "desmume", 42 | "gcm": "dolphin", 43 | "wdf": "dolphin", 44 | "tzx": "spectrum", 45 | "szx": "fuse", 46 | "z80": "fuse", 47 | "tap": "fuse", 48 | "tzx": "fuse", 49 | "udi": "fuse", 50 | "mgt": "fuse", 51 | "trd": "fuse", 52 | "scl": "fuse", 53 | "a26": "stella", 54 | "a52": "atari800", 55 | "xex": "atari800", 56 | "a78": "prosystem", 57 | "crt": "vice", 58 | "d64": "vice", 59 | "g64": "vice", 60 | "t64": "vice", 61 | "x64": "vice", 62 | "adf": "uae", 63 | "int": "jzintv", 64 | "ngp": "ngp", 65 | "ngc": "ngp" 66 | } 67 | --------------------------------------------------------------------------------