@marmooo/midi-player 0.0.1 → 0.0.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 marmooo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,127 @@
1
+ # @marmooo/midi-player
2
+
3
+ `<midi-player>` HTML elements powered by
4
+ [Midy](https://github.com/marmooo/midy).
5
+
6
+ ## Demo
7
+
8
+ - [Basic usage](https://marmooo.github.io/midi-player/)
9
+
10
+ ## Usage
11
+
12
+ 1. Import icon font.
13
+
14
+ ```
15
+ @font-face {
16
+ font-family: "MIDIPlayerIcons";
17
+ src: url("midi-player-icons.woff2") format("woff2");
18
+ }
19
+ .midi-player-btn {
20
+ font-family: MIDIPlayerIcons;
21
+ font-size: 24px;
22
+ line-height: 1;
23
+ }
24
+ ```
25
+
26
+ 2. Import the appropriate level of Midy.
27
+
28
+ ```
29
+ // import { MidyGMLite as Midy } from "midy/dist/midy-GMLite.min.js";
30
+ // import { MidyGM1 as Midy } from "midy/dist/midy-GM1.min.js";
31
+ // import { MidyGM2 as Midy } from "midy/dist/midy-GM2.min.js";
32
+ import { Midy } from "midy/dist/midy.min.js";
33
+
34
+ const midy = new Midy(new AudioContext());
35
+ await midy.audioContext.suspend();
36
+ ```
37
+
38
+ 3. Add Player.
39
+
40
+ ```
41
+ import { MIDIPlayer } from "@marmooo/midi-player";
42
+
43
+ const midiPlayer = new MIDIPlayer(midy);
44
+ midiPlayer.defaultLayout();
45
+ document.getElementById("root").appendChild(midiPlayer.root);
46
+ await midiPlayer.midy.loadMIDI("test.mid");
47
+ ```
48
+
49
+ ## Configuration
50
+
51
+ ### SoundFont
52
+
53
+ This library supports SF2 and SF3. In addition, it supports multiple soundfonts
54
+ and [splitted soundfonts](https://github.com/marmooo/free-soundfonts) that are
55
+ optimized for playback on the web. it will automatically use splitted
56
+ [GeneralUser GS](https://www.schristiancollins.com/generaluser) for playback,
57
+ but you can also set it as follows.
58
+
59
+ ```
60
+ const midiPlayer = new MIDIPlayer(midy);
61
+ midiPlayer.soundFontURL = "https://soundfonts.pages.dev/SGM-V2.01";
62
+ ```
63
+
64
+ ```
65
+ const midiPlayer = new MIDIPlayer(midy);
66
+ await midiPlayer.midy.loadSoundFont("test.sf3")
67
+ ```
68
+
69
+ ### Layout
70
+
71
+ All parts can freely change their layout by not using `defaultLayout()`.
72
+
73
+ ```
74
+ const midiPlayer = new MIDIPlayer(midy);
75
+ const div = midiPlayer.row();
76
+ div.appendChild(midiPlayer.playPauseResume());
77
+ div.appendChild(midiPlayer.seekBar());
78
+ ```
79
+
80
+ ### Theme
81
+
82
+ All parts have midi-player-* class so you can be themed with CSS.
83
+
84
+ - Basic classes
85
+ - `midi-player-row`
86
+ - `midi-player-btn`
87
+ - `midi-player-range`
88
+ - `midi-player-text`
89
+ - Part classes
90
+ - `midi-player-play`
91
+ - `midi-player-pause`
92
+ - `midi-player-resume`
93
+ - `midi-player-stop`
94
+ - `midi-player-currTime`
95
+ - `midi-player-timeSeparator`
96
+ - `midi-player-totalTime`
97
+ - `midi-player-seekBar`
98
+ - `midi-player-volumeOn`
99
+ - `midi-player-volumeff`
100
+ - `midi-player-volumeBar`
101
+
102
+ You can also style the parts using JavaScript and CSS Framework.
103
+
104
+ ```
105
+ const midiPlayer = new MIDIPlayer(midy);
106
+ for (const btn of root.getElementsByClassName("midi-player-btn")) {
107
+ btn.classList.add("btn", "btn-light-subtle", "p-1");
108
+ }
109
+ ```
110
+
111
+ ### Icon font
112
+
113
+ We use [Material Icons](https://github.com/marella/material-icons) licensed
114
+ under the
115
+ [Apache-2.0](https://github.com/marella/material-icons/blob/main/LICENSE).
116
+ Search for the ligature names you want to use from the
117
+ [official web app](https://marella.me/material-icons/demo/), save them, and
118
+ minimize them using [fontconv](https://github.com/marmooo/fontconv).
119
+
120
+ ```
121
+ fontconv --ligature play_arrow,pause,stop,volume_down,volume_off \
122
+ material-icons.woff2 src/midi-player-icons.woff2
123
+ ```
124
+
125
+ ## License
126
+
127
+ MIT
@@ -1,6 +1,6 @@
1
1
  export class MIDIPlayer {
2
2
  constructor(midy: any);
3
- soundFontDir: string;
3
+ soundFontURL: string;
4
4
  midy: any;
5
5
  timer: any;
6
6
  currentTime: number;
@@ -22,8 +22,13 @@ export class MIDIPlayer {
22
22
  startTimer(): void;
23
23
  loadMIDI(file: any): Promise<void>;
24
24
  setSoundFontDir(dir: any): void;
25
+ getSoundFontPaths(): string[];
25
26
  start(): Promise<void>;
27
+ handleStop(): Promise<void>;
26
28
  stop(): any;
29
+ handlePlay(): Promise<void>;
30
+ handlePause(): void;
31
+ handleResume(): Promise<void>;
27
32
  playPauseResume(): any;
28
33
  volumeText(): any;
29
34
  volume(): any;
@@ -1 +1 @@
1
- {"version":3,"file":"midi-player.d.ts","sourceRoot":"","sources":["../src/midi-player.js"],"names":[],"mappings":"AAAA;IAcE,uBAGC;IAhBD,qBAAoE;IACpE,UAAK;IACL,WAAM;IACN,oBAAgB;IAChB,yBAAuB;IACvB,kBAAa;IACb,mBAAc;IACd,iBAAY;IACZ,cAAS;IACT,eAAU;IACV,gBAAW;IACX,cAAS;IAIP,UAAiD;IAGnD,sBAMC;IAED,WAOC;IAED,iCASC;IAED,qEASC;IAED,qEAOC;IAED,qCAKC;IAED,mBAYC;IAED,mCAKC;IAED,gCAEC;IAED,uBAoBC;IAED,YAYC;IAED,uBA2CC;IAED,kBAEC;IAED,cA8BC;IAED,eAgBC;IAED,gBAIC;IAED,iBAIC;IAED,yBAWC;CACF"}
1
+ {"version":3,"file":"midi-player.d.ts","sourceRoot":"","sources":["../src/midi-player.js"],"names":[],"mappings":"AAAA;IAcE,uBAGC;IAhBD,qBAAoE;IACpE,UAAK;IACL,WAAM;IACN,oBAAgB;IAChB,yBAAuB;IACvB,kBAAa;IACb,mBAAc;IACd,iBAAY;IACZ,cAAS;IACT,eAAU;IACV,gBAAW;IACX,cAAS;IAIP,UAAiD;IAGnD,sBAMC;IAED,WAOC;IAED,iCASC;IAED,qEASC;IAED,qEAOC;IAED,qCAKC;IAED,mBAYC;IAED,mCAKC;IAED,gCAEC;IAED,8BAcC;IAED,uBAaC;IAED,4BAQC;IAED,YAKC;IAED,4BAUC;IAED,oBAOC;IAED,8BAYC;IAED,uBA2BC;IAED,kBAEC;IAED,cAwCC;IAED,eAgBC;IAED,gBAIC;IAED,iBAIC;IAED,yBAWC;CACF"}
@@ -1,6 +1,6 @@
1
1
  export class MIDIPlayer {
2
2
  constructor(midy) {
3
- Object.defineProperty(this, "soundFontDir", {
3
+ Object.defineProperty(this, "soundFontURL", {
4
4
  enumerable: true,
5
5
  configurable: true,
6
6
  writable: true,
@@ -144,111 +144,126 @@ export class MIDIPlayer {
144
144
  }
145
145
  }
146
146
  setSoundFontDir(dir) {
147
- this.soundFontDir = dir;
147
+ this.soundFontURL = dir;
148
+ }
149
+ getSoundFontPaths() {
150
+ const paths = [];
151
+ const { midy, soundFontURL } = this;
152
+ for (const instrument of midy.instruments) {
153
+ const [bankNumber, programNumber] = instrument.split(":").map(Number);
154
+ const table = midy.soundFontTable[programNumber];
155
+ if (table.has(bankNumber))
156
+ continue;
157
+ const program = programNumber.toString().padStart(3, "0");
158
+ const path = bankNumber === 128
159
+ ? `${soundFontURL}/128.sf3`
160
+ : `${soundFontURL}/${program}.sf3`;
161
+ paths.push(path);
162
+ }
163
+ return paths;
148
164
  }
149
165
  async start() {
150
- if (this.midy.soundFonts.length === 0) {
151
- for (const instrument of this.midy.instruments) {
152
- const [bankNumber, programNumber] = instrument.split(":").map(Number);
153
- if (this.midy.soundFontTable[programNumber].has(bankNumber))
154
- continue;
155
- const program = programNumber.toString().padStart(3, "0");
156
- if (bankNumber === 128) {
157
- await this.midy.loadSoundFont(`${this.soundFontDir}/128.sf3`);
158
- }
159
- else {
160
- await this.midy.loadSoundFont(`${this.soundFontDir}/${program}.sf3`);
161
- }
162
- }
166
+ const midy = this.midy;
167
+ if (midy.soundFonts.length === 0) {
168
+ const paths = this.getSoundFontPaths();
169
+ await midy.loadSoundFont(paths);
163
170
  }
164
171
  this.startTimer();
165
- await this.midy.start();
172
+ await midy.start();
166
173
  clearInterval(this.timer);
167
- if (!this.midy.isPaused && this.currTimeNode) {
174
+ if (!midy.isPaused && this.currTimeNode) {
168
175
  this.currTimeNode.textContent = "0:00";
169
176
  this.seekBarNode.value = 0;
170
177
  }
171
178
  }
179
+ async handleStop() {
180
+ const midy = this.midy;
181
+ if (!midy.isPlaying)
182
+ return;
183
+ clearInterval(this.timer);
184
+ this.playNode.style.display = "initial";
185
+ this.pauseNode.style.display = "none";
186
+ this.resumeNode.style.display = "none";
187
+ await midy.stop();
188
+ }
172
189
  stop() {
173
- const stop = this.button("start", "start", "stop", "initial");
174
- stop.onclick = () => {
175
- if (!this.midy.isPlaying)
176
- return;
177
- clearInterval(this.timer);
178
- this.playNode.style.display = "initial";
179
- this.pauseNode.style.display = "none";
180
- this.resumeNode.style.display = "none";
181
- this.midy.stop();
182
- };
190
+ const stop = this.button("start", "midi-player-start", "stop", "initial");
191
+ stop.onclick = () => this.handleStop();
183
192
  this.stopNode = stop;
184
193
  return stop;
185
194
  }
195
+ async handlePlay() {
196
+ const { midy, playNode, pauseNode } = this;
197
+ if (midy.isPlaying || midy.isPaused)
198
+ return;
199
+ playNode.style.display = "none";
200
+ pauseNode.style.display = "initial";
201
+ await this.start();
202
+ if (!midy.isPaused) {
203
+ pauseNode.style.display = "none";
204
+ playNode.style.display = "initial";
205
+ }
206
+ }
207
+ handlePause() {
208
+ const midy = this.midy;
209
+ if (!midy.isPlaying || midy.isPaused)
210
+ return;
211
+ this.pauseNode.style.display = "none";
212
+ this.resumeNode.style.display = "initial";
213
+ clearInterval(this.timer);
214
+ midy.pause();
215
+ }
216
+ async handleResume() {
217
+ const { midy, playNode, pauseNode, resumeNode } = this;
218
+ if (!midy.isPaused)
219
+ return;
220
+ pauseNode.style.display = "initial";
221
+ resumeNode.style.display = "none";
222
+ this.startTimer();
223
+ await midy.resume();
224
+ clearInterval(this.timer);
225
+ if (!midy.isPaused) {
226
+ pauseNode.style.display = "none";
227
+ playNode.style.display = "initial";
228
+ }
229
+ }
186
230
  playPauseResume() {
187
- const play = this.button("start", "start", "play_arrow", "initial");
188
- const pause = this.button("pause", "pause", "pause", "none");
189
- const resume = this.button("resume", "resume", "play_arrow", "none");
190
- play.onclick = async () => {
191
- if (this.midy.isPlaying || this.midy.isPaused)
192
- return;
193
- play.style.display = "none";
194
- pause.style.display = "initial";
195
- await this.start();
196
- if (!this.midy.isPaused) {
197
- pause.style.display = "none";
198
- play.style.display = "initial";
199
- }
200
- };
201
- pause.onclick = () => {
202
- if (!this.midy.isPlaying || this.midy.isPaused)
203
- return;
204
- pause.style.display = "none";
205
- resume.style.display = "initial";
206
- clearInterval(this.timer);
207
- this.midy.pause();
208
- };
209
- resume.onclick = async () => {
210
- if (!this.midy.isPaused)
211
- return;
212
- pause.style.display = "initial";
213
- resume.style.display = "none";
214
- this.startTimer();
215
- await this.midy.resume();
216
- clearInterval(this.timer);
217
- if (!this.midy.isPaused) {
218
- pause.style.display = "none";
219
- play.style.display = "initial";
220
- }
221
- };
231
+ const play = this.button("start", "midi-player-start", "play_arrow", "initial");
232
+ const pause = this.button("pause", "midi-player-pause", "pause", "none");
233
+ const resume = this.button("resume", "midi-player-resume", "play_arrow", "none");
234
+ this.playNode = play;
235
+ this.pauseNode = pause;
236
+ this.resumeNode = resume;
237
+ play.onclick = () => this.handlePlay();
238
+ pause.onclick = () => this.handlePause();
239
+ resume.onclick = () => this.handleResume();
222
240
  const div = document.createElement("div");
223
241
  div.style.display = "flex";
224
242
  div.style.alignItems = "center";
225
243
  div.appendChild(play);
226
244
  div.appendChild(pause);
227
245
  div.appendChild(resume);
228
- this.playNode = play;
229
- this.pauseNode = pause;
230
- this.resumeNode = resume;
231
246
  return div;
232
247
  }
233
248
  volumeText() {
234
- return this.text("volume", "volumeText");
249
+ return this.text("volume", "midi-player-volumeText");
235
250
  }
236
251
  volume() {
237
- const muteOn = this.button("mute ON", "muteOn", "volume_down", "initial");
238
- const muteOff = this.button("mute OFF", "muteOff", "volume_off", "none");
239
- const volumeBar = this.formRange("volume", "volume", 1, "none");
252
+ const muteOn = this.button("mute ON", "midi-player-muteOn", "volume_down", "initial");
253
+ const muteOff = this.button("mute OFF", "midi-player-muteOff", "volume_off", "none");
254
+ const volumeBar = this.formRange("volume", "midi-player-volume", 1, "none");
240
255
  muteOn.onclick = () => {
241
256
  muteOn.style.display = "none";
242
257
  muteOff.style.display = "initial";
243
- this.midy.handleMasterVolume(0);
258
+ this.midy.setMasterVolume(0);
244
259
  };
245
260
  muteOff.onclick = () => {
246
261
  muteOn.style.display = "initial";
247
262
  muteOff.style.display = "none";
248
- this.midy.handleMasterVolume(1);
263
+ this.midy.setMasterVolume(1);
249
264
  };
250
265
  volumeBar.oninput = (event) => {
251
- this.midy.handleMasterVolume(event.target.value);
266
+ this.midy.setMasterVolume(event.target.value);
252
267
  };
253
268
  const div = document.createElement("div");
254
269
  div.style.display = "flex";
@@ -265,7 +280,7 @@ export class MIDIPlayer {
265
280
  return div;
266
281
  }
267
282
  seekBar() {
268
- const seekBar = this.formRange("playback position", "seekBar", 0, "initial");
283
+ const seekBar = this.formRange("playback position", "midi-player-seekBar", 0, "initial");
269
284
  seekBar.oninput = (event) => {
270
285
  const time = event.target.value * this.midy.totalTime;
271
286
  this.midy.seekTo(time);
@@ -277,18 +292,18 @@ export class MIDIPlayer {
277
292
  return seekBar;
278
293
  }
279
294
  currTime() {
280
- const currTime = this.text("0:00", "currTime");
295
+ const currTime = this.text("0:00", "midi-player-currTime");
281
296
  this.currTimeNode = currTime;
282
297
  return currTime;
283
298
  }
284
299
  totalTime() {
285
- const totalTime = this.text("0:00", "totalTime");
300
+ const totalTime = this.text("0:00", "midi-player-totalTime");
286
301
  this.totalTimeNode = totalTime;
287
302
  return totalTime;
288
303
  }
289
304
  currTimeTotalTime() {
290
305
  const currTime = this.currTime();
291
- const separator = this.text("/", "timeSeparator");
306
+ const separator = this.text("/", "midi-player-timeSeparator");
292
307
  const totalTime = this.totalTime();
293
308
  const div = document.createElement("div");
294
309
  div.style.display = "flex";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marmooo/midi-player",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "<midi-player> HTML elements powered by Midy.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,6 +1,6 @@
1
1
  export class MIDIPlayer {
2
2
  constructor(midy: any);
3
- soundFontDir: string;
3
+ soundFontURL: string;
4
4
  midy: any;
5
5
  timer: any;
6
6
  currentTime: number;
@@ -22,8 +22,13 @@ export class MIDIPlayer {
22
22
  startTimer(): void;
23
23
  loadMIDI(file: any): Promise<void>;
24
24
  setSoundFontDir(dir: any): void;
25
+ getSoundFontPaths(): string[];
25
26
  start(): Promise<void>;
27
+ handleStop(): Promise<void>;
26
28
  stop(): any;
29
+ handlePlay(): Promise<void>;
30
+ handlePause(): void;
31
+ handleResume(): Promise<void>;
27
32
  playPauseResume(): any;
28
33
  volumeText(): any;
29
34
  volume(): any;
@@ -1 +1 @@
1
- {"version":3,"file":"midi-player.d.ts","sourceRoot":"","sources":["../src/midi-player.js"],"names":[],"mappings":"AAAA;IAcE,uBAGC;IAhBD,qBAAoE;IACpE,UAAK;IACL,WAAM;IACN,oBAAgB;IAChB,yBAAuB;IACvB,kBAAa;IACb,mBAAc;IACd,iBAAY;IACZ,cAAS;IACT,eAAU;IACV,gBAAW;IACX,cAAS;IAIP,UAAiD;IAGnD,sBAMC;IAED,WAOC;IAED,iCASC;IAED,qEASC;IAED,qEAOC;IAED,qCAKC;IAED,mBAYC;IAED,mCAKC;IAED,gCAEC;IAED,uBAoBC;IAED,YAYC;IAED,uBA2CC;IAED,kBAEC;IAED,cA8BC;IAED,eAgBC;IAED,gBAIC;IAED,iBAIC;IAED,yBAWC;CACF"}
1
+ {"version":3,"file":"midi-player.d.ts","sourceRoot":"","sources":["../src/midi-player.js"],"names":[],"mappings":"AAAA;IAcE,uBAGC;IAhBD,qBAAoE;IACpE,UAAK;IACL,WAAM;IACN,oBAAgB;IAChB,yBAAuB;IACvB,kBAAa;IACb,mBAAc;IACd,iBAAY;IACZ,cAAS;IACT,eAAU;IACV,gBAAW;IACX,cAAS;IAIP,UAAiD;IAGnD,sBAMC;IAED,WAOC;IAED,iCASC;IAED,qEASC;IAED,qEAOC;IAED,qCAKC;IAED,mBAYC;IAED,mCAKC;IAED,gCAEC;IAED,8BAcC;IAED,uBAaC;IAED,4BAQC;IAED,YAKC;IAED,4BAUC;IAED,oBAOC;IAED,8BAYC;IAED,uBA2BC;IAED,kBAEC;IAED,cAwCC;IAED,eAgBC;IAED,gBAIC;IAED,iBAIC;IAED,yBAWC;CACF"}
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MIDIPlayer = void 0;
4
4
  class MIDIPlayer {
5
5
  constructor(midy) {
6
- Object.defineProperty(this, "soundFontDir", {
6
+ Object.defineProperty(this, "soundFontURL", {
7
7
  enumerable: true,
8
8
  configurable: true,
9
9
  writable: true,
@@ -147,111 +147,126 @@ class MIDIPlayer {
147
147
  }
148
148
  }
149
149
  setSoundFontDir(dir) {
150
- this.soundFontDir = dir;
150
+ this.soundFontURL = dir;
151
+ }
152
+ getSoundFontPaths() {
153
+ const paths = [];
154
+ const { midy, soundFontURL } = this;
155
+ for (const instrument of midy.instruments) {
156
+ const [bankNumber, programNumber] = instrument.split(":").map(Number);
157
+ const table = midy.soundFontTable[programNumber];
158
+ if (table.has(bankNumber))
159
+ continue;
160
+ const program = programNumber.toString().padStart(3, "0");
161
+ const path = bankNumber === 128
162
+ ? `${soundFontURL}/128.sf3`
163
+ : `${soundFontURL}/${program}.sf3`;
164
+ paths.push(path);
165
+ }
166
+ return paths;
151
167
  }
152
168
  async start() {
153
- if (this.midy.soundFonts.length === 0) {
154
- for (const instrument of this.midy.instruments) {
155
- const [bankNumber, programNumber] = instrument.split(":").map(Number);
156
- if (this.midy.soundFontTable[programNumber].has(bankNumber))
157
- continue;
158
- const program = programNumber.toString().padStart(3, "0");
159
- if (bankNumber === 128) {
160
- await this.midy.loadSoundFont(`${this.soundFontDir}/128.sf3`);
161
- }
162
- else {
163
- await this.midy.loadSoundFont(`${this.soundFontDir}/${program}.sf3`);
164
- }
165
- }
169
+ const midy = this.midy;
170
+ if (midy.soundFonts.length === 0) {
171
+ const paths = this.getSoundFontPaths();
172
+ await midy.loadSoundFont(paths);
166
173
  }
167
174
  this.startTimer();
168
- await this.midy.start();
175
+ await midy.start();
169
176
  clearInterval(this.timer);
170
- if (!this.midy.isPaused && this.currTimeNode) {
177
+ if (!midy.isPaused && this.currTimeNode) {
171
178
  this.currTimeNode.textContent = "0:00";
172
179
  this.seekBarNode.value = 0;
173
180
  }
174
181
  }
182
+ async handleStop() {
183
+ const midy = this.midy;
184
+ if (!midy.isPlaying)
185
+ return;
186
+ clearInterval(this.timer);
187
+ this.playNode.style.display = "initial";
188
+ this.pauseNode.style.display = "none";
189
+ this.resumeNode.style.display = "none";
190
+ await midy.stop();
191
+ }
175
192
  stop() {
176
- const stop = this.button("start", "start", "stop", "initial");
177
- stop.onclick = () => {
178
- if (!this.midy.isPlaying)
179
- return;
180
- clearInterval(this.timer);
181
- this.playNode.style.display = "initial";
182
- this.pauseNode.style.display = "none";
183
- this.resumeNode.style.display = "none";
184
- this.midy.stop();
185
- };
193
+ const stop = this.button("start", "midi-player-start", "stop", "initial");
194
+ stop.onclick = () => this.handleStop();
186
195
  this.stopNode = stop;
187
196
  return stop;
188
197
  }
198
+ async handlePlay() {
199
+ const { midy, playNode, pauseNode } = this;
200
+ if (midy.isPlaying || midy.isPaused)
201
+ return;
202
+ playNode.style.display = "none";
203
+ pauseNode.style.display = "initial";
204
+ await this.start();
205
+ if (!midy.isPaused) {
206
+ pauseNode.style.display = "none";
207
+ playNode.style.display = "initial";
208
+ }
209
+ }
210
+ handlePause() {
211
+ const midy = this.midy;
212
+ if (!midy.isPlaying || midy.isPaused)
213
+ return;
214
+ this.pauseNode.style.display = "none";
215
+ this.resumeNode.style.display = "initial";
216
+ clearInterval(this.timer);
217
+ midy.pause();
218
+ }
219
+ async handleResume() {
220
+ const { midy, playNode, pauseNode, resumeNode } = this;
221
+ if (!midy.isPaused)
222
+ return;
223
+ pauseNode.style.display = "initial";
224
+ resumeNode.style.display = "none";
225
+ this.startTimer();
226
+ await midy.resume();
227
+ clearInterval(this.timer);
228
+ if (!midy.isPaused) {
229
+ pauseNode.style.display = "none";
230
+ playNode.style.display = "initial";
231
+ }
232
+ }
189
233
  playPauseResume() {
190
- const play = this.button("start", "start", "play_arrow", "initial");
191
- const pause = this.button("pause", "pause", "pause", "none");
192
- const resume = this.button("resume", "resume", "play_arrow", "none");
193
- play.onclick = async () => {
194
- if (this.midy.isPlaying || this.midy.isPaused)
195
- return;
196
- play.style.display = "none";
197
- pause.style.display = "initial";
198
- await this.start();
199
- if (!this.midy.isPaused) {
200
- pause.style.display = "none";
201
- play.style.display = "initial";
202
- }
203
- };
204
- pause.onclick = () => {
205
- if (!this.midy.isPlaying || this.midy.isPaused)
206
- return;
207
- pause.style.display = "none";
208
- resume.style.display = "initial";
209
- clearInterval(this.timer);
210
- this.midy.pause();
211
- };
212
- resume.onclick = async () => {
213
- if (!this.midy.isPaused)
214
- return;
215
- pause.style.display = "initial";
216
- resume.style.display = "none";
217
- this.startTimer();
218
- await this.midy.resume();
219
- clearInterval(this.timer);
220
- if (!this.midy.isPaused) {
221
- pause.style.display = "none";
222
- play.style.display = "initial";
223
- }
224
- };
234
+ const play = this.button("start", "midi-player-start", "play_arrow", "initial");
235
+ const pause = this.button("pause", "midi-player-pause", "pause", "none");
236
+ const resume = this.button("resume", "midi-player-resume", "play_arrow", "none");
237
+ this.playNode = play;
238
+ this.pauseNode = pause;
239
+ this.resumeNode = resume;
240
+ play.onclick = () => this.handlePlay();
241
+ pause.onclick = () => this.handlePause();
242
+ resume.onclick = () => this.handleResume();
225
243
  const div = document.createElement("div");
226
244
  div.style.display = "flex";
227
245
  div.style.alignItems = "center";
228
246
  div.appendChild(play);
229
247
  div.appendChild(pause);
230
248
  div.appendChild(resume);
231
- this.playNode = play;
232
- this.pauseNode = pause;
233
- this.resumeNode = resume;
234
249
  return div;
235
250
  }
236
251
  volumeText() {
237
- return this.text("volume", "volumeText");
252
+ return this.text("volume", "midi-player-volumeText");
238
253
  }
239
254
  volume() {
240
- const muteOn = this.button("mute ON", "muteOn", "volume_down", "initial");
241
- const muteOff = this.button("mute OFF", "muteOff", "volume_off", "none");
242
- const volumeBar = this.formRange("volume", "volume", 1, "none");
255
+ const muteOn = this.button("mute ON", "midi-player-muteOn", "volume_down", "initial");
256
+ const muteOff = this.button("mute OFF", "midi-player-muteOff", "volume_off", "none");
257
+ const volumeBar = this.formRange("volume", "midi-player-volume", 1, "none");
243
258
  muteOn.onclick = () => {
244
259
  muteOn.style.display = "none";
245
260
  muteOff.style.display = "initial";
246
- this.midy.handleMasterVolume(0);
261
+ this.midy.setMasterVolume(0);
247
262
  };
248
263
  muteOff.onclick = () => {
249
264
  muteOn.style.display = "initial";
250
265
  muteOff.style.display = "none";
251
- this.midy.handleMasterVolume(1);
266
+ this.midy.setMasterVolume(1);
252
267
  };
253
268
  volumeBar.oninput = (event) => {
254
- this.midy.handleMasterVolume(event.target.value);
269
+ this.midy.setMasterVolume(event.target.value);
255
270
  };
256
271
  const div = document.createElement("div");
257
272
  div.style.display = "flex";
@@ -268,7 +283,7 @@ class MIDIPlayer {
268
283
  return div;
269
284
  }
270
285
  seekBar() {
271
- const seekBar = this.formRange("playback position", "seekBar", 0, "initial");
286
+ const seekBar = this.formRange("playback position", "midi-player-seekBar", 0, "initial");
272
287
  seekBar.oninput = (event) => {
273
288
  const time = event.target.value * this.midy.totalTime;
274
289
  this.midy.seekTo(time);
@@ -280,18 +295,18 @@ class MIDIPlayer {
280
295
  return seekBar;
281
296
  }
282
297
  currTime() {
283
- const currTime = this.text("0:00", "currTime");
298
+ const currTime = this.text("0:00", "midi-player-currTime");
284
299
  this.currTimeNode = currTime;
285
300
  return currTime;
286
301
  }
287
302
  totalTime() {
288
- const totalTime = this.text("0:00", "totalTime");
303
+ const totalTime = this.text("0:00", "midi-player-totalTime");
289
304
  this.totalTimeNode = totalTime;
290
305
  return totalTime;
291
306
  }
292
307
  currTimeTotalTime() {
293
308
  const currTime = this.currTime();
294
- const separator = this.text("/", "timeSeparator");
309
+ const separator = this.text("/", "midi-player-timeSeparator");
295
310
  const totalTime = this.totalTime();
296
311
  const div = document.createElement("div");
297
312
  div.style.display = "flex";