0

I'm trying to load different sounds (.mp3 audio) on different audio players appeared on one HTML page. That is, the length of the array determines the number of players appeared on the screen. So, in this example I have 3 elements in the array. Therefore, 3 audio players playing 3 different things.

I've managed to place 3 players on the page one underneath each other as I did for their equivalent texts (Animals sounds) but I'm facing the following problems:

  1. Each player is playing the same sound rather incrementing and playing each for different player. I used a "for loop" to increment through the array, but I couldn't find a way to let it "remember" the old audio so it always plays the last sound through all players. In this case it only plays "Cat".

  2. Even when I click on the empty line, between the 1st and 2nd player, where there's no audio player - the sound is still playing and I can't figure out why...

I would appreciate very much any help!!!

//use JQuery to grab the audioID and play the audio 
jQuery(document).ready(function() {
 var speakWord = document.getElementsByClassName('speakout');
   var nowPlaying = speakWord[0];
   nowPlaying.load();
   $("#divAudio").on("click", function() {
   nowPlaying.play();
   });
 }); 

var textBox = document.getElementById('inBox');      //Responsible for printing words
var player = document.getElementById('myPlayer');   //PLAYING the sound (<audio>)
var outArr = ['Dog', 'Cow','Cat'];
var pathArr = ['http://cd.textfiles.com/mmplus/MEDIA/WAV/EFFECTS/BARK.WAV', 'http://www.internetstart.se/download/ljud/moo.wav', 'http://area512.htmlplanet.com/wavs/blackcat.wav'];
var audioLogo = document.getElementById('divAudio');  //for the APPEREANCE of the audio player (LOGO)
var img_audio = document.createElement("IMG");    // properties of the IMAGE 
br = document.createElement("br");             //creating a break in the document 
var new_audio = document.createElement("audio");

var points = 50;

if(outArr.constructor === Array) {
 //audioLogo.style.display = "initial";
 for(i=0; i < outArr.length; ++i) {
  
  //regarding the TEXT elements:
  textBox.innerHTML += outArr[i]+'<br>';  
  textBox.style.fontSize = "30px";
  textBox.style.position = "absolute";
  textBox.style.top = String(points)+'pt';
  textBox.style.marginRight= "5pt";
  textBox.style.lineHeight = "71pt";
  textBox.style.right = '5pt'; 
 }
}
else {
 textBox.innerHTML += outArr;
 textBox.style.fontSize = "30px";
 textBox.style.position = "absolute";
 textBox.style.top = "76pt";
}
var points = 70;
for(i=0; i < pathArr.length; ++i) {
   var new_audio = document.createElement("audio");
   var multiAud = audioLogo.querySelectorAll('.multiple_audio');
   
   imgArr =  Array(pathArr.length).fill('http://www.coli.uni-saarland.de/~andreeva/powin/images/sound.png');
   if(i<1){
   img_audio.style.height = "9%";  //the size of the audio logo
   img_audio.style.width = "9%";
   img_audio.setAttribute("src", imgArr[i]); //creating an attribute (image) to be added to doc
   audioLogo.style.position = "absolute";   
   audioLogo.style.top = '58pt';  
   audioLogo.style.lineHeight = "73pt";
   player.src = pathArr[i]; 
   audioLogo.appendChild(img_audio); 
   audioLogo.innerHTML +=  '<br>';
   }
   else {
   var audio = new Audio(pathArr[i]);
   audio.className = 'multiple_audio';
   img_audio.style.height = "9%";
   img_audio.style.width = "9%";
   img_audio.setAttribute("src", imgArr[i]); //creating an attribute (image) to be added to doc
   audioLogo.style.position = "absolute";
   audioLogo.style.top = '58pt';
   audioLogo.style.lineHeight = "73pt";
   audioLogo.appendChild(img_audio);
   player.src = pathArr[i]; 
   audioLogo.innerHTML +=  '<br>';
   //player.parentNode.insertBefore(audio , player.nextNode); 
   }
   
  }
#layout {
position: relative;
overflow: auto;
left: 225px;
width:  800px;
height: 370px;
background-color: white;  
padding-left: 1px;
max-width:100%;
}

