Skip to content

Commit 8f44f67

Browse files
authored
piano metronome fix (#4344)
* piano metronome fix * fake rest notes fix * countdown added * final fix * update * bug fix * turn off bool when closed * removed set timeout
1 parent 0e5fc93 commit 8f44f67

File tree

2 files changed

+151
-71
lines changed

2 files changed

+151
-71
lines changed

dist/css/keyboard.css

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,30 @@
88
cursor: pointer;
99
position: relative;
1010
}
11+
12+
#countdownContainer {
13+
position: absolute;
14+
top: 0;
15+
left: 0;
16+
width: 100%;
17+
height: 100%;
18+
z-index: 200;
19+
background: rgba(53, 53, 53, 0.492);
20+
pointer-events: all;
21+
}
22+
23+
#countdownDisplay {
24+
position: absolute;
25+
top: 50%;
26+
left: 50%;
27+
transform: translate(-50%, -50%);
28+
background: black;
29+
color: white;
30+
padding: 20px;
31+
border-radius: 10px;
32+
text-align: center;
33+
}
34+
1135
table {
1236
table-layout: fixed;
1337
}

js/widgets/musickeyboard.js

Lines changed: 127 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,18 @@ function MusicKeyboard(activity) {
132132
* @type {Array}
133133
*/
134134
this.idContainer = [];
135-
135+
136136
/**
137137
* Flag to track tick status.
138138
* @type {boolean}
139139
*/
140140
this.tick = false;
141141

142+
/** Flag to track if the metronome is on.
143+
* @type {boolean}
144+
*/
145+
this.metronomeInterval = false;
146+
142147
/**
143148
* Meter arguments.
144149
* @type {Array}
@@ -164,6 +169,12 @@ function MusicKeyboard(activity) {
164169
*/
165170
this.instrumentMapper = {};
166171

172+
/**
173+
* Flag to track first note while using metronome.
174+
* @type {boolean}
175+
*/
176+
this.firstNote = false;
177+
167178
/**
168179
* Array of selected notes.
169180
* @type {Array}
@@ -260,37 +271,47 @@ function MusicKeyboard(activity) {
260271
* Adds keyboard shortcuts for triggering musical notes.
261272
*/
262273
this.addKeyboardShortcuts = function () {
263-
// ;
274+
264275
let duration = 0;
265276
const startTime = {};
266277
const temp1 = {};
267278
const temp2 = {};
268279
const current = new Set();
269280

281+
/**
282+
* Gets the ID of the musical note associated with a keyboard event.
283+
* @param {KeyboardEvent} event - The keyboard event.
284+
* @returns {string} The ID of the musical note.
285+
*/
286+
const __getNoteId = (event) => {
287+
let id;
288+
const key = event.keyCode;
289+
290+
if (WHITEKEYS.includes(key)) {
291+
id = `whiteRow${WHITEKEYS.indexOf(key)}`;
292+
} else if (BLACKKEYS.includes(key)) {
293+
const i = BLACKKEYS.indexOf(key);
294+
if ([2, 6, 9, 13, 16, 20].includes(i)) return null;
295+
id = `blackRow${i}`;
296+
} else if (HERTZKEYS.includes(key)) {
297+
id = `hertzRow${HERTZKEYS.indexOf(key)}`;
298+
} else if (key === SPACE) {
299+
id = 'rest';
300+
}
301+
302+
return id;
303+
};
304+
270305
/**
271306
* Handles the start of a musical note when a keyboard key is pressed.
272307
* @param {KeyboardEvent} event - The keyboard event.
273308
*/
274309
const __startNote = (event) => {
275-
let i, id;
276-
if (WHITEKEYS.includes(event.keyCode)) {
277-
i = WHITEKEYS.indexOf(event.keyCode);
278-
id = "whiteRow" + i.toString();
279-
} else if (BLACKKEYS.includes(event.keyCode)) {
280-
i = BLACKKEYS.indexOf(event.keyCode);
281-
if ([2, 6, 9, 13, 16, 20].includes(i)) return;
282-
id = "blackRow" + i.toString();
283-
} else if (HERTZKEYS.includes(event.keyCode)) {
284-
i = HERTZKEYS.indexOf(event.keyCode);
285-
id = "hertzRow" + i.toString();
286-
} else if (SPACE == event.keyCode) {
287-
id = "rest";
288-
}
310+
const id = __getNoteId(event);
289311

290312
const ele = docById(id);
291313
if (!(id in startTime)) {
292-
const startDate = new Date();
293-
startTime[id] = startDate.getTime();
314+
startTime[id] = new Date().getTime();
294315
}
295316

296317
if (ele !== null && ele !== undefined) {
@@ -309,7 +330,6 @@ function MusicKeyboard(activity) {
309330
}
310331

311332
if (id == "rest") {
312-
this.endTime = undefined;
313333
return;
314334
}
315335

@@ -322,31 +342,28 @@ function MusicKeyboard(activity) {
322342
null
323343
);
324344

325-
if (this.tick) {
345+
if (this.tick && this.endTime !== undefined && this.firstNote) {
326346
let restDuration = (startTime[id] - this.endTime) / 1000.0;
327-
328-
restDuration /= 60; // time in minutes
347+
restDuration /= 60; // Convert time to minutes
329348
restDuration *= this.bpm;
330349
restDuration *= this.meterArgs[1];
331-
332350
restDuration = parseFloat((Math.round(restDuration * unit) / unit).toFixed(4));
351+
const EPSILON = 0.0600;
333352

334-
if (restDuration === 0) {
335-
restDuration = 0;
336-
} else {
353+
if (restDuration > EPSILON && current.size === 0) {
337354
this._notesPlayed.push({
338355
startTime: this.endTime,
339356
noteOctave: "R",
340357
objId: null,
341358
duration: parseFloat(restDuration)
342359
});
343-
//this._createTable();
344360
}
345361
}
346-
this.endTime = undefined;
362+
this.firstNote = true;
347363
}
348364
};
349365

366+
350367
/**
351368
* Handles the keyboard key down event to start playing musical notes.
352369
* @param {KeyboardEvent} event - The keyboard event triggered when a key is pressed down.
@@ -365,25 +382,11 @@ function MusicKeyboard(activity) {
365382
* @param {KeyboardEvent} event - The keyboard event triggered when a key is released.
366383
*/
367384
const __endNote = (event) => {
368-
let i, id;
369-
if (WHITEKEYS.includes(event.keyCode)) {
370-
i = WHITEKEYS.indexOf(event.keyCode);
371-
id = "whiteRow" + i.toString();
372-
} else if (BLACKKEYS.includes(event.keyCode)) {
373-
i = BLACKKEYS.indexOf(event.keyCode);
374-
if ([2, 6, 9, 13, 16, 20].includes(i)) return;
375-
id = "blackRow" + i.toString();
376-
} else if (HERTZKEYS.includes(event.keyCode)) {
377-
i = HERTZKEYS.indexOf(event.keyCode);
378-
id = "hertzRow" + i.toString();
379-
} else if (SPACE == event.keyCode) {
380-
id = "rest";
381-
}
382-
385+
const id = __getNoteId(event);
383386
const ele = docById(id);
384387
const newDate = new Date();
385-
this.endTime = newDate.getTime();
386-
duration = (this.endTime - startTime[id]) / 1000.0;
388+
const noteEndTime = newDate.getTime();
389+
duration = (noteEndTime - startTime[id]) / 1000.0;
387390

388391
if (ele !== null && ele !== undefined) {
389392
if (id.includes("blackRow")) {
@@ -394,31 +397,29 @@ function MusicKeyboard(activity) {
394397

395398
// no = ele.getAttribute("alt").split("__")[2];
396399

397-
duration /= 60;
398-
duration *= this.bpm;
399-
duration *= this.meterArgs[1];
400-
401-
duration = parseFloat((Math.round(duration * unit) / unit).toFixed(4));
400+
let processedDuration = duration / 60;
401+
processedDuration *= this.bpm;
402+
processedDuration *= this.meterArgs[1];
403+
processedDuration = parseFloat((Math.round(processedDuration * unit) / unit).toFixed(4));
402404

403-
if (duration === 0) {
404-
duration = 1 / unit;
405-
} else if (duration < 0) {
406-
duration = -duration;
405+
if (processedDuration <= 0) {
406+
processedDuration = 1 / unit;
407407
}
408+
408409
if (id == "rest") {
409410
this._notesPlayed.push({
410411
startTime: startTime[id],
411412
noteOctave: "R",
412413
objId: null,
413-
duration: parseFloat(duration)
414+
duration: parseFloat(processedDuration)
414415
});
415416
} else {
416417
this.activity.logo.synth.stopSound(0, this.instrumentMapper[id], temp2[id]);
417418
this._notesPlayed.push({
418419
startTime: startTime[id],
419420
noteOctave: temp2[id],
420421
objId: id,
421-
duration: duration,
422+
duration: processedDuration,
422423
voice: this.instrumentMapper[id],
423424
blockNumber: this.blockNumberMapper[id]
424425
});
@@ -448,6 +449,7 @@ function MusicKeyboard(activity) {
448449
docById("mkbOuterDiv").style.width = w + "px";
449450
docById("mkbInnerDiv").style.height = "100%";
450451
}
452+
this.endTime = noteEndTime;
451453
delete startTime[id];
452454
delete temp1[id];
453455
delete temp2[id];
@@ -673,6 +675,10 @@ function MusicKeyboard(activity) {
673675
myNode.innerHTML = "";
674676
}
675677

678+
this.tick = false;
679+
this.firstNote = false;
680+
this.metronomeON = false;
681+
676682
selectedNotes = [];
677683
if (this.loopTick) this.loopTick.stop();
678684
docById("wheelDivptm").style.display = "none";
@@ -761,24 +767,74 @@ function MusicKeyboard(activity) {
761767
*/
762768
this.tickButton = widgetWindow.addButton("metronome.svg", ICONSIZE, _("Metronome"));
763769
this.tickButton.onclick = () => {
764-
if (this.tick) {
770+
if (this.metronomeInterval || this.metronomeON) {
771+
// Turn off metronome
772+
this.tickButton.style.removeProperty("background");
773+
774+
if (this.tick && this.loopTick) {
775+
this.loopTick.stop();
776+
}
765777
this.tick = false;
766-
this.loopTick.stop();
778+
this.firstNote = false;
779+
this.metronomeON = false;
780+
781+
const countdownContainer = docById("countdownContainer");
782+
if (countdownContainer) {
783+
countdownContainer.remove();
784+
}
785+
if (this.metronomeInterval) {
786+
clearInterval(this.metronomeInterval);
787+
this.metronomeInterval = null;
788+
}
789+
767790
} else {
768-
this.tick = true;
769-
this.activity.logo.synth.loadSynth(0, "cow bell");
770-
this.loopTick = this.activity.logo.synth.loop(
771-
0,
772-
"cow bell",
773-
"C5",
774-
1 / 64,
775-
0,
776-
this.bpm || 90,
777-
0.07
778-
);
779-
setTimeout(() => {
791+
// Turn on metronome
792+
this.metronomeON = true;
793+
this.tickButton.style.background = platformColor.orange;
794+
795+
const winBody = document.getElementsByClassName("wfbWidget")[0];
796+
const countdownContainer = document.createElement("div");
797+
countdownContainer.id = "countdownContainer";
798+
799+
const countdownDisplay = document.createElement("div");
800+
countdownDisplay.id = "countdownDisplay";
801+
countdownDisplay.textContent = "3";
802+
countdownContainer.appendChild(countdownDisplay);
803+
winBody.appendChild(countdownContainer);
804+
805+
// Start countdown
806+
let count = 3;
807+
this.metronomeInterval = setInterval(() => {
808+
count--;
809+
810+
if (count === 0) {
811+
clearInterval(this.metronomeInterval);
812+
this.metronomeInterval = null;
813+
814+
countdownContainer.remove();
815+
816+
if (this.metronomeON) {
817+
this.tick = true;
818+
this.activity.logo.synth.loadSynth(0, "cow bell");
819+
this.loopTick = this.activity.logo.synth.loop(
820+
0,
821+
"cow bell",
822+
"C5",
823+
1 / 64,
824+
0,
825+
this.bpm || 90,
826+
0.07
827+
);
828+
}
829+
} else {
830+
countdownDisplay.textContent = count;
831+
}
832+
}, 1000);
833+
834+
// Start audio
835+
if (this.metronomeON) {
780836
this.activity.logo.synth.start();
781-
}, 500);
837+
}
782838
}
783839
};
784840

0 commit comments

Comments
 (0)