Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions dist/css/keyboard.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,30 @@
cursor: pointer;
position: relative;
}

#countdownContainer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 200;
background: rgba(53, 53, 53, 0.492);
pointer-events: all;
}

#countdownDisplay {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: black;
color: white;
padding: 20px;
border-radius: 10px;
text-align: center;
}

table {
table-layout: fixed;
}
Expand Down
198 changes: 127 additions & 71 deletions js/widgets/musickeyboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,18 @@ function MusicKeyboard(activity) {
* @type {Array}
*/
this.idContainer = [];

/**
* Flag to track tick status.
* @type {boolean}
*/
this.tick = false;

/** Flag to track if the metronome is on.
* @type {boolean}
*/
this.metronomeInterval = false;

/**
* Meter arguments.
* @type {Array}
Expand All @@ -164,6 +169,12 @@ function MusicKeyboard(activity) {
*/
this.instrumentMapper = {};

/**
* Flag to track first note while using metronome.
* @type {boolean}
*/
this.firstNote = false;

/**
* Array of selected notes.
* @type {Array}
Expand Down Expand Up @@ -260,37 +271,47 @@ function MusicKeyboard(activity) {
* Adds keyboard shortcuts for triggering musical notes.
*/
this.addKeyboardShortcuts = function () {
// ;

let duration = 0;
const startTime = {};
const temp1 = {};
const temp2 = {};
const current = new Set();

/**
* Gets the ID of the musical note associated with a keyboard event.
* @param {KeyboardEvent} event - The keyboard event.
* @returns {string} The ID of the musical note.
*/
const __getNoteId = (event) => {
let id;
const key = event.keyCode;

if (WHITEKEYS.includes(key)) {
id = `whiteRow${WHITEKEYS.indexOf(key)}`;
} else if (BLACKKEYS.includes(key)) {
const i = BLACKKEYS.indexOf(key);
if ([2, 6, 9, 13, 16, 20].includes(i)) return null;
id = `blackRow${i}`;
} else if (HERTZKEYS.includes(key)) {
id = `hertzRow${HERTZKEYS.indexOf(key)}`;
} else if (key === SPACE) {
id = 'rest';
}

return id;
};

/**
* Handles the start of a musical note when a keyboard key is pressed.
* @param {KeyboardEvent} event - The keyboard event.
*/
const __startNote = (event) => {
let i, id;
if (WHITEKEYS.includes(event.keyCode)) {
i = WHITEKEYS.indexOf(event.keyCode);
id = "whiteRow" + i.toString();
} else if (BLACKKEYS.includes(event.keyCode)) {
i = BLACKKEYS.indexOf(event.keyCode);
if ([2, 6, 9, 13, 16, 20].includes(i)) return;
id = "blackRow" + i.toString();
} else if (HERTZKEYS.includes(event.keyCode)) {
i = HERTZKEYS.indexOf(event.keyCode);
id = "hertzRow" + i.toString();
} else if (SPACE == event.keyCode) {
id = "rest";
}
const id = __getNoteId(event);

const ele = docById(id);
if (!(id in startTime)) {
const startDate = new Date();
startTime[id] = startDate.getTime();
startTime[id] = new Date().getTime();
}

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

if (id == "rest") {
this.endTime = undefined;
return;
}

Expand All @@ -322,31 +342,28 @@ function MusicKeyboard(activity) {
null
);

if (this.tick) {
if (this.tick && this.endTime !== undefined && this.firstNote) {
let restDuration = (startTime[id] - this.endTime) / 1000.0;

restDuration /= 60; // time in minutes
restDuration /= 60; // Convert time to minutes
restDuration *= this.bpm;
restDuration *= this.meterArgs[1];

restDuration = parseFloat((Math.round(restDuration * unit) / unit).toFixed(4));
const EPSILON = 0.0600;

if (restDuration === 0) {
restDuration = 0;
} else {
if (restDuration > EPSILON && current.size === 0) {
this._notesPlayed.push({
startTime: this.endTime,
noteOctave: "R",
objId: null,
duration: parseFloat(restDuration)
});
//this._createTable();
}
}
this.endTime = undefined;
this.firstNote = true;
}
};


/**
* Handles the keyboard key down event to start playing musical notes.
* @param {KeyboardEvent} event - The keyboard event triggered when a key is pressed down.
Expand All @@ -365,25 +382,11 @@ function MusicKeyboard(activity) {
* @param {KeyboardEvent} event - The keyboard event triggered when a key is released.
*/
const __endNote = (event) => {
let i, id;
if (WHITEKEYS.includes(event.keyCode)) {
i = WHITEKEYS.indexOf(event.keyCode);
id = "whiteRow" + i.toString();
} else if (BLACKKEYS.includes(event.keyCode)) {
i = BLACKKEYS.indexOf(event.keyCode);
if ([2, 6, 9, 13, 16, 20].includes(i)) return;
id = "blackRow" + i.toString();
} else if (HERTZKEYS.includes(event.keyCode)) {
i = HERTZKEYS.indexOf(event.keyCode);
id = "hertzRow" + i.toString();
} else if (SPACE == event.keyCode) {
id = "rest";
}

const id = __getNoteId(event);
const ele = docById(id);
const newDate = new Date();
this.endTime = newDate.getTime();
duration = (this.endTime - startTime[id]) / 1000.0;
const noteEndTime = newDate.getTime();
duration = (noteEndTime - startTime[id]) / 1000.0;

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

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

duration /= 60;
duration *= this.bpm;
duration *= this.meterArgs[1];

duration = parseFloat((Math.round(duration * unit) / unit).toFixed(4));
let processedDuration = duration / 60;
processedDuration *= this.bpm;
processedDuration *= this.meterArgs[1];
processedDuration = parseFloat((Math.round(processedDuration * unit) / unit).toFixed(4));

if (duration === 0) {
duration = 1 / unit;
} else if (duration < 0) {
duration = -duration;
if (processedDuration <= 0) {
processedDuration = 1 / unit;
}

if (id == "rest") {
this._notesPlayed.push({
startTime: startTime[id],
noteOctave: "R",
objId: null,
duration: parseFloat(duration)
duration: parseFloat(processedDuration)
});
} else {
this.activity.logo.synth.stopSound(0, this.instrumentMapper[id], temp2[id]);
this._notesPlayed.push({
startTime: startTime[id],
noteOctave: temp2[id],
objId: id,
duration: duration,
duration: processedDuration,
voice: this.instrumentMapper[id],
blockNumber: this.blockNumberMapper[id]
});
Expand Down Expand Up @@ -448,6 +449,7 @@ function MusicKeyboard(activity) {
docById("mkbOuterDiv").style.width = w + "px";
docById("mkbInnerDiv").style.height = "100%";
}
this.endTime = noteEndTime;
delete startTime[id];
delete temp1[id];
delete temp2[id];
Expand Down Expand Up @@ -673,6 +675,10 @@ function MusicKeyboard(activity) {
myNode.innerHTML = "";
}

this.tick = false;
this.firstNote = false;
this.metronomeON = false;

selectedNotes = [];
if (this.loopTick) this.loopTick.stop();
docById("wheelDivptm").style.display = "none";
Expand Down Expand Up @@ -761,24 +767,74 @@ function MusicKeyboard(activity) {
*/
this.tickButton = widgetWindow.addButton("metronome.svg", ICONSIZE, _("Metronome"));
this.tickButton.onclick = () => {
if (this.tick) {
if (this.metronomeInterval || this.metronomeON) {
// Turn off metronome
this.tickButton.style.removeProperty("background");

if (this.tick && this.loopTick) {
this.loopTick.stop();
}
this.tick = false;
this.loopTick.stop();
this.firstNote = false;
this.metronomeON = false;

const countdownContainer = docById("countdownContainer");
if (countdownContainer) {
countdownContainer.remove();
}
if (this.metronomeInterval) {
clearInterval(this.metronomeInterval);
this.metronomeInterval = null;
}

} else {
this.tick = true;
this.activity.logo.synth.loadSynth(0, "cow bell");
this.loopTick = this.activity.logo.synth.loop(
0,
"cow bell",
"C5",
1 / 64,
0,
this.bpm || 90,
0.07
);
setTimeout(() => {
// Turn on metronome
this.metronomeON = true;
this.tickButton.style.background = platformColor.orange;

const winBody = document.getElementsByClassName("wfbWidget")[0];
const countdownContainer = document.createElement("div");
countdownContainer.id = "countdownContainer";

const countdownDisplay = document.createElement("div");
countdownDisplay.id = "countdownDisplay";
countdownDisplay.textContent = "3";
countdownContainer.appendChild(countdownDisplay);
winBody.appendChild(countdownContainer);

// Start countdown
let count = 3;
this.metronomeInterval = setInterval(() => {
count--;

if (count === 0) {
clearInterval(this.metronomeInterval);
this.metronomeInterval = null;

countdownContainer.remove();

if (this.metronomeON) {
this.tick = true;
this.activity.logo.synth.loadSynth(0, "cow bell");
this.loopTick = this.activity.logo.synth.loop(
0,
"cow bell",
"C5",
1 / 64,
0,
this.bpm || 90,
0.07
);
}
} else {
countdownDisplay.textContent = count;
}
}, 1000);

// Start audio
if (this.metronomeON) {
this.activity.logo.synth.start();
}, 500);
}
}
};

Expand Down
Loading