Skip to content

mmontag/chip-player-js

Repository files navigation

Chip Player JS

Screen Shot 2019-11-19 at 1 21 04 PM

Play online: Chip Player JS. Feature requests? Create an issue.

Features

  • Support popular game console formats and tracker formats (not exhaustive)
  • Advanced sound control (channel volume, panning, etc.) like NotSoFatso's stereo and bandlimiting controls
  • Built-in online music library like Chipmachine
  • Simple music management (at least the ability to save favorites) like Winamp/Spotify
  • High-quality MIDI playback with JS wavetable synthesis
    • Bonus: user-selectable soundbanks
  • Track sequencer with player controls and shuffle mode
  • Media key support in Chrome
  • High performance

Development Notes

Architecture

This project was bootstrapped with Create React App.

The player engines come from C/C++ libraries such as game-music-emu and libxmp, compiled to JS with Emscripten. Where possible, these projects are incorporated using git subtree.

The C/C++ code is compiled by scripts/build-chip-core.js. This file also defines the list of exports that will be available to the JavaScript program. Components that go into this build are as follows:

  • Manually selected cpp sources from game-music-emu.
  • For libraries with their own build system like LibXMP and Fluidlite (detailed below):
    • Build a static library with Emscripten (i.e. using emconfigure, emmake)
    • Link the static library in build-chip-core.js
  • tinyplayer.c: a super light MIDI file reader/player
  • showcqtbar.c: a modified FFMPEG plugin providing lovely constant Q spectrum analysis for the visualizer.

The music catalog is created by scripts/build-catalog.js. This script looks for a ./catalog folder to build a music index. This location is untracked, so put a symlink here that points to your local music archive. TODO: Document the corresponding public location (CATALOG_PREFIX).

Local Development Setup

Prerequisites: yarn, cmake, emsdk.

  • Clone the repository.
  • Run yarn install.

In building the subprojects, we ultimately invoke emmake make instead of make to yield an object file that Emscripten can link to in the final build.

  • Install the Emscripten SDK (emsdk).

  • The build script in package.json looks for the emsdk in ~/src/emsdk. Modify this line to match your emsdk install location if necessary:

    "build-chip-core": "source ~/src/emsdk/emsdk_env.sh; node scripts/build-chip-core.js",

Tight coupling to Github Pages

The project is currently set up to deploy to Github Pages. The deploy and deploy-lite NPM scripts invoke the gh-pages NPM module.

If you wish to deploy to your own Github Pages account, change the "homepage" field in package.json.

User Accounts and Saved Favorites Functionality

User account management is provided through Firebase Cloud Firestore. You must obtain your own Google Firebase credentials and update src/config/firebaseConfig.js with these credentials. This file is not tracked. Without these credentials, Login/Favorites functionality won't work.

Subproject: libxmp-lite

Our goal is to produce libxmp/libxmp-lite-stagedir/lib/libxmp-lite.a. Build libxmp (uses GNU make):

cd chip-player-js/libxmp/        # navigate to libxmp root
source ~/src/emsdk/emsdk_env.sh  # load the emscripten environment variables
autoconf
emconfigure ./configure
emmake make

Proceed to build libxmp-lite:

emmake make -f Makefile.lite     # this will have some errors, but they can be ignored
cd libxmp-lite-stagedir/
autoconf
emconfigure ./configure --enable-static --disable-shared
emmake make

Subproject: fluidlite

Our goal is to produce fluidlite/build/libfluidlite.a. Build fluidlite (uses Cmake):

cd chip-player-js/fluidlite/     # navigate to fluidlite root
source ~/src/emsdk/emsdk_env.sh  # load the emscripten environment variables
mkdir build                      # create a build folder for Cmake output
cd build                         
emcmake cmake -DDISABLE_SF3=1 .. # Cmake will generate a Makefile by default
                                 # Problems here? Try deleting CMake cache files
emmake make fluidlite-static

Subproject: psflib and lazyusf2