#myText {
pointer-events: none;
width:  800px;
height: 370px;
resize: none;
font-size: 45px;
font-family: Arial, Helvetica, Verdana;
background: url(https://qph.is.quoracdn.net/main-qimg-47327da6ae3e0b3727a9b9a7ea7f1adb?convert_to_webp=true);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<html lang="en">
    <head>
 <meta charset="utf-8"/>
    <script type="text/javascript" src="jquery-1.11.3.js"></script>
    </head>
    <body>
 <br>
  <div id="layout" readonly="readonly">
  <div contenteditable maxlength="200" readonly="readonly" id="myText" dir="auto" name="outtest" class = "fetchBox"></div> 
  <div id="inBox" class="fetch" dir="auto"></div>
  
   <audio class="speakout" id="myPlayer"> 

   Your Browser does not support the HTML audio Tag!
  </audio>
  
  <div class="play" id="divAudio"><img id="play_image"> </div>
  
  </div>
    
</body>
  
</html>

P.S

  • The audio tags must not be the standard one with play/pause appeared as default. I used my own player logo but for this example I linked a logo from an absolute URL.

  • I tried to use hints from this other post (multiple and dynamic audio players applied for a dictionary in HTML/JavaScript) but that didn't work so well. I tried to use

    var audio = new Audio(); and

    player.parentNode.insertBefore(audio , player.nextNode);

to solve problem 1. Not sure, maybe because didn't use the standard player?

Community
  • 1
  • 1
Apython
  • 453
  • 6
  • 19

1 Answers1

1

Update 2

As requested by OP, the controls native to the HTML5 audio element is replaced by a custom pause/play button. Rather than add an event listener to each audio, I employed a technique that is in this article.

  • The new function handlePlay() is called when a click is detected on .arrayBox (the <section> that contains all of the players).

  • handlePlay() will determine which of the buttons was actually clicked, then play or pause the audio element that is directly after the clicked button.

  • Added the new button Object ybtn to generate before an audio element is generated.

    • The new buttons can be styled with the .btn class.
    • Notice that the button's content is a font:
      • 🔈 &#128264; off
      • 🔊 &#128266; on
      • This alternative is faster to load than an image, plus it'll cut down on HTTP requests.

Plunker

Snippet

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>DeXY Player</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1, maximum-scale=1, user-scalable=0" />
  <link href='https://fonts.googleapis.com/css?family=Raleway:600' rel='stylesheet' />
  <style>
    html {
      box-sizing: border-box;
      font: 500 16px/1.428 'Raleway';
      height: 100vh;
      width: 100vw;
    }
    
    *,
    *:before,
    *:after {
      box-sizing: inherit;
      margin: 0;
      padding: 0;
    }
    
    body {
      position: relative;
      font-size: 1rem;
      line-height: 1;
      height: 100%;
      width: 100%;
      overflow-x: hidden;
      overflow-y: auto;
      -webkit-font-smoothing: antialiased;
      background: #222;
      color: #fc2;
    }
    
    button {
      font: inherit;
      line-height: 1.5;
      padding: 1px 3px;
      border-radius: 8px;
      border: 1px solid #00f;
      margin: 20px;
      background: rgba(0, 0, 0, .4);
      color: #00f;
      cursor: pointer;
    }
    
    button:hover {
      border: 1px solid #0ff;
      color: #0ff;
    }

    .btn {/* The audio buttons' styles */
      display: inline-block;
    }
  </style>
</head>

<body>
  <h1>DeXY Audio Array Player</h1>
  <button id="btn1"><a>Load</a></button>
  <section id="arrayBox">
    
  </section>
  <script>
//This array of strings is a required input needed to run DeXY Player.
 
    var playList = ['http://glpjt.s3.amazonaws.com/so/av/day01.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day02.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day03.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day04.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day05.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day06.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day07.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day08.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day09.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day10.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day11.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day12.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day13.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day14.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day15.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day16.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day17.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day18.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day19.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day20.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day21.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day22.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day23.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day24.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day25.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day26.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day27.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day28.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day29.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day30.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day31.mp3'];

//qty is the total quantity of elements within the playList array.

    var qty = playList.length;
    console.log('qty: ' + qty);
  </script>
  <script>
    var aBox = document.getElementById('arrayBox');
    var btn1 = document.getElementById('btn1');
//Click event triggers a callback: loadPlayers()
    aBox.addEventListener('click', handlePlay, false);
    btn1.addEventListener('click', loadPlayers, false);

    function loadPlayers() {
      var dArray = [];
//Each iteration creates a div#dx{?}.snd, appends it to the section, and then is pushed into dArray.

      for (var d = 0; d < qty; d++) {
        var division = document.createElement('div');
        division.id = "dx" + d;
        division.className = 'snd';
        aBox.appendChild(division);
        dArray.push(division);
      }
//Each iteration creates an audio element audio#x{?}, adds a series of attributes, and is assigned a MP3 from thr playlist.     
      
      for (var x = 0; x < qty; x++) {
        var ID = dArray[x].getAttribute('id');
        var xTag = document.createElement('audio');
        var yBtn = document.createElement('button');
        var xDiv = document.getElementById(ID);
        var xID = ID.substr(1, 3);
        var yID = ID.substr(2, 3);
        var xUrl = playList[x];
        
        xDiv.appendChild(yBtn);
        yBtn.setAttribute('id', 'y' + yID);
        yBtn.className ="btn";
        console.log('Player Button ID: '+ yBtn.id);
        yBtn.innerHTML = "&#128264;&nbsp;"; 
        yBtn.style.fontSize = "24px";
        yBtn.style.lineHeight = 1;

        xDiv.appendChild(xTag);
        xTag.setAttribute('id', xID);
        xTag.setAttribute('preload', 'auto');
        xTag.setAttribute('src', xUrl);
      }
    }
    
    function handlePlay(e) {
      if (e.target !== e.currentTarget) {
        var button = e.target.id;
        var btn = document.getElementById(button);
        console.log('button: '+btn);
        var clip = btn.nextSibling.id;
        console.log('clip: '+clip);
        var audio = document.getElementById(clip);
        console.log('audio '+audio);
        if(audio.paused) {
          audio.play();
          btn.innerHTML ="&#128266;"
          btn.style.color ="#0ff";
          btn.style.padding = '1px';
          btn.style.border = '1px solid #0ff';
        }
        else {
          audio.pause();
          btn.innerHTML ="&#128264;&nbsp;"
          btn.style.color ="#00f";
          btn.style.padding = '1px 5px';
          btn.style.border = '1px solid #00f';
        }
      }
      e.stopPropagation();
    }

  </script>
</body>

</html>

Update

After a brief discussion with OP, I have updated the last version. This version will accept and utilize an array of strings as a playlist. Refactored everything into a single function. One click of the button and 31 functional audio players appear in a blink. There are comments in the JS as a simple walkthrough of what the function loadPlayers().

Plunker

Snippet

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>dXPlayer</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1, maximum-scale=1, user-scalable=0" />
  <link href='https://fonts.googleapis.com/css?family=Raleway:600' rel='stylesheet' />
  <style>
    html {
      box-sizing: border-box;
      font: 500 16px/1.428 'Raleway';
      height: 100vh;
      width: 100vw;
    }
    
    *,
    *:before,
    *:after {
      box-sizing: inherit;
      margin: 0;
      padding: 0;
    }
    
    body {
      position: relative;
      font-size: 1rem;
      line-height: 1;
      height: 100%;
      width: 100%;
      overflow-x: hidden;
      overflow-y: auto;
      -webkit-font-smoothing: antialiased;
      background: #222;
      color: #fc2;
    }
    
    button {
      font: inherit;
      line-height: 1.5;
      padding: 1px 3px;
      border-radius: 8px;
      border: 1px solid #0ec;
      margin: 20px;
      background: rgba(0, 0, 0, .4);
      color: #0FF;
    }
  </style>
</head>

<body>
  <h1>dX Audio Array Player</h1>
  <section id="arrayBox">
    <button id="btn1">Load</button>
  </section>
  <script>
//This array of strings is a required input needed to run dXPlayer.
 
    var playList = ['http://glpjt.s3.amazonaws.com/so/av/day01.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day02.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day03.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day04.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day05.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day06.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day07.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day08.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day09.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day10.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day11.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day12.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day13.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day14.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day15.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day16.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day17.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day18.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day19.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day20.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day21.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day22.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day23.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day24.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day25.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day26.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day27.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day28.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day29.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day30.mp3', 'http://glpjt.s3.amazonaws.com/so/av/day31.mp3'];
    
//qty is the total quantity of elements within the playList array.

    var qty = playList.length;
    console.log('qty: ' + qty);
  </script>
  <script>
    var btn1 = document.getElementById('btn1');
//Click event triggers a callback: loadPlayers()

    btn1.addEventListener('click', loadPlayers, false);

    function loadPlayers() {
      var tgtArea = document.getElementById('arrayBox');
      var dArray = [];
//Each iteration creates a div#dx{?}.snd, appends it to the section, and then is pushed into dArray.

      for (var d = 0; d < qty; d++) {
        var division = document.createElement('div');
        division.id = "dx" + d;
        division.className = 'snd';
        tgtArea.appendChild(division);
        dArray.push(division);
      }
//Each iteration creates an audio element audio#x{?}, adds a series of attributes, and is assigned a MP3 from thr playlist.     
      
      for (var x = 0; x < qty; x++) {
        var ID = dArray[x].getAttribute('id');
        var xTag = document.createElement('audio');
        var xDiv = document.getElementById(ID);
        var xID = ID.substr(1, 3);
        var xUrl = playList[x];

        xDiv.appendChild(xTag);
        xTag.setAttribute('id', xID);
        xTag.setAttribute('controls', 'controls');
        xTag.setAttribute('preload', 'auto')
        xTag.setAttribute('src', xUrl);
      }
    }
  </script>
</body>

</html>



There was too much in the OP's code to debug, so I am providing a working demo that achieves the same objectives as the OP's. The demo comprises of:

  • Two event listeners ...
    • one when DOM Content is loaded (JS's near equivalent of jQuery's DOM Ready), and ...
    • the other on a button (btn1) click.
  • Two functions ...
    • loadPlayers()is called when the click event on btn1 is triggered.
      • It collects the div.snd in a NodeList...
      • ... which in turn gets converted to an Array ...
      • ... which is iterated by a for loop.
      • Each instance of the loop produces a unique audio element loaded with unique content.
    • xStruct is a function that's called within loadPlayers() to do the cloning, adding attributes, and assigning content.

When preparing a project like this, I prefer to have all my assets close at hand and easily accessible. - Insure that the audio files are all in one directory (folder). - Use short functional filenames that are numbered consecutively. (e.g. wav1.wav, `wav2.wav, etc..) - Assign the ids in a similar fashion. - If you use content that's scattered across multiple locations, with long verbose names and have classes and ids that have no easy to follow pattern, you will be more prone to mistakes and errors.

There's a couple things that need to be adhered to when setting up this demo:

  • For every player you want created, you must have a div already in the HTML:

    • ids should be identical with the exception of the number.
    • You must assign the class .snd to each div as well.
  • Name each file in the same manner the div ids were done.

Plunker

Snippet

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>35529918</title>
  <style>
    section {
      margin: 30px
    }
  </style>
</head>

<body>
  <button id="btn1">Load</button>
  <section>
    <div id="wav1" class="snd"></div>
    <div id="wav2" class="snd"></div>
    <div id="wav3" class="snd"></div>
  </section>
  <script>
    window.addEventListener('DOMContentLoaded', function(e) {

      var btn1 = document.getElementById('btn1');

      btn1.addEventListener('click', loadPlayers, false)

      function loadPlayers() {
        var divList = document.querySelectorAll('.snd');
        var divArray = Array.prototype.slice.call(divList);
        for (var i = 0; i < divArray.length; i++) {
          var ID = divArray[i].id;
          xStruct(ID);
        }
      }

      function xStruct(ID) {
        var xTag = document.createElement('audio');
        var xDiv = document.getElementById(ID);
        var xUrl = 'https://glpjt.s3.amazonaws.com/so/av/';
        var xWav = xUrl + ID + '.wav';
        var xID = ID.substr(1, 3);
        xDiv.appendChild(xTag);
        xTag.setAttribute('id', xID);
        xTag.setAttribute('controls', 'controls');
        xTag.setAttribute('src', xWav);
      }
    }, false);
  </script>
</body>

</html>
zer00ne
  • 41,936
  • 6
  • 41
  • 68
  • Thanks zer00ne! you gave me allot of things to think about and improve. However, that doesn't quite solve the core problem. I need to have a flexible number of audio players in the array. If the array has 5 elements - there should be 5 players, and that can't be determined in advanced! The reason is that I prompt the user to enter word in input. When the word is found in the database it grabs the number of elements in the array and that should be flexible... – Apython Feb 21 '16 at 12:52
  • You're welcome, sir. User input? That's easier to write. What does the user input? name of song? Does the media come from one source / url / location? As long as your audio files aren't over 10MB each, you shouldn't be slowed down, but if you do plan to play bigger files, it might be better to run one player on a page. – zer00ne Feb 21 '16 at 13:52
  • Well, I already wrote that. I didn't add this part (input) to this question cause I only want to handle the player issue, you see? for simplification I just wrote an pseudo array. The source is an .mp3 path (right now on hard drive), so I used just a random URL from the web just for visualization. You wrote "For every player you want created, you must have a div already". but how come? isn't it possible to iterate and add a player inside one fixed div? – Apython Feb 21 '16 at 14:03
  • Yeah, I was worried about rendering times, but it seems my fears are unfounded, So to recap, you want the array length unlimited, the src coming from an input, and everything dynamically generated. – zer00ne Feb 21 '16 at 14:20
  • Yes! imagine you enter "Birds" as input, you will get ["Sparrow, Blackbird", Dove"] and their sounds on the left (3 diff. sounds) and if you will enter "Dogs" you will get ["Collie, "terrier"] (2). But again, you don't have to modify the code for input, as I have it, just showing how to create X number of players which depend on the array's length - would be sufficient! thanks! – Apython Feb 21 '16 at 14:30
  • and my (original) audio source is a relative URL source. An array of strings that looks something like: Array = ['audio/dog.mp3', 'audio/cow.mp3','audio/cat.mp3']. The players can play the sound (as in the example) but again, each player plays the last element and not each! – Apython Feb 21 '16 at 14:40
  • @Apython This update takes an array, generates 31 players ( it can be a lot more), I didn't have 31 different sounds available, so look in the dev-tools and you'll see all new content with proper id attribute and 31 unique urls as well. – zer00ne Feb 21 '16 at 19:12
  • Thanks zer00one! now the players work fine and can take any length. I really appreciate your help! though i'm still struggling with the Audio players design (see my other logo in the Code snipped), cause I don't want the browser's audio player default, but a customized player design. As you might have seen in my code, I used a JQuery function (in the beginning of my script) that was taken from a nice tutorial on YouTube (https://www.youtube.com/watch?v=8uJ9Tu5GXmc.). Since you and the other coder used different approaches, it's quite complicated to combine them together.. – Apython Feb 22 '16 at 19:29
  • @Apython Indeed, but not impossible. The original demo wasn't working, so to clarify, the criteria for your interface is one play/pause button per player, correct? – zer00ne Feb 22 '16 at 19:40
  • @zer00one: which one do you refer to as "original demo"? As you've probably seen in my code, you click on the audio logo and it plays the same sound ("Cat") for all of them. "Play" button only (no pause) works just fine for me and it's simply shown in the JQuery code that I've mentioned before. do you know how to upgrade yours with that audio custom logo? – Apython Feb 22 '16 at 20:38
  • @Apython My bad it works as you described, it sounds hilarious, it got my dog startled lol. Ok, just finished update, it'll be ready for review @ 9:40PM UTC. – zer00ne Feb 22 '16 at 21:34