An Introduction to Collective Algorithmic Music Composition

Using JavaScript for Algorithmic Composition

JavaScript is a prototype-based scripting language that supports object-oriented, functional and imperative programming styles. It is known for its wide use in web development but it's also used as a scripting language for computer-assisted music composition software, game development and even databases. JavaScript's syntax comes from the C and Java languages; however, JavaScript is very different from Java and C. A key difference is that JavaScript is a scripting language whereas Java and C are compiled languages. It is important to note that JavaScript's functions are objects and class functionality is accomplished by using prototypes.

The main objective of this chapter is to give the reader the basic skills for solving problems using the JavaScript programming language. This guide will be useful for people with no or little programming experience. A great amount of resources are available for learning JavaScript; this guide covers the essential characteristics of the language as well as a variety of techniques useful for algorithmic problem solving.

Primitive Types

When we are manipulating data it's often useful to know what type of data we're using. JavaScript, as many other programming languages, support different data types. Some of these data types include: Boolean, Numeric Types and Strings.

Boolean

There are only two types of boolean values: true and false.

var a = true;
var b = false;

Numeric Types

We can also define integer and decimal numbers and perform arithmetic operations.

var x = 1000;
var y = 54.123;
var z = x + y;
z;

What do you think would happen if we use different data types to perform mathematical operations? Consider the following case and try it out to see what happens.

var x = "1000";
var y = 54.123;
var z = x + y;
z;

Strings

We use strings for text. We use quotes to surround the text we want to define as a string.

var s = "foo";
var c = 'f';

Conditional Statements

Conditional statements are fundamental in computer programming because they allow us to solve problems, control events and control conditions. In short, it allows us to instruct the computer what to do if something happens.

if

We use the following syntax to tell the computer how to proceed if a condition is met.

if(condition){
    // do something
}

Consider the following example. Consider that we have variable n, and if variable n is less than 10 we will assign a 1 to variable x. We could do this in JavaScript like this:

var n = 1;
var x;

if(n < 10){
    x = 1;
}

if...else

What if we have other cases and want to tell the computer how to handle does other cases? We can use an else to do that.

if(condition){
    // do something
}else{
    // do something else
}

Consider the following example.

var n = 1;
var x;

if(n < 10){
    x = 1;
}else{
    x = 0;
}

if...else if...else

We can add many else ifs, to make more complex conditions to be met. The syntax for doing so, is the following:

if(condition){
    // do something
}else if(other condition){
    // do something else
}else{
    // do something else
}

The following example show how we can use multiple statements to make more complex instructions.

var n = 11;
var x;

if(n < 10){
    x = 1;
}else if(n === 11){
    x = 123;
}else{
    x = 0;
}

Sameness in JavaScript

JavaScript has an equality operator ( == ) and an identity operator ( === ). The main difference is that the identity operator compares the types and the equality operator doesn't.

var x = 1;
var y = "1";

if (x == y){
    alert("x and y are equal without considering their type");
}

if (x === y){
    alert("This won't appear because x and y have different types");
}

Loops

Loops are essential because they allows us to execute chunks of code until a condition is met.

while

A while loop executes an instruction as long as the test condition is true. The syntax for a while loop is the following:

while(condition){
    // do something
}

In the following example, an alert will be displayed while n is greater than 0.

var n = 2;

while(n > 0){
    alert(n);
    n--;
}

do...while

A do while loop executes an instruction until the test condition is false. The instructions are executed and then the condition is evaluated. The specified instruction is executed at least once.

do{
    //do something
}while(condition);

The following example

var x = 0;

do{
    alert(x);
    x++;
}while(x < 2);

for

A for loop is similar to a while loop but it is often used with an initialization variable, a condition and ending statement which usually is used to increment or decrement a variable. The syntax for a for loop is the following:

for(initialization; condition; end){
    // do something
}

An example of a for loop is the following

for(var i = 0; i < 2; i++){
    alert(i);
}

Functions

A function is basically a block of code that will be executed when it's called. We can use functions to solve problems and to better organize code for later reuse. We define a function in the following manner:

function function_name(name){
    alert("hello " + name);
}
function hello(name){
    alert("hello " + name);
}

To call the function, we simply type the name of the function and put a parameter in it:

hello("Mr. Ostrich");

A function can also be defined like this:

var hi = function hello(name){
    alert("hello " + name);
};

Nested Functions

