A browser based HTML5/JS karaoke 'Player', that takes a .zip
rile containing an .mp3
and .cdg
file, allowing the
user to render and play directly in the browser.
CDGPlayer
is written for modern browsers, in ECMAScript 6. You may require Babel to bundle the
player into your application. Code does not support Internet Explorer. (It might work in IE 10 or 11, but I'm not
testing for it.)
The CDGPlayer
requires that JSZip, JSZipUtils
and jsmediatags be included in your html.
<script type="text/javascript" src="my/assets/jszip.min.js"></script>
<script type="text/javascript" src="my/assets/jszip-utils.min.js"></script>
<script type="text/javascript" src="my/assets/jsmediatags.min.js"></script>
To include the player in your application, simply install it via npm:
npm install cdgplayer
The package contains two objects for use in your code. Import the objects that you require directly into your project.
import { CDGPlayer, CDGControls } from 'cdgplayer';
The CDGPlayer
object will handle adding the output 'screen' to a container that you define in your html, and provides
methods for loading a .zip
file from your server.
const player = new CDGPlayer('#cdg_video_wrapper');
To load your karaoke file into the player, the player expects that the file is a .zip
file containing the two
necessary files for CD+G playback: the .mp3
file and it's corresponding .cdg
file. This is the industry standard
today for distributing CD+G files.
Currently loading a file takes a string as a relative path on your server. The player will handle the GET
request
to request the file.
const myFilePath = 'path/on/my/server/to/song.zip';
player.load(myFilePath);
The other methods are really only necessary for anyone not using the CDGControls, which handle all of these function calls automatically. If you want to use a custom control set, these methods are provided for your convenience. If you don't require a custom control set, then I suggest you jump straight to the CDGControls documentation.
Starts the audio and video display
player.start();
Pauses the audio and video display
player.pause();
Stops the audio and video display, and resets the playhead to the beginning of the song
player.stop();
Will start or pause the audio and video display, depending on it's current state
player.togglePlay();
Resets the playhead to the percentage of the song passed in.
player.changePlayerPosition(36);
Changes the song key by semitones (half steps) up or down. Maintains the song tempo regardless.
player.changeKey(-1); // takes it down half a step
Changes the song volume up or down.
player.volume(.5); // takes it up a few steps
player.volume(-.5); // takes it down a few steps
Toggles the "Mute". If volume is greater than 0 it will "Mute" the audio. If already "Mute"d it will put the volume back to it's previous value.
player.toggleMute();
None. Video is loaded with the file, and plays/pauses when the audio plays/pauses. Size of your overall video is controlled by how you size your 'player' container, and will automatically maintain it's aspect ratio of 300:216.
Convenience method to remove all DOM listeners, classes, and elements that had been applied to the DOM.
Note: Calling methods on the instance, after calling destroy()
, will throw many errors.
player.destroy();
There are several properties that are 'observed' in the prayer. It is possible to subscribe to updates of these properties, so that your application can automatically respond to player changes. The 'observed' properties are
- status - String (Gives status updates during player operations)
- loaded - Boolean (Is the song loaded)
- loading - Boolean (Is the song loading)
- isPlaying - Boolean (Is the song playing)
- timePlayed - String (Current time code of the playhead, in minutes:seconds [m:ss] format)
- trackLength - String (Length of currently loaded song, in minutes:seconds [m:ss] format)
- destroy - Boolean (Is the player 'destroyed')
These are 'observed' properties, so you can 'listen' for changes.
const onLoadingChange = player.props.on('loading', (val, prev) => {
if (val !== prev) {
// loading changed, so now do something
}
});
Remember to clean up your 'listeners' if you're tearing down your player instance.
player.props.off(onLoadingChange);
player.destroy(); // 'destroy()' doesn't know about **your** listeners, so you have to handle it yourself
The CDGControls
object provides you with a prebuilt, fully configured player interface for controlling the song
loaded into the CDGPlayer
, including base styling. It allows you to start/pause your song, change the playhead
position, and change the key. This makes setting up a fully functional player very easy. Control defaults to 100% of
the width of it's container.
constructor(String - CSS selector for video wrapper container, CDGPlayer - your 'player' instance [,options])
<div class="cdg-player">
<div id="cdg_controls"></div>
<div id="cdg_wrapper"></div>
</div>
import { CDGPlayer, CDGControls } from 'cdgplayer';
const player = new CDGPlayer('#cdg_wrapper');
const controls = new CDGControls('#cdg_controls', player);
// logic to get your songlist and load songs
Options is an optional object. Currently the only option is position
, which defaults to bottom
. If you place the
controls above your player, use postion: 'top'
. This will allow the volume slider to switch positions.
There are no methods, as all control is handled directly from the interface and it's connection to your player.
- Play/Pause Button - Disabled until your song is 'loaded' into the player, 'click' will toggle the play state
- Progress Meter - Shows the percentage of the current playhead. 'Click'ing this will change to position in the song.
- Pitch Control - Disabled until your song is 'loaded' into the player, a Number input to change your key up or down (on change). Defaults to 0;
It's fairly common to want something to display when the player is not yet loaded. We've provided a container, with a transparent background, which will automatically cover the video canvas whenever the player is not 'loaded'. Here you can add your own CSS to include your own title image. Because you want to use something that works at almost any size, we suggest you use a large SVG (maybe 1024x1024). Just remember that your video window's aspect ration is 75:54. Here's an example of your possible CSS.
.titleImage {
background-image: url('./myTitleGraphic.svg');
background-size: 90% 90%;
background-position: center;
background-repeat: no-repeat;
}
The following classes are automatically appended to the head of your document, by the package. If you choose to override the default display, write a css file that is appened to the body of your document.
- .cdg-video-wrapper -- automatically applied to the wrapper passed in to your
CDGPlayer
constructor - .cdg-video-player -- applied to the video
canvas
(base size is 300px x 216px) + 12px padding - .cdg-video-player.x2 -- 2x the base player size
- .cdg-video-player.x3 -- 3x the base player size
- .cdg-video-player.x4 -- 4x the base player size
- .titleImage -- A container for a title image to display when the player isn't loaded
- cdg-controls (HTML element) flexbox container
- .playButton -- The play/pause 'button'
- .playButton>i -- The icon in the play button
- .playButton>i.icofont-play-alt-1 -- The icon when song not playing (play icon)
- .playButton>i.icofont-pause -- The icon when song is playing (pause icon)
- .playButton[disabled] -- change the cursor and font color when disabled
- .timePlayed -- The current playhead time position
- .progress-meter -- Container for the meter
- .progress -- The actual
progress
HTML element - .progress::-webkit-progress-bar -- Style the progress bar
- .progress::-webkit-progress-value -- Style the "progress" of the progress bar
- .trackLength -- The current song's track length
- .pitch -- The key changer Number input
- .pitch[disabled] -- change the cursor when disabled
- .volumeControl -- container for the volume button and slider
- .volumeButton -- the volume button itself
- .volumeButton.i -- the icon for volume
- .volumeButton.i.icofont-audio -- the actual icon
- .volumeButton[disabled] -- change the cursor and font color when disabled
- .volumeSlider -- the container for the volume range slider
- .volumeSlider.under -- moves the range slider to below the controls (defaults to above)
- .volumeRange -- the volume range slider
- .volumeRange::-webkit-slider-thumb -- the slider knob
If you cloned this repository you can easily run the included example.
- Run
npm install
& Place a CD+G karaoke.zip
file in thezipfiles
folder - Write the
.zip
filename into the rootindex.js
file. - Run
npm start
- Open your browser to http://localhost:8081
I've done a lot of back-and-forth/trial-and-error on this player over the last year or so. I had a working player
that worked with the HTML audio
element, but it didn't give me the control to change the key (critical for any
real karaoke player). The original player was based on the HTML5 cdg player from CD+Graphics Magic.
I rewrote SoundTouch JS to a distributable SoundTouchJS
package, and included a PitchShifter
component for handling key changes. See that repository for credits there.
The current player is based on, and uses pieces of the karaoke player written by Keith McKnight. He gives some additional credits in that repository too.
I got my observable properties courtesy of proxy-observable by Anton Lapshin.
And I got royalty free play
and pause
font icons courtesy of IcoFont.