Giter VIP home page Giter VIP logo

mmontag / chip-player-js Goto Github PK

View Code? Open in Web Editor NEW
330.0 5.0 18.0 647.67 MB

Web-based music player for a variety of video game and chiptune music formats.

Home Page: https://chiptune.app

License: GNU General Public License v3.0

JavaScript 1.88% HTML 0.03% CSS 0.10% CMake 1.07% C++ 23.98% C 71.50% Makefile 0.38% Shell 0.15% Roff 0.01% M4 0.11% Assembly 0.54% Python 0.11% Perl 0.02% QMake 0.01% Batchfile 0.07% Dockerfile 0.02%
chiptunes midi music-player video-games retro

chip-player-js's Introduction

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.

chip-player-js's People

Contributors

boukichi avatar chouquette avatar cmatsuoka avatar dependabot[bot] avatar derselbst avatar divideconcept avatar flamefire avatar hexwab avatar jpcima avatar jprjr avatar kode54 avatar loki666 avatar mistydemeo avatar mmontag avatar nosuck avatar nyanpasu64 avatar okaxaki avatar opna2608 avatar pmachapman avatar schellingb avatar sezero avatar shlomif avatar superctr avatar tatokis avatar terriblefire avatar valleybell avatar vitamin-caig avatar wallneradam avatar wiliamsouza avatar wohlstand avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

chip-player-js's Issues

Arcade VGZ playback voice volume inconsistency issue

On certain VGZ files there's volume inconsistency. One of the prime examples is in Black Knight 2000 main theme. Notice how the vocals, as well as percussion are very quiet compared to the rest of available voices.
https://mmontag.github.io/chip-player-js/?q=black+kni&play=VGM+Rips%2FBlack_Knight_2000_(Williams_System_11B)%2F04+Main+Theme.vgz

Here's the video of the main theme BGM of this pinball machine. Notice how the percussion can be heard, as well as all the vocals.
https://www.youtube.com/watch?v=p61YjWczwLM&t=17s

NSF ends too early

  • The NSF format doesn't have any built-in notion of song duration.
  • game-music-emu determines the end of an NSF song when 2 seconds of silence is detected.
  • Some NSF repeat forever, so you need a max-length in addition to silence detection.
  • NSF format is fixed at max-length 2:30 in game-music-emu.
  • If you set the max length to something like 99:00, you will end up listening to the repeating songs for a long time.

Support UI themes/skins

Right now the CSS style situation is scattered.

Most styles are defined in a single styles.css file, but some styles are defined in component-local CSS objects. Some styles are defined inline in JSX.

The local component CSS rules out the possibility of supporting separate skins for the player.

The layout of the player is tightly coupled to the component structure. (Maybe a fixed layout is fine for now.)

In order to support themes, all the CSS needs to exist either in a styles.css file, or using a CSS-in-JS library.

Yarn install error

I clone this repository successful, and cd chip-player-js, run bash-command yarn install, then console tips compile-failed, and output stack-error on console, and I found this error:

node-pre-gyp WARN Tried to download(404): https://node-precompiled-binaries.grpc.io/grpc/v1.20.0/node-v83-linux-x64-glibc.tar.gz

How to resolve this? I'm not good at node.js, because node.js dependency is so complex...

System/Software Environment/Runtime:

[root@centos7-console chip-player-js]# cat /etc/redhat-release 
CentOS Linux release 7.8.2003 (Core)

[root@centos7-console chip-player-js]# gcc --version

gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

[root@centos7-console chip-player-js]# npm -v
6.14.8
[root@centos7-console chip-player-js]# yarn -v
1.22.5

[root@centos7-console chip-player-js]# npm config get registry
https://registry.npmjs.org/
[root@centos7-console chip-player-js]# yarn config get registry
https://registry.yarnpkg.com

yarn_install_error.log

Hotkeys guide

Add a link or button somewhere to display keyboard shortcuts.

Add catalog directory descriptions

Add some support to display a description.txt/info.txt in each directory.

I want to curate these to add provenance and other details to the main directories of the catalog.
At the root directory, this can be used to display latest updates to the catalog (or to chip player itself).

Slightly different from the TXT link displayed along with individual song files.

Problematic songs

List of troublesome files

MIDI

