Аудио плеер на Java Script продвинутый

4.7 (94.55%) 11 vote[s]

Развивая тему, как сделать аудио плеер на Java Script, усложним задачу. Поставим цель: сделать возможность прослушивания плейлиста, добавить эквалайзер, громкость, панораму. Главное условие — чтобы это всё играло.

В коде дополнительно к уже имеющемуся (см. статью), реализован выпадающий список, функция получения значения атрибута «src» и вставка ссылок в зависимости от выбора. Также реализован простенький эквалайзер, громкость, баланс. Для красоты — бегущая строка с наименованием выбранной композиции.

Этот аудио плеер на Java Script уже достоин быть использованным для воспроизведения плейлистов на сайте. Для примера вставлены несколько композиций, в списке разделённые на категории. Треки можно вставлять свои, по усмотрению.

mp3Player

Воспроизведение:

00:00

Selected to play...

000

0 dB
0 dB
0 dB
0 dB
0 dB
0 dB

10    
0    

HTML:

<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  <title>mp3Player</title>
 <style>
	
#myCanvas {
  animation: color-me-in 5s infinite;
}

@keyframes color-me-in {
  50% {
    background: #64e4ed;
  }
  50% {
    background: #025721;
  }
  50% {
    background: #01232e;
  }
  50% {
    background: #64e4ed;
  }
}

div audio {
  display: block;
  margin-bottom:10px;
  margin-left:10px;
}

#myCanvas {
  width: 100%;
  height: 25% !important;
  border:1px solid;
  margin-left:auto;
  margin-right:auto;
  
}
.main {
  margin: 30px;
  border:1px solid #014347;
  border-radius:15px;
  background: linear-gradient(to top, #64bee8, #012c40);
  padding:10px;
  width:90%;
  
  box-shadow: 5px 5px 5px grey;
  text-align:center;
  font-family: "Open Sans";
  font-size: 12px;
}

div.controls label {
  display: inline-block;
  text-align: center;
  width: 10%;
}

div.controls label, div.controls input, output {
    width: 90%;
    vertical-align: middle;
    padding: 0;
    margin: 0;
    font-family: "Open Sans",Verdana,Geneva,sans-serif,sans-serif;
    font-size: 12px;
}

#key {
  margin-left:10%;
  width:80%;
  font-size: 22px;
  font-family: "Open Sans";
  color: #ffffff;
  padding:10px;
  border: 1px solid #04040d;
  border-radius: 4px;
  background:#17a3d1;
}
#sub {
  font-size: 18px;
  font-weight:normal;
  color:#001117;
  background:#7ed9f7;
}

</style>	
</head>
<body>  
  <form >
   <p><select id="key">
    <optgroup label="Рок" id="sub">
     <option value="https://www.babulya.com.ua/wp-content/uploads/2019/06/Queen-These-Are-The-Days-Of-Our-Lives.mp3"  
	 alt="Queen-These-Are-The-Days-Of-Our-Lives">Queen-These-Are-The-Days-Of-Our-Lives</option>
     <option value="https://www.babulya.com.ua/wp-content/uploads/2019/07/Bon-Jovi-It-My-Life.mp3" alt="Bon Jovi - It' My Life">Bon Jovi - It' My Life</option>
    </optgroup>
    
    <optgroup label="Блюз-рок  Поп-рок" id="sub">
      <option value="https://www.babulya.com.ua/wp-content/uploads/2019/07/Joe-Cocker-My-Fathers-Son.mp3" alt="Joe Cocker My Father's Son">Joe Cocker My 
        Father's Son</option>
       <option value="https://www.babulya.com.ua/wp-content/uploads/2019/07/Roxette-Crash-Boom-Bang.mp3" alt="Roxette - Crash! Boom! Bang!">Roxette - 
        Crash! Boom! Bang!</option>
    </optgroup>

    <optgroup label="Фолк" id="sub">
      <option value="https://www.babulya.com.ua/wp-content/uploads/2019/07/Квітка-Душа.mp3" alt="Квітка Душа">Квітка Душа</option>
    </optgroup>

    <optgroup label="New-Wave Techno" id="sub">
      <option value="https://www.babulya.com.ua/wp-content/uploads/2019/07/Yello-Drive-Driven.mp3" alt="Yello - Drive Driven">Yello - Drive 
        Driven</option>
    </optgroup>

    <optgroup label="Саундтреки" id="sub">
     <option value="https://www.babulya.com.ua/wp-content/uploads/2019/07/Игорь-Корнелюк-Воланд.mp3" alt="Игорь Корнелюк - Воланд">Игорь Корнелюк - 
        Воланд</option>
     <option value="https://www.babulya.com.ua/wp-content/uploads/2019/07/Игорь-Корнелюк-Титры.mp3" alt="Игорь Корнелюк - Титры">Игорь Корнелюк - Титры</option>
    </optgroup>

   </select></p>
   
  </form>
  
