0.4.3 • Public • Published

OPL3 emulator

OPL3 emulator usable as a CLI tool or as a library.

Ported from Yamaha YMF262 (OPL3) Emulator by Robson Cozendey.

Using from command line

Install OPL3 emulator as npm install -g opl3.

OPL3 emulator v0.4.2
Usage: opl3 <input file> [OPTIONS]

  --mp3            Export to MP3/Lame
  --wav            Export to WAV
  --ogg            Export to OGG/Vorbis
  --opus           Export to OGG/Opus
  --mid            Export to MIDI
  --laa            Use LAA format
  --mus            Use MUS format
  --dro            Use DRO format
  --imf            Use IMF format
  --raw            Use RAW format
  -h, --help       You read that just now
  -i, --genmidi    Use external GENMIDI lump (only MUS format)
  -n, --normalize  PCM audio normalization (default on, turn off with -n0)
  -p, --play       Play after processing
  -o, --output     Output directory

  opl3 D_E1M1.mus

Copyright (c) 2016 IDDQD@doom.js

Accepts glob patterns as input file, like opl3 **/*.mus.

Using from JavaScript

Use OPL3 and a format handler (like LAA) to process:

var fs = require('fs');
var OPL3 = require('opl3').OPL3;
var LAA = require('opl3').format.LAA;
var Player = require('opl3').Player;
var WAV = require('opl3').WAV;
var player = new Player(LAA);
player.load(fs.readFileSync('./laa/dott logo.laa'), function(err, result){
    if (err) return console.log(err);
    fs.writeFileSync('./dott.wav', new Buffer(WAV(result, 49700)));
player.on('progress', function(value){

To convert source (in LAA format) to raw PCM audio, you can use the Readable stream approach:

var fs = require('fs');
var OPL3 = require('opl3').OPL3;
var LAA = require('opl3').format.LAA;
var Player = require('opl3').Player;
var player = new Player(LAA);
var file = fs.createWriteStream('./dott.pcm');
player.load(fs.readFileSync('./laa/dott logo.laa'));
player.on('progress', function(value){

Convert source DRO to MP3 using node-lame:

var fs = require('fs');
var lame = require('lame');
var OPL3 = require('./').OPL3;
var LAA = require('./').format.LAA;
var Player = require('./').Player;
var player = new Player(LAA);
var file = fs.createWriteStream('./dott.mp3');
var encoder = new lame.Encoder({
    // input
    channels: 2,        // 2 channels (left and right)
    bitDepth: 16,       // 16-bit samples
    sampleRate: 49700   // 49,700 Hz sample rate
player.load(fs.readFileSync('./laa/dott logo.laa'));
player.on('progress', function(value){

Using in a browser

OPL3 is also available as a Bower package, install with bower install opl3.

If installed from Bower, include OPL3 client library as:

<script src="bower_components/opl3/dist/opl3.min.js"></script>

OPL3 client library is supporting UMD. When included as a global script, the library is available as window.OPL3. If WebWorker support is available in the browser, the library will automatically use a Worker to process audio in the background. You can find a browser example here.

The OPL3 client library has a built-in realtime playback feature using Web Audio API, see here. See an example here for realtime playback using pico.js.

Class: Player

Player is a Readable stream, with extra events.

new Player(format[, options])

  • format <FormatHandler> Any format handler included in opl3 module or a custom format handler.
  • options <Object$gt; Optional options object.

options properties are:

  • normalization: true to enable normalization (not available in realtime), default is false.
  • bitDepth: set bit depth of output PCM audio (16 or 32), default is 16.
  • bufferSize: size of audio chunk buffer for a single channel, default is 64 for realtime playback.
  • sampleRate: set sample rate of output PCM audio, default is 49700.
  • instruments: only supported in MUS format handler, override default GENMIDI instruments. This can be a raw lump file extracted from a WAD file or a JSON exported with WAD Commander.
  • prebuffer: prebuffer size in milliseconds for realtime audio playback, default is 200. Set this value to -1 if you want to disable any prebuffering.
  • volume: realtime audio playback starting volume, default is 1.
  • disableWorker: force processing on main thread.

player.load(buffer[, callback])

  • buffer <Buffer> | <ArrayBuffer> Source buffer
  • callback <Function> Optional callback when the audio processing is finished (including normalization if enabled). The result PCM audio buffer is passed to the callback function as an ArrayBuffer.
  • Return: Promise

Load source buffer for audio processing and start processing immediately. Result PCM audio buffer is 2-channel (stereo) 16-bit with 49700Hz sample rate.


  • buffer <Buffer> | <ArrayBuffer> Source buffer

Start or continue playing source buffer in realtime. Only available if AudioContext is supported.


Pause realtime audio playback.


  • ms <number> milliseconds

Seek realtime audio playback to position in milliseconds.

player.position <number>

Get position of realtime audio playback in milliseconds.

player.length <number>

Get length of realtime audio in milliseconds. Starts at zero and growing to full length while processing source buffer in background WebWorker.

player.volume <number>

Get or set audio volume, from 0 to Infinity

Event: 'progress'

  • <number>

The 'progress' event is emitted on audio processing and returns the current position of the audio processing in percentage (from 0 to 100).

Event: 'midi'

  • <ArrayBuffer>

The 'midi' event is emitted only if the format handler supports MIDI conversion. Emitted only once after audio is fully processed. Returns MIDI file buffer as an ArrayBuffer.

Event: 'normalization'

  • <number>

The 'normalization' event is emitted on audio normalization (if enabled) and returns the current current position of the normalization in percentage (from 0 to 100).

Event: 'gain'

  • <number>

The 'gain' event is emitted after normalization and returns the scale of normalization.

Event: 'position'

  • <number>

Emitted on realtime audio playback, returns audio playback position in milliseconds (same as player.position).

Class: ConvertTo32Bit

ConvertTo32Bit is a Transform stream class, use this to convert 16-bit PCM audio data to 32-bit.

Class: Normalizer

Normalizer is a Transform stream class, use this to normalize PCM audio data. Used internally in Player class.

WAV(data[, options])

See more details here. Use this function to generate WAV audio format buffer from PCM audio data.

Supported format types

  • LAA: LucasArts music
  • MUS: Doom music
  • DRO: DosBox RAW OPL
  • IMF: Id Music Format
  • RAW: Rdos Raw OPL Capture

MUS format GENMIDI instruments support

The OPL3 library includes GENMIDI lump from shareware Doom as the default instrument set. You can override this in the CLI tool and in the Player class as well.

Use opl3 doom2/*.mus --genmidi DOOM2.OP2 to inject the DOOM2.OP2 GENMIDI lump file into the MUS format handler.

From JavaScript:

new OPL3.Player(OPL3.format.MUS, {
    instruments: genmidi // ArrayBuffer or JSON

Supported audio export formats

MP3, OGG and audio playback support are based on optional dependencies. If a dependency install has failed, the export format won't be available.

PCM audio normalization

By default the command line utility uses peak normalization on the PCM audio result buffer. To turn off this feature, please use -n0 argument.

To enable normalization in the Player class, instantiate the player like:

var player = new Player(LAA, { normalization: true });

Special thanks to

  • Robson Cozendey, for creating That Vintage Tone OPL3 emulator
  • Paul Radek, for creating the MUS format
  • Vladimir Arnost, for creating MUSLib
  • Nathan Rajlich, for creating the MP3, OGG, Vorbis and Speaker node.js modules


npm i opl3

DownloadsWeekly Downloads






Last publish


  • iddqd