minikeys 0.2.0 → 0.3.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 +69 -20
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4,36 +4,85 @@
|
|
|
4
4
|
|
|
5
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://www.npmjs.com/package/@minikeys/react)
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
- Add instructions for npm
|
|
11
|
-
- Add link to CDN
|
|
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" />
|
|
12
10
|
|
|
13
|
-
##
|
|
11
|
+
## Install
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
```
|
|
14
|
+
$ yarn add minikeys
|
|
15
|
+
# OR
|
|
16
|
+
$ npm install minikeys
|
|
17
|
+
```
|
|
16
18
|
|
|
17
|
-
##
|
|
19
|
+
## Using MiniKeys
|
|
20
|
+
|
|
21
|
+
### Basic Setup
|
|
22
|
+
|
|
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.)
|
|
24
|
+
|
|
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')
|
|
42
|
+
```
|
|
43
|
+
|
|
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.
|
|
45
|
+
|
|
46
|
+
### Main Functions
|
|
47
|
+
|
|
48
|
+
#### loadNotes
|
|
49
|
+
|
|
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
|
+
|
|
52
|
+
```
|
|
53
|
+
{
|
|
54
|
+
note: NoteName; // 'A4', 'C#3' etc.
|
|
55
|
+
url: string;
|
|
56
|
+
velocity: Velocity; // 'piano' or 'forte'
|
|
57
|
+
}[]
|
|
58
|
+
```
|
|
18
59
|
|
|
19
|
-
|
|
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.
|
|
20
61
|
|
|
21
|
-
|
|
62
|
+
#### playNoteFromMidi
|
|
22
63
|
|
|
23
|
-
-
|
|
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.
|
|
65
|
+
|
|
66
|
+
#### playNoteFromName
|
|
67
|
+
|
|
68
|
+
This does the same as `playNoteFromMidi`, but with note names (_A3_, _C#4_ etc.)
|
|
69
|
+
|
|
70
|
+
#### setSustain
|
|
71
|
+
|
|
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)
|
|
73
|
+
|
|
74
|
+
### Keyboard Functions
|
|
75
|
+
|
|
76
|
+
Various functions are provided for interacting with MiniKeys through the keyboard. Full documentation is coming soon!
|
|
77
|
+
|
|
78
|
+
## Finding Samples
|
|
79
|
+
|
|
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!
|
|
24
81
|
|
|
25
82
|
## TODO
|
|
26
83
|
|
|
27
84
|
- Function to play multiple notes
|
|
28
|
-
- Add tests
|
|
85
|
+
- Add more tests
|
|
29
86
|
- Look into replacing compressor
|
|
30
87
|
- 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.
|
|
88
|
+
- Custom labels for piano (for showing keyboard keys)
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var c=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var D=Object.prototype.hasOwnProperty;var b=(s,e)=>{for(var t in e)c(s,t,{get:e[t],enumerable:!0})},F=(s,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of g(e))!D.call(s,o)&&o!==t&&c(s,o,{get:()=>e[o],enumerable:!(i=C(e,o))||i.enumerable});return s};var w=s=>F(c({},"__esModule",{value:!0}),s);var G={};b(G,{MiniKeys:()=>m,MiniKeysKeyboard:()=>M,keyboardBlackNotes:()=>h,keyboardWhiteNotes:()=>p,midiToNote:()=>d,noteToMidi:()=>n});module.exports=w(G);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(([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"],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"]],A=(s,e,t,i)=>{let o;if(i&&i<64&&e.size>0)o=e;else if(s.size>0)o=s;else throw new Error("No notes loaded");let a=Array.from(o.keys()).reduce((l,r)=>Math.abs(r-t)<Math.abs(l-t)?r:l);return{closestNoteMidi:a,closestNote:o.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=e=>{this.sustain=e,e?this.playingNotes.forEach(t=>{let i=this.audioContext.currentTime;t.node.gain.cancelScheduledValues(i),t.node.gain.setValueAtTime(t.node.gain.value,i)}):this.playingNotes.forEach(t=>{let i=this.audioContext.currentTime;t.node.gain.cancelScheduledValues(i),t.node.gain.setValueAtTime(t.node.gain.value,i),t.node.gain.linearRampToValueAtTime(.001,i+.5)})};loadNotes=async(e,t)=>{this.forteNotes.clear(),this.pianoNotes.clear();let i=e.map(async o=>{let l=await(await fetch(o.url)).arrayBuffer(),r=await this.audioContext.decodeAudioData(l);if(o.velocity==="piano"?this.pianoNotes.set(n[o.note],r):this.forteNotes.set(n[o.note],r),t){let u=(this.pianoNotes.size+this.forteNotes.size)/e.length;u>this.progress&&(this.progress=u,t(this.progress))}});return await Promise.all(i)};playNoteFromMidi=(e,t)=>{if(e<0||e>127)throw new Error("Invalid midi note");if(t&&(t<0||t>127))throw new Error("Invalid velocity value");if(!this.audioContext)throw new Error("Audio context not initialized");let o=this.audioContext.createBufferSource(),{closestNoteMidi:a,closestNote:l}=A(this.forteNotes,this.pianoNotes,e,t);if(l){o.buffer=l;let r=this.audioContext.createGain(),u=Math.min(127,t??127);r.gain.value=(u/127*.9+.1)*.5,o.connect(r),r.connect(this.compressorNode),o.playbackRate.value=2**((e-a)/12),o.start(),this.playingNotes.set(o,{node:r,note:e}),o.onended=()=>{o.disconnect(),this.playingNotes.delete(o)}}else throw new Error("Note not found")};playNoteFromName=(e,t)=>{this.playNoteFromMidi(n[e],t)};liftNoteFromMidi=e=>{this.playingNotes.forEach(t=>{if(t.note===e&&!this.sustain){let i=this.audioContext.currentTime;t.node.gain.cancelScheduledValues(i),t.node.gain.setValueAtTime(t.node.gain.value,i),t.node.gain.exponentialRampToValueAtTime(Number.EPSILON,i+8)}})};liftNoteFromName=(e,t)=>{this.liftNoteFromMidi(n[e])}};var M=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,o)=>o.midiNote&&o.midiNote<i?o.midiNote:i,127),t=Array.from(this.keyMap.values()).reduce((i,o)=>o.midiNote&&o.midiNote>i?o.midiNote:i,0);return{low:e,high:t}};getNoteRange=()=>{let e=this.getMidiRange();return{low:d[e.low],high:d[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"?(y(this.keyMap,1,this.offset),N(this.keyMap,2,this.offset)):(y(this.keyMap,0,this.offset),N(this.keyMap,1,this.offset),y(this.keyMap,2,this.offset+12),N(this.keyMap,3,this.offset+12))}},y=(s,e,t)=>{f[e].forEach((i,o)=>{let a=h[t+o];if(a===null)s.set(i,{midiNote:null,type:"disabled"});else if(a!==void 0)s.set(i,{midiNote:n[a],type:"black"});else throw new Error("Invalid note")})},N=(s,e,t)=>{f[e].forEach((i,o)=>{let a=p[t+o];if(a)s.set(i,{midiNote:n[a],type:"white"});else throw new Error("Invalid note")})};0&&(module.exports={MiniKeys,MiniKeysKeyboard,keyboardBlackNotes,keyboardWhiteNotes,midiToNote,noteToMidi});
|
package/dist/index.d.cts
CHANGED
|
@@ -160,6 +160,8 @@ declare class MiniKeys {
|
|
|
160
160
|
loadNotes: (samples: Sample[], handleSampleLoaded?: (progress: number) => void) => Promise<void[]>;
|
|
161
161
|
playNoteFromMidi: (midiNote: number, velocity?: number) => void;
|
|
162
162
|
playNoteFromName: (noteName: NoteName, velocity?: number) => void;
|
|
163
|
+
liftNoteFromMidi: (midiNote: number) => void;
|
|
164
|
+
liftNoteFromName: (noteName: NoteName, velocity?: number) => void;
|
|
163
165
|
}
|
|
164
166
|
|
|
165
167
|
declare class MiniKeysKeyboard {
|
package/dist/index.d.ts
CHANGED
|
@@ -160,6 +160,8 @@ declare class MiniKeys {
|
|
|
160
160
|
loadNotes: (samples: Sample[], handleSampleLoaded?: (progress: number) => void) => Promise<void[]>;
|
|
161
161
|
playNoteFromMidi: (midiNote: number, velocity?: number) => void;
|
|
162
162
|
playNoteFromName: (noteName: NoteName, velocity?: number) => void;
|
|
163
|
+
liftNoteFromMidi: (midiNote: number) => void;
|
|
164
|
+
liftNoteFromName: (noteName: NoteName, velocity?: number) => void;
|
|
163
165
|
}
|
|
164
166
|
|
|
165
167
|
declare class MiniKeysKeyboard {
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var r={"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(r).map(([a,t])=>[t,a])),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"],c=[["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"]],y=(a,t,e,i)=>{let o;if(i&&i<64&&t.size>0)o=t;else if(a.size>0)o=a;else throw new Error("No notes loaded");let s=Array.from(o.keys()).reduce((l,n)=>Math.abs(n-e)<Math.abs(l-e)?n:l);return{closestNoteMidi:s,closestNote:o.get(s)}};var N=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(e=>{let i=this.audioContext.currentTime;e.node.gain.cancelScheduledValues(i),e.node.gain.setValueAtTime(e.node.gain.value,i)}):this.playingNotes.forEach(e=>{let i=this.audioContext.currentTime;e.node.gain.cancelScheduledValues(i),e.node.gain.setValueAtTime(e.node.gain.value,i),e.node.gain.linearRampToValueAtTime(.001,i+.5)})};loadNotes=async(t,e)=>{this.forteNotes.clear(),this.pianoNotes.clear();let i=t.map(async o=>{let l=await(await fetch(o.url)).arrayBuffer(),n=await this.audioContext.decodeAudioData(l);if(o.velocity==="piano"?this.pianoNotes.set(r[o.note],n):this.forteNotes.set(r[o.note],n),e){let d=(this.pianoNotes.size+this.forteNotes.size)/t.length;d>this.progress&&(this.progress=d,e(this.progress))}});return await Promise.all(i)};playNoteFromMidi=(t,e)=>{if(t<0||t>127)throw new Error("Invalid midi note");if(e&&(e<0||e>127))throw new Error("Invalid velocity value");if(!this.audioContext)throw new Error("Audio context not initialized");let o=this.audioContext.createBufferSource(),{closestNoteMidi:s,closestNote:l}=y(this.forteNotes,this.pianoNotes,t,e);if(l){o.buffer=l;let n=this.audioContext.createGain(),d=Math.min(127,e??127);n.gain.value=(d/127*.9+.1)*.5,o.connect(n),n.connect(this.compressorNode),o.playbackRate.value=2**((t-s)/12),o.start(),this.playingNotes.set(o,{node:n,note:t}),o.onended=()=>{o.disconnect(),this.playingNotes.delete(o)}}else throw new Error("Note not found")};playNoteFromName=(t,e)=>{this.playNoteFromMidi(r[t],e)};liftNoteFromMidi=t=>{this.playingNotes.forEach(e=>{if(e.note===t&&!this.sustain){let i=this.audioContext.currentTime;e.node.gain.cancelScheduledValues(i),e.node.gain.setValueAtTime(e.node.gain.value,i),e.node.gain.exponentialRampToValueAtTime(Number.EPSILON,i+8)}})};liftNoteFromName=(t,e)=>{this.liftNoteFromMidi(r[t])}};var M=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,o)=>o.midiNote&&o.midiNote<i?o.midiNote:i,127),e=Array.from(this.keyMap.values()).reduce((i,o)=>o.midiNote&&o.midiNote>i?o.midiNote:i,0);return{low:t,high:e}};getNoteRange=()=>{let t=this.getMidiRange();return{low:u[t.low],high:u[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"?(f(this.keyMap,1,this.offset),m(this.keyMap,2,this.offset)):(f(this.keyMap,0,this.offset),m(this.keyMap,1,this.offset),f(this.keyMap,2,this.offset+12),m(this.keyMap,3,this.offset+12))}},f=(a,t,e)=>{c[t].forEach((i,o)=>{let s=h[e+o];if(s===null)a.set(i,{midiNote:null,type:"disabled"});else if(s!==void 0)a.set(i,{midiNote:r[s],type:"black"});else throw new Error("Invalid note")})},m=(a,t,e)=>{c[t].forEach((i,o)=>{let s=p[e+o];if(s)a.set(i,{midiNote:r[s],type:"white"});else throw new Error("Invalid note")})};export{N as MiniKeys,M as MiniKeysKeyboard,h as keyboardBlackNotes,p as keyboardWhiteNotes,u as midiToNote,r as noteToMidi};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "minikeys",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "A javascript library that plays the piano",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"minikeys",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"vitest": "^3.0.5"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
|
-
"build": "tsup",
|
|
40
|
+
"build": "tsup src/index.ts --out-dir dist",
|
|
41
41
|
"ci": "npm run build && npm run check-format && npm run lint && npm run test",
|
|
42
42
|
"lint": "tsc",
|
|
43
43
|
"test": "vitest run",
|