@marmooo/midi-player 0.0.1 → 0.0.3

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/GeneralUser_GS_v1.471";
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,8BAaC;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,125 @@ 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 [bank, program] = instrument.split(":");
154
+ const bankNumber = Number(bank);
155
+ const programNumber = Number(program);
156
+ const index = midy.soundFontTable[programNumber][bankNumber];
157
+ if (index !== undefined)
158
+ continue;
159
+ const baseName = bankNumber === 128 ? "128" : program;
160
+ paths.push(`${soundFontURL}/${baseName}.sf3`);
161
+ }
162
+ return paths;
148
163
  }
149
164
  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
- }
165
+ const midy = this.midy;
166
+ if (midy.soundFonts.length === 0) {
167
+ const paths = this.getSoundFontPaths();
168
+ await midy.loadSoundFont(paths);
163
169
  }
164
170
  this.startTimer();
165
- await this.midy.start();
171
+ await midy.start();
166
172
  clearInterval(this.timer);
167
- if (!this.midy.isPaused && this.currTimeNode) {
173
+ if (!midy.isPaused && this.currTimeNode) {
168
174
  this.currTimeNode.textContent = "0:00";
169
175
  this.seekBarNode.value = 0;
170
176
  }
171
177
  }
178
+ async handleStop() {
179
+ const midy = this.midy;
180
+ if (!midy.isPlaying)
181
+ return;
182
+ clearInterval(this.timer);
183
+ this.playNode.style.display = "initial";
184
+ this.pauseNode.style.display = "none";
185
+ this.resumeNode.style.display = "none";
186
+ await midy.stop();
187
+ }
172
188
  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
- };
189
+ const stop = this.button("start", "midi-player-start", "stop", "initial");
190
+ stop.onclick = () => this.handleStop();
183
191
  this.stopNode = stop;
184
192
  return stop;
185
193
  }
194
+ async handlePlay() {
195
+ const { midy, playNode, pauseNode } = this;
196
+ if (midy.isPlaying || midy.isPaused)
197
+ return;
198
+ playNode.style.display = "none";
199
+ pauseNode.style.display = "initial";
200
+ await this.start();
201
+ if (!midy.isPaused) {
202
+ pauseNode.style.display = "none";
203
+ playNode.style.display = "initial";
204
+ }
205
+ }
206
+ handlePause() {
207
+ const midy = this.midy;
208
+ if (!midy.isPlaying || midy.isPaused)
209
+ return;
210
+ this.pauseNode.style.display = "none";
211
+ this.resumeNode.style.display = "initial";
212
+ clearInterval(this.timer);
213
+ midy.pause();
214
+ }
215
+ async handleResume() {
216
+ const { midy, playNode, pauseNode, resumeNode } = this;
217
+ if (!midy.isPaused)
218
+ return;
219
+ pauseNode.style.display = "initial";
220
+ resumeNode.style.display = "none";
221
+ this.startTimer();
222
+ await midy.resume();
223
+ clearInterval(this.timer);
224
+ if (!midy.isPaused) {
225
+ pauseNode.style.display = "none";
226
+ playNode.style.display = "initial";
227
+ }
228
+ }
186
229
  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
- };
230
+ const play = this.button("start", "midi-player-start", "play_arrow", "initial");
231
+ const pause = this.button("pause", "midi-player-pause", "pause", "none");
232
+ const resume = this.button("resume", "midi-player-resume", "play_arrow", "none");
233
+ this.playNode = play;
234
+ this.pauseNode = pause;
235
+ this.resumeNode = resume;
236
+ play.onclick = () => this.handlePlay();
237
+ pause.onclick = () => this.handlePause();
238
+ resume.onclick = () => this.handleResume();
222
239
  const div = document.createElement("div");
223
240
  div.style.display = "flex";
224
241
  div.style.alignItems = "center";
225
242
  div.appendChild(play);
226
243
  div.appendChild(pause);
227
244
  div.appendChild(resume);
228
- this.playNode = play;
229
- this.pauseNode = pause;
230
- this.resumeNode = resume;
231
245
  return div;
232
246
  }
233
247
  volumeText() {
234
- return this.text("volume", "volumeText");
248
+ return this.text("volume", "midi-player-volumeText");
235
249
  }
236
250
  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");