<div id='cntls'>
  <div class="main">

    <audio  id="player" controls  type="audio/mp3">
      <a type="audio/mp3"></a>
    </audio>
 
    <canvas id="myCanvas" width=1200 height=250></canvas>
 
      <p>
        Selected to play...<marquee><span id="keyTyped" style="font-size:18px;color:white;"></span></marquee>
      </p>
      <p id="demo"></p>
      <p id="demo2"></p>
      <p id="uot" style="color:black" >000</p>
<div id="myForm">	  
	  <div class="controls">
    <label>60Hz</label>
    <input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 0);"></input>
  <output id="gain0">0 dB</output>
  </div>
  <div class="controls">
    <label>170Hz</label>
    <input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 1);"></input>
<output id="gain1">0 dB</output>
  </div>
  <div class="controls">
    <label>350Hz</label>
    <input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 2);"></input>
<output id="gain2">0 dB</output>
  </div>
  <div class="controls">
    <label>1000Hz</label>
    <input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 3);"></input>
<output id="gain3">0 dB</output>
  </div>
  <div class="controls">
    <label>3500Hz</label>
    <input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 4);"></input>
<output id="gain4">0 dB</output>
  </div>
  <div class="controls">
    <label>10000Hz</label>
    <input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 5);"></input>
<output id="gain5">0 dB</output>
<p>
  </div>
  <div class="controls">
    <label>Master volume</label>
    <input type="range" value="10" step="0.1" min="0" max="10" oninput="changeMasterGain(this.value);"></input>
<output id="masterGainOutput">10&nbsp;&nbsp;&nbsp;&nbsp;</output>
  </div>
  <div class="controls">
    <label>Balance</label>
    <input type="range" value="0" step="0.1" min="-1" max="1" oninput="changeBalance(this.value);"></input>
<output id="balanceOutput">0&nbsp;&nbsp;&nbsp;&nbsp;</output>
  </div>
</div>	  
	  
  </div>
</div>

<script>
function say_hi() {
 var fname = document.getElementById('key').value;
 
$(document).ready(function() {

$('#key').change(function() { 
    var value = $('#key option:selected').text();
    $('#keyTyped').empty();
    $('#keyTyped').append('<span >'+value+'</span>');
  });
});
   
var x = document.getElementsByTagName("audio")[0].getAttribute("src"); 
  $("audio").attr("src", fname);

}
 
document.getElementById('key').addEventListener('click', say_hi);

//построить эквалайзер с несколькими фильтрами 
var audioCtx = window.AudioContext || window.webkitAudioContext;
var canvas;
var audioContext, canvasContext;
var analyser;
var width, height;
var dataArray, bufferLength;

window.onload = function() {
  audioContext= new audioCtx();
  
  canvas = document.querySelector("#myCanvas");
  width = canvas.width;
  height = canvas.height;
  canvasContext = canvas.getContext('2d');
  
  buildAudioGraph();
  
  requestAnimationFrame(visualize);
};

function buildAudioGraph() {
  var mediaElement = document.getElementById('player');
      mediaElement.onplay = (e) => {audioContext.resume();}

  // исправлено для политики автозапуска
  mediaElement.addEventListener('play',() => audioContext.resume());

  var sourceNode =   audioContext.createMediaElementSource(mediaElement);
  
analyser = audioContext.createAnalyser();
  
  analyser.fftSize = 512;
  bufferLength = analyser.frequencyBinCount;
  dataArray = new Uint8Array(bufferLength);
  
  sourceNode.connect(analyser);
  analyser.connect(audioContext.destination);
}

function visualize() {
  
  canvasContext.clearRect(0, 0, width, height);
  
  analyser.getByteFrequencyData(dataArray);

   var barWidth = width / bufferLength;
      var barHeight;
      var x = 0;
   
      heightScale = height/128;
  
      for(var i = 0; i < bufferLength; i++) {
        barHeight = dataArray[i];

        canvasContext.fillStyle = 'rgb(' + (barHeight+0) + ',4,160)';
        barHeight *= heightScale;
        canvasContext.fillRect(x, height-barHeight/2, barWidth, barHeight/2);

        x += barWidth + 2;
      }
  
  requestAnimationFrame(visualize);
  
}

var filters = [];
var masterGain, stereoPanner;
function buildAudioGraph() {
  var mediaElement = document.getElementById('player');
    mediaElement.onplay = (e)=>{audioContext.resume();}
    mediaElement.addEventListener('play',() => audioContext.resume());

  var sourceNode =   audioContext.createMediaElementSource(mediaElement);
  analyser = audioContext.createAnalyser();
  
  analyser.fftSize = 512;
  bufferLength = analyser.frequencyBinCount;
  dataArray = new Uint8Array(bufferLength);
  
  // создать эквалайзер из набора Фильтров

    // создать фильтры
    [60, 170, 350, 1000, 3500, 10000].forEach(function(freq, i) {
      var eq = audioContext.createBiquadFilter();
      eq.frequency.value = freq;
      eq.type = "peaking";
      eq.gain.value = 0;
      filters.push(eq);
    });

   // Подключить фильтры
   sourceNode.connect(filters[0]);
   for(var i = 0; i < filters.length - 1; i++) {
      filters[i].connect(filters[i+1]);
    }
  
    // Мастер громкости является узлом усиления
  masterGain = audioContext.createGain();
  masterGain.value = 1;

   // подключить последний фильтр к динамикам
   filters[filters.length - 1].connect(masterGain);
  
  // для стерео баланса, разделить сигнал
  stereoPanner = audioContext.createStereoPanner();
  // подключите вывод мастер-громкости к паннеру
  masterGain.connect(stereoPanner);
  
  // Подключить стерео паннер к анализатору, а анализатор к месту назначения
  stereoPanner.connect(analyser);  
  analyser.connect(audioContext.destination);
}