MDX

  • HDV01.MDX: locks up the player.
  • STC30.MDX: timer runs slow, never advances to next track.

VGM

On certain VGZ files there's volume inconsistency. One of the prime examples is in Black Knight 2000 main theme. Notice how the vocals, as well as percussion are very quiet compared to the rest of available voices. Here's the video of the main theme BGM of this pinball machine. Notice how the percussion can be heard, as well as all the vocals. https://www.youtube.com/watch?v=p61YjWczwLM&t=17s This was fixed when vgm playback was switched to libvgm.

MOD

  • saga_musix_-_daydreams.it puts the player in broken state

Don't ask for WebMIDI until it is needed

It's confusing that the page asks for WebMIDI permission on first load.
This should be requested only as needed, when the user chooses WebMIDI in MIDI Player Settings.

Favourite saving doesn't appear to work

Hi
When I attempt to save a song as favourite the little heart icon goes yellow for a second and then reverts back to its original colour. Nothing can be found under the favourites tab.

Naturally, I am logged in.

Here's my user agent string in case that is useful: Mozilla/5.0 (X11; Linux x86_64; rv:69.0) Gecko/20100101 Firefox/69.0

Song still playable with media keys after end of context

Steps to reproduce:

  1. Browse to a folder with a few songs.
  2. Click on the last song.
  3. Press next. The song should end and the context should be removed, disabling the player controls.
  4. Press the play button media key on the keyboard. Last song starts playing, but it should not play anything.

Player appears for a brief moment before disappearing

When I try to open the player it simply disappears shortly during loading process. Once that happens the "Error initializing constant Q transform." error pops up in the developer console.
Zrzut ekranu (44)

This screenshot is made while Chrome is in Incognito Mode to rule out adblock extensions interfering with site's functionality.

Chrome version: 83.0.4103.97 64-bit

Repeat-One should use loop points where supported

Follow up to #51. Some formats have native support for looping, i.e. NSF files that run forever, or MIDI with loop points.

Repeat-One mode should take advantage of this, i.e. Repeat-One should have multiple effects:

  • Repeating
    • Lock the sequencer to the current song (advancing the sequencer restarts the song; already implemented)
  • Looping
    • Disable auto-advance when player position reaches end of song. Slider handle should stick at the end of the slider range
    • Enable looping behavior within the player engines that support it

These are two distinct behaviors, but I think it makes sense to link them together under Repeat-One.

Volume control for external MIDI devices

Why not allow the Chip Player JS volume control to adjust the volume of Web MIDI devices? Even though devices have hardware volume controls, it can be a pain if you have multiple devices.

One of the following methods should work:

  1. Sysex master volume 0xF0 0x7F 0xid 0x04 0x01 0xmm 0xnn 0xF7 (ignoring this if it appears in songs)
  2. Multiply all channel volume events (CC 7) by master volume level
  3. (worst case) Multiply all note velocities by master volume level

This is complicated by MIDI statefulness, but it doesn't have to be perfect. Consider restarting songs acceptable.

Include artwork info in catalog.json

The artwork info for each music file should be included in catalog.json (in a compact representation - maybe just a flag to indicate its presence, such as img: 1) so that HTTP requests don't have to be made for every single item played, resulting in a lot of 404s. This will also allow synchronous logic in the case where there is no artwork. User should not have to wait for an HTTP request to 404 in order to see the fallback artwork for a given file.

Fix dirty audio buffer issues

Sometimes there is an audio glitch when switching songs. A player might leave stale sample data in the buffer when switching player engines or switching songs. I don't really know the cause.

Search results: folders are not segregated

The search results are interrupted by folders because the entire path is used for sorting.
The comparator should be aware of folders.

Folder/a.v2m
Folder/B/a.v2m
Folder/B/C/b.v2m
Folder/c.v2m
Folder/D/x.v2m

should be

Folder/B/C/b.v2m
Folder/B/a.v2m
Folder/D/x.v2m
Folder/a.v2m
Folder/c.v2m

image

Fix inferred metadata

game-music-emu sometimes finds artist metadata.

Yuzo Koshiro - The Super Three
Streets of Rage II - Sega Master System / Game Gear (1993/7/23)

4 bits of information:

  • composer
  • track title
  • game title
  • game system

should be

