View Sidebar

A Million Little Pieces Of My Mind

Step 2: The OrganicaAudio Constructor

By: Paul S. Cilwa Viewed: 4/27/2024
Posted: 11/17/2017
Page Views: 732
Topics: #Computers #Cross-fadingMusicPlayer #JavaScript #MusicPlayer #OrganicaAudio #Programming #Projects #WebAudioAPI
Accessing an audio context from the Web Audio API.

It's now time to open the empty OrganicaAudio.js file and create the constructor for the object that will encapsulate the Web Audio API. We can start by typing in some preliminary lines:

// Requires <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
"use strict";		
/*****************************************************************************
/*	
/* OrganicaAudio
/*	
/*****************************************************************************/

var MyOrganicaAudio = new OrganicaAudio();

We start by actually creating an object of the OrganicaAudio type. This isn't usually done; but in the case of the Web Audio API the new class is intended to encapsulate, there will normally only be one; and because of weird JavaScript behavior regarding the this identifier in asynchronous functions, we'll need an unambiguous pointer back to that one object.

Now, if you've been reading this just to find out how to access a Web Audio API context, that happens in the OrganicaAudio constructor:

function OrganicaAudio() 
	{
	console.log ('OrganicaAudio initializing...');
	
	var ContextClass = (window.AudioContext || 
		window.webkitAudioContext ||
		window.mozAudioContext ||
		window.oAudioContext ||
		window.msAudioContext);
		
	if (ContextClass)
		{
		// Web Audio API is available.
		this.Context = new ContextClass();
		this.Playlist = [];
		console.log('OrganicaAudio: Hello');
		}
	else
		{
		// Trigger error??
		alert('OrganicaAudio: Unable to obtain Web Audio API context.');
		}
	}

The calls to console.log are there to help trace execution in the browser; when everything is working they can be deleted.

The assignment to ContextClass is interesting. In fully-implemented browsers, the Audio Context we'll require from the Web Audio API can be created by calling window.AudioContext. But what if someone wants to run this code on a slightly older browser? The Web Audio API was originally implemented on a browser-by-browser basis using Web kits. So this block of code tries every possible implementation in hopes of finding one that works:

var ContextClass = (window.AudioContext ||
	window.webkitAudioContext |
	window.mozAudioContext ||
	window.oAudioContext ||
	window.msAudioContext);

The final code block makes sure that a context was obtained (failing if it could not); then

  1. Creates a variable of the successful context class

  2. Initializes a class variable, Playlist, to an empty array

  3. Displays a console message for success (can be removed)

After saving your work, try dragging the AudioTest.html file onto Firefox to test. Once the page has loaded (will look exactly like it did in the last step), right-click on anything you can see and select Inspect Element, then re-load the page. It should now look like this, displaying the output from the console.log messages.

So: What do we have? A global object, MyOrganicaAudio, that, when instantiated, provides access to the OrganicaAudio class, which, so far, only creates an Audio Context from the Web Audio API. That object can't do anything yet, other than provide access to the Web Audio API context, which will be needed for anything else we want to do with it.

First, however, we must invent a new class that will work with OrganicaAudio. This new class will represent a single track to be played. (Objects of this class will populate the Playlist property of OrganicaAudio.) We'll do that in the next step.

Notes on JavaScript Style

JavaScript comes from the C/C++ tradition, and most JavaScript programmers put the open braces on the same line as the function declaration, like so:

function MyFunction(){
	console.log("Do something...");
}

However, despite my years of programming in C and C++ (including having written books on the subject), I prefer the Visual Basic tradition, in which each physical line of code is syntactically significant. Thus:

function MyFunction()
	{
	console.log("Do something...");
	}

This tradition also includes Classes, which do not quite exist in JavaScript. JavaScript is an object-oriented language, yet manages to accomplish that without actual classes. And a major weakness there is the keyword this often doesn't mean what you think it will. That's why I had to create the global variable, MyOrganicaAudio: Because many of the object methods will be invoked asynchronously, and through callback functions, Javascript quickly loses track of which object this is. MyOrganicaAudio provides an alternate, if less elegant, means of figuring that out.

Finally, on the topic of capitalization: JavaScript, like C/C++, is case sensitive. That means that MyOrganicaAudio, myOrganicaAudio, and MYORGANICAAUDIO are three separate variables or functions.

Most JavaScript programmers are in the habit of beginning variable and function names with a lower case letter (i.e., myOrganicaAudio). However, I hate that. Most languages use regular camelcase (each lexical word that makes up the name is capitalized, as in MyOrganicaAudio) and that's my preference as well.