Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

A web audio sampler instrument

NotificationsYou must be signed in to change notification settings

danigb/smplr

Repository files navigation

npm version

smplr is a collection of sampled instruments for Web Audio API ready to be used with no setup required.

Examples:

import{Soundfont}from"smplr";constcontext=newAudioContext();constmarimba=newSoundfont(context,{instrument:"marimba"});marimba.start({note:60,velocity:80});
import{DrumMachine}from"smplr";constcontext=newAudioContext();constdm=newDrumMachine(context);dm.start({note:"kick"});
import{SplendidGrandPiano,Reverb}from"smplr";constcontext=newAudioContext();constpiano=newSplendidGrandPiano(context);piano.output.addEffect("reverb",newReverb(context),0.2);piano.start({note:"C4"});

See demo:https://danigb.github.io/smplr/

smplr is still under development and features are considered unstable until v 1.0

ReadCHANGELOG for changes.

Library goals

  • No setup: specifically, all samples are online, so no need for a server.
  • Easy to use: everything should be intuitive for non-experienced developers
  • Decent sounding: uses high quality open source samples. For better or worse, it is sample based 🤷

Setup

You can install the library with a package manager or use it directly by importing from the browser.

Samples are stored athttps://github.com/smpldsnds and there is no need to download them. Kudos to allsamplerist 🙌

Using a package manger

Use npm or your favourite package manager to install the library to use it in your project:

npm i smplr

Usage from the browser

You can import directly from the browser. For example:

<html><body><buttonid="btn">play</button></body><scripttype="module">import{SplendidGrandPiano}from"https://unpkg.com/smplr/dist/index.mjs";// needs to be a urlconstcontext=newAudioContext();// create the audio contextconstmarimba=newSplendidGrandPiano(context);// create and load the instrumentdocument.getElementById("btn").onclick=()=>{context.resume();// enable audio context after a user interactionmarimba.start({note:60,velocity:80});// play the note};</script></html>

The package needs to be serve as a url from a service likeunpkg or similar.

Documentation

Create and load an instrument

All instruments follows the same pattern:new Instrument(context, options). For example:

import{SplendidGrandPiano,Soundfont}from"smplr";constcontext=newAudioContext();constpiano=newSplendidGrandPiano(context,{decayTime:0.5});constmarimba=newSoundfont(context,{instrument:"marimba"});

Wait for audio loading

You can start playing notes as soon as one audio is loaded. But if you want to wait for all of them, you can use theload property that returns a promise:

