npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@maple-kaede/picoaudio

v3.0.0

Published

PicoAudio.js is light MIDI player using Web Audio API

Readme

PicoAudio.js

PicoAudio.jsについて

Web上でMIDI(Standard MIDI File=SMF)を再生するためのJavaScriptライブラリです。 SMF形式のバイナリのパースや、Web Audio API を用いた楽曲の再生ができます。

Web Audio API から提供される数種の音源を組み合わせて、8bitサウンドで演奏を行います。 また、別途音源の準備をする必要がなく、Webと音楽を組み合わせた開発がすぐに始められます!

A JavaScript library for playing MIDI (Standard MIDI File = SMF) on Web. You can parse SMF Files and play music using Web Audio API.

Play with 8-bit sound by combining several types of sound sources provided by Web Audio API. There is no need to prepare a sound source, and development that combines the Web and Music can be started immediately!

主な機能

  • MIDIファイル(SMF)のパース
  • パースしたデータの再生
  • 再生時のnoteOn/noteOffイベント受け取り など

利用されているプロダクト

サンプル

導入方法

Browser

<script src="https://unpkg.com/picoaudio/dist/browser/PicoAudio.js"></script>
または、
<script src="https://unpkg.com/picoaudio/dist/browser/PicoAudio.min.js"></script>

※ グローバル変数に PicoAudio が定義されます

Module

$ npm install picoaudio

https://www.npmjs.com/package/picoaudio (pico-audio-js has deprecated)

はじめ方

初期化

const picoAudio = new PicoAudio();
picoAudio.init();

再生

// Standard MIDI Fileの準備
const file = /* FileReaderやFetchなどで取得 */
const smfData = new Uint8Array(file);

// SMF形式のバイナリのパースを行う
const parsedData = picoAudio.parseSMF(smfData);

// パースしたデータをセット
picoAudio.setData(parsedData);

// 再生
picoAudio.play();

※ PicoAudio.play メソッドは、ユーザのジェスチャーイベントから呼び出す必要がある場合があります (参考)

停止

// 一時停止
picoAudio.pause();

API

Main Functions

PicoAudio.init

// PicoAudioインスタンスの生成
new PicoAudio({
  debug: boolean, // デバッグON/OFF
  audioContext: AudioContext, // 生成済みのAudioContextを再利用
  picoAudio: PicoAudio, // 生成済みのPicoAudioインスタンスを再利用
}): PicoAudio

※ 細かいパラメータも設定可能 (参考)

PicoAudio.parseSMF

// SMFファイルをパースし、PicoAudioで再生できる形式にする
// ピアノロールの描画を行いたい場合などに、ParsedSMFが利用できる
PicoAudio.parseSMF(smfFile: Uint8Array): ParsedSMF

PicoAudio.setData

// パースされたデータをセットする
PicoAudio.setData(parsedSMF: ParsedSMF): void

PicoAudio.play

// セットされているデータで再生する
PicoAudio.play(isLoop: boolean): void

PicoAudio.pause

// 楽曲の一時停止
PicoAudio.pause(): void

PicoAudio.initStatus

// 再生状態の初期化
PicoAudio.initStatus(): void

PicoAudio.setStartTime

// 再生開始位置の設定
PicoAudio.setStartTime(offseTime: number) :void

ステータスのSetter/Getter

// 全体音量の設定
PicoAudio.getMasterVolume(): number
PicoAudio.setMasterVolume(volume: number): void

// リバーブの設定
PicoAudio.isReverb(): boolean
PicoAudio.setReverb(enable: boolean): void
PicoAudio.getReverbVolume(): number
PicoAudio.setReverbVolume(volume: number): void

// コーラスの設定
PicoAudio.isChorus(): boolean
PicoAudio.setChorus(enable: boolean): void
PicoAudio.getChorusVolume(): number
PicoAudio.setChorusVolume(volume: number): void

// チャンネルの音色情報や音量の設定
PicoAudio.initChannels(): void
PicoAudio.getChannels(): Array
PicoAudio.setChannels(channels: Array): void

// ループの設定
PicoAudio.isLoop(): boolean
PicoAudio.setLoop(enable: boolean): void

// Web MIDI APIの設定
PicoAudio.isWebMIDI(): boolean
PicoAudio.setWebMIDI(enable: boolean): void

// Control Change 111 のループの設定
PicoAudio.isCC111(): boolean
PicoAudio.setCC111(enable: boolean): void

Event周辺

PicoAudio.addEventListener

// イベントリスナを登録
PicoAudio.addEventListener(
  type: <'play' | 'pause' | 'noteOn' | 'noteOff' | 'songEnd'>,
  listener: Function
): void
PicoAudio.addEventListener (noteOn)
// 音の開始イベントのリスナ登録ができる
// 発音される音のタイミングや高さ、強さなどが取得できる
PicoAudio.addEventListener(
  type: 'noteOn',
  listener: (event: NoteEvent) => void
): void

type NoteEvent = {
  channel: number, // チャンネル(0-15)
  instrument: number, // 楽器の種類(0-127)

  start: number, // 音の始まりのタイミング(tick=SMF時間)
  stop: number, // 音の終わりのタイミング(tick)
  startTime: number, // 音の始まりのタイミング(秒数)
  stopTime: number, // 音の終わりのタイミング(秒数)

  velocity: number, // ベロシティ(0-1)
  pitch: number, // 音の高さ(0-127)

  // CCパラメータ
  pan: CCEvent[],
  pitchBend: CCEvent[],
  expression: CCEvent[],
  modulation: CCEvent[],
  chorus: CCEvent[],
  reberb: CCEvent[],
}