251
+ const muteOn = this.button("mute ON", "midi-player-muteOn", "volume_down", "initial");
252
+ const muteOff = this.button("mute OFF", "midi-player-muteOff", "volume_off", "none");
253
+ const volumeBar = this.formRange("volume", "midi-player-volume", 1, "none");
240
254
  muteOn.onclick = () => {
241
255
  muteOn.style.display = "none";
242
256
  muteOff.style.display = "initial";
243
- this.midy.handleMasterVolume(0);
257
+ this.midy.setMasterVolume(0);
244
258
  };
245
259
  muteOff.onclick = () => {
246
260
  muteOn.style.display = "initial";
247
261
  muteOff.style.display = "none";
248
- this.midy.handleMasterVolume(1);
262
+ this.midy.setMasterVolume(1);
249
263
  };
250
264
  volumeBar.oninput = (event) => {
251
- this.midy.handleMasterVolume(event.target.value);
265
+ this.midy.setMasterVolume(event.target.value);
252
266
  };
253
267
  const div = document.createElement("div");
254
268
  div.style.display = "flex";
@@ -265,7 +279,7 @@ export class MIDIPlayer {
265
279
  return div;
266
280
  }
267
281
  seekBar() {
268
- const seekBar = this.formRange("playback position", "seekBar", 0, "initial");
282
+ const seekBar = this.formRange("playback position", "midi-player-seekBar", 0, "initial");
269
283
  seekBar.oninput = (event) => {
270
284
  const time = event.target.value * this.midy.totalTime;
271
285
  this.midy.seekTo(time);
@@ -277,18 +291,18 @@ export class MIDIPlayer {
277
291
  return seekBar;
278
292
  }
279
293
  currTime() {
280
- const currTime = this.text("0:00", "currTime");
294
+ const currTime = this.text("0:00", "midi-player-currTime");
281
295
  this.currTimeNode = currTime;
282
296
  return currTime;
283
297
  }
284
298
  totalTime() {
285
- const totalTime = this.text("0:00", "totalTime");
299
+ const totalTime = this.text("0:00", "midi-player-totalTime");
286
300
  this.totalTimeNode = totalTime;
287
301
  return totalTime;
288
302
  }
289
303
  currTimeTotalTime() {
290
304
  const currTime = this.currTime();
291
- const separator = this.text("/", "timeSeparator");
305
+ const separator = this.text("/", "midi-player-timeSeparator");
292
306
  const totalTime = this.totalTime();
293
307
  const div = document.createElement("div");
294
308
  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.3",
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,8BAaC;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,125 @@ 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 [bank, program] = instrument.split(":");
157
+ const bankNumber = Number(bank);
158
+ const programNumber = Number(program);
159
+ const index = midy.soundFontTable[programNumber][bankNumber];
160
+ if (index !== undefined)
161
+ continue;
162
+ const baseName = bankNumber === 128 ? "128" : program;
163
+ paths.push(`${soundFontURL}/${baseName}.sf3`);
164
+ }
165
+ return paths;
151
166
  }
152
167
  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
- }
168
+ const midy = this.midy;
169
+ if (midy.soundFonts.length === 0) {
170
+ const paths = this.getSoundFontPaths();
171
+ await midy.loadSoundFont(paths);
166
172
  }
167
173
  this.startTimer();
168
- await this.midy.start();
174
+ await midy.start();
169
175
  clearInterval(this.timer);
170
- if (!this.midy.isPaused && this.currTimeNode) {
176
+ if (!midy.isPaused && this.currTimeNode) {
171
177
  this.currTimeNode.textContent = "0:00";
172
178
  this.seekBarNode.value = 0;
173
179
  }
174
180
  }
181
+ async handleStop() {
182
+ const midy = this.midy;
183
+ if (!midy.isPlaying)
184
+ return;
185
+ clearInterval(this.timer);
186
+ this.playNode.style.display = "initial";
187
+ this.pauseNode.style.display = "none";
188
+ this.resumeNode.style.display = "none";
189
+ await midy.stop();
190
+ }
175
191
  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
- };
192
+ const stop = this.button("start", "midi-player-start", "stop", "initial");
193
+ stop.onclick = () => this.handleStop();
186
194
  this.stopNode = stop;
187
195
  return stop;
188
196
  }
