Spaces:
Runtime error
Runtime error
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]; | |
} | |