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 >
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>
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