197
+ async handlePlay() {
198
+ const { midy, playNode, pauseNode } = this;
199
+ if (midy.isPlaying || midy.isPaused)
200
+ return;
201
+ playNode.style.display = "none";
202
+ pauseNode.style.display = "initial";
203
+ await this.start();
204
+ if (!midy.isPaused) {
205
+ pauseNode.style.display = "none";
206
+ playNode.style.display = "initial";
207
+ }
208
+ }
209
+ handlePause() {
210
+ const midy = this.midy;
211
+ if (!midy.isPlaying || midy.isPaused)
212
+ return;
213
+ this.pauseNode.style.display = "none";
214
+ this.resumeNode.style.display = "initial";
215
+ clearInterval(this.timer);
216
+ midy.pause();
217
+ }
218
+ async handleResume() {
219
+ const { midy, playNode, pauseNode, resumeNode } = this;
220
+ if (!midy.isPaused)
221
+ return;
222
+ pauseNode.style.display = "initial";
223
+ resumeNode.style.display = "none";
224
+ this.startTimer();
225
+ await midy.resume();
226
+ clearInterval(this.timer);
227
+ if (!midy.isPaused) {
228
+ pauseNode.style.display = "none";
229
+ playNode.style.display = "initial";
230
+ }
231
+ }
189
232
  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
- };
233
+ const play = this.button("start", "midi-player-start", "play_arrow", "initial");
234
+ const pause = this.button("pause", "midi-player-pause", "pause", "none");
235
+ const resume = this.button("resume", "midi-player-resume", "play_arrow", "none");
236
+ this.playNode = play;
237
+ this.pauseNode = pause;
238
+ this.resumeNode = resume;
239
+ play.onclick = () => this.handlePlay();
240
+ pause.onclick = () => this.handlePause();
241
+ resume.onclick = () => this.handleResume();
225
242
  const div = document.createElement("div");
226
243
  div.style.display = "flex";
227
244
  div.style.alignItems = "center";
228
245
  div.appendChild(play);
229
246
  div.appendChild(pause);
230
247
  div.appendChild(resume);
231
- this.playNode = play;
232
- this.pauseNode = pause;
233
- this.resumeNode = resume;
234
248
  return div;
235
249
  }
236
250
  volumeText() {
237
- return this.text("volume", "volumeText");
251
+ return this.text("volume", "midi-player-volumeText");
238
252
  }
239
253
  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");
254
+ const muteOn = this.button("mute ON", "midi-player-muteOn", "volume_down", "initial");
255
+ const muteOff = this.button("mute OFF", "midi-player-muteOff", "volume_off", "none");
256
+ const volumeBar = this.formRange("volume", "midi-player-volume", 1, "none");
243
257
  muteOn.onclick = () => {
244
258
  muteOn.style.display = "none";
245
259
  muteOff.style.display = "initial";
246
- this.midy.handleMasterVolume(0);
260
+ this.midy.setMasterVolume(0);
247
261
  };
248
262
  muteOff.onclick = () => {
249
263
  muteOn.style.display = "initial";
250
264
  muteOff.style.display = "none";
251
- this.midy.handleMasterVolume(1);
265
+ this.midy.setMasterVolume(1);
252
266
  };
253
267
  volumeBar.oninput = (event) => {
254
- this.midy.handleMasterVolume(event.target.value);
268
+ this.midy.setMasterVolume(event.target.value);
255
269
  };
256
270
  const div = document.createElement("div");
257
271
  div.style.display = "flex";
@@ -268,7 +282,7 @@ class MIDIPlayer {
268
282
  return div;
269
283
  }
270
284
  seekBar() {
271
- const seekBar = this.formRange("playback position", "seekBar", 0, "initial");
285
+ const seekBar = this.formRange("playback position", "midi-player-seekBar", 0, "initial");
272
286
  seekBar.oninput = (event) => {
273
287
  const time = event.target.value * this.midy.totalTime;
274
288
  this.midy.seekTo(time);
@@ -280,18 +294,18 @@ class MIDIPlayer {
280
294
  return seekBar;
281
295
  }
282
296
  currTime() {
283
- const currTime = this.text("0:00", "currTime");
297
+ const currTime = this.text("0:00", "midi-player-currTime");
284
298
  this.currTimeNode = currTime;
285
299
  return currTime;
286
300
  }
287
301
  totalTime() {
288
- const totalTime = this.text("0:00", "totalTime");
302
+ const totalTime = this.text("0:00", "midi-player-totalTime");
289
303
  this.totalTimeNode = totalTime;
290
304
  return totalTime;
291
305
  }
292
306
  currTimeTotalTime() {
293
307
  const currTime = this.currTime();
294
- const separator = this.text("/", "timeSeparator");
308
+ const separator = this.text("/", "midi-player-timeSeparator");
295
309
  const totalTime = this.totalTime();
296
310
  const div = document.createElement("div");
297
311
  div.style.display = "flex";