polyphemus / static /script.js
EmanueleCosenza's picture
Working version
d896bd4
let tsPerBar = 32;
let nBars = 2;
let tssPerStep = 4;
let isDragging = false;
let action = null;
let player;
let isPlaying = false;
let ts = 0;
let lastTime = 0;
document.addEventListener("DOMContentLoaded", function () {
setupGridListeners();
// Clear grid on button click
const clearButton = document.getElementById('clearButton');
clearButton.addEventListener('click', clearGrid);
loadGrid();
setupVisualizer();
setupPlayer();
setupGenerationListeners();
});
function setupGridListeners() {
const grid = document.getElementById('grid');
const rows = grid.querySelectorAll('tr');
rows.forEach((row, i) => {
const cells = row.querySelectorAll('td');
cells.forEach((cell, j) => {
setupCellListeners(cell);
});
});
document.addEventListener('mouseup', function () {
isDragging = false;
});
}
function setupCellListeners(cell) {
cell.addEventListener('dragstart', function (e) {
e.preventDefault();
});
cell.addEventListener('mousedown', function (e) {
if (e.button !== 0) return;
e.preventDefault();
isDragging = true;
// Determine action based on initial cell's state
action = cell.classList.contains('activated') ? 'deactivate' : 'activate';
applyAction(cell, action);
});
cell.addEventListener('mouseover', function () {
if (isDragging) applyAction(cell, action);
});
cell.addEventListener('mouseup', function () {
isDragging = false; // End dragging once mouse is released
});
}
function applyAction(cell, action) {
if (action === 'activate') {
cell.classList.remove('deactivated');
cell.classList.add('activated');
} else {
cell.classList.add('deactivated');
cell.classList.remove('activated');
}
}
function clearGrid() {
const grid = document.getElementById('grid');
const cells = grid.querySelectorAll('td');
cells.forEach(cell => {
cell.classList.add('deactivated');
cell.classList.remove('activated');
});
}
function loadGrid() {
fetch('/load_grid')
.then(response => response.json())
.then(data => applyConfiguration(data[0]))
.catch(error => console.error('Error fetching grid:', error));
}
function applyConfiguration(config) {
const grid = document.getElementById('grid');
const rows = grid.querySelectorAll('tr');
for (let i = 0; i < rows.length && i < config.length; i++) {
const cells = rows[i].querySelectorAll('td');
for (let j = 0; j < cells.length && j < config[i].length; j++) {
const cell = cells[j];
if (config[i][j] === true) {
cell.classList.add('activated');
cell.classList.remove('deactivated');
} else {
cell.classList.add('deactivated');
cell.classList.remove('activated');
}
}
}
}
function setupPlayer() {
player = document.getElementById('midiplayer');
player.loop = true;
player.addEventListener('start', function () {
isPlaying = true;
lastTime = -1;
ts = 0;
update();
});
player.addEventListener('stop', function (event) {
if (event.detail.finished) isPlaying = false;
});
}
function update() {
if (!isPlaying) return;
currentTime = player.currentTime;
dur = player.duration;
if (currentTime != lastTime) {
tsTime = dur / (nBars * tsPerBar);
ts = Math.min(nBars * tsPerBar - 1, currentTime / tsTime);
ts = tssPerStep * Math.floor(ts / tssPerStep);
pianorollStep(ts);
}
lastTime = currentTime;
requestAnimationFrame(update);
}
function pianorollStep(ts) {
const grid = document.getElementById('grid');
const rows = grid.querySelectorAll('tr');
// Clear previously darkened cells
const previouslyDarkened = document.querySelectorAll('.darkened');
previouslyDarkened.forEach(cell => cell.classList.remove('darkened'));
for (let row of rows) {
const cell = row.cells[(ts % tsPerBar) + 1];
if (cell) {
cell.classList.add('darkened');
}
}
}
function setupVisualizer() {
const visualizer = document.getElementById('midivisualizer');
visualizer.config = {
noteHeight: 5,
pixelsPerTimeStep: 100,
minPitch: 40,
maxPitch: 80
};
}
const emptyMessages = [
"\"Hello Darkness, my old friend...\"",
]
function setupGenerationListeners() {
const generateButton = document.getElementById('generate');
const keepTonality = document.getElementById('keepTonality');
const useGrid = document.getElementById('useGrid');
generateButton.addEventListener('click', async function () {
generateButton.disabled = true;
const config = getGridConfiguration();
const emptyMessage = document.getElementById('emptyMessage');
if (!config) {
const r = Math.floor(Math.random() * emptyMessages.length);
emptyMessage.textContent = emptyMessages[r];
generateButton.disabled = false;
emptyMessage.style.display = 'block';
return;
} else {
emptyMessage.textContent = '';
emptyMessage.style.display = 'none';
}
sendJSONToBackend(config).then(response => {
console.log(response.message);
});
const shouldKeepTonality = keepTonality.checked;
let shouldUseGrid;
if (useGrid != null) {
shouldUseGrid = useGrid.checked;
} else {
shouldUseGrid = true;
}
try {
const response = await fetch('/generate_midi', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
keepTonality: shouldKeepTonality,
useGrid: shouldUseGrid
})
});
if (response.ok) {
const data = await response.json();
const filename = data.filename;
reinitializePlayer(filename);
} else {
console.error('Failed to generate MIDI.');
}
} catch (error) {
console.error('Error:', error);
} finally {
generateButton.disabled = false;
}
});
}
async function sendJSONToBackend(data) {
const response = await fetch('/save_json', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
return response.json();
}
function reinitializePlayer(filename) {
const player = document.getElementById('midiplayer');
const visualizer = document.getElementById('midivisualizer');
const staticUrl = document.body.getAttribute('static-url');
// Reset properties
player.currentTime = 0;
player.noteSequence = null;
// Load the new MIDI file
path = staticUrl + '0/' + filename;
player.src = path;
// Reload the player
player.reload();
visualizer.src = path;
visualizer.noteSequence = null;
// Reload the player and visualizer
player.reload();
visualizer.reload();
visualizer.clearActiveNotes();
visualizer.redraw();
}
function getGridConfiguration() {
const grid = document.getElementById('grid');
const rows = grid.querySelectorAll('tr');
let isEmpty = true;
const config = [];
rows.forEach(row => {
const cells = Array.from(row.querySelectorAll('td'));
const rowData = cells.map(cell => {
if (cell.classList.contains('activated')) {
isEmpty = false;
return 1;
}
return 0;
});
config.push(rowData);
});
return isEmpty ? null : [config];
}