type CCEvent = {
  timing: number, // タイミング(tick)
  time: number, // タイミング(秒数)
  value: number // 値(0-127)
}
PicoAudio.addEventListener (noteOff)
// 音の終了イベントのリスナ登録ができる
PicoAudio.addEventListener(
  type: 'noteOff',
  listener: (event: NoteEvent) => void
): void

removeEventListener

// 指定のイベントリスナを解除
PicoAudio.removeEventListener(
  type: <'play' | 'pause' | 'noteOn' | 'noteOff' | 'songEnd'>,
  listener: Function
): void

removeAllEventListener

// 指定typeのイベントリスナをすべて解除
PicoAudio.removeAllEventListener(
  type: <'play' | 'pause' | 'noteOn' | 'noteOff' | 'songEnd'>
): void

SMFパース周辺

parsed SMF

// 準備中
変換関数
PicoAudio.getTime
// tick から 時間に変換 (テンポも考慮される)
PicoAudio.getTime(tick: number): number
PicoAudio.getTiming
// 時間からtickに変換
PicoAudio.getTiming(time: number): number

License

Code released under the MIT License

SoundFont (SF2) 再生

soundQuality = 4 のとき、PicoAudio は SoundFont2 (.sf2) ファイルで発音します。 エンジンは TinySoundFont の JavaScript 移植版 (src/player/sf2/tsf-font.js, tsf-synth.js, tsf.js) で、プリセット/ゾーンの解決、 ボリューム/モジュレーション エンベロープ、フィルタ、LFO、ループ、パン、音量まで 参照実装と同じ計算を使います。そのため C 版 TinySoundFont とほぼ同一の波形になり、 ノート単位の照合で最大誤差 2.5e-6 です。

// SoundFont2 ファイル (ArrayBuffer) を読み込む
picoAudio.loadSF2(arrayBuffer);   // -> boolean
picoAudio.isSF2Loaded();          // -> boolean

// サンプル補間アルゴリズムを選ぶ
//   'linear'  : 既定。TinySoundFont (参照実装) と同じ
//   'nearest' : 最軽量、やや粗い
//   'cubic'   : 4点 Catmull-Rom、最も滑らか
picoAudio.setSF2Interpolation('cubic');
picoAudio.getSF2Interpolation();

settings.soundQuality = 4 と併せて settings.sf2Interpolation を直接設定しても構いません。 ドラム (MIDI チャンネル 10) は GM のキットバンク (bank 128) からプリセットを選びます。

長い音符はチャンク単位でストリーミング合成されます。音符を開始した瞬間に必要なのは 先頭 2 秒分だけで、残りは再生に合わせて少しずつ合成されるため、数秒〜数十秒の持続音でも メインスレッドが固まりません (60 秒の音符で 42ms → 1.2ms、メモリ 20MB → 0.7MB)。 OfflineAudioContext (WAV/動画書き出し) では従来どおり一括合成します。 settings.sf2Streaming = false で無効化できます。 バックグラウンドのタブではタイマーが間引かれるため、非表示になった時点で 再生中の音符の残りを全て合成し、以降の音符は一括合成に切り替えます (音が途切れません)。

Build variants / ビルドバリエーション

Four bundles are built from the same sources. They only differ in which sound engines are compiled in: src/features.js is replaced per variant, so the excluded engines (and the embedded waveform table) are dropped from the bundle instead of merely being switched off at runtime.

| variant | nodejs esm | soundQuality | size (nodejs esm) | | --- | --- | --- | --- | | full (default) | dist/nodejs/picoaudio.mjs | 0, 1, 4 | 341 KB | | sf2-wave-nodefault | dist/nodejs/picoaudio.sf2-wave-nodefault.mjs | 0, 1, 4 (no built in table) | 302 KB | | sf2 | dist/nodejs/picoaudio.sf2.mjs | 0, 4 | 279 KB | | wave | dist/nodejs/picoaudio.wave.mjs | 0, 1 | 232 KB | | wave-nodefault | dist/nodejs/picoaudio.wave-nodefault.mjs | 0, 1 (no built in table) | 192 KB | | basic | dist/nodejs/picoaudio.basic.mjs | 0 | 170 KB |

Every variant is also built for the browser as dist/browser/PicoAudio[.variant].js and .min.js.

soundQuality 0 is the basic oscillator mode (the upstream PicoAudio feature set), 1 the periodic wave / wavetable mode and 4 SoundFont 2 playback (loadSF2). The old sample bank value 3 is gone: 3 now plays SF2. The basic build keeps percussion, that kit is synthesised from oscillators and noise, like upstream.

npm run build                # build every variant
npm run build:full           # ...or one of them:
npm run build:sf2            # build:sf2-wave-nodefault, build:wave,
npm run build:wave           # build:wave-nodefault, build:basic

At runtime PicoAudio.features reports what a bundle contains, e.g. { wave: true, sf2: true }.

Engines that are not ready are never used: selecting soundQuality 1 or 4 without a loaded wavetable / soundfont - or in a build that does not contain that engine at all - plays the basic waveform engine instead, so a player that has not prepared its sound source still makes sound. loadSF2() returns false in builds without the SF2 engine, and loadSamples() is a deprecated no-op (that engine is gone).

The wave-nodefault build carries no waveform table at all, so a host that wants the wavetable mode must supply its own: picoAudio.loadWaves(buffer) before the first note. Until then soundQuality: 1 plays the basic engine.

Credits

FM tones: sneakernets/DMXOPL (MIT License)

SF2 synthesis: TinySoundFont © Bernhard Schelling, based on SFZero © Steve Folta (MIT License) — ported to JavaScript in src/player/sf2/tsf-font.js, src/player/sf2/tsf-synth.js and src/player/sf2/tsf.js. The upstream copyright notice is kept in those files.