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]; | |
| } | |