New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

karaoke-player

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

karaoke-player

A Node.js library for reading and playing MIDI/KAR karaoke files with multi-encoding support (UTF-8, TIS-620, Windows-874). Includes browser-only MIDI player with Web Audio API support.

latest
Source
npmnpm
Version
1.1.2
Version published
Weekly downloads
4
Maintainers
1
Weekly downloads
 
Created
Source

Karaoke Player - Node.js Library

A Node.js library for reading and extracting lyrics from MIDI/KAR karaoke files. This library allows you to easily read MIDI and KAR files, extract lyrics, and access MIDI event data.

Features

  • Web-based karaoke player - Run npm start to launch the web interface
  • Read MIDI and KAR files from disk or buffer
  • Extract lyrics with timing information
  • Get raw text from MIDI meta events
  • Access MIDI events and file information
  • Compatible with MIDI File type 0, 1, and 2
  • Multi-encoding support: UTF-8, TIS-620 (Thai), Windows-874/CP874 (Thai), and Latin1
  • Automatic encoding detection
  • No external dependencies for file reading (uses Node.js built-in modules)

Note: This library focuses on reading and extracting data from MIDI/KAR files. For MIDI playback, you'll need to integrate with a MIDI output library (like easymidi or midi) or a software synthesizer. The extracted MIDI events can be used to drive any MIDI playback system.

Encoding Support

The library automatically detects and handles multiple text encodings commonly used in MIDI/KAR files:

  • UTF-8 - Standard Unicode encoding
  • TIS-620 - Thai Industrial Standard 620-2533 (Thai language)
  • Windows-874 (CP874) - Windows code page 874 (Thai language with extended characters)
  • Latin1 (ISO-8859-1) - Western European encoding

Lyrics Decoding Fallback Chain

For lyrics extraction, the library uses a specific fallback chain to ensure maximum compatibility:

  • TIS-620 - Tried first (common for Thai karaoke files)
  • Windows-874 - Tried if TIS-620 fails
  • UTF-8 - Final fallback for Unicode text

This fallback mechanism ensures that lyrics are correctly decoded regardless of the encoding used in the MIDI/KAR file. The order prioritizes Thai encodings since many karaoke files use them, while still supporting UTF-8 for international content.

Installation

npm install

Building Browser-Compatible Files

Before using the library in a browser, you need to build the browser-compatible files:

npm run build

This will create browser-compatible files in the dist/ directory:

  • UTF8.js
  • MIDIEvents.js
  • MIDIFileHeader.js
  • MIDIFileTrack.js
  • TextEncoding.js
  • MIDIFile.js
  • karfiletis.js

These files can be included directly in your HTML using <script> tags.

Running the Web Player

To start the web-based karaoke player interface:

npm start

This will start a local HTTP server at http://localhost:3000/ where you can:

  • Open and play MIDI/KAR files from your computer
  • View karaoke lyrics in real-time
  • Use the web-based player interface

You can change the port by setting the PORT environment variable:

PORT=8080 npm start

Usage

Basic Example - Read Lyrics

const karaoke = require('./lib');

// Read a KAR file and get lyrics
karaoke.readFile('path/to/file.kar', (err, karFile) => {
  if (err) {
    console.error('Error:', err);
    return;
  }
  
  // Get lyrics with timing
  const lyrics = karFile.getLyrics();
  lyrics.forEach(line => {
    console.log(`[${Math.round(line.time / 1000)}s] ${line.text}`);
  });
});

Read from Buffer

const fs = require('fs');
const karaoke = require('./lib');

const buffer = fs.readFileSync('path/to/file.kar');
const karFile = karaoke.readBuffer(buffer, 'filename.kar');

const lyrics = karFile.getLyrics();
console.log(lyrics);

Get File Information

karaoke.getInfo('path/to/file.kar', (err, info) => {
  if (err) {
    console.error('Error:', err);
    return;
  }
  
  console.log('Format:', info.format);
  console.log('Tracks:', info.trackCount);
  console.log('Time Division:', info.timeDivision);
});

Get Raw Text

karaoke.getText('path/to/file.kar', (err, text) => {
  if (err) {
    console.error('Error:', err);
    return;
  }
  
  // text is an object with track numbers as keys
  for (const track in text) {
    console.log(`Track ${track}:`, text[track]);
  }
});

Get MIDI Events

