minikeys 0.1.1 → 0.2.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 CHANGED
@@ -1,31 +1,39 @@
1
1
  # MiniKeys
2
2
 
3
- A small javascript library for playing piano samples. Pass in an array of samples with the following naming scheme:
3
+ <!-- TODO add badges from CD -->
4
4
 
5
- `[p/f][midi note]`
5
+ A tiny javascript library that plays the piano. [Try it out here!](http://liamp.uk/minikeys)
6
6
 
7
- *piano* (low velocity) samples should begin with **p**, and *forte* (high velocity) samples should begin with **f**. *midi note* should correspond to the midi value of the note (ie. **60** for *C4*).
7
+ ## Get Started
8
8
 
9
- example:
10
- ```
11
- [
12
- '/samples/p45.ogg',
13
- '/samples/f45.ogg'
14
- ]
15
- ```
16
- - 1 sample of *C4* provided for *piano* and *forte* dynamics.
9
+ - TODO
10
+ - Add instructions for npm
11
+ - Add link to CDN
12
+
13
+ ## Reference
14
+
15
+ - TODO: update guide
16
+
17
+ ## Finding Samples
18
+
19
+ [Pianobook](www.pianobook.co.uk) is a fantastic community project to provide free piano (and other instruments) samples. The samples used in the example are from a [Steinway Concert Grand in Kristiansand, Norway](https://www.pianobook.co.uk/library/kristiansand-concert-steinway/). Thank you to [Pete Malkin](https://www.petemalkin.co.uk/) for sampling this lovely instrument!
20
+
21
+ ## Build process
22
+
23
+ - TODO: update build process
17
24
 
18
25
  ## TODO
19
26
 
20
- - [x] clean up interface with keyboard (move validation of key into library)
21
- - [x] compress samples (.ogg)
22
- - [x] trim start of samples
23
- - [ ] tidy/comment code
24
- - [ ] add tests
25
- - [ ] write build guide for readme
26
- - [x] add method for adding loading bar
27
- - [x] add animations to page
28
- - [ ] fix on iOS
29
- - [ ] add midi parser and player
30
- - [ ] add tuning mode (perfect atm, out of tune with actual piano)
31
- - [ ] move keyboard with mouse in example
27
+ - Function to play multiple notes
28
+ - Add tests
29
+ - Look into replacing compressor
30
+ - New package for chords? @minikeys/chords?
31
+ - Custom labels for piano (for showing keyboard keys?)
32
+
33
+ ## Demos
34
+
35
+ - Jazznotes
36
+ - Minikeys website
37
+ - Orchid style chord player
38
+ - Music theory demo
39
+ - piano on bottom, circle of fifths, stave showing notes, colour coded for extensions etc.
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";var f=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var F=(s,e)=>{for(var o in e)f(s,o,{get:e[o],enumerable:!0})},w=(s,e,o,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of D(e))!b.call(s,t)&&t!==o&&f(s,t,{get:()=>e[t],enumerable:!(i=g(e,t))||i.enumerable});return s};var G=s=>w(f({},"__esModule",{value:!0}),s);var K={};F(K,{MiniKeys:()=>y,MiniKeysKeyboard:()=>A,keyboardBlackNotes:()=>h,keyboardWhiteNotes:()=>p,midiToNote:()=>u,noteToMidi:()=>n});module.exports=G(K);var n={"C-1":0,"C#-1":1,"D-1":2,"D#-1":3,"E-1":4,"F-1":5,"F#-1":6,"G-1":7,"G#-1":8,"A-1":9,"A#-1":10,"B-1":11,C0:12,"C#0":13,D0:14,"D#0":15,E0:16,F0:17,"F#0":18,G0:19,"G#0":20,A0:21,"A#0":22,B0:23,C1:24,"C#1":25,D1:26,"D#1":27,E1:28,F1:29,"F#1":30,G1:31,"G#1":32,A1:33,"A#1":34,B1:35,C2:36,"C#2":37,D2:38,"D#2":39,E2:40,F2:41,"F#2":42,G2:43,"G#2":44,A2:45,"A#2":46,B2:47,C3:48,"C#3":49,D3:50,"D#3":51,E3:52,F3:53,"F#3":54,G3:55,"G#3":56,A3:57,"A#3":58,B3:59,C4:60,"C#4":61,D4:62,"D#4":63,E4:64,F4:65,"F#4":66,G4:67,"G#4":68,A4:69,"A#4":70,B4:71,C5:72,"C#5":73,D5:74,"D#5":75,E5:76,F5:77,"F#5":78,G5:79,"G#5":80,A5:81,"A#5":82,B5:83,C6:84,"C#6":85,D6:86,"D#6":87,E6:88,F6:89,"F#6":90,G6:91,"G#6":92,A6:93,"A#6":94,B6:95,C7:96,"C#7":97,D7:98,"D#7":99,E7:100,F7:101,"F#7":102,G7:103,"G#7":104,A7:105,"A#7":106,B7:107,C8:108,"C#8":109,D8:110,"D#8":111,E8:112,F8:113,"F#8":114,G8:115,"G#8":116,A8:117,"A#8":118,B8:119,C9:120,"C#9":121,D9:122,"D#9":123,E9:124,F9:125,"F#9":126,G9:127},u=Object.fromEntries(Object.entries(n).map(([s,e])=>[e,s])),h=[null,"A#0",null,"C#1","D#1",null,"F#1","G#1","A#1",null,"C#2","D#2",null,"F#2","G#2","A#2",null,"C#3","D#3",null,"F#3","G#3","A#3",null,"C#4","D#4",null,"F#4","G#4","A#4",null,"C#5","D#5",null,"F#5","G#5","A#5",null,"C#6","D#6",null,"F#6","G#6","A#6",null,"C#7","D#7",null,"F#7","G#7","A#7",null,null,null],p=["A0","B0","C1","D1","E1","F1","G1","A1","B1","C2","D2","E2","F2","G2","A2","B2","C3","D3","E3","F3","G3","A3","B3","C4","D4","E4","F4","G4","A4","B4","C5","D5","E5","F5","G5","A5","B5","C6","D6","E6","F6","G6","A6","B6","C7","D7","E7","F7","G7","A7","B7","C8"],m=[["Digit1","Digit2","Digit3","Digit4","Digit5","Digit6","Digit7","Digit8","Digit9","Digit0","Minus","Equal"],["KeyQ","KeyW","KeyE","KeyR","KeyT","KeyY","KeyU","KeyI","KeyO","KeyP","BracketLeft","BracketRight"],["KeyA","KeyS","KeyD","KeyF","KeyG","KeyH","KeyJ","KeyK","KeyL","Semicolon","Quote"],["KeyZ","KeyX","KeyC","KeyV","KeyB","KeyN","KeyM","Comma","Period","Slash"]],C=(s,e,o,i)=>{let t;if(i&&i<64&&e.size>0)t=e;else if(s.size>0)t=s;else throw new Error("No notes loaded");let r=Array.from(t.keys()).reduce((l,a)=>Math.abs(a-o)<Math.abs(l-o)?a:l);return{closestNoteMidi:r,closestNote:t.get(r)}};var y=class{audioContext;compressorNode;forteNotes=new Map;pianoNotes=new Map;sustain=!1;playingNotes=new Map;progress=0;constructor(){this.audioContext=new AudioContext,this.compressorNode=this.audioContext.createDynamicsCompressor(),this.compressorNode.threshold.value=-24,this.compressorNode.knee.value=0,this.compressorNode.ratio.value=2,this.compressorNode.attack.value=.001,this.compressorNode.release.value=.5,this.compressorNode.connect(this.audioContext.destination)}setSustain=e=>{this.sustain=e,e?this.playingNotes.forEach(o=>{let i=this.audioContext.currentTime;o.gain.cancelScheduledValues(i),o.gain.setValueAtTime(o.gain.value,i)}):this.playingNotes.forEach(o=>{let i=this.audioContext.currentTime;o.gain.cancelScheduledValues(i),o.gain.setValueAtTime(o.gain.value,i),o.gain.linearRampToValueAtTime(.001,i+.5)})};loadNotes=async(e,o)=>{this.forteNotes.clear(),this.pianoNotes.clear();let i=e.map(async t=>{let l=await(await fetch(t.url)).arrayBuffer(),a=await this.audioContext.decodeAudioData(l);if(t.velocity==="piano"?this.pianoNotes.set(n[t.note],a):this.forteNotes.set(n[t.note],a),o){let d=(this.pianoNotes.size+this.forteNotes.size)/e.length;d>this.progress&&(this.progress=d,o(this.progress))}});return await Promise.all(i)};playNoteFromMidi=(e,o)=>{if(e<0||e>127)throw new Error("Invalid midi note");if(o&&(o<0||o>127))throw new Error("Invalid velocity value");if(!this.audioContext)throw new Error("Audio context not initialized");let t=this.audioContext.createBufferSource(),{closestNoteMidi:r,closestNote:l}=C(this.forteNotes,this.pianoNotes,e,o);if(l){t.buffer=l;let a=this.audioContext.createGain(),d=Math.min(127,o??127);if(a.gain.value=(d/127*.9+.1)*.5,t.connect(a),a.connect(this.compressorNode),t.playbackRate.value=2**((e-r)/12),t.start(),this.playingNotes.set(t,a),!this.sustain){let c=this.audioContext.currentTime;a.gain.cancelScheduledValues(c),a.gain.setValueAtTime(a.gain.value,c),a.gain.exponentialRampToValueAtTime(Number.EPSILON,c+8)}t.onended=()=>{t.disconnect(),this.playingNotes.delete(t)}}else throw new Error("Note not found")};playNoteFromName=(e,o)=>{this.playNoteFromMidi(n[e],o)}};var A=class{mode;keyMap=new Map;offset;constructor(e){this.mode=e,e==="single"?this.offset=23:this.offset=16,this.buildNoteMap()}getNoteMap=()=>this.keyMap;getMidiRange=()=>{let e=Array.from(this.keyMap.values()).reduce((i,t)=>t.midiNote&&t.midiNote<i?t.midiNote:i,127),o=Array.from(this.keyMap.values()).reduce((i,t)=>t.midiNote&&t.midiNote>i?t.midiNote:i,0);return{low:e,high:o}};getNoteRange=()=>{let e=this.getMidiRange();return{low:u[e.low],high:u[e.high]}};shiftLeft=()=>{this.offset=Math.max(this.offset-1,0),this.keyMap=new Map,this.buildNoteMap()};shiftLeftOctave=()=>{this.offset=Math.max(this.offset-7,0),this.keyMap=new Map,this.buildNoteMap()};shiftRight=()=>{this.offset=Math.min(this.offset+1,this.mode==="dual"?30:41),this.keyMap=new Map,this.buildNoteMap()};shiftRightOctave=()=>{this.offset=Math.min(this.offset+7,this.mode==="dual"?30:41),this.keyMap=new Map,this.buildNoteMap()};buildNoteMap=()=>{this.mode==="single"?(N(this.keyMap,1,this.offset),M(this.keyMap,2,this.offset)):(N(this.keyMap,0,this.offset),M(this.keyMap,1,this.offset),N(this.keyMap,2,this.offset+12),M(this.keyMap,3,this.offset+12))}},N=(s,e,o)=>{m[e].forEach((i,t)=>{let r=h[o+t];if(r===null)s.set(i,{midiNote:null,type:"disabled"});else if(r!==void 0)s.set(i,{midiNote:n[r],type:"black"});else throw new Error("Invalid note")})},M=(s,e,o)=>{m[e].forEach((i,t)=>{let r=p[o+t];if(r)s.set(i,{midiNote:n[r],type:"white"});else throw new Error("Invalid note")})};0&&(module.exports={MiniKeys,MiniKeysKeyboard,keyboardBlackNotes,keyboardWhiteNotes,midiToNote,noteToMidi});
@@ -0,0 +1,186 @@
1
+ declare const noteToMidi: {
2
+ readonly "C-1": 0;
3
+ readonly "C#-1": 1;
4
+ readonly "D-1": 2;
5
+ readonly "D#-1": 3;
6
+ readonly "E-1": 4;
7
+ readonly "F-1": 5;
8
+ readonly "F#-1": 6;
9
+ readonly "G-1": 7;
10
+ readonly "G#-1": 8;
11
+ readonly "A-1": 9;
12
+ readonly "A#-1": 10;
13
+ readonly "B-1": 11;
14
+ readonly C0: 12;
15
+ readonly "C#0": 13;
16
+ readonly D0: 14;
17
+ readonly "D#0": 15;
18
+ readonly E0: 16;
19
+ readonly F0: 17;
20
+ readonly "F#0": 18;
21
+ readonly G0: 19;
22
+ readonly "G#0": 20;
23
+ readonly A0: 21;
24
+ readonly "A#0": 22;
25
+ readonly B0: 23;
26
+ readonly C1: 24;
27
+ readonly "C#1": 25;
28
+ readonly D1: 26;
29
+ readonly "D#1": 27;
30
+ readonly E1: 28;
31
+ readonly F1: 29;
32
+ readonly "F#1": 30;
33
+ readonly G1: 31;
34
+ readonly "G#1": 32;
35
+ readonly A1: 33;
36
+ readonly "A#1": 34;
37
+ readonly B1: 35;
38
+ readonly C2: 36;
39
+ readonly "C#2": 37;
40
+ readonly D2: 38;
41
+ readonly "D#2": 39;
42
+ readonly E2: 40;
43
+ readonly F2: 41;
44
+ readonly "F#2": 42;
45
+ readonly G2: 43;
46
+ readonly "G#2": 44;
47
+ readonly A2: 45;
48
+ readonly "A#2": 46;
49
+ readonly B2: 47;
50
+ readonly C3: 48;
51
+ readonly "C#3": 49;
52
+ readonly D3: 50;
53
+ readonly "D#3": 51;
54
+ readonly E3: 52;
55
+ readonly F3: 53;
56
+ readonly "F#3": 54;
57
+ readonly G3: 55;
58
+ readonly "G#3": 56;
59
+ readonly A3: 57;
60
+ readonly "A#3": 58;
61
+ readonly B3: 59;
62
+ readonly C4: 60;
63
+ readonly "C#4": 61;
64
+ readonly D4: 62;
65
+ readonly "D#4": 63;
66
+ readonly E4: 64;
67
+ readonly F4: 65;
68
+ readonly "F#4": 66;
69
+ readonly G4: 67;
70
+ readonly "G#4": 68;
71
+ readonly A4: 69;
72
+ readonly "A#4": 70;
73
+ readonly B4: 71;
74
+ readonly C5: 72;
75
+ readonly "C#5": 73;
76
+ readonly D5: 74;
77
+ readonly "D#5": 75;
78
+ readonly E5: 76;
79
+ readonly F5: 77;
80
+ readonly "F#5": 78;
81
+ readonly G5: 79;
82
+ readonly "G#5": 80;
83
+ readonly A5: 81;
84
+ readonly "A#5": 82;
85
+ readonly B5: 83;
86
+ readonly C6: 84;
87
+ readonly "C#6": 85;
88
+ readonly D6: 86;
89
+ readonly "D#6": 87;
90
+ readonly E6: 88;
91
+ readonly F6: 89;
92
+ readonly "F#6": 90;
93
+ readonly G6: 91;
94
+ readonly "G#6": 92;
95
+ readonly A6: 93;
96
+ readonly "A#6": 94;
97
+ readonly B6: 95;
98
+ readonly C7: 96;
99
+ readonly "C#7": 97;
100
+ readonly D7: 98;
101
+ readonly "D#7": 99;
102
+ readonly E7: 100;
103
+ readonly F7: 101;
104
+ readonly "F#7": 102;
105
+ readonly G7: 103;
106
+ readonly "G#7": 104;
107
+ readonly A7: 105;
108
+ readonly "A#7": 106;
109
+ readonly B7: 107;
110
+ readonly C8: 108;
111
+ readonly "C#8": 109;
112
+ readonly D8: 110;
113
+ readonly "D#8": 111;
114
+ readonly E8: 112;
115
+ readonly F8: 113;
116
+ readonly "F#8": 114;
117
+ readonly G8: 115;
118
+ readonly "G#8": 116;
119
+ readonly A8: 117;
120
+ readonly "A#8": 118;
121
+ readonly B8: 119;
122
+ readonly C9: 120;
123
+ readonly "C#9": 121;
124
+ readonly D9: 122;
125
+ readonly "D#9": 123;
126
+ readonly E9: 124;
127
+ readonly F9: 125;
128
+ readonly "F#9": 126;
129
+ readonly G9: 127;
130
+ };
131
+ declare const midiToNote: { [K in keyof typeof noteToMidi as (typeof noteToMidi)[K]]: K; };
132
+ declare const keyboardBlackNotes: readonly [null, "A#0", null, "C#1", "D#1", null, "F#1", "G#1", "A#1", null, "C#2", "D#2", null, "F#2", "G#2", "A#2", null, "C#3", "D#3", null, "F#3", "G#3", "A#3", null, "C#4", "D#4", null, "F#4", "G#4", "A#4", null, "C#5", "D#5", null, "F#5", "G#5", "A#5", null, "C#6", "D#6", null, "F#6", "G#6", "A#6", null, "C#7", "D#7", null, "F#7", "G#7", "A#7", null, null, null];
133
+ declare const keyboardWhiteNotes: readonly ["A0", "B0", "C1", "D1", "E1", "F1", "G1", "A1", "B1", "C2", "D2", "E2", "F2", "G2", "A2", "B2", "C3", "D3", "E3", "F3", "G3", "A3", "B3", "C4", "D4", "E4", "F4", "G4", "A4", "B4", "C5", "D5", "E5", "F5", "G5", "A5", "B5", "C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7", "D7", "E7", "F7", "G7", "A7", "B7", "C8"];
134
+
135
+ type NoteName = keyof typeof noteToMidi;
136
+ type MidiRange = (typeof noteToMidi)[NoteName];
137
+ type Velocity = 'piano' | 'forte';
138
+ type Sample = {
139
+ note: NoteName;
140
+ url: string;
141
+ velocity: Velocity;
142
+ };
143
+ type KeyboardMode = 'dual' | 'single';
144
+ type KeyType = 'black' | 'white' | 'disabled';
145
+ type KeyMap = Map<string, {
146
+ midiNote: MidiRange | null;
147
+ type: KeyType;
148
+ }>;
149
+
150
+ declare class MiniKeys {
151
+ private audioContext;
152
+ private compressorNode;
153
+ private forteNotes;
154
+ private pianoNotes;
155
+ private sustain;
156
+ private playingNotes;
157
+ private progress;
158
+ constructor();
159
+ setSustain: (sustain: boolean) => void;
160
+ loadNotes: (samples: Sample[], handleSampleLoaded?: (progress: number) => void) => Promise<void[]>;
161
+ playNoteFromMidi: (midiNote: number, velocity?: number) => void;
162
+ playNoteFromName: (noteName: NoteName, velocity?: number) => void;
163
+ }
164
+
165
+ declare class MiniKeysKeyboard {
166
+ private mode;
167
+ private keyMap;
168
+ private offset;
169
+ constructor(mode: KeyboardMode);
170
+ getNoteMap: () => KeyMap;
171
+ getMidiRange: () => {
172
+ low: MidiRange;
173
+ high: MidiRange;
174
+ };
175
+ getNoteRange: () => {
176
+ low: "C-1" | "C#-1" | "D-1" | "D#-1" | "E-1" | "F-1" | "F#-1" | "G-1" | "G#-1" | "A-1" | "A#-1" | "B-1" | "C0" | "C#0" | "D0" | "D#0" | "E0" | "F0" | "F#0" | "G0" | "G#0" | "A0" | "A#0" | "B0" | "C1" | "C#1" | "D1" | "D#1" | "E1" | "F1" | "F#1" | "G1" | "G#1" | "A1" | "A#1" | "B1" | "C2" | "C#2" | "D2" | "D#2" | "E2" | "F2" | "F#2" | "G2" | "G#2" | "A2" | "A#2" | "B2" | "C3" | "C#3" | "D3" | "D#3" | "E3" | "F3" | "F#3" | "G3" | "G#3" | "A3" | "A#3" | "B3" | "C4" | "C#4" | "D4" | "D#4" | "E4" | "F4" | "F#4" | "G4" | "G#4" | "A4" | "A#4" | "B4" | "C5" | "C#5" | "D5" | "D#5" | "E5" | "F5" | "F#5" | "G5" | "G#5" | "A5" | "A#5" | "B5" | "C6" | "C#6" | "D6" | "D#6" | "E6" | "F6" | "F#6" | "G6" | "G#6" | "A6" | "A#6" | "B6" | "C7" | "C#7" | "D7" | "D#7" | "E7" | "F7" | "F#7" | "G7" | "G#7" | "A7" | "A#7" | "B7" | "C8" | "C#8" | "D8" | "D#8" | "E8" | "F8" | "F#8" | "G8" | "G#8" | "A8" | "A#8" | "B8" | "C9" | "C#9" | "D9" | "D#9" | "E9" | "F9" | "F#9" | "G9";
177
+ high: "C-1" | "C#-1" | "D-1" | "D#-1" | "E-1" | "F-1" | "F#-1" | "G-1" | "G#-1" | "A-1" | "A#-1" | "B-1" | "C0" | "C#0" | "D0" | "D#0" | "E0" | "F0" | "F#0" | "G0" | "G#0" | "A0" | "A#0" | "B0" | "C1" | "C#1" | "D1" | "D#1" | "E1" | "F1" | "F#1" | "G1" | "G#1" | "A1" | "A#1" | "B1" | "C2" | "C#2" | "D2" | "D#2" | "E2" | "F2" | "F#2" | "G2" | "G#2" | "A2" | "A#2" | "B2" | "C3" | "C#3" | "D3" | "D#3" | "E3" | "F3" | "F#3" | "G3" | "G#3" | "A3" | "A#3" | "B3" | "C4" | "C#4" | "D4" | "D#4" | "E4" | "F4" | "F#4" | "G4" | "G#4" | "A4" | "A#4" | "B4" | "C5" | "C#5" | "D5" | "D#5" | "E5" | "F5" | "F#5" | "G5" | "G#5" | "A5" | "A#5" | "B5" | "C6" | "C#6" | "D6" | "D#6" | "E6" | "F6" | "F#6" | "G6" | "G#6" | "A6" | "A#6" | "B6" | "C7" | "C#7" | "D7" | "D#7" | "E7" | "F7" | "F#7" | "G7" | "G#7" | "A7" | "A#7" | "B7" | "C8" | "C#8" | "D8" | "D#8" | "E8" | "F8" | "F#8" | "G8" | "G#8" | "A8" | "A#8" | "B8" | "C9" | "C#9" | "D9" | "D#9" | "E9" | "F9" | "F#9" | "G9";
178
+ };
179
+ shiftLeft: () => void;
180
+ shiftLeftOctave: () => void;
181
+ shiftRight: () => void;
182
+ shiftRightOctave: () => void;
183
+ private buildNoteMap;
184
+ }
185
+
186
+ export { type KeyMap, type KeyboardMode, MiniKeys, MiniKeysKeyboard, type NoteName, type Sample, type Velocity, keyboardBlackNotes, keyboardWhiteNotes, midiToNote, noteToMidi };
@@ -0,0 +1,186 @@
1
+ declare const noteToMidi: {
2
+ readonly "C-1": 0;
3
+ readonly "C#-1": 1;
4
+ readonly "D-1": 2;
5
+ readonly "D#-1": 3;
6
+ readonly "E-1": 4;
7
+ readonly "F-1": 5;
8
+ readonly "F#-1": 6;
9
+ readonly "G-1": 7;
10
+ readonly "G#-1": 8;
11
+ readonly "A-1": 9;
12
+ readonly "A#-1": 10;
13
+ readonly "B-1": 11;
14
+ readonly C0: 12;
15
+ readonly "C#0": 13;
16
+ readonly D0: 14;
17
+ readonly "D#0": 15;
18
+ readonly E0: 16;
19
+ readonly F0: 17;
20
+ readonly "F#0": 18;
21
+ readonly G0: 19;
22
+ readonly "G#0": 20;
23
+ readonly A0: 21;
24
+ readonly "A#0": 22;
25
+ readonly B0: 23;
26
+ readonly C1: 24;
27
+ readonly "C#1": 25;
28
+ readonly D1: 26;
29
+ readonly "D#1": 27;
30
+ readonly E1: 28;
31
+ readonly F1: 29;
32
+ readonly "F#1": 30;
33
+ readonly G1: 31;
34
+ readonly "G#1": 32;
35
+ readonly A1: 33;
36
+ readonly "A#1": 34;
37
+ readonly B1: 35;
38
+ readonly C2: 36;
39
+ readonly "C#2": 37;
40
+ readonly D2: 38;
41
+ readonly "D#2": 39;
42
+ readonly E2: 40;
43
+ readonly F2: 41;
44
+ readonly "F#2": 42;
45
+ readonly G2: 43;
46
+ readonly "G#2": 44;
47
+ readonly A2: 45;
48
+ readonly "A#2": 46;
49
+ readonly B2: 47;
50
+ readonly C3: 48;
51
+ readonly "C#3": 49;
52
+ readonly D3: 50;
53
+ readonly "D#3": 51;
54
+ readonly E3: 52;
55
+ readonly F3: 53;
56
+ readonly "F#3": 54;
57
+ readonly G3: 55;
58
+ readonly "G#3": 56;
59
+ readonly A3: 57;
60
+ readonly "A#3": 58;
61
+ readonly B3: 59;
62
+ readonly C4: 60;
63
+ readonly "C#4": 61;
64
+ readonly D4: 62;
65
+ readonly "D#4": 63;
66
+ readonly E4: 64;
67
+ readonly F4: 65;
68
+ readonly "F#4": 66;
69
+ readonly G4: 67;
70
+ readonly "G#4": 68;
71
+ readonly A4: 69;
72
+ readonly "A#4": 70;
73
+ readonly B4: 71;
74
+ readonly C5: 72;
75
+ readonly "C#5": 73;
76
+ readonly D5: 74;
77
+ readonly "D#5": 75;
78
+ readonly E5: 76;
79
+ readonly F5: 77;
80
+ readonly "F#5": 78;
81
+ readonly G5: 79;
82
+ readonly "G#5": 80;
83
+ readonly A5: 81;
84
+ readonly "A#5": 82;
85
+ readonly B5: 83;
86
+ readonly C6: 84;
87
+ readonly "C#6": 85;
88
+ readonly D6: 86;
89
+ readonly "D#6": 87;
90
+ readonly E6: 88;
91
+ readonly F6: 89;
92
+ readonly "F#6": 90;
93
+ readonly G6: 91;
94
+ readonly "G#6": 92;
95
+ readonly A6: 93;
96
+ readonly "A#6": 94;
97
+ readonly B6: 95;
98
+ readonly C7: 96;
99
+ readonly "C#7": 97;
100
+ readonly D7: 98;
101
+ readonly "D#7": 99;
102
+ readonly E7: 100;
103
+ readonly F7: 101;
104
+ readonly "F#7": 102;
105
+ readonly G7: 103;
106
+ readonly "G#7": 104;
107
+ readonly A7: 105;
108
+ readonly "A#7": 106;
109
+ readonly B7: 107;
110
+ readonly C8: 108;
111
+ readonly "C#8": 109;
112
+ readonly D8: 110;
113
+ readonly "D#8": 111;
114
+ readonly E8: 112;
115
+ readonly F8: 113;
116
+ readonly "F#8": 114;
117
+ readonly G8: 115;
118
+ readonly "G#8": 116;
119
+ readonly A8: 117;
120
+ readonly "A#8": 118;
121
+ readonly B8: 119;
122
+ readonly C9: 120;
123
+ readonly "C#9": 121;
124
+ readonly D9: 122;
125
+ readonly "D#9": 123;
126
+ readonly E9: 124;
127
+ readonly F9: 125;
128
+ readonly "F#9": 126;
129
+ readonly G9: 127;
130
+ };
131
+ declare const midiToNote: { [K in keyof typeof noteToMidi as (typeof noteToMidi)[K]]: K; };
132
+ declare const keyboardBlackNotes: readonly [null, "A#0", null, "C#1", "D#1", null, "F#1", "G#1", "A#1", null, "C#2", "D#2", null, "F#2", "G#2", "A#2", null, "C#3", "D#3", null, "F#3", "G#3", "A#3", null, "C#4", "D#4", null, "F#4", "G#4", "A#4", null, "C#5", "D#5", null, "F#5", "G#5", "A#5", null, "C#6", "D#6", null, "F#6", "G#6", "A#6", null, "C#7", "D#7", null, "F#7", "G#7", "A#7", null, null, null];
133
+ declare const keyboardWhiteNotes: readonly ["A0", "B0", "C1", "D1", "E1", "F1", "G1", "A1", "B1", "C2", "D2", "E2", "F2", "G2", "A2", "B2", "C3", "D3", "E3", "F3", "G3", "A3", "B3", "C4", "D4", "E4", "F4", "G4", "A4", "B4", "C5", "D5", "E5", "F5", "G5", "A5", "B5", "C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7", "D7", "E7", "F7", "G7", "A7", "B7", "C8"];
134
+
135
+ type NoteName = keyof typeof noteToMidi;
136
+ type MidiRange = (typeof noteToMidi)[NoteName];
137
+ type Velocity = 'piano' | 'forte';
138
+ type Sample = {
139
+ note: NoteName;
140
+ url: string;
141
+ velocity: Velocity;
142
+ };
143
+ type KeyboardMode = 'dual' | 'single';
144
+ type KeyType = 'black' | 'white' | 'disabled';
145
+ type KeyMap = Map<string, {
146
+ midiNote: MidiRange | null;
147
+ type: KeyType;
148
+ }>;
149
+
150
+ declare class MiniKeys {
151
+ private audioContext;
152
+ private compressorNode;
153
+ private forteNotes;
154
+ private pianoNotes;
155
+ private sustain;
156
+ private playingNotes;
157
+ private progress;
158
+ constructor();
159
+ setSustain: (sustain: boolean) => void;
160
+ loadNotes: (samples: Sample[], handleSampleLoaded?: (progress: number) => void) => Promise<void[]>;
161
+ playNoteFromMidi: (midiNote: number, velocity?: number) => void;
162
+ playNoteFromName: (noteName: NoteName, velocity?: number) => void;
163
+ }
164
+
165
+ declare class MiniKeysKeyboard {
166
+ private mode;
167
+ private keyMap;
168
+ private offset;
169
+ constructor(mode: KeyboardMode);
170
+ getNoteMap: () => KeyMap;
171
+ getMidiRange: () => {
172
+ low: MidiRange;
173
+ high: MidiRange;
174
+ };
175
+ getNoteRange: () => {
176
+ low: "C-1" | "C#-1" | "D-1" | "D#-1" | "E-1" | "F-1" | "F#-1" | "G-1" | "G#-1" | "A-1" | "A#-1" | "B-1" | "C0" | "C#0" | "D0" | "D#0" | "E0" | "F0" | "F#0" | "G0" | "G#0" | "A0" | "A#0" | "B0" | "C1" | "C#1" | "D1" | "D#1" | "E1" | "F1" | "F#1" | "G1" | "G#1" | "A1" | "A#1" | "B1" | "C2" | "C#2" | "D2" | "D#2" | "E2" | "F2" | "F#2" | "G2" | "G#2" | "A2" | "A#2" | "B2" | "C3" | "C#3" | "D3" | "D#3" | "E3" | "F3" | "F#3" | "G3" | "G#3" | "A3" | "A#3" | "B3" | "C4" | "C#4" | "D4" | "D#4" | "E4" | "F4" | "F#4" | "G4" | "G#4" | "A4" | "A#4" | "B4" | "C5" | "C#5" | "D5" | "D#5" | "E5" | "F5" | "F#5" | "G5" | "G#5" | "A5" | "A#5" | "B5" | "C6" | "C#6" | "D6" | "D#6" | "E6" | "F6" | "F#6" | "G6" | "G#6" | "A6" | "A#6" | "B6" | "C7" | "C#7" | "D7" | "D#7" | "E7" | "F7" | "F#7" | "G7" | "G#7" | "A7" | "A#7" | "B7" | "C8" | "C#8" | "D8" | "D#8" | "E8" | "F8" | "F#8" | "G8" | "G#8" | "A8" | "A#8" | "B8" | "C9" | "C#9" | "D9" | "D#9" | "E9" | "F9" | "F#9" | "G9";
177
+ high: "C-1" | "C#-1" | "D-1" | "D#-1" | "E-1" | "F-1" | "F#-1" | "G-1" | "G#-1" | "A-1" | "A#-1" | "B-1" | "C0" | "C#0" | "D0" | "D#0" | "E0" | "F0" | "F#0" | "G0" | "G#0" | "A0" | "A#0" | "B0" | "C1" | "C#1" | "D1" | "D#1" | "E1" | "F1" | "F#1" | "G1" | "G#1" | "A1" | "A#1" | "B1" | "C2" | "C#2" | "D2" | "D#2" | "E2" | "F2" | "F#2" | "G2" | "G#2" | "A2" | "A#2" | "B2" | "C3" | "C#3" | "D3" | "D#3" | "E3" | "F3" | "F#3" | "G3" | "G#3" | "A3" | "A#3" | "B3" | "C4" | "C#4" | "D4" | "D#4" | "E4" | "F4" | "F#4" | "G4" | "G#4" | "A4" | "A#4" | "B4" | "C5" | "C#5" | "D5" | "D#5" | "E5" | "F5" | "F#5" | "G5" | "G#5" | "A5" | "A#5" | "B5" | "C6" | "C#6" | "D6" | "D#6" | "E6" | "F6" | "F#6" | "G6" | "G#6" | "A6" | "A#6" | "B6" | "C7" | "C#7" | "D7" | "D#7" | "E7" | "F7" | "F#7" | "G7" | "G#7" | "A7" | "A#7" | "B7" | "C8" | "C#8" | "D8" | "D#8" | "E8" | "F8" | "F#8" | "G8" | "G#8" | "A8" | "A#8" | "B8" | "C9" | "C#9" | "D9" | "D#9" | "E9" | "F9" | "F#9" | "G9";
178
+ };
179
+ shiftLeft: () => void;
180
+ shiftLeftOctave: () => void;
181
+ shiftRight: () => void;
182
+ shiftRightOctave: () => void;
183
+ private buildNoteMap;
184
+ }
185
+
186
+ export { type KeyMap, type KeyboardMode, MiniKeys, MiniKeysKeyboard, type NoteName, type Sample, type Velocity, keyboardBlackNotes, keyboardWhiteNotes, midiToNote, noteToMidi };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ var n={"C-1":0,"C#-1":1,"D-1":2,"D#-1":3,"E-1":4,"F-1":5,"F#-1":6,"G-1":7,"G#-1":8,"A-1":9,"A#-1":10,"B-1":11,C0:12,"C#0":13,D0:14,"D#0":15,E0:16,F0:17,"F#0":18,G0:19,"G#0":20,A0:21,"A#0":22,B0:23,C1:24,"C#1":25,D1:26,"D#1":27,E1:28,F1:29,"F#1":30,G1:31,"G#1":32,A1:33,"A#1":34,B1:35,C2:36,"C#2":37,D2:38,"D#2":39,E2:40,F2:41,"F#2":42,G2:43,"G#2":44,A2:45,"A#2":46,B2:47,C3:48,"C#3":49,D3:50,"D#3":51,E3:52,F3:53,"F#3":54,G3:55,"G#3":56,A3:57,"A#3":58,B3:59,C4:60,"C#4":61,D4:62,"D#4":63,E4:64,F4:65,"F#4":66,G4:67,"G#4":68,A4:69,"A#4":70,B4:71,C5:72,"C#5":73,D5:74,"D#5":75,E5:76,F5:77,"F#5":78,G5:79,"G#5":80,A5:81,"A#5":82,B5:83,C6:84,"C#6":85,D6:86,"D#6":87,E6:88,F6:89,"F#6":90,G6:91,"G#6":92,A6:93,"A#6":94,B6:95,C7:96,"C#7":97,D7:98,"D#7":99,E7:100,F7:101,"F#7":102,G7:103,"G#7":104,A7:105,"A#7":106,B7:107,C8:108,"C#8":109,D8:110,"D#8":111,E8:112,F8:113,"F#8":114,G8:115,"G#8":116,A8:117,"A#8":118,B8:119,C9:120,"C#9":121,D9:122,"D#9":123,E9:124,F9:125,"F#9":126,G9:127},d=Object.fromEntries(Object.entries(n).map(([r,t])=>[t,r])),p=[null,"A#0",null,"C#1","D#1",null,"F#1","G#1","A#1",null,"C#2","D#2",null,"F#2","G#2","A#2",null,"C#3","D#3",null,"F#3","G#3","A#3",null,"C#4","D#4",null,"F#4","G#4","A#4",null,"C#5","D#5",null,"F#5","G#5","A#5",null,"C#6","D#6",null,"F#6","G#6","A#6",null,"C#7","D#7",null,"F#7","G#7","A#7",null,null,null],c=["A0","B0","C1","D1","E1","F1","G1","A1","B1","C2","D2","E2","F2","G2","A2","B2","C3","D3","E3","F3","G3","A3","B3","C4","D4","E4","F4","G4","A4","B4","C5","D5","E5","F5","G5","A5","B5","C6","D6","E6","F6","G6","A6","B6","C7","D7","E7","F7","G7","A7","B7","C8"],f=[["Digit1","Digit2","Digit3","Digit4","Digit5","Digit6","Digit7","Digit8","Digit9","Digit0","Minus","Equal"],["KeyQ","KeyW","KeyE","KeyR","KeyT","KeyY","KeyU","KeyI","KeyO","KeyP","BracketLeft","BracketRight"],["KeyA","KeyS","KeyD","KeyF","KeyG","KeyH","KeyJ","KeyK","KeyL","Semicolon","Quote"],["KeyZ","KeyX","KeyC","KeyV","KeyB","KeyN","KeyM","Comma","Period","Slash"]],N=(r,t,o,i)=>{let e;if(i&&i<64&&t.size>0)e=t;else if(r.size>0)e=r;else throw new Error("No notes loaded");let a=Array.from(e.keys()).reduce((l,s)=>Math.abs(s-o)<Math.abs(l-o)?s:l);return{closestNoteMidi:a,closestNote:e.get(a)}};var M=class{audioContext;compressorNode;forteNotes=new Map;pianoNotes=new Map;sustain=!1;playingNotes=new Map;progress=0;constructor(){this.audioContext=new AudioContext,this.compressorNode=this.audioContext.createDynamicsCompressor(),this.compressorNode.threshold.value=-24,this.compressorNode.knee.value=0,this.compressorNode.ratio.value=2,this.compressorNode.attack.value=.001,this.compressorNode.release.value=.5,this.compressorNode.connect(this.audioContext.destination)}setSustain=t=>{this.sustain=t,t?this.playingNotes.forEach(o=>{let i=this.audioContext.currentTime;o.gain.cancelScheduledValues(i),o.gain.setValueAtTime(o.gain.value,i)}):this.playingNotes.forEach(o=>{let i=this.audioContext.currentTime;o.gain.cancelScheduledValues(i),o.gain.setValueAtTime(o.gain.value,i),o.gain.linearRampToValueAtTime(.001,i+.5)})};loadNotes=async(t,o)=>{this.forteNotes.clear(),this.pianoNotes.clear();let i=t.map(async e=>{let l=await(await fetch(e.url)).arrayBuffer(),s=await this.audioContext.decodeAudioData(l);if(e.velocity==="piano"?this.pianoNotes.set(n[e.note],s):this.forteNotes.set(n[e.note],s),o){let u=(this.pianoNotes.size+this.forteNotes.size)/t.length;u>this.progress&&(this.progress=u,o(this.progress))}});return await Promise.all(i)};playNoteFromMidi=(t,o)=>{if(t<0||t>127)throw new Error("Invalid midi note");if(o&&(o<0||o>127))throw new Error("Invalid velocity value");if(!this.audioContext)throw new Error("Audio context not initialized");let e=this.audioContext.createBufferSource(),{closestNoteMidi:a,closestNote:l}=N(this.forteNotes,this.pianoNotes,t,o);if(l){e.buffer=l;let s=this.audioContext.createGain(),u=Math.min(127,o??127);if(s.gain.value=(u/127*.9+.1)*.5,e.connect(s),s.connect(this.compressorNode),e.playbackRate.value=2**((t-a)/12),e.start(),this.playingNotes.set(e,s),!this.sustain){let h=this.audioContext.currentTime;s.gain.cancelScheduledValues(h),s.gain.setValueAtTime(s.gain.value,h),s.gain.exponentialRampToValueAtTime(Number.EPSILON,h+8)}e.onended=()=>{e.disconnect(),this.playingNotes.delete(e)}}else throw new Error("Note not found")};playNoteFromName=(t,o)=>{this.playNoteFromMidi(n[t],o)}};var A=class{mode;keyMap=new Map;offset;constructor(t){this.mode=t,t==="single"?this.offset=23:this.offset=16,this.buildNoteMap()}getNoteMap=()=>this.keyMap;getMidiRange=()=>{let t=Array.from(this.keyMap.values()).reduce((i,e)=>e.midiNote&&e.midiNote<i?e.midiNote:i,127),o=Array.from(this.keyMap.values()).reduce((i,e)=>e.midiNote&&e.midiNote>i?e.midiNote:i,0);return{low:t,high:o}};getNoteRange=()=>{let t=this.getMidiRange();return{low:d[t.low],high:d[t.high]}};shiftLeft=()=>{this.offset=Math.max(this.offset-1,0),this.keyMap=new Map,this.buildNoteMap()};shiftLeftOctave=()=>{this.offset=Math.max(this.offset-7,0),this.keyMap=new Map,this.buildNoteMap()};shiftRight=()=>{this.offset=Math.min(this.offset+1,this.mode==="dual"?30:41),this.keyMap=new Map,this.buildNoteMap()};shiftRightOctave=()=>{this.offset=Math.min(this.offset+7,this.mode==="dual"?30:41),this.keyMap=new Map,this.buildNoteMap()};buildNoteMap=()=>{this.mode==="single"?(m(this.keyMap,1,this.offset),y(this.keyMap,2,this.offset)):(m(this.keyMap,0,this.offset),y(this.keyMap,1,this.offset),m(this.keyMap,2,this.offset+12),y(this.keyMap,3,this.offset+12))}},m=(r,t,o)=>{f[t].forEach((i,e)=>{let a=p[o+e];if(a===null)r.set(i,{midiNote:null,type:"disabled"});else if(a!==void 0)r.set(i,{midiNote:n[a],type:"black"});else throw new Error("Invalid note")})},y=(r,t,o)=>{f[t].forEach((i,e)=>{let a=c[o+e];if(a)r.set(i,{midiNote:n[a],type:"white"});else throw new Error("Invalid note")})};export{M as MiniKeys,A as MiniKeysKeyboard,p as keyboardBlackNotes,c as keyboardWhiteNotes,d as midiToNote,n as noteToMidi};
package/package.json CHANGED
@@ -1,26 +1,47 @@
1
1
  {
2
2
  "name": "minikeys",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "A javascript library that plays the piano",
5
- "main": "dist/minikeys.min.js",
6
- "scripts": {
7
- "test": "mocha -u tdd --require @babel/register",
8
- "build": "webpack --mode production"
5
+ "keywords": [
6
+ "minikeys",
7
+ "piano"
8
+ ],
9
+ "main": "dist/index.js",
10
+ "types": "dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/index.cjs"
16
+ }
17
+ },
18
+ "homepage": "https://liamp.uk/minikeys",
19
+ "bugs": {
20
+ "url": "https://github.com/liampuk/minikeys/issues"
9
21
  },
10
- "keywords": [],
11
- "author": "liampuk",
12
- "license": "ISC",
22
+ "author": "Liam Piesley <liampuk@gmail.com> (https://liamp.uk)",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/liampuk/minikeys.git"
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "README.md"
30
+ ],
31
+ "type": "module",
32
+ "license": "MIT",
13
33
  "devDependencies": {
14
- "@babel/core": "^7.10.2",
15
- "@babel/preset-env": "^7.10.2",
16
- "@babel/register": "^7.10.1",
17
- "babel-loader": "^8.1.0",
18
- "chai": "^4.2.0",
19
- "mocha": "^8.0.1",
20
- "webpack": "^4.43.0",
21
- "webpack-cli": "^3.3.11"
34
+ "prettier": "^3.5.1",
35
+ "tsup": "^8.3.6",
36
+ "typescript": "^5.7.2",
37
+ "vitest": "^3.0.5"
22
38
  },
23
- "files": [
24
- "minikeys.min.js"
25
- ]
39
+ "scripts": {
40
+ "build": "tsup",
41
+ "ci": "npm run build && npm run check-format && npm run lint && npm run test",
42
+ "lint": "tsc",
43
+ "test": "vitest run",
44
+ "format": "prettier --write .",
45
+ "check-format": "prettier --check ."
46
+ }
26
47
  }
