minikeys 0.1.2 → 0.2.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 +56 -67
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +186 -0
- package/dist/index.d.ts +186 -0
- package/dist/index.js +1 -0
- package/package.json +40 -19
package/README.md
CHANGED
|
@@ -1,99 +1,88 @@
|
|
|
1
1
|
# MiniKeys
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<!-- TODO add badges from CD -->
|
|
4
4
|
|
|
5
|
-
A tiny javascript library that plays the piano.
|
|
5
|
+
A tiny javascript library that plays the piano. [Try it out here!](http://liamp.uk/minikeys)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
To use MiniKeys in a React app, you can use components from [@minikeys/react](https://npmjs.com/)
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- Latest verison:
|
|
11
|
-
```html
|
|
12
|
-
<script src="https://cdn.jsdelivr.net/npm/minikeys/dist/minikeys.min.js"></script>
|
|
13
|
-
```
|
|
14
|
-
- Specific release (v0.1.1):
|
|
15
|
-
```html
|
|
16
|
-
<script src="https://cdn.jsdelivr.net/npm/minikeys@0.1.1/dist/minikeys.min.js"></script>
|
|
17
|
-
```
|
|
9
|
+
<img width="1269" height="486" alt="Screenshot 2025-07-31 at 21 23 08" src="https://github.com/user-attachments/assets/1ff24de7-9222-42f0-ba74-9a3618ef9cd6" />
|
|
18
10
|
|
|
19
|
-
##
|
|
11
|
+
## Install
|
|
20
12
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
13
|
+
```
|
|
14
|
+
$ yarn add minikeys
|
|
15
|
+
# OR
|
|
16
|
+
$ npm install minikeys
|
|
25
17
|
```
|
|
26
18
|
|
|
27
|
-
|
|
19
|
+
## Using MiniKeys
|
|
28
20
|
|
|
29
|
-
|
|
30
|
-
miniKeys.init();
|
|
31
|
-
```
|
|
21
|
+
### Basic Setup
|
|
32
22
|
|
|
33
|
-
|
|
23
|
+
First, instantiate a new instance of MiniKeys, then call `loadNotes` with a list of sample audio files. You can then call `playNote` with either the midi note value or the note name (_A3_, _C#4_ etc.)
|
|
34
24
|
|
|
35
|
-
```
|
|
36
|
-
miniKeys
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
25
|
+
```
|
|
26
|
+
const miniKeys = new MiniKeys();
|
|
27
|
+
|
|
28
|
+
miniKeys.loadNotes([
|
|
29
|
+
{
|
|
30
|
+
note: 'A#2',
|
|
31
|
+
url: '/samples/a2.ogg
|
|
32
|
+
velocity: 'piano'
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
note: 'A#6',
|
|
36
|
+
url: '/samples/a6.ogg
|
|
37
|
+
velocity: 'piano'
|
|
38
|
+
},
|
|
39
|
+
])
|
|
40
|
+
|
|
41
|
+
miniKeys.playNoteFromName('C#4')
|
|
40
42
|
```
|
|
41
43
|
|
|
42
|
-
MiniKeys works with any number of samples. When a note is played, MiniKeys finds the closest loaded sample and tunes it to the correct frequency.
|
|
44
|
+
MiniKeys works with any number of samples. When a note is played, MiniKeys finds the closest loaded sample and tunes it to the correct frequency.
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
### Main Functions
|
|
45
47
|
|
|
46
|
-
|
|
47
|
-
miniKeys.playNote(60, 100);
|
|
48
|
-
```
|
|
48
|
+
#### loadNotes
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
`loadNotes` takes an array of Samples objects, where _note_ is the name of the note and _velocity_ is if the sample is a soft (piano) or hard (forte) sample.
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
```
|
|
53
|
+
{
|
|
54
|
+
note: NoteName; // 'A4', 'C#3' etc.
|
|
55
|
+
url: string;
|
|
56
|
+
velocity: Velocity; // 'piano' or 'forte'
|
|
57
|
+
}[]
|
|
58
|
+
```
|
|
53
59
|
|
|
54
|
-
|
|
60
|
+
`loadNotes` returns a Promise that resolves when all notes are loaded or if there is an error. You can provide `loadNotes` with a callback function to handle progress updates.
|
|
55
61
|
|
|
56
|
-
|
|
57
|
-
miniKeys.shift(-1, miniKeys.OCTAVE);
|
|
58
|
-
```
|
|
62
|
+
#### playNoteFromMidi
|
|
59
63
|
|
|
60
|
-
|
|
64
|
+
`playNoteFromMidi` takes a midi note (0-127), and a velocity value (0-127). The sample closest to the midi value is chosen, and is pitch shifted to play the correct note. The volume and correct dynamic (_piano_ or _forte_) is chosen based on the velocity.
|
|
61
65
|
|
|
62
|
-
|
|
66
|
+
#### playNoteFromName
|
|
63
67
|
|
|
64
|
-
|
|
65
|
-
miniKeys.volume(0.5);
|
|
66
|
-
```
|
|
68
|
+
This does the same as `playNoteFromMidi`, but with note names (_A3_, _C#4_ etc.)
|
|
67
69
|
|
|
68
|
-
|
|
70
|
+
#### setSustain
|
|
69
71
|
|
|
70
|
-
|
|
72
|
+
This function takes a boolean value and behaves the same as a sustain pedal on a piano. If it sustain is set to true notes are held (including already played notes), if sustain is set to false notes are faded out (including already played notes)
|
|
71
73
|
|
|
72
|
-
|
|
73
|
-
npm install
|
|
74
|
-
npm run build
|
|
75
|
-
```
|
|
74
|
+
### Keyboard Functions
|
|
76
75
|
|
|
77
|
-
|
|
76
|
+
Various functions are provided for interacting with MiniKeys through the keyboard. Full documentation is coming soon!
|
|
78
77
|
|
|
79
|
-
|
|
78
|
+
## Finding Samples
|
|
80
79
|
|
|
81
|
-
|
|
82
|
-
npm test
|
|
83
|
-
```
|
|
80
|
+
[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/packs/kristiansand-concert-steinway/). Thank you to [Pete Malkin](https://www.petemalkin.co.uk/) for sampling this lovely instrument!
|
|
84
81
|
|
|
85
82
|
## TODO
|
|
86
83
|
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
-
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
- [ ] cover all functions with tests
|
|
93
|
-
- [x] write build guide for readme
|
|
94
|
-
- [x] add method for adding loading bar
|
|
95
|
-
- [x] add animations to page
|
|
96
|
-
- [ ] fix on iOS
|
|
97
|
-
- [ ] add midi parser and player
|
|
98
|
-
- [ ] add tuning mode (perfect atm, out of tune with actual piano)
|
|
99
|
-
- [ ] move keyboard with mouse in example
|
|
84
|
+
- Function to play multiple notes
|
|
85
|
+
- Add more tests
|
|
86
|
+
- Look into replacing compressor
|
|
87
|
+
- New package for chords? @minikeys/chords?
|
|
88
|
+
- Custom labels for piano (for showing keyboard keys)
|
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});
|
package/dist/index.d.cts
ADDED
|
@@ -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.d.ts
ADDED
|
@@ -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
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "A javascript library that plays the piano",
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
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
|
-
"
|
|
11
|
-
"
|
|
12
|
-
|
|
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
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
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
|
-
"
|
|
24
|
-
"
|
|
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
|
}
|