High quality multisampled web audio piano with progressive loading and caching
This is a fork of @tonejs/piano by Yotam Mann with performance optimizations, sample caching, progressive loading, and more active maintaince. Built on high-quality samples from Salamander Grand Piano.
- High-quality samples - Up to 16 velocity levels across 88 keys (Yamaha C5)
- Complete instrument - Includes pedal sounds and string harmonics
- Progressive loading - Loads 1 velocity level immediately for fast startup, then upgrades to full quality in the background and seemlessly improves audio quality
- Cache-aware - Probes the Cache Storage API at startup; if target-velocity samples are already cached, starts at full quality immediately rather than the single-velocity warm-up pass
- Buffer caching - Audio buffers are shared across multiple piano instances and across progressive upgrade steps without no re-fetching
Install the npm package:
npm install --save d-pianod-piano requires Tone.js as a peer dependency:
npm install --save toneimport { Piano } from 'd-piano'// Create the piano — progressive loading is automatic
const piano = new Piano({
velocities: 8 // target quality; default is 8
})
// Connect to speaker output
piano.toDestination()
// Resolves as soon as the first pass (1 velocity) is ready to play.
// Upgrading to full quality happens automatically in the background.
piano.load().then(() => {
console.log('Piano ready — playing at 1 velocity, upgrading in background')
})load() resolves after a fast first pass (1 velocity layer) so you can start playing immediately. The upgrade to the target velocity count happens in the background, expanding the velocity layers in-place without interrupting notes that are already playing.
If the target samples are already in the Cache Storage API, the piano starts at full quality immediately instead of going through the single-velocity warm-up pass first. This pairs well with preloadSamples and any service worker caching strategy in your own app.
Cold load (nothing cached):
load() resolves → playing at 1 velocity
[idle] → upgrades to 8 velocities in-place, no interruption
Warm load (samples cached):
load() resolves → playing at 8 velocities immediately
Use preloadSamples to fetch samples ahead of time without importing the full Tone.js piano. Combined with a service worker caching strategy in your app, this means Piano will detect the cached samples on the next load and start at full quality immediately.
import { preloadSamples } from 'd-piano'
await preloadSamples(8, {
baseUrl: '/assets/samples/piano/',
minNote: 21,
maxNote: 108,
})interface PianoOptions {
velocities: number; // Target velocity levels (default: 8, max: 16). Progressive
// loading starts at 1 and upgrades to this in the background.
minNote: number; // Lowest MIDI note to load (default: 21)
maxNote: number; // Highest MIDI note to load (default: 108)
release: boolean; // Include release sounds (default: false)
pedal: boolean; // Include pedal sounds (default: true)
url: string; // Sample directory URL
maxPolyphony: number; // Max simultaneous notes (default: 32)
volume: { // Component volume levels in dB (default: 0)
pedal: number;
strings: number;
keybed: number;
harmonics: number;
}
}Press a note down on the piano.
// Play a 'C4' immediately
piano.keyDown({ note: 'C4' })
// Play a 'C4' 1 second from now with velocity 0.8
piano.keyDown({ note: 'C4', time: '+1', velocity: 0.8 })Release a note at the given time.
// Release the pressed 'C4' immediately
piano.keyUp({ note: 'C4' })Press and hold the sustain pedal. Notes played while the pedal is down will be sustained until the pedal is released.
Release the sustain pedal and dampen any sustained notes.
Start loading samples. Resolves as soon as the first velocity pass is ready to play. The upgrade to full velocity resolution continues in the background and requires no further interaction.
true once the first velocity pass has finished loading and the piano is ready to play.
Clean up the piano instance and free resources.
npm run buildnpm testnpm run lintThis project builds upon the great work of:
- @tonejs/piano by Yotam Mann - The original high-quality piano instrument that serves as the foundation for this project
- Tone.js by Yotam Mann - The Web Audio framework that powers the audio engine
- Salamander Grand Piano - The high-quality piano samples used in this instrument
MIT License - see LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.