@@ -1 +0,0 @@
1
- var MiniKeys=function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=0)}([function(e,t,r){"use strict";r.r(t);var n=function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this._sampleNotes=new Array,this._noteBuffers=new Array,this._context=null,this._whiteKeys={a:60,s:62,d:64,f:65,g:67,h:69,j:71,k:72,l:74,";":76,"'":77},this._blackKeys={q:-1,w:61,e:63,r:-1,t:66,y:68,u:70,i:-1,o:73,p:75,"[":-1,"]":78},this._WHITEKEYSET=[21,23,24,26,28,29,31,33,35,36,38,40,41,43,45,47,48,50,52,53,55,57,59,60,62,64,65,67,69,71,72,74,76,77,79,81,83,84,86,88,89,91,93,95,96,98,100,101,103,105,107,108],this._BLACKKEYSET=[-1,22,-1,25,27,-1,30,32,34,-1,37,39,-1,42,44,46,-1,49,51,-1,54,56,58,-1,61,63,-1,66,68,70,-1,73,75,-1,78,80,82,-1,85,87,-1,90,92,94,-1,97,99,-1,102,104,106,-1,-1],this._keySetIndex=23,this.OCTAVE=7,this.TONE=1,this._volume=.9,this._compressorNode=null};n.prototype.getWhiteMidiNotes=function(){return this._WHITEKEYSET},n.prototype.getBlackMidiNotes=function(){return this._BLACKKEYSET},n.prototype.getKeyIndex=function(){return this._keySetIndex},n.prototype.getKeys=function(){var e=this,t=[];return Object.keys(this._whiteKeys).forEach((function(e){t.push(e)})),Object.keys(this._blackKeys).forEach((function(r){-1!=e._blackKeys[r]&&t.push(r)})),t};var o=n;o.prototype.init=function(){window.AudioContext=window.AudioContext||window.webkitAudioContext,this._context=new AudioContext;var e=this._context;this._compressorNode=e.createDynamicsCompressor(),this._compressorNode.threshold.setValueAtTime(-12,e.currentTime),this._compressorNode.knee.setValueAtTime(0,e.currentTime),this._compressorNode.ratio.setValueAtTime(15,e.currentTime),this._compressorNode.attack.setValueAtTime(.005,e.currentTime),this._compressorNode.release.setValueAtTime(.05,e.currentTime),this._compressorNode.connect(e.destination)},o.prototype.loadSamples=function(e){var t=this,r=0;return new Promise((function(n,o){var i=e.map((function(n,o){return t._loadBuffer(n,o).then((function(n){t._sampleNotes[o]=n,t._sampleNotes.includes(n)||(t._sampleNotes[o]=n),r++;var i=new CustomEvent("sampleloaded",{detail:r/e.length});document.dispatchEvent(i)}))}));Promise.all(i).then((function(){n(t._sampleNotes)})).catch((function(e){return o(e)}))}))},o.prototype._loadBuffer=function(e,t){var r=this;return new Promise((function(t,n){var o,i=e.split("/").pop().split(".")[0];if("p"==i.substring(0,1)||"f"==i.substring(0,1)?i.substring(0,1):n(Error("Invalid file name")),(o=parseInt(i.substring(1)))>=21&&o<=108){var s=new XMLHttpRequest;s.open("GET",e,!0),s.responseType="arraybuffer";var u=r;s.onload=function(){u._context.decodeAudioData(s.response,(function(r){r?(u._noteBuffers[i]=r,t(o)):n(Error("error decoding file data: "+e))}),(function(e){throw new Error(e)}))},s.onerror=function(){alert("BufferLoader: XHR error"),n(Error("BufferLoader: XHR error"))},s.send()}else n(Error("Invalid file name"))}))},o.prototype.playNote=function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,n=null,o=null;t>=64&&t<=128?(n="f",o=((t-64)/256+.25)*this._volume):t>=0&&(n="p",o=t/256*this._volume);var i=this._sampleNotes.reduce((function(t,r){return Math.abs(r-e)<Math.abs(t-e)?r:t}),this._sampleNotes[0]),s=this._context.createBufferSource();s.buffer=this._noteBuffers[n+i];var u=this._context.createGain();u.gain.value=o,s.connect(u),u.connect(this._compressorNode),s.playbackRate.value=Math.pow(2,(e-i)/12),s.start(0,r)},o.prototype.volume=function(e){if(e<0||e>1)throw new Error("volume must be between 0 and 1");this._volume=e,this._gainNode.gain.value=this._volume},o.prototype.shift=function(e){var t=this,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.OCTAVE;if(1!=e&&-1!=e||r!=this.OCTAVE&&r!=this.TONE)throw new Error("shift must be 1 or -1 and step must be OCTAVE or TONE");this._keySetIndex+=e*r,this._keySetIndex<0?this._keySetIndex=0:this._keySetIndex+11>this._WHITEKEYSET.length&&(this._keySetIndex=this._WHITEKEYSET.length-11);var n=this._keySetIndex;Object.keys(this._whiteKeys).forEach((function(e){t._whiteKeys[e]=t._WHITEKEYSET[n],n++})),n=this._keySetIndex,Object.keys(this._blackKeys).forEach((function(e){t._blackKeys[e]=t._BLACKKEYSET[n],n++}))};t.default=o}]).default;