Skip to content

crescent-stdio/wave-roll

Repository files navigation

WaveRoll

WaveRoll

WaveRoll is an interactive JavaScript library that enables comparative visualization and synchronized playback of multiple MIDI piano rolls on a browser.

NPM Version NPM License

Screenshot of WaveRoll

Installation

npm install wave-roll

Usage (NPM)

<!DOCTYPE html>
<html>
<head>
  <script type="module">
    import 'wave-roll';
  </script>
</head>
<body>
  <wave-roll
    style="width: 100%;"
    files='[
      {"path": "./audio/track.wav", "name": "Track Audio", "type": "audio"},
      {"path": "./midi/ground_truth.mid", "name": "Ground Truth", "type": "midi"},
      {"path": "./midi/modelA.mid", "name": "Model A", "type": "midi"}
    ]'>
  </wave-roll>
</body>
</html>

Using CDN (ES Module)

You can try the ES Module demo here and sample codes.

<!DOCTYPE html>
<html>
<head>
  <script type="module">
    import 'https://cdn.jsdelivr.net/npm/wave-roll@latest/dist/wave-roll.es.js';
  </script>
</head>
<body>
  <wave-roll
    style="width: 100%;"
    files='[
      {"path": "./audio/track.wav", "name": "Track Audio", "type": "audio"},
      {"path": "./midi/ground_truth.mid", "name": "Ground Truth", "type": "midi"},
      {"path": "./midi/modelA.mid", "name": "Model A", "type": "midi"}
    ]'>
  </wave-roll>
</body>
</html>

Using UMD CDN (Traditional Script)

You can try the UMD demo here and sample codes.

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/wave-roll@latest/dist/wave-roll.umd.js"></script>
</head>
<body>
  <wave-roll
    style="width: 100%;"
    files='[
      {"path": "./audio/track.wav", "name": "Track Audio", "type": "audio"},
      {"path": "./midi/ground_truth.mid", "name": "Ground Truth", "type": "midi"},
      {"path": "./midi/modelA.mid", "name": "Model A", "type": "midi"}
    ]'>
  </wave-roll>
</body>
</html>

GitHub Pages Usage

For GitHub Pages deployment, you can use the CDN directly:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>WaveRoll Demo</title>
  <script type="module">
    import 'https://cdn.jsdelivr.net/npm/wave-roll@latest/dist/wave-roll.es.js';
  </script>
</head>
<body>
  <wave-roll
    style="width: 100%"
    files='[
      {"path": "./audio/track.wav", "name": "Track Audio", "type": "audio"},
      {"path": "./midi/ground_truth.mid", "name": "Ground Truth", "type": "midi"},
      {"path": "./midi/modelA.mid", "name": "Model A", "type": "midi"}
    ]'>
  </wave-roll>
</body>
</html>

In React

import 'wave-roll';

function MidiComparison() {
  const files = [
    { path: "./audio/track.wav", name: "Track Audio", type: "audio" },
    { path: "./midi/ground_truth.mid", name: "Ground Truth", type: "midi" },
    { path: "./midi/modelA.mid", name: "Model A", type: "midi" }
  ];

  return (
    <wave-roll 
      style={{ width: '100%' }}
      files={JSON.stringify(files)}
    />
  );
}

Standalone Demo

Try the standalone version with drag-and-drop file upload interface:

The standalone demo is a minimal, ready-to-use interface where users can directly upload and compare MIDI/audio files without any additional setup.

Using in Jupyter Notebook

You can embed WaveRoll in Jupyter notebooks using IFrame:

from IPython.display import IFrame
IFrame(src='https://crescent-stdio.github.io/wave-roll/standalone.html', width='100%', height='800px')

This is particularly useful for music information retrieval (MIR) research, allowing you to visualize and compare transcription results directly in your analysis notebooks.

API

Attributes

Attribute Type Description
files string JSON string array of file objects with path and name properties
style string CSS styles for the component container
readonly boolean attribute When present, hides UI controls for adding/removing files (read‑only mode)

Read‑only Mode

Add the readonly attribute to disable file addition and deletion in the Settings modal (the "Add MIDI Files" button and per‑file delete buttons are hidden):

<wave-roll
  style="width: 100%; height: 600px;"
  files='[
    {"path": "./audio/track.wav", "name": "Track Audio", "type": "audio"},
    {"path": "./midi/ground_truth.mid", "name": "Ground Truth", "type": "midi"},
    {"path": "./midi/modelA.mid", "name": "Model A", "type": "midi"}
  ]'
  readonly
></wave-roll>

You can toggle this at runtime too:

const el = document.querySelector('wave-roll');
el.setAttribute('readonly', '');      // enable read-only
el.removeAttribute('readonly');       // disable read-only

File Object Structure

interface FileItem {
  path: string;   // URL or relative path to the file
  name: string;   // Display name shown in UI
  type?: "midi" | "audio"; // Defaults to "midi" when omitted
}

Development

# Install dependencies
npm install

# Run development server
npm run dev

# Build for production
npm run build

# Run tests
npm test

Acknowledgments

This library includes functionality ported from mir_eval, Music Information Retrieval evaluation library.

License

MIT License - see LICENSE file for details

Citation

If you use WaveRoll in your research, please cite:

About

[ISMIR 2025 LBD] JavaScript Library for Comparative MIDI Piano-Roll Visualization

Topics

Resources

License

Stars

Watchers

Forks