123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- const mp3Files = document.getElementById('mp3Files');
- const tapeLengthInput = document.getElementById('tapeLength');
- const trackList = document.getElementById('trackList');
- const totalDurationDisplay = document.getElementById('totalDuration');
- const remainingTimeDisplay = document.getElementById('remainingTime');
- const recordButton = document.getElementById('recordButton');
- const progress = document.getElementById('progress');
- const volumeIndicator = document.createElement('div');
- volumeIndicator.className = 'volume-indicator';
- document.body.appendChild(volumeIndicator);
- const reelImage = document.querySelector('.reel-spinner');
- const STATIC_REEL = 'reel-to-reel-static.svg';
- const ANIMATED_REEL = 'reel-to-reel-animated.svg';
- const trackGapInput = document.getElementById('trackGap');
- const body = document.body;
- let totalDuration = 0;
- let files = [];
- let audioContext;
- let analyser;
- mp3Files.addEventListener('change', handleFiles);
- tapeLengthInput.addEventListener('input', updateRemainingTime);
- recordButton.addEventListener('click', recordToTape);
- async function handleFiles(event) {
- const newFiles = Array.from(event.target.files);
-
- for (const file of newFiles) {
- files.push(file);
- const duration = await getDuration(file);
- totalDuration += duration;
- addTrackToPlaylist(file.name, duration, files.length - 1);
- }
- updateTotalDuration();
- updateRemainingTime();
- }
- async function getDuration(file) {
- return new Promise((resolve) => {
- const audio = new Audio();
- audio.preload = 'metadata';
- audio.src = URL.createObjectURL(file);
- audio.onloadedmetadata = () => {
- resolve(audio.duration / 60); // Duration in minutes
- URL.revokeObjectURL(audio.src);
- };
- });
- }
- function addTrackToPlaylist(name, duration, index) {
- const li = document.createElement('li');
- li.draggable = true;
- li.dataset.index = index;
- li.textContent = `${name} (${duration.toFixed(2)} minutes)`;
-
- li.addEventListener('dragstart', handleDragStart);
- li.addEventListener('dragover', handleDragOver);
- li.addEventListener('drop', handleDrop);
- li.addEventListener('dragend', handleDragEnd);
-
- trackList.appendChild(li);
- }
- function updateTotalDuration() {
- totalDurationDisplay.textContent = totalDuration.toFixed(2);
- }
- function updateRemainingTime() {
- const tapeLength = parseFloat(tapeLengthInput.value);
- if (tapeLength) {
- const remainingTime = tapeLength - totalDuration;
- remainingTimeDisplay.textContent = remainingTime.toFixed(2);
- }
- }
- // ... other parts of the script
- async function recordToTape() {
- if (files.length === 0) {
- alert('Please add MP3 files to the playlist.');
- return;
- }
- audioContext = new (window.AudioContext || window.webkitAudioContext)();
- analyser = audioContext.createAnalyser();
- analyser.fftSize = 256;
- analyser.connect(audioContext.destination);
- updateVolumeIndicator();
- startReelAnimation();
- body.classList.add('recording-active');
- console.log("Starting playback with order:");
- logPlaylist();
- const gapSeconds = parseFloat(trackGapInput.value) || 0;
-
- try {
- for (let i = 0; i < files.length; i++) {
- console.log(`Playing track ${i}: ${files[i].name}`);
- const duration = await getDuration(files[i]);
- await playTrack(files[i], duration);
-
- if (i < files.length - 1 && gapSeconds > 0) {
- await addGapBetweenTracks(gapSeconds);
- }
- }
- } catch (error) {
- console.error("Playback error:", error);
- }
- stopReelAnimation();
- body.classList.remove('recording-active');
- alert('Recording completed!');
- }
- async function playTrack(file, duration) {
- return new Promise((resolve) => {
- const audio = new Audio();
- audio.src = URL.createObjectURL(file);
- const source = audioContext.createMediaElementSource(audio);
- source.connect(analyser);
- audio.currentTime = 0; // Always start from beginning
- audio.play();
- audio.onended = () => {
- resolve();
- URL.revokeObjectURL(audio.src);
- };
- audio.ontimeupdate = () => {
- const currentPlayTime = audio.currentTime;
- const progressPercent = (currentPlayTime / (totalDuration * 60)) * 100;
- updateProgress(progressPercent);
- const tapeLength = parseFloat(tapeLengthInput.value) * 60;
- const remainingTime = tapeLength - currentPlayTime;
- remainingTimeDisplay.textContent = (remainingTime / 60).toFixed(2);
- };
- });
- }
- // ... rest of the script
- function updateProgress(percent) {
- progress.innerHTML = `<div class="progress-bar" style="width: ${percent}%;"></div>`;
- }
- function updateRemainingTimeDisplay(currentTime) {
- const tapeLength = parseFloat(tapeLengthInput.value) * 60;
- const remainingTime = tapeLength - currentTime;
- remainingTimeDisplay.textContent = (remainingTime / 60).toFixed(2);
- }
- function updateVolumeIndicator() {
- const dataArray = new Uint8Array(analyser.frequencyBinCount);
- analyser.getByteFrequencyData(dataArray);
- const averageVolume = dataArray.reduce((a, b) => a + b) / dataArray.length;
- volumeIndicator.style.height = `${averageVolume / 255 * 100}px`; // Scale height based on volume
- requestAnimationFrame(updateVolumeIndicator);
- }
- function startReelAnimation() {
- reelImage.src = ANIMATED_REEL;
- }
- function stopReelAnimation() {
- reelImage.src = STATIC_REEL;
- }
- function addGapBetweenTracks(seconds) {
- return new Promise(resolve => {
- console.log(`Adding ${seconds} second gap`);
- const startTime = audioContext.currentTime;
-
- function checkGap() {
- const elapsed = audioContext.currentTime - startTime;
- if (elapsed >= seconds) {
- resolve();
- } else {
- requestAnimationFrame(checkGap);
- }
- }
-
- checkGap();
- });
- }
- let draggedItem = null;
- function handleDragStart(e) {
- draggedItem = e.target;
- e.target.style.opacity = '0.4';
- }
- function handleDragOver(e) {
- e.preventDefault();
- const targetItem = e.target;
-
- // Only handle drag over list items
- if (targetItem.tagName === 'LI') {
- const bounding = targetItem.getBoundingClientRect();
- const offset = bounding.y + (bounding.height/2);
-
- if (e.clientY - offset > 0) {
- targetItem.style.borderBottom = 'solid 2px #eed49f';
- targetItem.style.borderTop = '';
- } else {
- targetItem.style.borderTop = 'solid 2px #eed49f';
- targetItem.style.borderBottom = '';
- }
- }
- }
- function handleDrop(e) {
- e.preventDefault();
- const targetItem = e.target;
-
- // Only handle drops on list items
- if (targetItem.tagName === 'LI' && draggedItem !== targetItem) {
- // Get the current order of all items
- const items = Array.from(trackList.children);
- const oldIndex = items.indexOf(draggedItem);
-
- // Remove and insert the dragged item
- draggedItem.parentNode.removeChild(draggedItem);
-
- // Determine if dropping before or after the target
- const bounding = targetItem.getBoundingClientRect();
- const insertAfter = e.clientY > (bounding.top + bounding.height / 2);
-
- if (insertAfter) {
- targetItem.parentNode.insertBefore(draggedItem, targetItem.nextSibling);
- } else {
- targetItem.parentNode.insertBefore(draggedItem, targetItem);
- }
-
- // Get the new order of items
- const newItems = Array.from(trackList.children);
- const newIndex = newItems.indexOf(draggedItem);
-
- // Reorder the files array to match
- const [movedFile] = files.splice(oldIndex, 1);
- files.splice(newIndex, 0, movedFile);
-
- // Update all indices
- newItems.forEach((item, index) => {
- item.dataset.index = index;
- });
-
- // Log the new order for debugging
- logPlaylist();
- }
-
- clearDragOverStyles();
- }
- function handleDragEnd(e) {
- e.target.style.opacity = '';
- clearDragOverStyles();
- }
- function clearDragOverStyles() {
- const items = trackList.querySelectorAll('li');
- items.forEach(item => {
- item.style.borderTop = '';
- item.style.borderBottom = '';
- });
- }
- function updatePlaylistIndices() {
- const items = trackList.querySelectorAll('li');
- items.forEach((item, index) => {
- item.dataset.index = index;
- });
- }
- // Add this function to help with debugging
- function logPlaylist() {
- console.log("Current playlist order:");
- files.forEach((file, index) => {
- console.log(`${index}: ${file.name}`);
- });
- }
|