2017-07-27 115 views
1

我希望能够选择一个音乐文件夹并随机播放所有歌曲,并有一个跳过按钮+将歌曲文件名返回到可视化器,以便它可以可视化每首歌曲。我仍然在学习数组和循环,所以我不确定如何去做这件事。现在我也想远离额外的图书馆,因为一切都已经提供。下面有什么,我至今选择音乐文件夹html

window.onload = function() { 
 
    
 
    var file = document.getElementById("file"); 
 
    var audio = document.getElementById("audio"); 
 
    
 
    file.onchange = function() { 
 
    var files = this.files; 
 
    audio.src = URL.createObjectURL(files[0]); 
 
    audio.load(); 
 
    audio.play(); 
 
    var context = new AudioContext(); 
 
    var src = context.createMediaElementSource(audio); 
 
    var analyser = context.createAnalyser(); 
 

 
    var canvas = document.getElementById("canvas"); 
 
    canvas.width = window.innerWidth; 
 
    canvas.height = window.innerHeight; 
 
    var ctx = canvas.getContext("2d"); 
 

 
    src.connect(analyser); 
 
    analyser.connect(context.destination); 
 

 
    analyser.fftSize = 256; 
 

 
    var bufferLength = analyser.frequencyBinCount; 
 
    console.log(bufferLength); 
 

 
    var dataArray = new Uint8Array(bufferLength); 
 

 
    var WIDTH = canvas.width; 
 
    var HEIGHT = canvas.height; 
 

 
    var barWidth = (WIDTH/bufferLength) * 1; 
 
    var barHeight; 
 
    var x = 0; 
 

 
    function renderFrame() { 
 
     requestAnimationFrame(renderFrame); 
 
     x = 0; 
 

 
     analyser.getByteFrequencyData(dataArray); 
 

 
     ctx.fillStyle = "#1b1b1b"; 
 
     ctx.fillRect(0, 0, WIDTH, HEIGHT); 
 

 
     for (var i = 0; i < bufferLength; i++) { 
 
     barHeight = dataArray[i]; 
 
     
 
     var r = 5; 
 
     var g = 195; 
 
     var b = 45; 
 

 
     ctx.fillStyle = "rgb(5,195,45)" 
 
     ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight); 
 

 
     x += barWidth + 2; 
 
     } 
 
    } 
 

 
    audio.play(); 
 
    renderFrame(); 
 
    }; 
 
};
#file { 
 
    position: fixed; 
 
    top: 10px; 
 
    left: 10px; 
 
    z-index: 100; 
 
} 
 

 
#canvas { 
 
    position: fixed; 
 
    left: 0; 
 
    top: 0; 
 
    width: 100%; 
 
    height: 100%; 
 
} 
 

 
audio { 
 
    position: fixed; 
 
    left: 350px; 
 
    top: 10px; 
 
    width: calc(50% - 20px); 
 
}
<div id="content"> 
 
    <input type="file" id="file" accept="audio/*" /> 
 
    <canvas id="canvas"></canvas> 
 
    <audio id="audio" controls></audio> 
 
</div>

+0

你使用HTML和JavaScript代码的问题遇到了什么问题? – guest271314

+0

我根本不知道如何为此设置数组和循环。我很确定我必须设置某种形式的数组来收集我选择的文件夹中的所有音频文件,并且它是子文件夹。我还必须修改这些数组,或者根据每首歌的位置和随机顺序创建一个新数组。我脑中有了基本想法,我只是不确定如何执行它。 – Nickh90

+0