karaoke.getEvents('path/to/file.kar', (err, events) => {
  if (err) {
    console.error('Error:', err);
    return;
  }
  
  // events is an object with track numbers as keys
  for (const track in events) {
    console.log(`Track ${track} has ${events[track].length} events`);
  }
});

Browser Usage - Play MIDI/KAR Files in HTML

To use the Player in a browser environment, you need to include the required scripts in your HTML file.

Step 1: Include Required Scripts

First, include all the necessary library files. You can use the built files from dist/ directory or use a bundler:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Karaoke Player</title>
</head>
<body>
  <!-- Include library scripts (order matters!) -->
  <script src="dist/UTF8.js"></script>
  <script src="dist/MIDIEvents.js"></script>
  <script src="dist/MIDIFileHeader.js"></script>
  <script src="dist/MIDIFileTrack.js"></script>
  <script src="dist/TextEncoding.js"></script>
  <script src="dist/MIDIFile.js"></script>
  <script src="assets/js/midiplayer/MIDIPlayer.js"></script>
  
  <!-- Optional: Include SpessaSynth for better sound quality -->
  <script type="importmap">
  {
    "imports": {
      "spessasynth_lib": "https://cdn.jsdelivr.net/npm/spessasynth_lib@latest/dist/index.js",
      "spessasynth_core": "https://cdn.jsdelivr.net/npm/spessasynth_core@latest/dist/index.js"
    }
  }
  </script>
  <script src="assets/js/midiplayer/SpessaSynthPlayer.js"></script>
</body>
</html>

Step 2: Create HTML Elements

<body>
  <!-- File input for selecting MIDI/KAR files -->
  <input type="file" id="fileInput" accept=".mid,.midi,.kar">
  
  <!-- Playback controls -->
  <button id="playBtn">Play</button>
  <button id="pauseBtn">Pause</button>
  <button id="stopBtn">Stop</button>
  
  <!-- Progress bar -->
  <input type="range" id="seekBar" min="0" max="100" value="0">
  
  <!-- Time display -->
  <span id="currentTime">0:00</span> / <span id="totalTime">0:00</span>
  
  <!-- Lyric display container -->
  <div id="lyricContainer"></div>
</body>

Step 3: Initialize and Use Player

<script>
  // Create player instance
  const player = new MIDIPlayer('fileInput', function(song) {
    console.log('Song loaded:', song);
    console.log('Duration:', song.duration);
    
    // Update UI when song is loaded
    document.getElementById('seekBar').max = song.duration;
    document.getElementById('totalTime').textContent = formatTime(song.duration);
    
    // Auto-play (optional)
    // player.play();
  });
  
  // Update position during playback
  player.ontick = function(song, position) {
    document.getElementById('seekBar').value = position;
    document.getElementById('currentTime').textContent = formatTime(position);
  };
  
  // Playback controls
  document.getElementById('playBtn').addEventListener('click', () => {
    player.play();
  });
  
  document.getElementById('pauseBtn').addEventListener('click', () => {
    player.pause();
  });
  
  document.getElementById('stopBtn').addEventListener('click', () => {
    player.stop();
  });
  
  // Seek functionality
  document.getElementById('seekBar').addEventListener('input', (e) => {
    const position = parseFloat(e.target.value);
    player.setPosition(position);
  });
  
  // Helper function to format time
  function formatTime(seconds) {
    const mins = Math.floor(seconds / 60);
    const secs = Math.floor(seconds % 60);
    return `${mins}:${secs.toString().padStart(2, '0')}`;
  }
</script>

Complete Example

Here's a complete working example:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Karaoke Player</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      max-width: 800px;
      margin: 0 auto;
      padding: 20px;
    }
    #lyricContainer {
      margin-top: 20px;
      padding: 20px;
      background: #f0f0f0;
      border-radius: 8px;
      min-height: 200px;
      text-align: center;
      font-size: 24px;
    }
    .controls {
      display: flex;
      gap: 10px;
      margin: 20px 0;
      align-items: center;
    }
    button {
      padding: 10px 20px;
      font-size: 16px;
      cursor: pointer;
    }
    #seekBar {
      flex: 1;
    }
  </style>
