Monday, December 16, 2013

Son of HTML5 Audio Followup (Game Programming)

While most of the rest of HTML5 has grown up and is very capable (we're looking at you, Canvas), HTML5 Audio still seems to have some growing pains. It may be replaced at some point soon by Web Audio, but for now, HTML5 Audio works pretty well if you don't ask too much out of it except play an audio.



There are a few more nooks and crannies I've been exploring, namely the Audio object properties of loop and controls.

Loop simply plays the audio over and over again. This is ideal for game music you want in the background, but I'm still investigating what happens if two audios overlap each other. I'm working on that and that's one of my next tasks. But loop works! How it works I'll explain in a minute.

The other fun bit for today are controls. If you just play audio, you don't see anything in your user interface. If you want to give the user some control over the controls of your audio, you have two ways to go.
  1. You can display a set of simple controls that will let you play, stop, and show your progress. This is what I'll cover in this post.
  2. You can make your own controls and fit it into your application the way you want. I'll show this soon.
Here's what the controls look like in Firefox OS on my ZTE Open:



Note that the words "Audio Controls" are NOT part of the control. They are text I put in the web page just for fun.

This takes up a fair amount of screen space, so it may not be useful. And then again, it may. The controls show the current time (0:02 seconds), the duration (0:09 seconds), and graphically shows you where the song is at this moment. The user also can press the pause ( || ) button in the top center and the mute button on the right.

If you tap the mute button, it turns color. The music still plays but you can't hear it. It looks like this:


Perhaps of limited interest, but you might find a use for it, especially if you put it on a separate page.

But there's a little bit more you can do. If you can get at the Audio object, you can modify some of the properties of the visual controls.

For example, you can change the background color, indent, and width of the box.



Oops, that's not what it looked like on the desktop! Yes, the controls are narrower, but I don't think they are indented, and the red background is, um, not behind the controls, but above it.

Here's what it looked like on the Firefox OS desktop browser (nightly):


Indented, narrow, and reddish (actually red + gray). So there's some work to do here and I probably should file a bug (except that I'm not sure how many people want to have standard controls in Firefox OS). The main problem is that you can't really adjust the height, and the default is too big.

I don't exactly fault Firefox OS folks for not making this work. There are much higher priorities and there's a workaround. You can make your own controls (or maybe all you want is to toggle mute). I'll cover that next time (or soon).

So here's the code, similar to the code for http://firefoxosgaming.blogspot.com/2013/12/html5-audio-followup-game-programming.html.

<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="utf-8">
    <title>
      Loop & Controls
    </title>
    
      <script>

      // Global variables
      var myAudio;

      // Load the page.
      window.addEventListener("load",
        runFirst, false);

      // Runs when the page is loaded.
      function runFirst() {

        console.log("page loaded");

        // Create audio object.
        // We like OGG.
        myAudio = new Audio("oggsong.ogg");
       
        // Need this to see the controls.
        document.getElementById("myBody").
            appendChild(myAudio);
           
        // Show the controls.
        myAudio.controls = true;
       
        // Allow looping.
        myAudio.loop = true;
       
        // Use an ID to work with controls.
        myAudio.id = "controlID";

        // Change width, margin, and color.
        controlID.style.width = "150px";
        controlID.style.marginLeft = "50px";
        controlID.style.backgroundColor = "red";

        // Listen for fully loaded audio.
        myAudio.addEventListener("canplaythrough",
          processMyAudio, false); 
      }

      // The audio is ready to play.
      function processMyAudio() {
     
        console.log("audio loaded");
       
        // Event no longer needed.
        myAudio.removeEventListener("canplaythrough",
            processMyAudio, false);
       
        // Play the audio.
        myAudio.play();     
      }

       </script>
    </head>

    <body id="myBody">
      <p>Audio Controls</p>
    </body>

</html>


Looping

Adding looping is pretty simple. Just add this line:

        myAudio.loop = true;

If you want to stop the looping (but not stop the audio playing), set loop to false.

Controls

Setting the controls is a little bit more work. The first part is easy:

        myAudio.controls = true;

But that won't work by itself. To make the controls visible, you must attach the control to the web page by this time-honored technique:

        document.getElementById("myBody").
            appendChild(myAudio);


This just attaches the myAudio object to the body of the web page. If you are just playing audio invisibly you don't need to do this. To display, all objects must be attached somewhere to the page.

Then, to modify the controls, you need to do one other thing, which is make an id for the audio control. This lets it be styled by CSS. Here's what you need to add:

        myAudio.id = "controlID";

This just give the audio object an id named controlID. It can be named anything as long as it doesn't conflict with any other names.

Now your control can be stylin'. Just add these three lines:

        controlID.style.width = "150px";
        controlID.style.marginLeft = "50px";
        controlID.style.backgroundColor = "red";


The width works just fine and could be very useful. The margin doesn't look like it works and the control is still centered. The background color is red, but not lined up with the control. "Oops" sounds like a good description here.

CSS to JavaScript

By the way, the sharp-eyed among you might have noticed that the syntax for background color is NOT background-color (like it would be in HTML), but is backgroundColor. When you move from the world of HTML tags to JavaScript properties, the wording changes slightly. It's maybe like switching from Spanish to Portuguese, where you can figure it out, but you don't want to make a mistake. I found a great page that has a great table comparing CSS property names to JavaScript references (properties) by Aaron Hancock at http://noobflash.com/set-style-dynamically-with-javascript/.

So stay tuned (but not iTuned) for more about audio as I dig deeper into this surprisingly mysterious world. What ever happened to the happy simple assembly language for MS-DOS that just produced a single beep?

Beep     PROC USES AX BX CX
    IN AL, 61h  ;Save state
    PUSH AX 
    MOV BX, 6818; 1193180/175
    MOV AL, 6Bh  ; Select Channel 2, write LSB/BSB mode 3
    OUT 43h, AL
    MOV AX, BX
    OUT 24h, AL  ; Send the LSB
    MOV AL, AH 
    OUT 42h, AL  ; Send the MSB
    IN AL, 61h   ; Get the 8255 Port Contence
    OR AL, 3h     
    OUT 61h, AL  ;End able speaker and use clock channel 2 for input
    MOV CX, 03h ; High order wait value
    MOV DX 0D04h; Low order wait value
    MOV AX, 86h;Wait service
    INT 15h       
    POP AX;restore Speaker state
    OUT 61h, AL
    RET
BEEP ENDP


Why doesn't JavaScript have a beep() command? Next they'll take out blink()!

And why doesn't Blogger let me insert smiley faces?