您可以在''元素中设置'webkitdirectory'和'allowdirs'属性来启用目录上传。迭代所有上传的目录以获取目录中的所有上传的'File'对象,设置为数组的元素,请参见[如何使用更改和放置事件在firefox和chrome/chromium上载和列出目录](https:// stackoverflow。 com/q/39664662 /) – guest271314

回答

1

的代码片段,您可以设定在<input type="file">元素webkitdirectoryallowdirs属性启用目录上传。

递归,或使用Promise反复迭代目录,包括目录中的目录,在目录中的所有文件推到全局定义File对象数组,见How to upload and list directories at firefox and chrome/chromium using change and drop events;其中Answer处的JavaScript被修改为删除drop事件处理程序,这不是需求的一部分。

使用Array.prototype.reduce()Promise调用按顺序的每个File对象播放媒体和ended事件HTMLMediaElement返回满足Promise的功能;例如,在Question的change处理程序处的匿名函数,在必要时进行修改,以实现通过上载N个目录或N个嵌套目录创建的播放列表的预期需求。请注意,调用时不止一次AudioContent.createMediaElementSource()更多具有相同<audio>元素作为参数,则将会抛出

Uncaught DOMException: Failed to execute 'createMediaElementSource' on 'AudioContext': HTMLMediaElement already connected previously to a different MediaElementSourceNode 

看到remove createMediaElementSource。您可以在全局范围内定义变量,并使用OR ||来引用变量以避免发生异常。

创建的Blob URL被分配给一个变量,在ended事件的HTMLMediaElement和被重新分配时,函数被再次调用,如果没有达到ended事件之前撤销。

包含<select>元素能够选择和播放任何一个上传的文件。

var input = document.getElementById("file"); 
 
    var audio = document.getElementById("audio"); 
 
    var selectLabel = document.querySelector("label[for=select]"); 
 
    var audioLabel = document.querySelector("label[for=audio]"); 
 
    var select = document.querySelector("select"); 
 
    var context = void 0, 
 
     src = void 0, 
 
     res = [], 
 
     url = ""; 
 

 
    function processDirectoryUpload(event) { 
 
     var webkitResult = []; 
 
     var mozResult = []; 
 
     var files; 
 
     console.log(event); 
 
     select.innerHTML = ""; 
 

 
     // do mozilla stuff 
 
     function mozReadDirectories(entries, path) { 
 
     console.log("dir", entries, path); 
 
     return [].reduce.call(entries, function(promise, entry) { 
 
      return promise.then(function() { 
 
       return Promise.resolve(entry.getFilesAndDirectories() || entry) 
 
       .then(function(dir) { 
 
        return dir 
 
       }) 
 
      }) 
 
      }, Promise.resolve()) 
 
      .then(function(items) { 
 
      var dir = items.filter(function(folder) { 
 
       return folder instanceof Directory 
 
      }); 
 
      var files = items.filter(function(file) { 
 
       return file instanceof File 
 
      }); 
 
      if (files.length) { 
 
       // console.log("files:", files, path); 
 
       mozResult = mozResult.concat.apply(mozResult, files); 
 
      } 
 
      if (dir.length) { 
 
       // console.log(dir, dir[0] instanceof Directory); 
 
       return mozReadDirectories(dir, dir[0].path || path); 
 

 
      } else { 
 
       if (!dir.length) { 
 
       return Promise.resolve(mozResult).then(function(complete) { 
 
        return complete 
 
       }) 
 
       } 
 
      } 
 

 
      }) 
 

 
     }; 
 

 
     function handleEntries(entry) { 
 
     let file = "webkitGetAsEntry" in entry ? entry.webkitGetAsEntry() : entry 
 
     return Promise.resolve(file); 
 
     } 
 

 
     function handleFile(entry) { 
 
     return new Promise(function(resolve) { 
 
      if (entry.isFile) { 
 
      entry.file(function(file) { 
 
       listFile(file, entry.fullPath).then(resolve) 
 
      }) 
 
      } else if (entry.isDirectory) { 
 
      var reader = entry.createReader(); 
 
      reader.readEntries(webkitReadDirectories.bind(null, entry, handleFile, resolve)) 
 
      } else { 
 
      var entries = [entry]; 
 
      return entries.reduce(function(promise, file) { 
 
       return promise.then(function() { 
 
        return listDirectory(file) 
 
       }) 
 
       }, Promise.resolve()) 
 
       .then(function() { 
 
       return Promise.all(entries.map(function(file) { 
 
        return listFile(file) 
 
       })).then(resolve) 
 
       }) 
 
      } 
 
     }) 
 

 
     function webkitReadDirectories(entry, callback, resolve, entries) { 
 
      console.log(entries); 
 
      return listDirectory(entry).then(function(currentDirectory) { 
 
      console.log(`iterating ${currentDirectory.name} directory`, entry); 
 
      return entries.reduce(function(promise, directory) { 
 
       return promise.then(function() { 
 
       return callback(directory) 
 
       }); 
 
      }, Promise.resolve()) 
 
      }).then(resolve); 
 
     } 
 

 
     } 
 

 
     function listDirectory(entry) { 
 
     console.log(entry); 
 
     return Promise.resolve(entry); 
 
     } 
 

 
     function listFile(file, path) { 
 
     path = path || file.webkitRelativePath || "/" + file.name; 
 
     console.log(`reading ${file.name}, size: ${file.size}, path:${path}`); 
 
     webkitResult.push(file); 
 
     return Promise.resolve(webkitResult) 
 
     }; 
 

 
     function processFiles(files) { 
 
     Promise.all([].map.call(files, function(file, index) { 
 
      return handleEntries(file, index).then(handleFile) 
 
      })) 
 
      .then(function() { 
 
      console.log("complete", webkitResult); 
 
      res = webkitResult; 
 
      res.reduce(function(promise, track) { 
 
       return promise.then(function() { 
 
       return playMusic(track) 
 
       }) 
 
      }, displayFiles(res)) 
 
      }) 
 
      .catch(function(err) { 
 
      alert(err.message); 
 
      }) 
 
     } 
 

 
     if ("getFilesAndDirectories" in event.target) { 
 
     return (event.type === "drop" ? event.dataTransfer : event.target).getFilesAndDirectories() 
 
      .then(function(dir) { 
 
      if (dir[0] instanceof Directory) { 
 
       console.log(dir) 
 
       return mozReadDirectories(dir, dir[0].path || path) 
 
       .then(function(complete) { 
 
        console.log("complete:", webkitResult); 
 
        event.target.value = null; 
 
       }); 
 
      } else { 
 
       if (dir[0] instanceof File && dir[0].size > 0) { 
 
       return Promise.resolve(dir) 
 
        .then(function() { 
 
        console.log("complete:", mozResult); 
 
        res = mozResult; 
 
        res.reduce(function(promise, track) { 
 
         return promise.then(function() { 
 
         return playMusic(track) 
 
         }) 
 
        }, displayFiles(res)) 
 
        }) 
 
       } else { 
 
       if (dir[0].size == 0) { 
 
        throw new Error("could not process '" + dir[0].name + "' directory" + " at drop event at firefox, upload folders at 'Choose folder...' input"); 
 
       } 
 
       } 
 
      } 
 
      }).catch(function(err) { 
 
      alert(err) 
 
      }) 
 
     } 
 

 
     files = event.target.files; 
 

 
     if (files) { 
 
     processFiles(files) 
 
     } 
 

 
    } 
 

 
    function displayFiles(files) { 
 
     select.innerHTML = ""; 
 
     return Promise.all(files.map(function(file, index) { 
 
     return new Promise(function(resolve) { 
 
      var option = new Option(file.name, index); 
 
      select.appendChild(option); 
 
      resolve() 
 
     }) 
 
     })) 
 
    } 
 

 
    function handleSelectedSong(event) { 
 
     if (res.length) { 
 
     var index = select.value; 
 
     var track = res[index]; 
 
     playMusic(track) 
 
      .then(function(filename) { 
 
      console.log(filename + " playback completed") 
 
      }) 
 
     } else { 
 
     console.log("No songs to play") 
 
     } 
 
    } 
 

 
    function playMusic(file) { 
 
     return new Promise(function(resolve) { 
 
     audio.pause(); 
 
     audio.onended = function() { 
 
      audio.onended = null; 
 
      if (url) URL.revokeObjectURL(url); 
 
      resolve(file.name); 
 
     } 
 
     if (url) URL.revokeObjectURL(url); 
 
     url = URL.createObjectURL(file); 
 
     audio.load(); 
 
     audio.src = url; 
 
     audio.play(); 
 
     audioLabel.textContent = file.name; 
 
     context = context || new AudioContext(); 
 
     src = src || context.createMediaElementSource(audio); 
 
     src.disconnect(context); 
 

 
     var analyser = context.createAnalyser(); 
 

 
     var canvas = document.getElementById("canvas"); 
 
     canvas.width = window.innerWidth; 
 
     canvas.height = window.innerHeight; 
 
     var ctx = canvas.getContext("2d"); 
 

 
     src.connect(analyser); 
 
     analyser.connect(context.destination); 
 

 
     analyser.fftSize = 256; 
 

 
     var bufferLength = analyser.frequencyBinCount; 
 
     console.log(bufferLength); 
 

 
     var dataArray = new Uint8Array(bufferLength); 
 

 
     var WIDTH = canvas.width; 
 
     var HEIGHT = canvas.height; 
 

 
     var barWidth = (WIDTH/bufferLength) * 1; 
 
     var barHeight; 
 
     var x = 0; 
 

 
     function renderFrame() { 
 
      requestAnimationFrame(renderFrame); 
 
      x = 0; 
 

 
      analyser.getByteFrequencyData(dataArray); 
 

 
      ctx.fillStyle = "#1b1b1b"; 
 
      ctx.fillRect(0, 0, WIDTH, HEIGHT); 
 

 
      for (var i = 0; i < bufferLength; i++) { 
 
      barHeight = dataArray[i]; 
 

 
      var r = 5; 
 
      var g = 195; 
 
      var b = 45; 
 

 
      ctx.fillStyle = "rgb(5,195,45)" 
 
      ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight); 
 

 
      x += barWidth + 2; 
 
      } 
 
     } 
 

 
     renderFrame(); 
 
     }) 
 
    } 
 

 
    input.addEventListener("change", processDirectoryUpload); 
 
    select.addEventListener("change", handleSelectedSong);
<div id="content"> 
 
    Upload directory: <input id="file" type="file" accept="audio/*" directory allowdirs webkitdirectory/><br> 
 
    <br>Now playing: <label for="audio"></label><br> 
 
    <br><label for="select">Select a song to play:</label><br> 
 
    <select id="select"> 
 
    </select> 
 
    <canvas id="canvas"></canvas> 
 
    <audio id="audio" controls></audio> 
 
</div>

+0

这个伟大的工程,但现在我将如何防止它能够选择特定的文件扩展像JPG和PNG防止“抛出:DOMException:无法加载,因为没有支持的源被找到。”错误 – Nickh90

+0

@NickHewitt您无法阻止用户选择某些文件类型。你可以做的是在设置之前使用'if..else'来检查在'Promise'构造函数的解析器函数的第一行'playMusic'函数中'File'对象'.type'属性是否以'audio'开头'' '