</head>
<body>
  <h1>Karaoke Player</h1>
  
  <input type="file" id="fileInput" accept=".mid,.midi,.kar">
  
  <div class="controls">
    <button id="playBtn">▶ Play</button>
    <button id="pauseBtn">⏸ Pause</button>
    <button id="stopBtn">⏹ Stop</button>
    <input type="range" id="seekBar" min="0" max="100" value="0">
    <span id="timeDisplay">0:00 / 0:00</span>
  </div>
  
  <div id="lyricContainer">Select a MIDI/KAR file to start</div>
  
  <!-- Include library scripts -->
  <script src="dist/UTF8.js"></script>
  <script src="dist/MIDIEvents.js"></script>
  <script src="dist/MIDIFileHeader.js"></script>
  <script src="dist/MIDIFileTrack.js"></script>
  <script src="dist/TextEncoding.js"></script>
  <script src="dist/MIDIFile.js"></script>
  <script src="assets/js/midiplayer/MIDIPlayer.js"></script>
  
  <script>
    // Initialize player
    const player = new MIDIPlayer('fileInput', function(song) {
      console.log('Song loaded:', song);
      document.getElementById('seekBar').max = song.duration;
      updateTimeDisplay(0, song.duration);
    });
    
    // Update position
    player.ontick = function(song, position) {
      document.getElementById('seekBar').value = position;
      updateTimeDisplay(position, song.duration);
    };
    
    // Controls
    document.getElementById('playBtn').onclick = () => player.play();
    document.getElementById('pauseBtn').onclick = () => player.pause();
    document.getElementById('stopBtn').onclick = () => player.stop();
    
    document.getElementById('seekBar').addEventListener('input', (e) => {
      player.setPosition(parseFloat(e.target.value));
    });
    
    function formatTime(seconds) {
      const mins = Math.floor(seconds / 60);
      const secs = Math.floor(seconds % 60);
      return `${mins}:${secs.toString().padStart(2, '0')}`;
    }
    
    function updateTimeDisplay(current, total) {
      document.getElementById('timeDisplay').textContent = 
        `${formatTime(current)} / ${formatTime(total)}`;
    }
  </script>
</body>
</html>

Using with SpessaSynth (Better Sound Quality)

For better sound quality, you can use SpessaSynth with a SoundFont file:

<!-- Include SpessaSynth -->
<script type="importmap">
{
  "imports": {
    "spessasynth_lib": "https://cdn.jsdelivr.net/npm/spessasynth_lib@latest/dist/index.js",
    "spessasynth_core": "https://cdn.jsdelivr.net/npm/spessasynth_core@latest/dist/index.js"
  }
}
</script>
<script src="assets/js/midiplayer/SpessaSynthPlayer.js"></script>

<script>
  // Initialize SpessaSynth
  const AudioContextFunc = window.AudioContext || window.webkitAudioContext;
  const audioContext = new AudioContextFunc();
  const spessaPlayer = new SpessaSynthPlayer(audioContext);
  
  // Load SoundFont (SF2/SF3/DLS format)
  const soundfontFile = await fetch('path/to/soundfont.sf3').then(r => r.arrayBuffer());
  await spessaPlayer.initialize('path/to/spessasynth_processor.min.js');
  await spessaPlayer.loadSoundFont(soundfontFile, 'main');
  
  // Create player and set soundfont engine
  const player = new MIDIPlayer('fileInput', function(song) {
    console.log('Song loaded');
  });
  
  player.setSoundfontEngine('spessasynth', spessaPlayer);
</script>

Note:

  • The Player requires browser environment with Web Audio API support
  • All scripts must be loaded in the correct order
  • For production, consider using a bundler (webpack, rollup, etc.) instead of individual script tags

Using with Bundlers (Webpack, Rollup, Vite, etc.)

If you're using a modern bundler, you can import the library directly:

// Using ES modules
import { KarFile, MIDIFile, Player } from 'karaoke-player';

// Or using CommonJS
const { KarFile, MIDIFile, Player } = require('karaoke-player');

Important: The Player class is browser-only and requires the MIDIPlayer script to be available globally. You'll need to:

  • Copy assets/js/midiplayer/MIDIPlayer.js to your project
  • Include it in your HTML or bundle it separately
  • Make sure window.MIDIPlayer is available before using Player

Example with Vite:

// main.js
import { Player } from 'karaoke-player';
import './assets/js/midiplayer/MIDIPlayer.js'; // Make MIDIPlayer available globally

// Now you can use Player
const player = new Player('fileInput', (song) => {
  console.log('Song loaded:', song);
});

