smplr 0.20.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +119 -77
- package/dist/index.d.mts +181 -177
- package/dist/index.d.ts +181 -177
- package/dist/index.js +318 -488
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +316 -487
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -6,37 +6,60 @@
|
|
|
6
6
|
|
|
7
7
|
Examples:
|
|
8
8
|
|
|
9
|
+
**Play a note from a General MIDI soundfont:**
|
|
10
|
+
|
|
9
11
|
```js
|
|
10
12
|
import { Soundfont } from "smplr";
|
|
11
13
|
|
|
12
14
|
const context = new AudioContext();
|
|
13
|
-
const marimba =
|
|
15
|
+
const marimba = Soundfont(context, { instrument: "marimba" });
|
|
14
16
|
marimba.start({ note: 60, velocity: 80 });
|
|
15
17
|
```
|
|
16
18
|
|
|
19
|
+
**Sequence a beat with a drum machine and a piano on the same clock:**
|
|
20
|
+
|
|
17
21
|
```js
|
|
18
|
-
import { DrumMachine } from "smplr";
|
|
22
|
+
import { Sequencer, SplendidGrandPiano, DrumMachine } from "smplr";
|
|
19
23
|
|
|
20
24
|
const context = new AudioContext();
|
|
21
|
-
const
|
|
22
|
-
|
|
25
|
+
const piano = SplendidGrandPiano(context);
|
|
26
|
+
const drums = DrumMachine(context, { instrument: "TR-808" });
|
|
27
|
+
|
|
28
|
+
const seq = new Sequencer(context, { bpm: 110, loop: true });
|
|
29
|
+
seq.addTrack(piano, [
|
|
30
|
+
{ note: "C4", at: "1:1", duration: "4n" },
|
|
31
|
+
{ note: "E4", at: "1:2", duration: "4n" },
|
|
32
|
+
{ note: "G4", at: "1:3", duration: "4n" },
|
|
33
|
+
]);
|
|
34
|
+
seq.addTrack(drums, [
|
|
35
|
+
{ note: "kick", at: "1:1" },
|
|
36
|
+
{ note: "snare", at: "1:2" },
|
|
37
|
+
{ note: "kick", at: "1:3" },
|
|
38
|
+
{ note: "snare", at: "1:4" },
|
|
39
|
+
]);
|
|
40
|
+
seq.start();
|
|
23
41
|
```
|
|
24
42
|
|
|
25
|
-
|
|
26
|
-
import { SplendidGrandPiano, Reverb } from "smplr";
|
|
43
|
+
**Render an arpeggio with reverb to a WAV file — offline, no speakers needed:**
|
|
27
44
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
piano.output.addEffect("reverb", new Reverb(context), 0.2);
|
|
45
|
+
```js
|
|
46
|
+
import { SplendidGrandPiano, Reverb, renderOffline } from "smplr";
|
|
31
47
|
|
|
32
|
-
|
|
48
|
+
const wav = await renderOffline(async (context) => {
|
|
49
|
+
const piano = await SplendidGrandPiano(context).load;
|
|
50
|
+
piano.output.addEffect("reverb", new Reverb(context), 0.3);
|
|
51
|
+
["C4", "E4", "G4", "C5"].forEach((note, i) => {
|
|
52
|
+
piano.start({ note, time: i * 0.4, duration: 0.4 });
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
wav.downloadWav("arpeggio.wav");
|
|
33
56
|
```
|
|
34
57
|
|
|
35
58
|
See demo: https://danigb.github.io/smplr/
|
|
36
59
|
|
|
37
|
-
`smplr` is
|
|
60
|
+
`smplr` is approaching 1.0. The 0.21.0 release is the **1.0 candidate** — the documented surface is intended to ship unchanged into 1.0; the formal stability commitment lands when a handful of coordinated sibling tickets are in (see the 0.21.0 [CHANGELOG](https://github.com/danigb/smplr/blob/main/CHANGELOG.md) entry).
|
|
38
61
|
|
|
39
|
-
|
|
62
|
+
> **Upgrading from an earlier 0.x?** No code changes are required — every documented `new X(ctx, opts)` keeps working. New code should drop the `new` (`X(ctx, opts)`) and prefer `await x.ready` over `await x.load`.
|
|
40
63
|
|
|
41
64
|
#### Library goals
|
|
42
65
|
|
|
@@ -50,7 +73,7 @@ You can install the library with a package manager or use it directly by importi
|
|
|
50
73
|
|
|
51
74
|
Samples are stored at https://github.com/smpldsnds and there is no need to download them. Kudos to all _samplerist_ 🙌
|
|
52
75
|
|
|
53
|
-
#### Using a package
|
|
76
|
+
#### Using a package manager
|
|
54
77
|
|
|
55
78
|
Use npm or your favourite package manager to install the library to use it in your project:
|
|
56
79
|
|
|
@@ -70,32 +93,42 @@ You can import directly from the browser. For example:
|
|
|
70
93
|
<script type="module">
|
|
71
94
|
import { SplendidGrandPiano } from "https://unpkg.com/smplr/dist/index.mjs"; // needs to be a url
|
|
72
95
|
const context = new AudioContext(); // create the audio context
|
|
73
|
-
const
|
|
96
|
+
const piano = SplendidGrandPiano(context); // create and load the instrument
|
|
74
97
|
|
|
75
98
|
document.getElementById("btn").onclick = () => {
|
|
76
99
|
context.resume(); // enable audio context after a user interaction
|
|
77
|
-
|
|
100
|
+
piano.start({ note: 60, velocity: 80 }); // play the note
|
|
78
101
|
};
|
|
79
102
|
</script>
|
|
80
103
|
</html>
|
|
81
104
|
```
|
|
82
105
|
|
|
83
|
-
The package needs to be
|
|
106
|
+
The package needs to be served as a URL from a service like [unpkg](https://unpkg.com) or similar.
|
|
107
|
+
|
|
108
|
+
> To author your own instrument or publish a third-party package, see the [Defining an instrument](./AUTHORING.md) guide.
|
|
84
109
|
|
|
85
110
|
## Documentation
|
|
86
111
|
|
|
112
|
+
### Defining an instrument
|
|
113
|
+
|
|
114
|
+
`smplr` ships ten instruments out of the box — `SplendidGrandPiano`, `Soundfont`, `DrumMachine`, `ElectricPiano`, `Mallet`, `Mellotron`, `Smolken`, `Versilian`, `Sampler`, `Soundfont2Sampler`. If none of them fit your use case, you can author your own with the `Instrument` builder and the `Smplr` interface.
|
|
115
|
+
|
|
116
|
+
See **[Defining an instrument](./AUTHORING.md)** for the full authoring guide — sync and async examples, third-party package layout, and how to use `Smplr` as a TypeScript type for generic helpers.
|
|
117
|
+
|
|
87
118
|
### Create and load an instrument
|
|
88
119
|
|
|
89
|
-
|
|
120
|
+
Every smplr instrument is a factory function: call it with an `AudioContext` and an options object to get back an instance.
|
|
90
121
|
|
|
91
122
|
```js
|
|
92
123
|
import { SplendidGrandPiano, Soundfont } from "smplr";
|
|
93
124
|
|
|
94
125
|
const context = new AudioContext();
|
|
95
|
-
const piano =
|
|
96
|
-
const marimba =
|
|
126
|
+
const piano = SplendidGrandPiano(context, { decayTime: 0.5 });
|
|
127
|
+
const marimba = Soundfont(context, { instrument: "marimba" });
|
|
97
128
|
```
|
|
98
129
|
|
|
130
|
+
> **Compatibility note:** All factories also support the `new` keyword — `new SplendidGrandPiano(context)` produces the same instance as `SplendidGrandPiano(context)`. Code from earlier `smplr` versions keeps working unchanged. Editors will mark the `new` form as `@deprecated` to nudge new code toward the call form; both remain supported throughout the 1.x line.
|
|
131
|
+
|
|
99
132
|
#### Wait for audio loading
|
|
100
133
|
|
|
101
134
|
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 the `load` property that returns a promise:
|
|
@@ -109,9 +142,13 @@ piano.load.then(() => {
|
|
|
109
142
|
Since the promise returns the instrument instance, you can create and wait in a single line:
|
|
110
143
|
|
|
111
144
|
```js
|
|
112
|
-
const piano = await
|
|
145
|
+
const piano = await SplendidGrandPiano(context).load;
|
|
113
146
|
```
|
|
114
147
|
|
|
148
|
+
The pre-1.0 `new`-prefixed form continues to work — `const piano = await new SplendidGrandPiano(context).load` resolves to the same instrument. This is the documented backward-compat path for code from earlier `smplr` versions.
|
|
149
|
+
|
|
150
|
+
> **New in 1.0:** prefer `await piano.ready` for new code. It resolves to `void` (not the instrument) and won't be removed — `.load` is kept as a deprecated alias for compatibility.
|
|
151
|
+
|
|
115
152
|
⚠️ In versions lower than 0.8.0 a `loaded()` function was exposed instead.
|
|
116
153
|
|
|
117
154
|
#### Load progress
|
|
@@ -119,7 +156,7 @@ const piano = await new SplendidGrandPiano(context).load;
|
|
|
119
156
|
Track how many samples have loaded via the `onLoadProgress` option or the `loadProgress` getter:
|
|
120
157
|
|
|
121
158
|
```js
|
|
122
|
-
const piano =
|
|
159
|
+
const piano = SplendidGrandPiano(context, {
|
|
123
160
|
onLoadProgress: ({ loaded, total }) => {
|
|
124
161
|
console.log(`${loaded} / ${total} samples loaded`);
|
|
125
162
|
},
|
|
@@ -133,17 +170,19 @@ console.log(piano.loadProgress); // { loaded: 12, total: 48 }
|
|
|
133
170
|
|
|
134
171
|
#### Shared configuration options
|
|
135
172
|
|
|
136
|
-
All instruments share some configuration options
|
|
173
|
+
All instruments share some configuration options, passed as the second argument to the factory. Every field is optional:
|
|
137
174
|
|
|
138
|
-
- `volume`:
|
|
139
|
-
- `
|
|
140
|
-
- `
|
|
141
|
-
- `
|
|
142
|
-
- `
|
|
143
|
-
- `
|
|
175
|
+
- `volume`: a number from 0 to 127 representing the instrument's global volume. 100 by default.
|
|
176
|
+
- `velocity`: default note velocity (0–127) when not specified per note. 100 by default.
|
|
177
|
+
- `pan`: stereo pan, -1 (full left) to +1 (full right). 0 by default.
|
|
178
|
+
- `destination`: the `AudioNode` the instrument writes to. `AudioContext.destination` by default.
|
|
179
|
+
- `volumeToGain`: a function to map MIDI volume to a linear gain. Uses the MIDI standard curve by default.
|
|
180
|
+
- `storage`: a [storage backend](#cache-requests) used to fetch sample buffers. `HttpStorage` by default.
|
|
181
|
+
- `loader`: a shared `SampleLoader` instance. Pass the same loader to multiple instruments to cache buffers across them (see [Buffer reuse](#buffer-reuse)).
|
|
182
|
+
- `scheduler`: a shared `Scheduler` instance. Construct your own to tune scheduling — for example, `new Scheduler(context, { lookaheadMs: 100, intervalMs: 25 })` — or omit to get a per-instrument default.
|
|
144
183
|
- `onLoadProgress`: a function called after each sample buffer is decoded. Receives `{ loaded, total }` where `total` is the full count known before loading starts.
|
|
145
|
-
- `onStart`:
|
|
146
|
-
- `onEnded`:
|
|
184
|
+
- `onStart`: called when a note is dispatched to the audio engine. Receives the started note. See ⚠️ note under [Events](#events) on timing precision.
|
|
185
|
+
- `onEnded`: called when each voice's audio node ends. Receives the started note.
|
|
147
186
|
|
|
148
187
|
#### Usage with standardized-audio-context
|
|
149
188
|
|
|
@@ -153,7 +192,7 @@ This package should be compatible with [standardized-audio-context](https://gith
|
|
|
153
192
|
import { AudioContext } from "standardized-audio-context";
|
|
154
193
|
|
|
155
194
|
const context = new AudioContext();
|
|
156
|
-
const piano =
|
|
195
|
+
const piano = SplendidGrandPiano(context);
|
|
157
196
|
```
|
|
158
197
|
|
|
159
198
|
However, if you are using Typescript, you might need to "force cast" the types:
|
|
@@ -163,7 +202,7 @@ import { Soundfont } from "smplr";
|
|
|
163
202
|
import { AudioContext as StandardizedAudioContext } from "standardized-audio-context";
|
|
164
203
|
|
|
165
204
|
const context = new StandardizedAudioContext() as unknown as AudioContext;
|
|
166
|
-
const marimba =
|
|
205
|
+
const marimba = Soundfont(context, { instrument: "marimba" });
|
|
167
206
|
```
|
|
168
207
|
|
|
169
208
|
In case you need to use the `Reverb` module (or any other module that needs `AudioWorkletNode`) you need to enforce to use the one from `standardized-audio-context` package. Here is how:
|
|
@@ -176,12 +215,12 @@ import {
|
|
|
176
215
|
} from "standardized-audio-context";
|
|
177
216
|
|
|
178
217
|
window.AudioWorkletNode = AudioWorkletNode as any;
|
|
179
|
-
const context = new StandardizedAudioContext() as unknown AudioContext;
|
|
218
|
+
const context = new StandardizedAudioContext() as unknown as AudioContext;
|
|
180
219
|
|
|
181
220
|
// ... rest of the code
|
|
182
221
|
```
|
|
183
222
|
|
|
184
|
-
|
|
223
|
+
See [standardized-audio-context issue #897](https://github.com/chrisguttandin/standardized-audio-context/issues/897) for background on why the cast is required.
|
|
185
224
|
|
|
186
225
|
### Play
|
|
187
226
|
|
|
@@ -211,11 +250,11 @@ Instruments have a global `stop` function that can be used to stop all notes:
|
|
|
211
250
|
piano.stop();
|
|
212
251
|
```
|
|
213
252
|
|
|
214
|
-
Or stop the specified one
|
|
253
|
+
Or stop the specified one. The argument is a `stopId` — by default the same value you passed as `note`, but you can override it via `start({ note, stopId })`:
|
|
215
254
|
|
|
216
255
|
```js
|
|
217
|
-
//
|
|
218
|
-
piano.stop(60);
|
|
256
|
+
piano.stop("C4"); // stop the note(s) started with `note: "C4"`
|
|
257
|
+
piano.stop(60); // stop the note(s) started with `note: 60`
|
|
219
258
|
```
|
|
220
259
|
|
|
221
260
|
#### Schedule notes
|
|
@@ -236,10 +275,13 @@ const now = context.currentTime;
|
|
|
236
275
|
You can loop a note by using `loop`, `loopStart` and `loopEnd`:
|
|
237
276
|
|
|
238
277
|
```js
|
|
239
|
-
const
|
|
278
|
+
const context = new AudioContext();
|
|
279
|
+
const sampler = Sampler(context, {
|
|
280
|
+
buffers: { duh: "https://example.com/duh-duh-ah.mp3" },
|
|
281
|
+
});
|
|
240
282
|
sampler.start({
|
|
241
|
-
note: "duh"
|
|
242
|
-
loop: true
|
|
283
|
+
note: "duh",
|
|
284
|
+
loop: true,
|
|
243
285
|
loopStart: 1.0,
|
|
244
286
|
loopEnd: 9.0,
|
|
245
287
|
});
|
|
@@ -265,7 +307,7 @@ Events can be configured globally:
|
|
|
265
307
|
|
|
266
308
|
```js
|
|
267
309
|
const context = new AudioContext();
|
|
268
|
-
const
|
|
310
|
+
const piano = SplendidGrandPiano(context, {
|
|
269
311
|
onStart: (note) => {
|
|
270
312
|
console.log(note.time, context.currentTime);
|
|
271
313
|
},
|
|
@@ -286,20 +328,20 @@ piano.start({
|
|
|
286
328
|
|
|
287
329
|
Global callbacks will be invoked regardless of whether local events are defined.
|
|
288
330
|
|
|
289
|
-
⚠️ The invocation time of `onStart` is not exact
|
|
331
|
+
⚠️ The invocation time of `onStart` is not exact: it fires slightly before the audio actually starts, by up to the scheduler's lookahead window (200ms by default; configurable via the `scheduler` option — see [Shared configuration options](#shared-configuration-options)).
|
|
290
332
|
|
|
291
333
|
### Effects
|
|
292
334
|
|
|
293
335
|
#### Reverb
|
|
294
336
|
|
|
295
|
-
|
|
337
|
+
A packaged version of the [DattorroReverbNode](https://github.com/khoin/DattorroReverbNode) algorithmic reverb is included.
|
|
296
338
|
|
|
297
339
|
Use `output.addEffect(name, effect, mix)` to connect an effect using a send bus:
|
|
298
340
|
|
|
299
341
|
```js
|
|
300
342
|
import { Reverb, SplendidGrandPiano } from "smplr";
|
|
301
343
|
const reverb = new Reverb(context);
|
|
302
|
-
const piano =
|
|
344
|
+
const piano = SplendidGrandPiano(context, { volume });
|
|
303
345
|
piano.output.addEffect("reverb", reverb, 0.2);
|
|
304
346
|
```
|
|
305
347
|
|
|
@@ -309,13 +351,11 @@ To change the mix level, use `output.sendEffect(name, mix)`:
|
|
|
309
351
|
piano.output.sendEffect("reverb", 0.5);
|
|
310
352
|
```
|
|
311
353
|
|
|
312
|
-
###
|
|
313
|
-
|
|
314
|
-
#### Cache requests
|
|
354
|
+
### Cache requests
|
|
315
355
|
|
|
316
|
-
|
|
356
|
+
The default sample sets are hosted on GitHub Pages, which rate-limits requests per second. That can be a problem, especially in a development environment with hot reload (most React frameworks).
|
|
317
357
|
|
|
318
|
-
|
|
358
|
+
To cache samples in the browser, use a `CacheStorage` object:
|
|
319
359
|
|
|
320
360
|
```ts
|
|
321
361
|
import { SplendidGrandPiano, CacheStorage } from "smplr";
|
|
@@ -323,21 +363,21 @@ import { SplendidGrandPiano, CacheStorage } from "smplr";
|
|
|
323
363
|
const context = new AudioContext();
|
|
324
364
|
const storage = new CacheStorage();
|
|
325
365
|
// First time the instrument loads, will fetch the samples from http. Subsequent times from cache.
|
|
326
|
-
const piano =
|
|
366
|
+
const piano = SplendidGrandPiano(context, { storage });
|
|
327
367
|
```
|
|
328
368
|
|
|
329
|
-
⚠️ `CacheStorage` is based on [Cache API](https://developer.mozilla.org/en-US/docs/Web/API/Cache) and only works in secure environments that
|
|
369
|
+
⚠️ `CacheStorage` is based on the [Cache API](https://developer.mozilla.org/en-US/docs/Web/API/Cache) and only works in secure environments that run over `https`. Check your framework's documentation for local-HTTPS setup — for example [next-dev-https](https://www.npmjs.com/package/next-dev-https) for Next.js or [vite-plugin-mkcert](https://github.com/liuweiGL/vite-plugin-mkcert) for Vite.
|
|
330
370
|
|
|
331
371
|
## Sequencer
|
|
332
372
|
|
|
333
|
-
`Sequencer` schedules notes from one or more tracks against any smplr instrument with sample-accurate timing.
|
|
373
|
+
`Sequencer` schedules notes from one or more tracks against any smplr instrument with sample-accurate timing. Unlike instruments, it's a regular class — always constructed with `new Sequencer(context, opts)`.
|
|
334
374
|
|
|
335
375
|
```js
|
|
336
376
|
import { Sequencer, SplendidGrandPiano, DrumMachine } from "smplr";
|
|
337
377
|
|
|
338
378
|
const context = new AudioContext();
|
|
339
|
-
const piano =
|
|
340
|
-
const drums =
|
|
379
|
+
const piano = SplendidGrandPiano(context);
|
|
380
|
+
const drums = DrumMachine(context, { instrument: "TR-808" });
|
|
341
381
|
|
|
342
382
|
const seq = new Sequencer(context, { bpm: 120, loop: true });
|
|
343
383
|
|
|
@@ -530,7 +570,7 @@ Render audio offline (faster than real-time) and export it as a WAV file. Uses `
|
|
|
530
570
|
import { renderOffline } from "smplr";
|
|
531
571
|
|
|
532
572
|
const result = await renderOffline(async (context) => {
|
|
533
|
-
const piano = await
|
|
573
|
+
const piano = await SplendidGrandPiano(context).load;
|
|
534
574
|
piano.start({ note: "C4", time: 0, duration: 1 });
|
|
535
575
|
piano.start({ note: "E4", time: 0.5, duration: 1 });
|
|
536
576
|
});
|
|
@@ -572,12 +612,12 @@ If you already have an instrument loaded, pass the same `SampleLoader` to avoid
|
|
|
572
612
|
import { SplendidGrandPiano, SampleLoader, renderOffline } from "smplr";
|
|
573
613
|
|
|
574
614
|
const loader = new SampleLoader(audioContext);
|
|
575
|
-
const piano =
|
|
615
|
+
const piano = SplendidGrandPiano(audioContext, { loader });
|
|
576
616
|
await piano.load;
|
|
577
617
|
|
|
578
618
|
// Offline render reuses cached buffers — no re-fetch
|
|
579
619
|
const result = await renderOffline(async (context) => {
|
|
580
|
-
const offlinePiano = await
|
|
620
|
+
const offlinePiano = await SplendidGrandPiano(context, { loader }).load;
|
|
581
621
|
offlinePiano.start({ note: "C4", time: 0, duration: 1 });
|
|
582
622
|
});
|
|
583
623
|
```
|
|
@@ -587,10 +627,11 @@ const result = await renderOffline(async (context) => {
|
|
|
587
627
|
Use offline rendering to generate reproducible audio files for issue reports. No install needed — just open your browser's DevTools console on any page and paste:
|
|
588
628
|
|
|
589
629
|
```js
|
|
590
|
-
const { renderOffline, SplendidGrandPiano } =
|
|
630
|
+
const { renderOffline, SplendidGrandPiano } =
|
|
631
|
+
await import("https://esm.sh/smplr");
|
|
591
632
|
|
|
592
633
|
const result = await renderOffline(async (context) => {
|
|
593
|
-
const piano = await
|
|
634
|
+
const piano = await SplendidGrandPiano(context).load;
|
|
594
635
|
piano.start({ note: "C4", time: 0, duration: 2 });
|
|
595
636
|
});
|
|
596
637
|
result.downloadWav16("bug-report.wav");
|
|
@@ -613,7 +654,7 @@ const buffers = {
|
|
|
613
654
|
kick: "https://smpldsnds.github.io/drum-machines/808-mini/kick.m4a",
|
|
614
655
|
snare: "https://smpldsnds.github.io/drum-machines/808-mini/snare-1.m4a",
|
|
615
656
|
};
|
|
616
|
-
const sampler =
|
|
657
|
+
const sampler = Sampler(new AudioContext(), { buffers });
|
|
617
658
|
```
|
|
618
659
|
|
|
619
660
|
And then use the name of the buffer as note name:
|
|
@@ -630,7 +671,7 @@ A Soundfont player. By default it loads audio from Benjamin Gleitzman's package
|
|
|
630
671
|
```js
|
|
631
672
|
import { Soundfont, getSoundfontNames, getSoundfontKits } from "smplr";
|
|
632
673
|
|
|
633
|
-
const marimba =
|
|
674
|
+
const marimba = Soundfont(new AudioContext(), { instrument: "marimba" });
|
|
634
675
|
marimba.start({ note: "C4" });
|
|
635
676
|
```
|
|
636
677
|
|
|
@@ -640,10 +681,10 @@ It's intended to be a modern replacement of [soundfont-player](https://github.co
|
|
|
640
681
|
|
|
641
682
|
Use `getSoundfontNames` to get all available instrument names and `getSoundfontKits` to get kit names.
|
|
642
683
|
|
|
643
|
-
There are two kits available: `MusyngKite` or `FluidR3_GM`. The first one is used by default: it sounds better but samples
|
|
684
|
+
There are two kits available: `MusyngKite` or `FluidR3_GM`. The first one is used by default: it sounds better but the samples are heavier.
|
|
644
685
|
|
|
645
686
|
```js
|
|
646
|
-
const marimba =
|
|
687
|
+
const marimba = Soundfont(context, {
|
|
647
688
|
instrument: "clavinet",
|
|
648
689
|
kit: "FluidR3_GM", // "MusyngKite" is used by default if not specified
|
|
649
690
|
});
|
|
@@ -652,7 +693,7 @@ const marimba = new Soundfont(context, {
|
|
|
652
693
|
Alternatively, you can pass your custom url as the instrument. In that case, the `kit` is ignored:
|
|
653
694
|
|
|
654
695
|
```js
|
|
655
|
-
const marimba =
|
|
696
|
+
const marimba = Soundfont(context, {
|
|
656
697
|
instrumentUrl:
|
|
657
698
|
"https://gleitz.github.io/midi-js-soundfonts/MusyngKite/marimba-mp3.js",
|
|
658
699
|
});
|
|
@@ -663,7 +704,7 @@ const marimba = new Soundfont(context, {
|
|
|
663
704
|
You can enable note looping to make note names indefinitely long by loading loop data:
|
|
664
705
|
|
|
665
706
|
```js
|
|
666
|
-
const marimba =
|
|
707
|
+
const marimba = Soundfont(context, {
|
|
667
708
|
instrument: "cello",
|
|
668
709
|
loadLoopData: true,
|
|
669
710
|
});
|
|
@@ -679,7 +720,7 @@ A sampled acoustic piano. It uses Steinway samples with 4 velocity groups from
|
|
|
679
720
|
```js
|
|
680
721
|
import { SplendidGrandPiano } from "smplr";
|
|
681
722
|
|
|
682
|
-
const piano =
|
|
723
|
+
const piano = SplendidGrandPiano(new AudioContext());
|
|
683
724
|
|
|
684
725
|
piano.start({ note: "C4" });
|
|
685
726
|
```
|
|
@@ -688,7 +729,7 @@ piano.start({ note: "C4" });
|
|
|
688
729
|
|
|
689
730
|
The second argument of the constructor accepts the following options:
|
|
690
731
|
|
|
691
|
-
- `baseUrl`:
|
|
732
|
+
- `baseUrl`: where the piano samples are fetched from. Defaults to the public hosted set on `smpldsnds.github.io`; override only if you mirror the samples yourself.
|
|
692
733
|
- `detune`: global detune in cents (0 if not specified)
|
|
693
734
|
- `velocity`: default velocity (100 if not specified)
|
|
694
735
|
- `volume`: default volume (100 if not specified)
|
|
@@ -698,7 +739,7 @@ The second argument of the constructor accepts the following options:
|
|
|
698
739
|
Example:
|
|
699
740
|
|
|
700
741
|
```ts
|
|
701
|
-
const piano =
|
|
742
|
+
const piano = SplendidGrandPiano(context, {
|
|
702
743
|
detune: -20,
|
|
703
744
|
volume: 80,
|
|
704
745
|
notesToLoad: {
|
|
@@ -715,9 +756,9 @@ A sampled electric pianos. Samples from https://github.com/sfzinstruments/GregSu
|
|
|
715
756
|
```js
|
|
716
757
|
import { ElectricPiano, getElectricPianoNames } from "smplr";
|
|
717
758
|
|
|
718
|
-
const instruments = getElectricPianoNames(); // => ["CP80", "PianetT", "WurlitzerEP200"]
|
|
759
|
+
const instruments = getElectricPianoNames(); // => ["CP80", "PianetT", "WurlitzerEP200", "TX81Z"]
|
|
719
760
|
|
|
720
|
-
const epiano =
|
|
761
|
+
const epiano = ElectricPiano(new AudioContext(), {
|
|
721
762
|
instrument: "PianetT",
|
|
722
763
|
});
|
|
723
764
|
|
|
@@ -732,6 +773,7 @@ Available instruments:
|
|
|
732
773
|
- `CP80`: Yamaha CP80 Electric Grand Piano v1.3 (29-Sep-2004)
|
|
733
774
|
- `PianetT`: Hohner Pianet T (type 2) v1.3 (24-Sep-2004)
|
|
734
775
|
- `WurlitzerEP200`: Wurlitzer EP200 Electric Piano v1.1 (16-May-1999)
|
|
776
|
+
- `TX81Z`: Yamaha TX81Z "FM Piano" patch (from the VCSL Electrophones set)
|
|
735
777
|
|
|
736
778
|
### Mallets
|
|
737
779
|
|
|
@@ -742,7 +784,7 @@ import { Mallet, getMalletNames } from "smplr";
|
|
|
742
784
|
|
|
743
785
|
const instruments = getMalletNames();
|
|
744
786
|
|
|
745
|
-
const mallet =
|
|
787
|
+
const mallet = Mallet(new AudioContext(), {
|
|
746
788
|
instrument: instruments[0],
|
|
747
789
|
});
|
|
748
790
|
```
|
|
@@ -756,7 +798,7 @@ import { Mellotron, getMellotronNames } from "smplr";
|
|
|
756
798
|
|
|
757
799
|
const instruments = getMellotronNames();
|
|
758
800
|
|
|
759
|
-
const
|
|
801
|
+
const mellotron = Mellotron(new AudioContext(), {
|
|
760
802
|
instrument: instruments[0],
|
|
761
803
|
});
|
|
762
804
|
```
|
|
@@ -771,13 +813,13 @@ import { DrumMachine, getDrumMachineNames } from "smplr";
|
|
|
771
813
|
const instruments = getDrumMachineNames();
|
|
772
814
|
|
|
773
815
|
const context = new AudioContext();
|
|
774
|
-
const drums =
|
|
816
|
+
const drums = DrumMachine(context, { instrument: "TR-808" });
|
|
775
817
|
drums.start({ note: "kick" });
|
|
776
818
|
|
|
777
819
|
// Drum samples are grouped and can have sample variations:
|
|
778
820
|
drums.getSampleNames(); // => ['kick-1', 'kick-2', 'snare-1', 'snare-2', ...]
|
|
779
821
|
drums.getGroupNames(); // => ['kick', 'snare']
|
|
780
|
-
drums.getSampleNamesForGroup("kick")
|
|
822
|
+
drums.getSampleNamesForGroup("kick"); // => ['kick-1', 'kick-2']
|
|
781
823
|
|
|
782
824
|
// You can trigger samples by group name or specific sample
|
|
783
825
|
drums.start("kick"); // Play the first sample of the group
|
|
@@ -793,7 +835,7 @@ const instruments = getSmolkenNames(); // => Arco, Pizzicato & Switched
|
|
|
793
835
|
|
|
794
836
|
// Create an instrument
|
|
795
837
|
const context = new AudioContext();
|
|
796
|
-
const doubleBass = await
|
|
838
|
+
const doubleBass = await Smolken(context, { instrument: "Arco" }).load;
|
|
797
839
|
```
|
|
798
840
|
|
|
799
841
|
### Versilian
|
|
@@ -809,7 +851,7 @@ import { Versilian, getVersilianInstruments } from "smplr";
|
|
|
809
851
|
const instrumentNames = await getVersilianInstruments();
|
|
810
852
|
|
|
811
853
|
const context = new AudioContext();
|
|
812
|
-
const
|
|
854
|
+
const versilian = Versilian(context, { instrument: instrumentNames[0] });
|
|
813
855
|
```
|
|
814
856
|
|
|
815
857
|
### Soundfont2Sampler
|
|
@@ -821,7 +863,7 @@ import { Soundfont2Sampler } from "smplr";
|
|
|
821
863
|
import { SoundFont2 } from "soundfont2";
|
|
822
864
|
|
|
823
865
|
const context = new AudioContext();
|
|
824
|
-
const sampler =
|
|
866
|
+
const sampler = Soundfont2Sampler(context, {
|
|
825
867
|
url: "https://smpldsnds.github.io/soundfonts/soundfonts/galaxy-electric-pianos.sf2",
|
|
826
868
|
createSoundfont: (data) => new SoundFont2(data),
|
|
827
869
|
});
|