piano.load.then(()=>{// now the piano is fully loaded});

Since the promise returns the instrument instance, you can create and wait in a single line:

constpiano=awaitnewSplendidGrandPiano(context).load;

⚠️ In versions lower than 0.8.0 aloaded() function was exposed instead.

Shared configuration options

All instruments share some configuration options that are passed as second argument of the constructor. As it name implies, all fields are optional:

  • volume: A number from 0 to 127 representing the instrument global volume. 100 by default
  • destination: AnAudioNode that is the output of the instrument.AudioContext.destination is used by default
  • volumeToGain: a function to convert the volume to gain. It uses MIDI standard as default.
  • disableScheduler: disable internal scheduler.false by default.
  • scheduleLookaheadMs: the lookahead of the scheduler. If the start time of the note is less than current time plus this lookahead time, the note will be started. 200ms by default.
  • scheduleIntervalMs: the interval of the scheduler. 50ms by default.
  • onStart: a function that is called when starting a note. It receives the note started as parameter. Bear in mind that the time this function is called is not precise, and it's determined by lookahead.
  • onEnded: a function that is called when the note ends. It receives the started note as parameter.

Usage with standardized-audio-context

This package should be compatible withstandardized-audio-context:

import{AudioContext}from"standardized-audio-context";constcontext=newAudioContext();constpiano=newSplendidGrandPiano(context);

However, if you are using Typescript, you might need to "force cast" the types:

import{Soundfont}from"smplr";import{AudioContextasStandardizedAudioContext}from"standardized-audio-context";constcontext=newStandardizedAudioContext()asunknownasAudioContext;constmarimba=newSoundfont(context,{instrument:"marimba"});

Play

Start and stop notes

Thestart function accepts a bunch of options:

piano.start({note:"C4",velocity:80,time:5,duration:1});

Thevelocity is a number between 0 and 127 the represents at which velocity the key is pressed. The bigger the number, louder the sound. Butvelocity not only controls the loudness. In some instruments, it also affects the timbre.

Thestart function returns astop function for the given note:

conststopNote=piano.start({note:60});stopNote({time:10});

Bear in mind that you may need to callcontext.resume() before playing a note

Instruments have a globalstop function that can be used to stop all notes:

// This will stop all notespiano.stop();

Or stop the specified one:

// This will stop C4 notepiano.stop(60);

Schedule notes

You can schedule notes usingtime andduration properties. Both are measured in seconds. Time is the number of seconds since the AudioContext was created, like inaudioContext.currentTime

For example, next example plays a C major arpeggio, one note per second:

constnow=context.currentTime;["C4","E4","G4","C5"].forEach((note,i)=>{piano.start({ note,time:now+i,duration:0.5});});

Looping

You can loop a note by usingloop,loopStart andloopEnd:

constsampler=newSampler(audioContext,{duh:"duh-duh-ah.mp3"});sampler.start({note:"duh"loop:trueloopStart:1.0,loopEnd:9.0,});

Ifloop is true butloopStart orloopEnd are not specified, 0 and total duration will be used by default, respectively.

Change volume

Instrumentoutput attribute represents the main output of the instrument.output.setVolume method accepts a number where 0 means no volume, and 127 is max volume without amplification:

piano.output.setVolume(80);

⚠️volume is global to the instrument, butvelocity is specific for each note.

Events

Two events are supportedonStart andonEnded. Both callbacks will receive as parameter started note.

Events can be configured globally:

constcontext=newAudioContext();constsampler=newSample(context,{onStart:(note)=>{console.log(note.time,context.currentTime);},});

or per note basis:

piano.start({note:"C4",duration:1,onEnded:()=>{// will be called after 1 second},});

Global callbacks will be invoked regardless of whether local events are defined.

⚠️ The invocation time ofonStart is not exact. It triggers slightly before the actual start time and is influenced by thescheduleLookaheadMs parameter.

Effects

Reverb

An packed version ofDattorroReverbNode algorithmic reverb is included.

Useoutput.addEffect(name, effect, mix) to connect an effect using a send bus:

import{Reverb,SplendidGrandPiano}from"smplr";constreverb=newReverb(context);constpiano=newSplendidGrandPiano(context,{ volume});piano.output.addEffect("reverb",reverb,0.2);

To change the mix level, useoutput.sendEffect(name, mix):

piano.output.sendEffect("reverb",0.5);

Experimental features

Cache requests

If you use default samples, they are stored at github pages. Github rate limits the number of requests per second. That could be a problem, specially if you're using a development environment with hot reload (like most React frameworks).

If you want to cache samples on the browser you can use aCacheStorage object:

import{SplendidGrandPiano,CacheStorage}from"smplr";constcontext=newAudioContext();conststorage=newCacheStorage();// First time the instrument loads, will fetch the samples from http. Subsequent times from cache.constpiano=newSplendidGrandPiano(context,{ storage});

⚠️CacheStorage is based onCache API and only works in secure environments that runs withhttps. Read your framework documentation for setup instructions. For example, in nextjs you can usehttps://www.npmjs.com/package/next-dev-https. For vite there'shttps://github.com/liuweiGL/vite-plugin-mkcert. Find the appropriate solution for your environment.

Instruments

Sampler

An audio buffer sampler. Pass abuffers object with the files to be load:

import{Sampler}from"smplr";constbuffers={kick:"https://smpldsnds.github.io/drum-machines/808-mini/kick.m4a",snare:"https://smpldsnds.github.io/drum-machines/808-mini/snare-1.m4a",};constsampler=newSampler(newAudioContext(),{ buffers});

And then use the name of the buffer as note name:

sampler.start({note:"kick"});

Soundfont

A Soundfont player. By default it loads audio from Benjamin Gleitzman's package ofpre-rendered sound fonts.

import{Soundfont,getSoundfontNames,getSoundfontKits}from"smplr";constmarimba=newSoundfont(newAudioContext(),{instrument:"marimba"});marimba.start({note:"C4"});

It's intended to be a modern replacement ofsoundfont-player

Soundfont instruments and kits

UsegetSoundfontNames to get all available instrument names andgetSoundfontKits to get kit names.

There are two kits available:MusyngKite orFluidR3_GM. The first one is used by default: it sounds better but samples weights more.

constmarimba=newSoundfont(context,{instrument:"clavinet",kit:"FluidR3_GM",// "MusyngKite" is used by default if not specified});

Alternatively, you can pass your custom url as the instrument. In that case, thekit is ignored:

constmarimba=newSoundfont(context,{instrumentUrl:"https://gleitz.github.io/midi-js-soundfonts/MusyngKite/marimba-mp3.js",});

Soundfont sustained notes

You can enable note looping to make note names indefinitely long by loading loop data:

constmarimba=newSoundfont(context,{instrument:"cello",loadLoopData:true,});

⚠️ This feature is still experimental and can produces clicks on lot of instruments.

SplendidGrandPiano

A sampled acoustic piano. It uses Steinway samples with 4 velocity groups fromSplendidGrandPiano

import{SplendidGrandPiano}from"smplr";constpiano=newSplendidGrandPiano(newAudioContext());piano.start({note:"C4"});

SplendidGrandPiano constructor

The second argument of the constructor accepts the following options:

  • baseUrl:
  • detune: global detune in cents (0 if not specified)
  • velocity: default velocity (100 if not specified)
  • volume: default volume (100 if not specified)
  • decayTime: default decay time (0.5 seconds)
  • notesToLoad: an object with the following shape:{ notes: number[], velocityRange: [number, number]} to specify a subset of notes to load

Example:

constpiano=newSplendidGrandPiano(context,{detune:-20,volume:80,notesToLoad:{notes:[60],velocityRange:[1,127],},});

Electric Piano

A sampled electric pianos. Samples fromhttps://github.com/sfzinstruments/GregSullivan.E-Pianos

import{ElectricPiano,getElectricPianoNames}from"smplr";constinstruments=getElectricPianoNames();// => ["CP80", "PianetT", "WurlitzerEP200"]constepiano=newElectricPiano(newAudioContext(),{instrument:"PianetT",});epiano.start({note:"C4"});// Includes a (basic) tremolo effect:epiano.tremolo.level(30);

Available instruments:

  • CP80: Yamaha CP80 Electric Grand Piano v1.3 (29-Sep-2004)
  • PianetT: Hohner Pianet T (type 2) v1.3 (24-Sep-2004)
  • WurlitzerEP200: Wurlitzer EP200 Electric Piano v1.1 (16-May-1999)

Mallets

Samples fromThe Versilian Community Sample Library

import{Mallet,getMalletNames}from"smplr";constinstruments=getMalletNames();constmallet=newMallet(newAudioContext(),{instrument:instruments[0],});

Mellotron

Samples fromarchive.org

import{Mellotron,getMellotronNames}from"smplr";constinstruments=getMellotronNames();constmallet=newMellotron(newAudioContext(),{instrument:instruments[0],});

Drum Machines

Sampled drum machines. Samples from different sources:

import{DrumMachine,getDrumMachineNames}from"smplr";constinstruments=getDrumMachineNames();constcontext=newAudioContext();constdrums=newDrumMachine(context,{instrument:"TR-808"});drums.start({note:"kick"});// Drum samples are grouped and can have sample variations:drums.getSampleNames();// => ['kick-1', 'kick-2', 'snare-1', 'snare-2', ...]drums.getGroupNames();// => ['kick', 'snare']drums.getSampleNamesForGroup("kick")=>// => ['kick-1', 'kick-2']// You can trigger samples by group name or specific sampledrums.start("kick");// Play the first sample of the groupdrums.start("kick-1");// Play this specific sample

Smolken double bass

import{Smolken,getSmolkenNames}from"smplr";constinstruments=getSmolkenNames();// => Arco, Pizzicato & Switched// Create an instrumentconstcontext=newAudioContext();constdoubleBass=awaitnewSmolken(context,{instrument:"Arco"}).load;

Versilian

Versilian is a sample capable of using theVersilian Community Sample Library.

⚠️ Not all features are implemented. Some instruments may sound incorrect⚠️

import{Versilian,getVersilianInstruments}from"smplr";// getVersilianInstruments returns a PromiseconstinstrumentNames=awaitgetVersilianInstruments();constcontext=newAudioContext();constsampler=newVersilian(context,{instrument:instrumentNames[0]});

Soundfont2Sampler

Sampler capable of reading .sf2 files directly:

import{Soundfont2Sampler}from"smplr";import{SoundFont2}from"soundfont2";constcontext=newAudioContext();constsampler=newSoundfont2Sampler(context,{url:"https://smpldsnds.github.io/soundfonts/soundfonts/galaxy-electric-pianos.sf2",createSoundfont:(data)=>newSoundFont2(data),});sampler.load.then(()=>{// list all available instruments for the soundfontconsole.log(sampler.instrumentNames);// load the first available instrumentsampler.loadInstrument(sampler.instrumentNames[0]);});

Still limited support. API may vary.

License

MIT License


[8]ページ先頭

©2009-2025 Movatter.jp