Or with webpack:

// webpack.config.js
module.exports = {
  // ... other config
  plugins: [
    new webpack.ProvidePlugin({
      MIDIPlayer: path.resolve(__dirname, 'assets/js/midiplayer/MIDIPlayer.js')
    })
  ]
};

API Reference

Classes

Player (Browser-only)

Browser-only MIDI player class that uses Web Audio API for playback. Requires browser environment.

Note: This class is browser-only and will throw an error if used in Node.js. For Node.js, use KarFile and MIDIFile classes directly.

// Browser usage only
const { Player } = require('karaoke-player');

// Create player instance
const player = new Player('fileInputId', (song) => {
  console.log('Song loaded:', song);
  console.log('Duration:', song.duration);
});

// Play the loaded song
player.play();

// Pause playback
player.pause();

// Stop playback
player.stop();

// Get current position
const position = player.getPosition();

// Set position (seek)
player.setPosition(5.5); // Seek to 5.5 seconds

// Set soundfont engine (SpessaSynth)
player.setSoundfontEngine('spessasynth', spessaSynthInstance);

Methods:

  • play() - Start or resume playback
  • pause() - Pause playback
  • stop() - Stop playback
  • getPosition() - Get current playback position in seconds
  • setPosition(position) - Seek to specific position
  • setSoundfontEngine(engine, instance) - Set soundfont engine (SpessaSynth)
  • openFile(fileObj) - Open MIDI file from ArrayBuffer
  • handleFileSelect(event) - Handle file input change event

Properties:

  • currentPosition - Current playback position
  • duration - Song duration
  • state - Current state: 'stopped', 'playing', or 'paused'
  • onload - Callback when song is loaded
  • ontick - Callback for position updates

KarFile

Main class for reading and parsing KAR/MIDI files.

Methods:

  • readFile(filePath, callback) - Read a file from disk
  • readBuffer(buffer) - Read from a buffer
  • getLyrics() - Get formatted lyrics with timing (auto-detects encoding)
  • getText() - Get raw text from all tracks (auto-detects encoding)
  • readEvents() - Get all MIDI events organized by track

MIDIFile

Low-level MIDI file parser.

Methods:

  • getLyrics() - Get lyrics from meta events (auto-detects encoding)
  • getMidiEvents() - Get all MIDI events
  • getEvents(type, subtype) - Get filtered events
  • getTrackEvents(index) - Get events from a specific track

TextEncoding

Text encoding utilities for detecting and decoding various encodings.

Methods:

  • detectEncoding(bytes, byteOffset, byteLength) - Detect encoding from bytes
  • decodeString(bytes, byteOffset, byteLength, encoding) - Decode bytes with specified encoding
  • autoDecode(bytes, byteOffset, byteLength) - Auto-detect and decode
  • decodeWithFallback(bytes, byteOffset, byteLength) - Decode with fallback chain (TIS-620 → Windows-874 → UTF-8)
  • decodeTIS620(buffer) - Decode TIS-620 encoding
  • decodeWindows874(buffer) - Decode Windows-874 encoding

Supported encodings: 'utf8', 'tis620', 'windows874', 'cp874', 'latin1'

Note: The decodeWithFallback() method is used automatically for lyrics decoding in MIDI/KAR files.

Functions

  • readFile(filePath, callback) - Read a KAR/MIDI file
  • readBuffer(buffer, fileName) - Read from a buffer
  • getLyrics(filePath, callback) - Get lyrics directly
  • getText(filePath, callback) - Get raw text directly
  • getEvents(filePath, callback) - Get events directly
  • getInfo(filePath, callback) - Get file information

Examples

See the examples/ directory for more usage examples:

  • basic.js - Basic lyrics reading example
  • read-buffer.js - Reading from buffer example
  • get-info.js - Getting file information example

Run examples:

node examples/basic.js path/to/file.kar

Lyrics Format

The getLyrics() method returns an array of lyric lines with the following structure:

[
  {
    time: 0,        // Time in milliseconds
    text: "Hello",  // Lyric text
    track: 0,      // Track number
    parts: [        // Word-by-word breakdown
      { time: 0, text: "Hello" }
    ]
  },
  // ...
]

License

MIT

Original Project

This library is based on the web-based karaoke player project. The core MIDI parsing code has been adapted for Node.js use.

Keywords

midi

FAQs

Package last updated on 16 Dec 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts