KISA 3 - A full function player - Setting volume, time, and file


It was neat to see that we could create play, pause and stop buttons but we still had to use the browser's audio control to change the volume and location in the file. Those capabilities will be added to the sketch. After determining how to write a full featured player in Processing.js, the control will no longer be needed. In addition, the user will be given a choice of files to play. (By this time, you may well bored with the music file that we have used so far.)

It would be highly desirable to use sliders for volume and location. But recall the meaning of KISA. Because we already have a button control, we will simply add buttons to increase or decrease these items by 10%. Two additional buttons will allow the user can select a file to play. (Actually, Processing.js makes it "easy" to display these items graphically. HTML5 Audio Demo displays the current time and some other items in bar graphs as part of the HTML API demo. In addition, Tutorial 5 Form shows how to use the proposed HTML5 range input sliders assuming the browser has implemented them.)

The new buttons are declared, initialized and drawn in the following lines:

 22  CircleButton volumeDownBtn, volumeUpBtn, timeDownBtn, timeUpBtn;
 23  CircleButton file1Btn, file2Btn;
...
 39    volumeDownBtn = new CircleButton(165, 170, "Volume down");
 40    volumeUpBtn = new CircleButton(270, 170, "Volume up");
 41    timeDownBtn = new CircleButton(165, 195, "Time down");
 42    timeUpBtn = new CircleButton(270, 195, "Time up");
 43    file1Btn = new CircleButton(20, 220, file1);
 44    file2Btn = new CircleButton(20, 245, file2);
...
 66    volumeDownBtn.draw();
 67    volumeUpBtn.draw();
 68    timeDownBtn.draw();
 69    timeUpBtn.draw();
 70    file1Btn.draw();
 71    file2Btn.draw();
 72  }

Mouse clicks are processed in lines 133 - 149.

133    } else if (volumeUpBtn.isOver()) {
134      v = audio.volume + 0.1;
135      audio.volume = constrain(v, 0, 1);
136    } else if (volumeDownBtn.isOver()) {
137      v = audio.volume - 0.1;
138      audio.volume = constrain(v, 0, 1);
139    } else if (timeUpBtn.isOver()) {
140      t = audio.currentTime + 0.1 * audio.duration;
141      audio.currentTime = constrain(t, 0, audio.duration);
142    } else if (timeDownBtn.isOver()) {
143      t = audio.currentTime - 0.1 * audio.duration;
144      audio.currentTime = constrain(t, 0, audio.duration);
145    } else if (file1Btn.isOver()) {
146      setSource(file1);
147    } else if (file2Btn.isOver()) {
148      setSource(file2);
149    }

A second audio file is declared in line 14.

 14  String file2 = "http://brinkje.com/KISA_Sounds/jingle";

The volume is changed by adding or subtracting 0.1 to the current audio volume. The new value is constrained to the range 0 to 1. The location time is changed by one tenths of audio.duration (the length of the sound) , then constrained to the range of 0 to audio.duration.

When the user selects a file, the mouseClicked function uses the setSouirce function. Setting the src attribute stops the current playback as well as changing the source file. The user can click "Play" to start the playback. If desired, one could call "playing" to automatically start playing the file. An other alternative would be to set

         audio.autoplay = true;

The resulting sketch has all the functions of the HTML controller so we can remove the controls="controls" attribute from the audio tag in line 12 of the html file.

 12     <audio  id="audiotag"  preload="auto">

The simple audio player is complete. In the next part, a small improvement will be made. It will not change the look or function from the user viewpoint but may be helpful.

< Previous     Next >

[+/-] The KISA3.html file

  1  <!DOCTYPE html>  
  2  <html>
  3  <head>
  4    <title>KISA 3 (Keep It Simple Audio)</title>
  5    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  6    <script type="text/javascript" src="processing.min.js"></script>
  7  </head>
  8  <body>
  9     <h1>Keep It Simple Audio 3</h1>
 10     <canvas id="KISA" data-processing-sources="KISA3.pde CircleButton.pde"></canvas>
 11     <br />
 12     <audio  id="audiotag"  preload="auto">
 13       Your browser does not support HTML 5 audio.  You may want to update your
 14       browser to a current version. 
 15    </audio>  
 16  </body>
 17  </html>

[+/-] The KISA3.pde file

  1  // KISA
  2  // Keep It Simple Audio version 3
  3  // James Brink  brinkje@plu.edu
  4  // 3/7/12  4/12/12  2/1/13
  5  
  6  // The constants can be modified.
  7  int width = 500;  // Width of canvas
  8  int height = 290; // Height of canvas
  9  // It is assumed that both .ogg and .mp3 versions of the files are available
 10  // in the same folder.  The file names must be complete URLs except for the
 11  // ending .ogg or .mp3 which must be omitted. It will be added as needed for
 12  // the browser.  Use the prefix "file:///" or "http:// as appropriate.
 13  String file1 = "http://brinkje.com/KISA_Sounds/groove";
 14  String file2 = "http://brinkje.com/KISA_Sounds/jingle";
 15  
 16  // Global variables
 17  Audio audio = document.getElementById("audiotag");
 18  
 19  int time;
 20  String audioStatus;
 21  CircleButton playBtn, pauseBtn, stopBtn;
 22  CircleButton volumeDownBtn, volumeUpBtn, timeDownBtn, timeUpBtn;
 23  CircleButton file1Btn, file2Btn;
 24  
 25  void setup() {
 26    // Setup the sketch
 27    size(width, height);
 28    smooth();
 29    frameRate(20);
 30    audio.addEventListener("loadstart", loadStart, false);
 31    audio.addEventListener("playing", playing, false);
 32    audio.addEventListener("pause", pause, false);
 33    audio.addEventListener("ended", ended, false);
 34    audio.addEventListener("error", error, false);
 35  
 36    playBtn = new CircleButton(130, 145,"Play");
 37    pauseBtn = new CircleButton(230, 145, "Pause");
 38    stopBtn = new CircleButton(330, 145, "Stop");
 39    volumeDownBtn = new CircleButton(165, 170, "Volume down");
 40    volumeUpBtn = new CircleButton(270, 170, "Volume up");
 41    timeDownBtn = new CircleButton(165, 195, "Time down");
 42    timeUpBtn = new CircleButton(270, 195, "Time up");
 43    file1Btn = new CircleButton(20, 220, file1);
 44    file2Btn = new CircleButton(20, 245, file2);
 45  
 46    audioStatus = "";
 47    setSource(file1);  // pick the initial audio file
 48  } // setup
 49  
 50  void draw() {
 51    // Draws the sketch on the canvas
 52    background(#FFFFAA);
 53  
 54    fill(#000000);
 55    textAlign(CENTER);
 56    text("KISA 3", width/2, 30);
 57    text("Source file: " + audio.src, width/2, 60);
 58    text("Status: " + audioStatus, width/2, 80);
 59    text("Current time: " + round(audio.currentTime)
 60         + " sec.   Length: " + round(audio.duration)+ " sec.", width/2, 100);        
 61    text("Volume (0 to 1): " + round(10 * audio.volume)/10.0, width/2, 120);
 62  
 63    playBtn.draw();
 64    pauseBtn.draw();
 65    stopBtn.draw();
 66    volumeDownBtn.draw();
 67    volumeUpBtn.draw();
 68    timeDownBtn.draw();
 69    timeUpBtn.draw();
 70    file1Btn.draw();
 71    file2Btn.draw();
 72  }
 73  
 74  void setSource(String url ) {
 75    // Called to set the source file.  Do not include the file extension
 76    // in the url.  It will be added here.
 77    if (audio.canPlayType && audio.canPlayType("audio/mpeg")) {
 78      audio.setAttribute("src", url + ".mp3");
 79    } else {
 80      audio.setAttribute("src", url + ".ogg");
 81    }
 82    audioStatus = "File selected";
 83  }
 84  
 85  void stop() {
 86    // Called stop playing the file by pausing it and setting the
 87    // time back to 0;
 88    audio.pause();
 89    audio.currentTime = 0;
 90    audioStatus = "Stopped";
 91  }
 92  
 93  void loadStart() {
 94    // LoadStart event processing
 95    audioStatus = "Loading";
 96  }
 97  
 98  void playing() {
 99    // Playing event processing
100    audioStatus = "Playing";
101  }
102  
103  void pause() {
104    // Pause event processing.
105    // There is no stop event but a "stop" causes a pause.  This
106    // method checks to see if the current time = 0. If so it assumes
107    // stopped
108    if (audio.currentTime == 0)
109      audioStatus = "Stopped";
110    else
111      audioStatus = "Paused";
112  }
113  
114  void ended() {
115    // Ending event processing
116    audioStatus = "Finished playing";
117  }
118  
119  void error() {
120    // error event processing
121    audioStatus = "Error";
122  }
123  
124  void mouseClicked() {
125    // Mouse clicked event processing
126    var v, t;
127    if (playBtn.isOver()) {
128      audio.play();
129    } else if (pauseBtn.isOver()) {
130      audio.pause();
131    } else if (stopBtn.isOver()) {
132      stop();
133    } else if (volumeUpBtn.isOver()) {
134      v = audio.volume + 0.1;
135      audio.volume = constrain(v, 0, 1);
136    } else if (volumeDownBtn.isOver()) {
137      v = audio.volume - 0.1;
138      audio.volume = constrain(v, 0, 1);
139    } else if (timeUpBtn.isOver()) {
140      t = audio.currentTime + 0.1 * audio.duration;
141      audio.currentTime = constrain(t, 0, audio.duration);
142    } else if (timeDownBtn.isOver()) {
143      t = audio.currentTime - 0.1 * audio.duration;
144      audio.currentTime = constrain(t, 0, audio.duration);
145    } else if (file1Btn.isOver()) {
146      setSource(file1);
147    } else if (file2Btn.isOver()) {
148      setSource(file2);
149    }
150  }

[+/-] The CircleButton.pde file

Updated 11/6 /14