Functions can be defined inside other functions. An inner function can use variables from the outer function. This is also known as a closure. For example:

var variable = "global";

function outerFunction(){

    var variable = "local";

    function innerFunction(){
        alert(variable);
    }

    innerFunction();
}

outerFunction();

In the preceding example, the inner function would alert "local" because the outer function

Recursion

To understand recursion, you must understand recursion. Recursion is basically a function that calls itself until a condition is met. Recursion can be very useful to solve some kind of problems.

Factorial

In mathematics, the factorial of a non-negative integer n, denoted by n!, is the product of all positive integers less than or equal to n. For example,

4! = 4*3*2*1 = 24

In JavaScript we can write it like this:

function factorial(n){
   if(n === 0 || n === 1){
        return 1;
   }else{ 
        return n * factorial(n - 1);
   }
}

factorial(5);

Fibonacci Sequence

A Fibonacci number is a number that is equal to the sum of the preceding two numbers. The Fibonacci sequence is a set of Fibonacci numbers. The first two Fibonacci numbers are 0 and 1. Dividing the last two numbers of a Fibonacci sequence results in an approximation of the Golden Ratio.

0, 1, 1, 2, 3, 5, 8, 13, 21, ...

In JavaScript we can write it like this:

function fibonacci(n){
    if(n === 0){
        return 0;
    }else if(n === 1){
        return 1;
    }else{
        return fibonacci(n - 2) + fibonacci(n - 1);
    }
}

Iterative Fibonacci

function iterative_fibonacci(n){
    if(n === 0){
        return 0;
    }else if(n === 1 || n === 2){
        return 1;
    }else if(n > 2){
        var fib_numbers = [0,1];
        for(var i = 2; i <= n; i++){
            fib_numbers.push(fib_numbers[i-2] + fib_numbers[i-1]);
        }
        return fib_numbers[fib_numbers.length - 1];
    }
}

Objects

Object-oriented programming is a technique that uses inheritance, polymorphism and other techniques to model things as objects.

function Bird(name, age){
    this.name = name;
    this.age = age;
}  

Bird.prototype.getName = function(){
    return this.name;
};

Bird.prototype.setName = function(name){
    this.name = name;
};

var bird = new Bird('Birdy', 23);
bird.getName();             // Birdy.
bird.setName('Nevermore');  // Change the bird's name to Nevermore.
bird.getName();             // Nevermore.

Inheritance


function Bird(){}  

Bird.prototype.sing = function(){
    alert('Bird sings');
};

function Ostrich(){
    Bird.call(this);
}

Ostrich.prototype = new Bird();
Ostrich.prototype.constructor = Ostrich;

Ostrich.prototype.sing = function(){
    alert('Ostrich sings');
};

var myOstrich = new Ostrich();
myOstrich.sing();

JS Bach: Crab Canon

First we create a Score object.


// Das Musikalische Opfer: Canon Cancrizans - J.S. Bach 

var crabCanon = createScore(); 
var t = createTrack("",1,0,180); 
var t2 = createTrack("",2,0,180); 

var CCPitches= "C4 Eb4 G4 Ab4 B3 R G4 Gb4 F4 E4 Eb4 D4 Db4 C4 B3 G3 C4 F4 Eb4 D4 C4 Eb4 G4 F4 G4 C5 G4 Eb4 D4 Eb4 F4 G4 A4 B4 C5 Eb4 F4 G4 Ab4 D4 Eb4 F4 G4 F4 Eb4 D4 Eb4 F4 G4 Ab4 Bb4 Ab4 G4 F4 G4 Ab4 Bb4 C5 Db5 Bb4 Ab4 G4 A4 B4 C5 D5 Eb5 C5 B4 A4 B4 C5 D5 Eb5 F5 D5 G4 D5 C5 D5 Eb5 F5 Eb5 D5 C5 B4 C5 G4 Eb4 C4"; 

var CCLengths = "H H H H H Q H H H H H Q Q Q Q Q Q Q H H H H E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E Q Q Q Q";

var sec = createSection(); 
sec.addEvents(CCPitches,CCLengths); 

t.addSection(sec,1); 
t2.addSection(clone(sec),1); 
t2.retrograde(); 

crabCanon.addTrack(t); 
crabCanon.addTrack(t2); 
crabCanon.saveMidi();

Calling JavaScript inside Scheme

JavaScript can be called inside the BiwaScheme interpreter.

(js-eval "alert('hello');")