smplr 0.3.0 → 0.4.1

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 CHANGED
@@ -4,26 +4,44 @@
4
4
 
5
5
  > `smplr` is a collection of sampled instruments for Web Audio API ready to be used with no setup required.
6
6
 
7
- Example:
7
+ Examples:
8
8
 
9
9
  ```js
10
- import { SplendidGrandPiano, Soundfont, Reverb } from "smplr";
10
+ import { Soundfont } from "smplr";
11
11
 
12
12
  const context = new AudioContext();
13
- const piano = new SplendidGrandPiano(context);
14
- piano.start({ note: "C4" });
15
-
16
13
  const marimba = new Soundfont(context, { instrument: "marimba" });
17
14
  marimba.start({ note: 60, velocity: 80 });
15
+ ```
16
+
17
+ ```js
18
+ import { DrumMachine } from "smplr";
18
19
 
19
- // Optionally, add reverb...
20
- piano.output.addEffect("reverb", new Reverb(context), 0.1);
21
- // ... and change how much
22
- piano.output.sendEffect("reverb", 0.2);
20
+ const context = new AudioContext();
21
+ const dm = new DrumMachine(context);
22
+ dm.start({ note: "kick" });
23
+ ```
24
+
25
+ ```js
26
+ import { SplendidGrandPiano, Reverb } from "smplr";
27
+
28
+ const context = new AudioContext();
29
+ const piano = new SplendidGrandPiano(context);
30
+ piano.output.addEffect("reverb", new Reverb(context), 0.2);
31
+
32
+ piano.start({ note: "C4" });
23
33
  ```
24
34
 
25
35
  See demo: https://danigb.github.io/smplr/
26
36
 
37
+ #### Library goals
38
+
39
+ - No setup: specifically, all samples are online, so no need for a server.
40
+ - Easy to use: everything should be intuitive for non-experienced developers
41
+ - Decent sounding: use high quality open source samples. For good or worst, is sample based 🤷
42
+
43
+ #### Installation
44
+
27
45
  Install with npm or your favourite package manager:
28
46
 
29
47
  ```
@@ -70,7 +88,7 @@ The `start` function accepts a bunch of options:
70
88
  piano.start({ note: "C4", velocity: 80, time: 5, duration: 1 });
71
89
  ```
72
90
 
73
- The `velocity` is a number between 0 and 128 the represents at which velocity the key is pressed. The bigger the number, louder the sound. But `velocity` not only controls the loudness. In some instruments, it also affects the timbre.
91
+ The `velocity` is a number between 0 and 127 the represents at which velocity the key is pressed. The bigger the number, louder the sound. But `velocity` not only controls the loudness. In some instruments, it also affects the timbre.
74
92
 
75
93
  The `start` function returns a `stop` function for the given note:
76
94
 
@@ -81,34 +99,36 @@ stopNote({ time: 10 });
81
99
 