Game Title - Track Title
Composer - Game System

i.e.

Streets of Rage II - The Super Three
Yuzo Koshiro - Sega Master System / Game Gear (1993/7/23)

some formats have a different set of metadata, such as MIDI, where there is virtually none. Any metadata has to be inferred from file path, which varies in use:

/Piano+E-Competition+MIDI/2014/Cheng+Guang+-+5th+Prize/Rachmaninoff+-+Prelude+in+D+Major,+Op.+23,+No.+4.mid yields

2014 - Rachmaninoff - Prelude in D Major, Op. 23, No. 4.mid
Piano E-Competition MIDI

vs.

/MIDI/Frankie+Valli/December+1963+(Oh+What+a+Night).mid yields

Frankie Valli - December 1963 (Oh What a Night).mid
MIDI

vs.

/Game+MIDI/Ultima+Online/CREATE1.MID

CREATE1.MID
Ultima Online - Game MIDI

A solution

The metadata formatting and fallback behavior should be consolidated in one place. The app, after receiving metadata back from whichever player engine is in use, should combine the info with the file path and reconcile something. The player can return whatever sparse metadata it knows about, but the app is responsible for resolving all this to a "Title" and "Subtitle".

i.e.

getTitleAndSubtitleFromMetadataAndFilepath(metadata, filepath) {
  let title, subtitle;
  // inspect metadata
  if (metadata.artist) { ... }
  ...
  // make a decision about how to put together a title and subtitle
  return { title, subtitle };
}

Channel muting improvements

  1. Channel muting should be reset when a new song starts playing
  2. Alt+click or other key modifier should perform inverse mute (solo)
  3. Fix issues muting channel 1 on MIDI files
  4. Better UI: align channels in two columns

Sequencer gets stuck between songs in background tab

It seems that Chrome will suspend XHR requests when a tab is in the background. When the sequencer is playing through a song list, and the player is in a background tab, it gets stuck between tracks. This indicates that the audio process (and JavaScript) continues to run just fine, but something else that only happens between songs (like a network request) is held up by the browser.

Keep voices updated in MIDI player

The "Voices" panel is slightly different for each player.
In the case of the MIDI player, it displays the initial GM instrument on each MIDI channel (not MIDI tracks).

The instrument played on each channel can change during the course of the song with a "program change" event. The voices displayed in Chip Player then will be incorrect because it does not update.

We should intercept program change events and update a state map of Channel → Instrument inside the MIDI player.

Rethink catalog.json

Problem

catalog.json is 2.6 MB (740 KB gzipped).
This is a blocking request for the whole player to function (unacceptable).

Brainstorming

What can be done to improve this situation? Anything short of building a backend?
Maybe a backend is okay, but it needs to be extremely simple and fast. PHP, mysql? Go? Node.js?

What about backend as a service? Firebase does not provide full text search in Cloud Firestore. The trie-search functionality is not covered by SQL.

Fluidsynth MIDI playback is glitchy

I have no idea how this regression was introduced, but my MIDI playback with the SoundFont engine is now glitchy and stuttery.

Doesn't seem correlated to CPU usage. Flame graph looks normal, unless the missing towers are causing the glitches.

image

Discrete voice audio routing

Export channels to wav files could be a nice feature. Could be possible to do that?
Currently I try to do this job with RYMCast, but the channels completely panned to the right, generate an empty wav file.

Thanks for this amazing project

More PC game music

I don't know how you would achieve this, but I would like to be able to listen to a few more PC game music tracks e.g:

  • Transport Tycoon
  • Theme Hospital
  • Normality / Normality Inc

Drag and drop local files

would love to be able to drag and drop songs and see the visualisation – it is mesmerising 😋

Mobile "first"

Fix layout on mobile devices.

  • text wraps ugly
  • title is not visible
  • buttons overlap

Visualizer is hidden on mobile. Hide Player Settings too?

Move player controls to top of viewport? Difficult to anchor to bottom of viewport on iOS.

add repeat function

Please, add repeat function! [ask for a function]

Sometimes, I want to listen to music more than it's length.

License?

Hi, @mmontag 😄 .
This is a very interesting and most feature complete javascript based music player.

I am really curious, what is license for this project as I cannot find any license notes here, except at every 3rd party player library project directory?

Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.