Парсить и играть список треков
Здравствуйте! Пишу сейчас плеер на JS.... Как играть аудио - я понимаю и знаю. Но, если это не ограничивается 1 mp3 файлом?
У меня страница отдает json со списком аудио, но как это обернуть так, чтоб играли все треки - не нашел материала. Так же как и не нашел о том, как сделать эвенты для смены треков (бинд клавиатуры так же знаю, загвоздка в логике смены аудиотреков) var playlist = new Array(); //console.log(musicarray); var musicarray = {<?=$playlist;?>}; //console.log(musicarray.playlist.length); var i; //var audioURL = new array(); //var audioindex = 0; for(i = 0; i < musicarray.playlist.length; i++) { //var audios = this; //console.log(i++); //console.log(musicarray.playlist[i].url); playlist[i] = musicarray.playlist[i].url; //console.log(audioURL); //audioindex ++; } //var audioURL = audiourls.url; i = 0; //clearTimeout(timeout) for(i = 0; i < playlist.length; i++) { // Load asynchronously var request = new XMLHttpRequest(); request.open("GET", playlist[i], true); console.log(request); request.responseType = "arraybuffer"; request.onload = function() { audioContext.decodeAudioData(request.response, function(buffer) { audioBuffer = buffer; var duration = audioBuffer.duration; //console.log(audioBuffer); startSound(); getduration(); }, function(e) { $('#prompt').text("error loading mp3"); console.log(e); }); }; request.send(); getduration = function(){ console.log(parseInt(audioBuffer.duration, 10)); //timeout = setTimeout(parseInt(audioBuffer.duration, 10)*1000); } }; var playing; function startSound() { if (source){ source.stop(0.0); source.disconnect(); } // Connect audio processing graph source = audioContext.createBufferSource(); source.connect(audioContext.destination); source.connect(analyser); source.buffer = audioBuffer; source.loop = false; source.start(0.0); startViz(); playing = this; return playing; console.log(playing); } /*source.onended = function() { console.log('Your audio has finished playing'); }*/ //} |
Обратите внимание, что первый объект (Audio) служит исключительно в качестве эмуляции элемента аудио (чтобы можно было запустить пример).
/** * Эмуляция аудио объекта * @param {string} src * @constructor */ var Audio = function (src) { this._time = Audio.randomInt(1000, 4000); this._timer = null; this._timeStart = null; this._events = {}; this.src = src; var that = this; setTimeout(function () { that._trigger("canplay"); }, Audio.randomInt(0, 500)); }; /** * подписка на события * @param {string} event * @param {function} handler */ Audio.prototype.addEventListener = function (event, handler) { if (!this._events[event]) this._events[event] = []; this._events[event].push(handler); }; /** * Запускаем проигрывание */ Audio.prototype.play = function () { var that = this; this._trigger("play"); this._timeStart = Date.now(); this._timer = setTimeout(function () { that._trigger("ended") }, this._time); }; /** * Ставим на паузу */ Audio.prototype.pause = function () { if (this._timer) { clearTimeout(this._timer); this._timer = null; this._time = Date.now() - this._timeStart; this._timeStart = null; } }; /** * Снимаем обработчики * @param {string} event * @param {function} handler */ Audio.prototype.removeEventListener = function (event, handler) { if (this._events[event]) { this._events[event] = this._events[event].filter(function ($handler) { return $handler != handler; }); } }; /** * Запускаем событие * @param event * @private */ Audio.prototype._trigger = function (event) { if (this._events[event]) { this._events[event].forEach(function (handler) { handler.call(this); }, this); } }; /** * Генерируем целое рандомное число * @param {number} min * @param {number} max * @returns {number} */ Audio.randomInt = function (min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }; /** * Менеджер треков * @param {string[]} tracks * @constructor */ var TrackManager = function (tracks) { this._active = 0; this._collection = []; this._createTracks(tracks); }; /** * Запускаем проигрывание треков */ TrackManager.prototype.play = function () { if (this._active in this._collection) { this._collection[this._active].play(); } }; /** * Создаем треки и подписываемся на события * @param {string[]} tracks * @private */ TrackManager.prototype._createTracks = function (tracks) { tracks.forEach(function (src) { var audio = new Audio(src), that = this; audio.addEventListener("canplay", function () { console.log(this.src + " canplay"); }); audio.addEventListener("play", function () { console.log(this.src + " play"); }); audio.addEventListener("ended", function () { alert(this.src + " ended"); that._onEnd(); }); this._collection.push(audio); }, this); }; /** * Запускаем следующий трек когда заканчивается предыдущий; * @private */ TrackManager.prototype._onEnd = function () { this._active++; this.play(); }; new TrackManager(["some1.mp3", "some2.mp3", "some3.mp3", "some4.mp3"]).play(); |
Огромное спасибо за наводку. Однако, Ваш пример у меня не отработал вовсе. Он сразу же выдал, что трек кончился, хотя даже и не начал играть.(
|
////////////////////////////// /** * Эмуляция аудио объекта * @param {string} src * @constructor */ var Audio = function (src) { this._time = Audio.randomInt(1000, 4000); this._timer = null; this._timeStart = null; this._events = {}; this.src = src; var that = this; setTimeout(function () { that._trigger("canplay"); }, Audio.randomInt(0, 500)); }; /** * подписка на события * @param {string} event * @param {function} handler */ Audio.prototype.addEventListener = function (event, handler) { if (!this._events[event]) this._events[event] = []; this._events[event].push(handler); }; /** * Запускаем проигрывание */ Audio.prototype.play = function () { var that = this; this._trigger("play"); this._timeStart = Date.now(); this._timer = setTimeout(function () { that._trigger("ended") }, this._time); }; /** * Ставим на паузу */ Audio.prototype.pause = function () { if (this._timer) { clearTimeout(this._timer); this._timer = null; this._time = Date.now() - this._timeStart; this._timeStart = null; } }; /** * Снимаем обработчики * @param {string} event * @param {function} handler */ Audio.prototype.removeEventListener = function (event, handler) { if (this._events[event]) { this._events[event] = this._events[event].filter(function ($handler) { return $handler != handler; }); } }; /** * Запускаем событие * @param event * @private */ Audio.prototype._trigger = function (event) { if (this._events[event]) { this._events[event].forEach(function (handler) { handler.call(this); }, this); } }; /** * Генерируем целое рандомное число * @param {number} min * @param {number} max * @returns {number} */ Audio.randomInt = function (min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }; /** * Менеджер треков * @param {string[]} tracks * @constructor */ var TrackManager = function (tracks) { this._active = 0; this._collection = []; this._createTracks(tracks); }; /** * Запускаем проигрывание треков */ TrackManager.prototype.play = function () { if (this._active in this._collection) { this._collection[this._active].play(); } }; /** * Создаем треки и подписываемся на события * @param {string[]} tracks * @private */ TrackManager.prototype._createTracks = function (tracks) { tracks.forEach(function (src) { var audio = new Audio(src), that = this; audio.addEventListener("canplay", function () { console.log(this.src + " canplay"); }); audio.addEventListener("play", function () { var request = new XMLHttpRequest(); request.open("GET", this.src, true); //console.log(request); request.responseType = "arraybuffer"; request.onload = function() { audioContext.decodeAudioData(request.response, function(buffer) { audioBuffer = buffer; var duration = audioBuffer.duration; //console.log(audioBuffer); startSound(); getduration(); }, function(e) { $('#prompt').text("error loading mp3"); console.log(e); }); }; request.send(); }); audio.addEventListener("ended", function () { alert(this.src + " ended"); that._onEnd(); }); this._collection.push(audio); }, this); }; /** * Запускаем следующий трек когда заканчивается предыдущий; * @private */ TrackManager.prototype._onEnd = function () { this._active++; var request = new XMLHttpRequest(); request.open("GET", this.src, true); //console.log(request); request.responseType = "arraybuffer"; request.onload = function() { audioContext.decodeAudioData(request.response, function(buffer) { audioBuffer = buffer; var duration = audioBuffer.duration; //console.log(audioBuffer); startSound(); getduration(); }, function(e) { $('#prompt').text("error loading mp3"); console.log(e); }); }; request.send(); }; var playlist = new Array(); var musicarray = {<?=$playlist;?>}; //console.log(musicarray.playlist.length); var i; //var audioURL = new array(); //var audioindex = 0; for(i = 0; i < musicarray.playlist.length; i++) { //var audios = this; //console.log(i++); //console.log(musicarray.playlist[i].url); playlist[i] = musicarray.playlist[i].url; //console.log(audioURL); //audioindex ++; } //console.log(playlist); new TrackManager(playlist).play(); console.log(TrackManager); ///////////////////////////// var playing; function startSound() { if (source){ source.stop(0.0); source.disconnect(); } // Connect audio processing graph source = audioContext.createBufferSource(); source.connect(audioContext.destination); source.connect(analyser); source.buffer = audioBuffer; source.loop = false; source.start(0.0); startViz(); playing = this; return playing; console.log(playing); } По вашему примеру сделал так - тут же выдает единоразово, что трек "url трека" ended и один раз он проиграл, а второй раз - нет. |
Добавил в функцию воспроизведения
this.onended = function() { console.log('Your audio has finished playing'); } Ничего не отработало |
Как не кручу - он не обрабатывает onended (
|
Спасибо огромное, сделал по вашему совету - все работает как надо, осталась проблема с вопросом рандомного воспроизведения, изменения уровней громкости по событиям клавиатуры (keyup и keydown) и смены треков по keyleft keyright и паузы по keyspace
////////////////////////////// /** * Эмуляция аудио объекта * @param {string} src * @constructor */ var Audio = function (src) { this._time = Audio.randomInt(1000, 4000); this._timer = null; this._timeStart = null; this._events = {}; this.src = src; var that = this; setTimeout(function () { that._trigger("canplay"); }, Audio.randomInt(0, 500)); }; /** * подписка на события * @param {string} event * @param {function} handler */ Audio.prototype.addEventListener = function (event, handler) { if (!this._events[event]) this._events[event] = []; this._events[event].push(handler); }; /** * Запускаем проигрывание */ Audio.prototype.play = function () { var that = this; this._trigger("play"); this._timeStart = Date.now(); this._timer = setTimeout(function () { that._trigger("ended") }, this._time); }; /** * Ставим на паузу */ Audio.prototype.pause = function () { if (this._timer) { clearTimeout(this._timer); this._timer = null; this._time = Date.now() - this._timeStart; this._timeStart = null; } }; /** * Снимаем обработчики * @param {string} event * @param {function} handler */ Audio.prototype.removeEventListener = function (event, handler) { if (this._events[event]) { this._events[event] = this._events[event].filter(function ($handler) { return $handler != handler; }); } }; /** * Запускаем событие * @param event * @private */ Audio.prototype._trigger = function (event) { if (this._events[event]) { this._events[event].forEach(function (handler) { handler.call(this); }, this); } }; /** * Генерируем целое рандомное число * @param {number} min * @param {number} max * @returns {number} */ Audio.randomInt = function (min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }; /** * Менеджер треков * @param {string[]} tracks * @constructor */ var TrackManager = function (tracks) { this._active = 0; this._collection = []; this._createTracks(tracks); }; console.log(i); /** * Запускаем проигрывание треков */ TrackManager.prototype.play = function () { if (this._active in this._collection) { var media = this; var request = new XMLHttpRequest(); request.open("GET", this._collection[this._active].src, true); //console.log(request); request.responseType = "arraybuffer"; request.onload = function() { audioContext.decodeAudioData(request.response, function(buffer) { audioBuffer = buffer; //console.log(audioBuffer); if (this.started){ source.stop(0.0); source.disconnect(); } // Connect audio processing graph source = audioContext.createBufferSource(); source.connect(audioContext.destination); source.connect(analyser); source.buffer = audioBuffer; source.loop = false; source.start(0.0); startViz(); source.onended = function(){ mediaplay = media; //return mediaplay; console.log(mediaplay._active); TrackManager.prototype._onEnd(mediaplay); }; }, function(e) { $('#prompt').text("error loading mp3"); console.log(e); }); }; request.send(); console.log(this); //console.log(source); }; }; /** * Создаем треки и подписываемся на события * @param {string[]} tracks * @private */ TrackManager.prototype._createTracks = function (tracks) { tracks.forEach(function (src) { var audio = new Audio(src), that = this; audio.addEventListener("canplay", function () { console.log(this.src + " canplay"); }); audio.addEventListener("play", function () { console.log(this.src + " play"); }); audio.addEventListener("ended", function () { alert(this.src + " ended"); that._onEnd(); }); this._collection.push(audio); }, this); }; /** * Запускаем следующий трек когда заканчивается предыдущий; * @private */ TrackManager.prototype._onEnd = function () { //var media = this; mediaplay._active++; if(mediaplay._active > mediaplay._collection.length - 1) { mediaplay._active = 0; } console.log(mediaplay); var request = new XMLHttpRequest(); request.open("GET", mediaplay._collection[mediaplay._active].src, true); //console.log(request); request.responseType = "arraybuffer"; request.onload = function() { audioContext.decodeAudioData(request.response, function(buffer) { audioBuffer = buffer; //console.log(audioBuffer); if (source){ source.stop(0.0); source.disconnect(); } // Connect audio processing graph source = audioContext.createBufferSource(); source.connect(audioContext.destination); source.connect(analyser); source.buffer = audioBuffer; source.loop = false; source.start(0.0); startViz(); playing = this; //return playing; console.log(playing); source.onended = function() { //console.log(mediaplay); console.log(mediaplay._collection.length); TrackManager.prototype._onEnd(mediaplay); } }, function(e) { $('#prompt').text("error loading mp3"); console.log(e); }); }; request.send(); }; //console.log(media); var playlist = new Array(); var musicarray = {<?=$playlist;?>}; var i; for(i = 0; i < musicarray.playlist.length; i++) { playlist[i] = musicarray.playlist[i].url; } new TrackManager(playlist).play(); console.log(TrackManager); |
С рандомным воспроизведением очень просто:
Вместо this._collection[this._active].play() надо this._collection[Audio.randomInt(0, this._collection.length)].play(); с кнопочками тоже просто: document.addEventListener("keydown", function (e) { if (e.keyCode == /*номер клавиш вверх и вниз посмотри в таблице символов*/) { /* добавляем или убовляем звук */ } }, false); |
Что-то с регулировкой звука никак((
///////////////////////// // do it with volume! ///////////////////////// console.log(gainNode); document.addEventListener("keydown", function (e) { if (e.keyCode == 40){ //alert('keydown'); gainNode.gain.value = gainNode.gain.value - 0.2; console.log(gainNode.gain.value); gainNode.connect(audioContext.destination); } }, false); } |
Полностью кусок кода с CreateGainNode
//init audio analyser = audioContext.createAnalyser(); analyser.smoothingTimeConstant = 0.1; analyser.fftSize = 1024; var gainNode = audioContext.createGain(); //init 3D scene container = document.createElement('div'); document.body.appendChild(container); camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000000); camera.position.z = 2000; scene = new THREE.Scene(); scene.add(camera); renderer = new THREE.WebGLRenderer({ antialias : false, sortObjects : false }); renderer.setSize(window.innerWidth, window.innerHeight); container.appendChild(renderer.domElement); // stop the user getting a text cursor document.onselectStart = function() { return false; }; //add stats stats = new Stats(); stats.domElement.style.position = 'absolute'; stats.domElement.style.top = '0px'; container.appendChild(stats.domElement); //init listeners $("#loadSample").loadSampleAudio; $(document).mousemove(onDocumentMouseMove); container.addEventListener( 'touchstart', onDocumentTouchStart, false ); container.addEventListener( 'touchmove', onDocumentTouchMove, false ); onWindowResize(null); LoopVisualizer.init(); ///////////////////////// // do it with volume! ///////////////////////// console.log(gainNode); document.addEventListener("keydown", function (e) { if (e.keyCode == 40){ //alert('keydown'); gainNode.gain.value = gainNode.gain.value - 0.2; console.log(gainNode.gain.value); } }, false); gainNode.connect(audioContext.destination); } ////////////////////////////// /** * Эмуляция аудио объекта * @param {string} src * @constructor */ var Audio = function (src) { this._time = Audio.randomInt(1000, 4000); this._timer = null; this._timeStart = null; this._events = {}; this.src = src; var that = this; setTimeout(function () { that._trigger("canplay"); }, Audio.randomInt(0, 500)); }; /** * подписка на события * @param {string} event * @param {function} handler */ Audio.prototype.addEventListener = function (event, handler) { if (!this._events[event]) this._events[event] = []; this._events[event].push(handler); }; /** * Запускаем проигрывание */ Audio.prototype.play = function () { var that = this; this._trigger("play"); this._timeStart = Date.now(); this._timer = setTimeout(function () { that._trigger("ended") }, this._time); }; /** * Ставим на паузу */ Audio.prototype.pause = function () { if (this._timer) { clearTimeout(this._timer); this._timer = null; this._time = Date.now() - this._timeStart; this._timeStart = null; } }; /** * Снимаем обработчики * @param {string} event * @param {function} handler */ Audio.prototype.removeEventListener = function (event, handler) { if (this._events[event]) { this._events[event] = this._events[event].filter(function ($handler) { return $handler != handler; }); } }; /** * Запускаем событие * @param event * @private */ Audio.prototype._trigger = function (event) { if (this._events[event]) { this._events[event].forEach(function (handler) { handler.call(this); }, this); } }; /** * Генерируем целое рандомное число * @param {number} min * @param {number} max * @returns {number} */ Audio.randomInt = function (min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }; /** * Менеджер треков * @param {string[]} tracks * @constructor */ var TrackManager = function (tracks) { this._active = 0; this._collection = []; this._createTracks(tracks); }; console.log(i); /** * Запускаем проигрывание треков */ TrackManager.prototype.play = function () { if (this._active in this._collection) { var media = this; var request = new XMLHttpRequest(); request.open("GET", this._collection[Audio.randomInt(0, this._collection.length-1)].src, true); //console.log(request); request.responseType = "arraybuffer"; request.onload = function() { audioContext.decodeAudioData(request.response, function(buffer) { audioBuffer = buffer; //console.log(audioBuffer); if (this.started){ source.stop(0.0); source.disconnect(); } // Connect audio processing graph source = audioContext.createBufferSource(); source.connect(audioContext.destination); source.connect(analyser); source.buffer = audioBuffer; source.loop = false; source.start(0.0); startViz(); source.onended = function(){ mediaplay = media; //return mediaplay; console.log(mediaplay._active); TrackManager.prototype._onEnd(mediaplay); }; }, function(e) { $('#prompt').text("error loading mp3"); console.log(e); }); }; request.send(); console.log(this); //console.log(source); }; }; console.log(audioContext); /** * Создаем треки и подписываемся на события * @param {string[]} tracks * @private */ TrackManager.prototype._createTracks = function (tracks) { tracks.forEach(function (src) { var audio = new Audio(src), that = this; audio.addEventListener("canplay", function () { console.log(this.src + " canplay"); }); audio.addEventListener("play", function () { console.log(this.src + " play"); }); audio.addEventListener("ended", function () { alert(this.src + " ended"); that._onEnd(); }); this._collection.push(audio); }, this); }; /** * Запускаем следующий трек когда заканчивается предыдущий; * @private */ TrackManager.prototype._onEnd = function () { //var media = this; mediaplay._active++; if(mediaplay._active > mediaplay._collection.length - 1) { mediaplay._active = 0; } console.log(mediaplay); var request = new XMLHttpRequest(); request.open("GET", mediaplay._collection[Audio.randomInt(0, mediaplay._collection.length-1)].src, true); //console.log(request); request.responseType = "arraybuffer"; request.onload = function() { audioContext.decodeAudioData(request.response, function(buffer) { audioBuffer = buffer; //console.log(audioBuffer); if (source){ source.stop(0.0); source.disconnect(); } // Connect audio processing graph source = audioContext.createBufferSource(); source.connect(audioContext.destination); source.connect(analyser); source.buffer = audioBuffer; source.loop = false; source.start(0.0); startViz(); playing = this; //return playing; console.log(playing); source.onended = function() { //console.log(mediaplay); //console.log(mediaplay._collection.length); TrackManager.prototype._onEnd(mediaplay); } }, function(e) { $('#prompt').text("error loading mp3"); console.log(e); }); }; request.send(); }; //console.log(media); var playlist = new Array(); var musicarray = {<?=$playlist;?>}; var i; for(i = 0; i < musicarray.playlist.length; i++) { playlist[i] = musicarray.playlist[i].url; } new TrackManager(playlist).play(); console.log(TrackManager); |
Часовой пояс GMT +3, время: 17:02. |