smplr 0.7.0 → 0.8.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
@@ -56,7 +56,7 @@ Samples are stored at https://github.com/danigb/samples and there is no need to
56
56
 
57
57
  ## Documentation
58
58
 
59
- ### Create an instrument
59
+ ### Create and load an instrument
60
60
 
61
61
  All instruments follows the same pattern: `new Instrument(context, options?)`. For example:
62
62
 
@@ -70,10 +70,10 @@ const marimba = new Soundfont(context, { instrument: "marimba" });
70
70
 
71
71
  #### Wait for audio loading
72
72
 
73
- 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 `loaded()` function that returns a promise:
73
+ 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:
74
74
 
75
75
  ```js
76
- piano.loaded().then(() => {
76
+ piano.load.then(() => {
77
77
  // now the piano is fully loaded
78
78
  });
79
79
  ```
@@ -81,7 +81,7 @@ piano.loaded().then(() => {
81
81
  Since the promise returns the instrument instance, you can create and wait in a single line:
82
82
 
83
83
  ```js
84
- const piano = await new SplendidGrandPiano(context).loaded();
84
+ const piano = await new SplendidGrandPiano(context).load;
85
85
  ```
86
86
 
87
87
  ### Play
@@ -132,7 +132,7 @@ const now = context.currentTime;
132
132
  });
133
133
  ```
134
134
 
135
- ### Looping
135
+ #### Looping
136
136
 
137
137
  You can loop a note by using `loop`, `loopStart` and `loopEnd`:
138
138
 
@@ -148,7 +148,7 @@ sampler.start({
148
148
 
149
149
  If `loopStart` or `loopEnd` is not specified it will be use by default 0 and total duration respectively.
150
150
 
151
- ### Change volume
151
+ #### Change volume
152
152
 
153
153
  Instrument `output` 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:
154
154
 
@@ -193,9 +193,9 @@ piano.start({
193
193
 
194
194
  The callback will receive as parameter the same object you pass to the `start` function;
195
195
 
196
- #### Cache requests
196
+ ### Experimental features
197
197
 
198
- [Experimental]
198
+ #### Cache requests
199
199
 
200
200
  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).
201
201
 
@@ -330,6 +330,20 @@ const mallet = new Mallet(new AudioContext(), {
330
330
  });
331
331
  ```
332
332
 