82
100
  Bear in mind that you may need to call [`context.resume()` before playing a note](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Best_practices#autoplay_policy)
83
101
 
84
- ### Schedule notes
85
-
86
- You can schedule notes using `time` and `duration` properties:
102
+ Instruments have a global `stop` function that can be used to stop all notes:
87
103
 
88
104
  ```js
89
- const now = context.currentTime;
90
- [60, 62, 64, 65, 67].forEach((note, i) => {
91
- piano.start({ note, time: now + i, duration: 0.5 });
92
- });
105
+ // This will stop all notes
106
+ piano.stop();
93
107
  ```
94
108
 
95
- ### Stop all notes
96
-
97
- Instruments have a global `stop` function that stops all notes:
109
+ Or stop the specified one:
98
110
 
99
111
  ```js
100
- button.onclick = () => piano.stop();
112
+ // This will stop C4 note
113
+ piano.stop(60);
101
114
  ```
102
115
 
103
- It can stop only the specified note:
116
+ ### Schedule notes
117
+
118
+ You can schedule notes using `time` and `duration` properties. Both are measured in seconds, and time is the number of seconds since the AudioContext was created.
119
+
120
+ For example, next example plays a C major arpeggio, one note per second:
104
121
 
105
122
  ```js
106
- piano.stop(60);
123
+ const now = context.currentTime;
124
+ ["C4", "E4", "G4", "C5"].forEach((note, i) => {
125
+ piano.start({ note, time: now + i, duration: 0.5 });
126
+ });
107
127
  ```
108
128
 
109
129
  ### Change volume
110
130
 
111
- `setVolume` uses a scale where 0 means no volume, and 128 is max volume without amplification:
131
+ `setVolume` uses a scale where 0 means no volume, and 127 is max volume without amplification:
112
132
 
113
133
  ```js
114
134
  piano.setVolume(80);
@@ -120,7 +140,7 @@ Bear in mind that `volume` is global to the instrument, but `velocity` is specif
120
140
 
121
141
  An packed version of [DattorroReverbNode](https://github.com/khoin/DattorroReverbNode) algorithmic reverb is included.
122
142
 
123
- Use `output.addEffect(name, effect, mix)` to create connect an effect using a send bus:
143
+ Use `output.addEffect(name, effect, mix)` to connect an effect using a send bus:
124
144
 
125
145
  ```js
126
146
  import { Reverb, SplendidGrandPiano } from "smplr";
@@ -129,7 +149,7 @@ const piano = new SplendidGrandPiano(context, { volume });
129
149
  piano.output.addEffect("reverb", reverb, 0.2);
130
150
  ```
131
151
 
132
- Use `output.sendEffect(name, mix)` to change the mix level:
152
+ To change the mix level, use `output.sendEffect(name, mix)`:
133
153
 
134
154
  ```js
135
155
  piano.output.sendEffect("reverb", 0.5);
@@ -160,7 +180,7 @@ A Soundfont player. By default it loads audio from Benjamin Gleitzman's package
160
180
  ```js
161
181
  import { Soundfont } from "smplr";
162
182
 
163
- const marimba = new Soundfont(new AudioContext(), "marimba");
183
+ const marimba = new Soundfont(new AudioContext(), { instrument: "marimba" });
164
184
  marimba.start({ note: "C4" });
165
185
  ```
166
186
 
@@ -184,7 +204,9 @@ piano.start({ note: "C4" });
184
204
  A sampled electric pianos. Samples from https://github.com/sfzinstruments/GregSullivan.E-Pianos
185
205
 
186
206
  ```js
187
- import { ElectricPiano } from "smplr";
207
+ import { ElectricPiano, getElectricPianoNames } from "smplr";
208
+
209
+ const instruments = getElectricPianoNames(); // => ["CP80", "PianetT", "WurlitzerEP200"]
188
210
 
189
211
  const epiano = new ElectricPiano(new AudioContext(), {
190
212
  instrument: "PianetT",
@@ -209,8 +231,30 @@ Samples from [The Versilian Community Sample Library](https://github.com/sgossne
209
231
  ```js
210
232
  import { Mallet, getMalletNames } from "smplr";
211
233
 
234
+ const instruments = getMalletNames();
235
+
212
236
  const mallet = new Mallet(new AudioContext(), {
213
- instrument: getMalletNames()[0],
237
+ instrument: instruments[0],
238
+ });
239
+ ```
240
+
241
+ ### Drum Machines
242
+
243
+ Sampled drum machines. Samples from different sources:
244
+
245
+ ```js
246
+ import { DrumMachine, getDrumMachineNames } from "smplr";
247
+
248
+ const instruments = getDrumMachineNames();
249
+
250
+ const context = new AudioContext();
251
+ const drums = new DrumMachine(context, { instrument: "TR-808" });
252
+ drums.start({ note: "kick" });
253
+
254
+ // Drum samples could have variations:
255
+ const now = context.currentTime;
256
+ drums.getVariations("kick").forEach((variation, index) => {
257
+ drums.start({ note: variation, time: now + index });
214
258
  });
215
259
  ```
216
260
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- type AudioBuffers = Record<string | number, AudioBuffer>;
2
-
3
1
  type AudioInsert = {
4
2
  input: AudioNode;
5
3
  output: AudioNode;
@@ -27,6 +25,8 @@ declare class Channel {
27
25
  disconnect(): void;
28
26
  }
29
27
 
28
+ type AudioBuffers = Record<string | number, AudioBuffer | undefined>;
29
+
30
30
  type StopSample = {
31
31
  stopId?: string | number;
32
32
  time?: number;
@@ -69,10 +69,27 @@ declare class Sampler {
69
69
  readonly buffers: AudioBuffers;
70
70
  constructor(context: AudioContext, options: Partial<SamplerConfig>);
71
71
  loaded(): Promise<this>;
72
- start(note: SamplerNote | string | number): (time?: number) => void;
72
+ start(note: SamplerNote | string | number): (time?: number | undefined) => void;
73
73
  stop(note?: StopSample | string | number): void;
74
74
  }
75
75
 
76
+ declare function getDrumMachineNames(): string[];
77
+ type DrumMachineConfig = {
78
+ instrument: string;
79
+ destination: AudioNode;
80
+ detune: number;
81
+ volume: number;
82
+ velocity: number;
83
+ decayTime?: number;
84
+ lpfCutoffHz?: number;
85
+ };
86
+ declare class DrumMachine extends Sampler {
87
+ #private;
88
+ constructor(context: AudioContext, options: Partial<DrumMachineConfig>);
89
+ get sampleNames(): string[];
90
+ getVariations(name: string): string[];
91
+ }
92
+
76
93
  type SfzInstrument = {
77
94
  name: string;
78
95
  formats?: string[];
@@ -166,7 +183,7 @@ declare class SfzSampler {
166
183
  disconnect(): void;
167
184
  }
168
185
 
169
- declare const ElectricPianoInstruments: Record<string, SfzInstrument>;
186
+ declare function getElectricPianoNames(): string[];
170
187
  declare class ElectricPiano extends SfzSampler {
171
188
  readonly tremolo: Readonly<{
172
189
  level: (value: number) => void;
@@ -182,21 +199,7 @@ declare class Mallet extends SfzSampler {
182
199
  instrument: string;
183
200
  });
184
201
  }
185
- declare const DATA: {
186
- readonly "Balafon - Hard Mallet": "Struck Idiophones/balafon-hard-mallet";
187
- readonly "Balafon - Keyswitch": "Struck Idiophones/balafon-keyswitch";
188
- readonly "Balafon - Soft Mallet": "Struck Idiophones/balafon-soft-mallet";
189
- readonly "Balafon - Traditional Mallet": "Struck Idiophones/balafon-traditional-mallet";
190
- readonly "Tubular Bells 1": "Struck Idiophones/tubular-bells-1";
191
- readonly "Tubular Bells 2": "Struck Idiophones/tubular-bells-2";
192
- readonly "Vibraphone - Hard Mallets": "Struck Idiophones/vibraphone-hard-mallets";
193
- readonly "Vibraphone - Keyswitch": "Struck Idiophones/vibraphone-keyswitch";
194
- readonly "Vibraphone - Soft Mallets": "Struck Idiophones/vibraphone-soft-mallets";
195
- readonly "Xylophone - Hard Mallets": "Struck Idiophones/xylophone-hard-mallets";
196
- readonly "Xylophone - Keyswitch": "Struck Idiophones/xylophone-keyswitch";
197
- readonly "Xylophone - Medium Mallets": "Struck Idiophones/xylophone-medium-mallets";
198
- readonly "Xylophone - Soft Mallets": "Struck Idiophones/xylophone-soft-mallets";
199
- };
202
+ declare const DATA: Record<string, string | undefined>;
200
203
 
201
204
  declare const PARAMS: readonly ["preDelay", "bandwidth", "inputDiffusion1", "inputDiffusion2", "decay", "decayDiffusion1", "decayDiffusion2", "damping", "excursionRate", "excursionDepth", "wet", "dry"];
202
205
  declare class Reverb {
@@ -213,7 +216,6 @@ declare class Reverb {
213
216
  type SoundfontConfig = {
214
217
  library: SoundfontLibrary | LibraryUrlBuilder;
215
218
  instrument: string;
216
- format: string;
217
219
  destination: AudioNode;
218
220
  detune: number;
219
221
  volume: number;
@@ -243,7 +245,6 @@ declare const SoundfontLibraries: Record<string, SoundfontLibrary>;
243
245
  */
244
246
  type SplendidGrandPianoConfig = {
245
247
  baseUrl: string;
246
- format: "ogg" | "m4a";
247
248
  destination: AudioNode;
248
249
  detune: number;
249
250
  volume: number;
@@ -266,4 +267,4 @@ declare const LAYERS: ({
266
267
  cutoff?: undefined;
267
268
  })[];
268
269
 
269
- export { DATA, ElectricPiano, ElectricPianoInstruments, FluidR3, LAYERS, LibraryUrlBuilder, Mallet, MusyngKite, Reverb, Sampler, SamplerAudioLoader, SamplerConfig, SamplerNote, Soundfont, SoundfontConfig, SoundfontLibraries, SoundfontLibrary, SplendidGrandPiano, SplendidGrandPianoConfig, getMalletNames, gleitzKitUrl };
270
+ export { DATA, DrumMachine, DrumMachineConfig, ElectricPiano, FluidR3, LAYERS, LibraryUrlBuilder, Mallet, MusyngKite, Reverb, Sampler, SamplerAudioLoader, SamplerConfig, SamplerNote, Soundfont, SoundfontConfig, SoundfontLibraries, SoundfontLibrary, SplendidGrandPiano, SplendidGrandPianoConfig, getDrumMachineNames, getElectricPianoNames, getMalletNames, gleitzKitUrl };