function changeGain(sliderVal,nbFilter) {
  var value = parseFloat(sliderVal);
  filters[nbFilter].gain.value = value;
  
  // обновить выходные метки
  var output = document.querySelector("#gain"+nbFilter);
  output.value = value + " dB";
}

function changeMasterGain(sliderVal) {
  var value = parseFloat(sliderVal);
  masterGain.gain.value =  value/10;
  
   // обновить выходные метки
  var output = document.querySelector("#masterGainOutput");
  output.value = value;
}

function changeBalance(sliderVal) {
  // между -1 and +1
  var value = parseFloat(sliderVal);
  
stereoPanner.pan.value = value;
   // обновить выходные метки
  var output = document.querySelector("#balanceOutput");
  output.value = value;
}

</script>  

</body>
</html>

Для этого примера использованы треки в сжатом формате .mp3, bitrate 96 kbps, depth 16 bit, resampling 128. Сжатие — для максимального уменьшения размера файлов без ущерба (относительного) качества звука.

Для доступа к атрибутам тегов использовался Jquery. Можете попробовать реализовать этот момент на чистом JS.

Бегущая строка реализована просто: при помощи тега HTML marquee:

<marquee><span id="keyTyped" style="font-size:18px;color:white;"></span></marquee>

П.с.(!): В обновленном варианте, который на странице, изменен стиль тега audio. Для этого удаляем атрибут controls (который указывает браузеру вставить стили по умолчанию — кнопку, слайдер, таймер, громкость) и создали свою форму при помощи элементов HTML-разметки и дополнительных Java Script-кодов (play, pause, timer, и, на всякий случай, вывод об ошибке, если возникнут проблемы с загрузкой трека или воспроизведением).

Добавлено:

CSS:

button {
background:#98f77e;
font-size:20px;
font-family: "Open Sans";
height:50px;
width:50%;
border: 1px solid #092900;
border-radius: 3px;
}
button:active {
background: #5f98ed;
}

HTML:

<div class="main">
  <!--вставляем после этого тега -->
<button onclick="playVid()" type="button" id="err">Play</button> 
   <button onclick="pauseVid()" type="button">Pause</button> 
 	<p style="font-size:18px;color:white;">Воспроизведение:<span id="demo4"></span></p>
	<p ><span id="demo5" style="font-size:18px;color:red;"></span></p>
	<span id="minutes" style="font-size:18px;color:white;">00</span><span style="font-size:18px;color:white;">:</span><span id="seconds" style="font-size:18px;color:white;">00</span>
<!--удаляем атрибут  controls -->
	<audio  id="player"   type="audio/mp3">

JS (вставляем сразу после открывающего тега <script>)

var vid = document.getElementById("player");
vid.onerror = function() {
    document.getElementById("demo5").innerHTML = "ОШИБКА! Что-то пошло не так...";
};

var vid = document.getElementById("player"); 

function playVid() { 
    vid.play(); 
	document.getElementById("demo5").innerHTML = "";	
} 

function pauseVid() { 
    vid.pause(); 
}

var vid = document.getElementById("player");

// Назначьте событие ontimeupdate для элемента и выполните функцию, если текущая позиция воспроизведения изменилась
vid.ontimeupdate = function() {myFunction()};

function myFunction() {
  // Показать текущую позицию воспроизведения в элементе p с id="demo"
  // Вычисляем кол-во минут, секунд и делаем корректный вывод в виде 00:00
  var d = parseInt((vid.currentTime)/60);
  var g = parseInt(vid.currentTime)%60;
  
  if(
  d<10)
  {document.getElementById("minutes").innerHTML = "0" + d + " ";
  }
  else
  {
  document.getElementById("minutes").innerHTML = " " + d + " ";
  }
  if(
  g<10)
  {
  document.getElementById("seconds").innerHTML = "0" + g ;
  }
  else{
  document.getElementById("seconds").innerHTML = " " + g ;
  }
}

Читайте больше по теме:

Подписаться
Уведомление о
guest
2 комментариев
старее
новее большинство голосов
Inline Feedbacks
View all comments
Роман
Роман
16.02.2020 23:03

Вы красавцы, правда! Молодцы! Спасибо)

Просмотры: 1629

Популярные записи