333
+ ### Mellotron
334
+
335
+ Samples from [archive.org](https://archive.org/details/mellotron-archive-cd-rom-nki-wav.-7z)
336
+
337
+ ```js
338
+ import { Mellotron, getMellotronNames } from "smplr";
339
+
340
+ const instruments = getMellotronNames();
341
+
342
+ const mallet = new Mellotron(new AudioContext(), {
343
+ instrument: instruments[0],
344
+ });
345
+ ```
346
+
333
347
  ### Drum Machines
334
348
 
335
349
  Sampled drum machines. Samples from different sources:
package/dist/index.d.ts CHANGED
@@ -27,6 +27,28 @@ declare class Channel {
27
27
  disconnect(): void;
28
28
  }
29
29
 
30
+ type StorageResponse = {
31
+ readonly status: number;
32
+ arrayBuffer(): Promise<ArrayBuffer>;
33
+ json(): Promise<any>;
34
+ text(): Promise<string>;
35
+ };
36
+ type Storage = {
37
+ fetch: (url: string) => Promise<StorageResponse>;
38
+ };
39
+ declare const HttpStorage: Storage;
40
+ declare class CacheStorage implements Storage {
41
+ #private;
42
+ constructor(name?: string);
43
+ fetch(url: string): Promise<StorageResponse>;
44
+ }
45
+
46
+ type AudioBuffers = Record<string | number, AudioBuffer | undefined>;
47
+ /**
48
+ * A function that downloads audio into a AudioBuffers
49
+ */
50
+ type AudioBuffersLoader = (context: BaseAudioContext, buffers: AudioBuffers) => Promise<void>;
51
+
30
52
  /**
31
53
  * A function to unsubscribe from an event or control
32
54
  */
@@ -40,6 +62,16 @@ type Listener<T> = (value: T) => void;
40
62
  */
41
63
  type Subscribe<T> = (listener: Listener<T>) => Unsubscribe;
42
64
 
65
+ /**
66
+ * @private
67
+ */
68
+ type InternalPlayer = {
69
+ readonly buffers: AudioBuffers;
70
+ readonly context: BaseAudioContext;
71
+ start(sample: SampleStart): (time?: number) => void;
72
+ stop(sample?: SampleStop): void;
73
+ disconnect(): void;
74
+ };
43
75
  type SampleStop = {
44
76
  stopId?: string | number;
45
77
  time?: number;
@@ -55,28 +87,26 @@ type SampleOptions = {
55
87
  loopEnd?: number;
56
88
  };
57
89
  type SampleStart = {
90
+ name?: string;
58
91
  note: string | number;
59
92
  onEnded?: (sample: SampleStart) => void;
60
93
  stop?: Subscribe<number>;
61
94
  stopId?: string | number;
62
95
  time?: number;
63
96
  } & SampleOptions;
64
-
65
- type StorageResponse = {
66
- readonly status: number;
67
- arrayBuffer(): Promise<ArrayBuffer>;
68
- json(): Promise<any>;
69
- text(): Promise<string>;
97
+ type SampleRegion = {
98
+ sampleName: string;
99
+ sampleCenter: number;
100
+ rangeMidi?: [number, number];
101
+ rangeVol?: [number, number];
102
+ offsetVol?: number;
103
+ offsetDetune?: number;
104
+ sample?: Partial<SampleOptions>;
70
105
  };
71
- type Storage = {
72
- fetch: (url: string) => Promise<StorageResponse>;
106
+ type SampleLayer = {
107
+ regions: SampleRegion[];
108
+ sample: Partial<SampleOptions>;
73
109
  };
74
- declare const HttpStorage: Storage;
75
- declare class CacheStorage implements Storage {
76
- #private;
77
- constructor(name?: string);
78
- fetch(url: string): Promise<StorageResponse>;
79
- }
80
110
 
81
111
  declare function getDrumMachineNames(): string[];
82
112
  type DrumMachineConfig = ChannelOptions & SampleOptions & {
@@ -86,6 +116,7 @@ type DrumMachineConfig = ChannelOptions & SampleOptions & {
86
116
  declare class DrumMachine {
87
117
  #private;
88
118
  private readonly player;
119
+ readonly load: Promise<this>;
89
120
  readonly output: OutputChannel;
90
121
  constructor(context: AudioContext, options?: Partial<DrumMachineConfig>);
91
122
  loaded(): Promise<this>;
@@ -182,6 +213,7 @@ declare class SfzSampler {
182
213
  readonly context: AudioContext;
183
214
  readonly options: Readonly<Partial<SfzSamplerConfig>>;
184
215
  private readonly player;
216
+ readonly load: Promise<this>;
185
217
  constructor(context: AudioContext, options: Partial<SfzSamplerConfig> & Pick<SfzSamplerConfig, "instrument">);
186
218
  get output(): OutputChannel;
187
219
  loaded(): Promise<this>;
@@ -208,6 +240,26 @@ declare class Mallet extends SfzSampler {
208
240
  }
209
241
  declare const NAME_TO_PATH: Record<string, string | undefined>;
210
242
 
243
+ declare function getMellotronNames(): string[];
244
+ type MellotronConfig = {
245
+ instrument: string;
246
+ storage: Storage;
247
+ };
248
+ type MellotronOptions = Partial<SampleOptions & ChannelOptions & MellotronConfig>;
249
+ declare class Mellotron implements InternalPlayer {
250
+ readonly context: BaseAudioContext;
251
+ private readonly config;
252
+ private readonly player;
253
+ private readonly layer;
254
+ readonly load: Promise<this>;
255
+ constructor(context: BaseAudioContext, options: MellotronOptions);
256
+ get buffers(): AudioBuffers;
257
+ get output(): OutputChannel;
258
+ start(sample: SampleStart | string | number): (time?: number | undefined) => void;
259
+ stop(sample?: SampleStop | string | number): void;
260
+ disconnect(): void;
261
+ }
262
+
211
263
  declare const PARAMS: readonly ["preDelay", "bandwidth", "inputDiffusion1", "inputDiffusion2", "decay", "decayDiffusion1", "decayDiffusion2", "damping", "excursionRate", "excursionDepth", "wet", "dry"];
212
264
  declare class Reverb {
213
265
  #private;
@@ -220,12 +272,6 @@ declare class Reverb {
220
272
  connect(output: AudioNode): void;
221
273
  }
222
274
 
223
- type AudioBuffers = Record<string | number, AudioBuffer | undefined>;
224
- /**
225
- * A function that downloads audio into a AudioBuffers
226
- */
227
- type AudioBuffersLoader = (context: BaseAudioContext, buffers: AudioBuffers) => Promise<void>;
228
-
229
275
  type SamplerConfig = {
230
276
  storage?: Storage;
231
277
  detune: number;
@@ -246,6 +292,7 @@ declare class Sampler {
246
292
  #private;
247
293
  readonly context: AudioContext;
248
294
  private readonly player;
295
+ readonly load: Promise<this>;
249
296
  constructor(context: AudioContext, options?: Partial<SamplerConfig>);
250
297
  loaded(): Promise<this>;
251
298
  get output(): OutputChannel;
@@ -271,12 +318,14 @@ declare class Soundfont {
271
318
  readonly context: AudioContext;
272
319
  readonly config: Readonly<SoundfontConfig>;
273
320
  private readonly player;
321
+ readonly load: Promise<this>;
322
+ readonly layer: SampleLayer;
274
323
  constructor(context: AudioContext, options: SoundfontOptions);
275
324
  get output(): OutputChannel;
276
- loaded(): Promise<this>;
277
325
  get hasLoops(): boolean;
326
+ loaded(): Promise<this>;
278
327
  disconnect(): void;
279
- start(sample: SampleStart): (time?: number | undefined) => void;
328
+ start(sample: SampleStart | string | number): (time?: number | undefined) => void;
280
329
  stop(sample?: SampleStop | string | number): void;
281
330
  }
282
331
 
@@ -298,6 +347,7 @@ declare class SplendidGrandPiano {
298
347
  readonly context: AudioContext;
299
348
  options: Readonly<SplendidGrandPianoConfig>;
300
349
  private readonly player;
350
+ readonly load: Promise<this>;
301
351
  constructor(context: AudioContext, options?: Partial<SplendidGrandPianoConfig>);
302
352
  get output(): OutputChannel;
303
353
  get buffers(): AudioBuffers;
@@ -317,4 +367,4 @@ declare const LAYERS: ({
317
367
  cutoff?: undefined;
318
368
  })[];
319
369
 
320
- export { CacheStorage, DrumMachine, DrumMachineConfig, ElectricPiano, HttpStorage, LAYERS, Mallet, NAME_TO_PATH, Reverb, Sampler, SamplerConfig, Soundfont, SoundfontOptions, SplendidGrandPiano, SplendidGrandPianoConfig, Storage, StorageResponse, getDrumMachineNames, getElectricPianoNames, getMalletNames, getSoundfontKits, getSoundfontNames };
370
+ export { CacheStorage, DrumMachine, DrumMachineConfig, ElectricPiano, HttpStorage, LAYERS, Mallet, Mellotron, MellotronConfig, MellotronOptions, NAME_TO_PATH, Reverb, Sampler, SamplerConfig, Soundfont, SoundfontOptions, SplendidGrandPiano, SplendidGrandPianoConfig, Storage, StorageResponse, getDrumMachineNames, getElectricPianoNames, getMalletNames, getMellotronNames, getSoundfontKits, getSoundfontNames };