Our goal is to produce psflib/libpsflib.a and lazyusf2/liblazyusf.a. These use a special Emscripten.Makefile (loosely based on Jeurgen Wothke's webn64 .bat script).

Build psflib:

cd chip-player-js/psflib/
source ~/src/emsdk/emsdk_env.sh  # load the emscripten environment variables
emmake make -f Emscripten.Makefile libpsflib.a

Build liblazyusf:

cd ../lazyusf2/
emmake make -f Emscripten.Makefile liblazyusf.a

Subproject: libvgm

Our goal is to produce libvgm/build/bin/libvgm-emu.a, libvgm/build/bin/libvgm-player.a, and libvgm/build/bin/libvgm-util.a.

cd chip-player-js/libvgm/
source ~/src/emsdk/emsdk_env.sh  # load the emscripten environment variables
mkdir build                      # create a build folder for Cmake output
cd build
emcmake cmake ..
emmake make

To reconfigure the build-enabled sound chips with CMake UI, run emcmake ccmake .. from the build folder. Make desired changes to build flags, then c to configure and g to generate new Makefile. Then run emmake make. Optionally, commit the same changes back to CMakeLists.txt in libvgm parent folder.

WebAssembly build

Once these are in place we can build the parent project. Our goal is to produce public/chip-core.wasm.

cd chip-player-js/
yarn run build-chip-core

This will use object files created in the previous steps and link them into chip-core.wasm. If you change some C/C++ component of the subprojects, you'll need to redo this process. Once we have chip-core.wasm, we can proceed to develop JavaScript interactively on localhost:

yarn start

Build the entire project:

yarn build

Or deploy to Github Pages:

yarn deploy

Deploy to Github Pages without rebuilding chip-core.wasm:

yarn deploy-lite

Related Projects

Chipmachine (Native)

http://sasq64.github.io/chipmachine/

Chipmachine is a multiplatform player supporting an enormous number of formats. Downloads music from an impressive variety of external sources. Most of these come from HTTP sources without CORS headers, not feasible for direct playback.

Muki (JS)

http://muki.io

Muki, by Tomás Pollak, is a polished JS player pulling together Timidity (MIDI), Munt (MT-32), libopenmpt (instead of libxmp), game-music-emu, Wildmidi, Adplug, Adlmidi (OPL3), mdxmini, and sc68. The music is a collection of PC game music.

Chiptune Blaster (JS)

https://github.com/wothke?tab=repositories

Jeurgen Wothke's collection of chipmusic projects ported to the web with Emscripten. He's beaten me to it, but with a rudimentary player and no built-in music collection. http://www.wothke.ch/blaster

SaltyGME (JS)

http://gamemusic.multimedia.cx/about

SaltyGME is a GME-based web player targeting Google Chrome NaCl. (Deprecated)

Cirrus Retro (JS)

https://github.com/multimediamike/cirrusretro-players

Cirrusretro is an updated version of SaltyGME compiled with Emscripten. Self-hosted file archive.

Audio Overload (Native)

https://www.bannister.org/software/ao.htm

Audio Overload is a multiplatform player supporting 33 formats.

JSGME (JS)

http://onakasuita.org/jsgme/

One of the first examples of GME compiled with Emscripten. Music collection is a self-hosted mirror of Famicompo entries.

MoseAmp (Native + JS)

https://github.com/osmose/moseamp

MoseAmp is a multiplatform player built with Electron. Some nice game console icons: https://www.deviantart.com/jaffacakelover/art/Pixel-Gaming-Machine-Icons-413704203

Resources

MIDI Stuff

The best modern option for playing MIDI is probably using a well-designed GM SoundFont bank with a good SoundFont 2.01 implementation like FluidSynth.

SoundFont Credits

Diverse and usable GM SoundFonts.

Music Archive Sources

Miscellaneous

ISO 226 Equal loudness curves

License

A word about licensing: chip-player-js represents the hard work of many individuals because it is built upon several open-source projects. Each of these projects carries their own license restrictions, and chip-player-js as a whole must adhere to the most restrictive licenses among these. Therefore, chip-player-js is generally licensed under GPLv3.

However, each subdirectory in this project may contain additional, more specific license info that pertains to files contained therein. For example, the code under src/ is written by me and is more permissively MIT licensed.