Csound

WEB BASED CSOUND

pNaCl - Csound for Portable Native Client

Csound can now be run within a web browser with no requirement for Csound to be installed on the system from which it is accessed. Csound for Portable Native Client has been developed by Victor Lazzarini and is made possible through Google's Native Client technology (NaCl) and HTML5.  

Csound for pNaCl will work by default with recent versions of the Google Chrome browser (it is not currently supported within Firefox) so this is the recommended browser.

Through pNaCl, web pages can run Csound .csds and the user can interact with the .csd through on-screen buttons, sliders and canvases.

More information on Csound for pNaCl can be found here.

 

 

CsoundEmscripten - A Javascript Library for Csound on the Web

Introduction

CsoundEmscripten is an audio API for the web that makes it possible to run Csound in any standards compliant web browser without the need for plugins or add ons. This is made possible by using Emscripten, a program that can convert software written in C (such as Csound) into Javascript, allowing it to be run natively within any web browser that supports modern web standards.

Caveats

CsoundEmscripten is currently in very early stages of development and therefore there are a number of caveats and limitations with its current implementation which should be noted.

  • Emscripten generates a highly optimisable subset of Javascript called asm.js. This allows Javascript engines which have been optimised for this subset to achieve substantial performance increases over other Javascript engines. At this time the only Javascript engine that supports asm.js optimisations is the Spider Monkey engine which is part of Firefox. Therefore CsoundEmscripten will perform best on the current version of Firefox.

  • At this time, due to the design of the Web Audio API, CsoundEmscripten can only execute within the main thread of a web page. This means that it must pause execution of any performance when any other process that uses the main thread (such as the UI) needs to execute. This can cause dropouts and/or glitching of the audio during a performance.

  • As this project is in its infancy, there are a minimal number of routines implemented so far in order to instantiate, compile and perform a .csd file. Additional routines will be added over time as the project matures.

Getting CsoundEmscripten

CsoundEmscripten can be downloaded using git from the repository at github.

git clone https://github.com/eddyc/CsoundEmscripten.git

This repository contains a website which uses CsoundEmscripten. The Csound library can be found in the javascripts directory. In order to view some examples of CsoundEmscripten in action the website can be loaded into a browser locally by opening index.html found in the root directory. A live example of this website can also be found on the internet here.

Using CsoundEmscripten

In order to demonstrate how to use CsoundEmscripten, what follows is a tutorial which shows the steps necessary to create a simple website that can open .csd files, compile them, and play them back from the browser.

Create a simple website

First create a new folder for the website and copy the javascripts folder from CsoundEmscripten into the new websites directory. Next, create an index.html file at the top level of the new websites directory that contains the following minimal html code:

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<script src="javascripts/libcsound.js"></script>
<script src="javascripts/CsoundObj.js"></script>
</head>
<body>
</body>
</html>

This html page imports the Csound javascript library from the javascripts directory along with the CsoundObj.js file. The CsoundObj.js file defines the CsoundObj object which wraps the libcsound.js library and defines a number of helper methods that make using the libcsound.js library more convenient.

Instantiate Csound

We need to write some Javascript to create an instance of CsoundObj, so within the body tags add new script tags and insert the following code:

...
<body>
<script>
var csound = new CsoundObj();
</script>
</body>
...

The Javascript console of the web browser should now show some messages that give the version number of Csound, the build date and the version of libsndfile being used by Csound.

Implement file upload facility

Now we will create a button for uploading a .csd file. This button will open up the browsers file choser dialogue where a .csd file can be selected for upload from the local file system. When the file has been chosen, it is uploaded to Emscriptens virtual file system. This allows Csound to get access to the .csd file for compilation.

Add the following code to the index.html file:

...
<body>
<script>
var csound = new CsoundObj();
var reader = new FileReader();
var file;
var fileInputButton = document.createElement("INPUT");
fileInputButton.setAttribute("type", "file");

document.body.appendChild(fileInputButton);

function handleFileSelect(evt) {

    var files = evt.target.files;
    file = files[0];
    console.log(file.name);
    reader.readAsBinaryString(file);
}

reader.onload = (function(theFile) {

    return function(e) {

        FS.createDataFile('/', file.name, e.target.result, true, false);
    };
})(file)

fileInputButton.addEventListener('change', handleFileSelect, false);

</script>
</body>
...

After Csound has been instantiated a FileReader object is created. The FileReader object allows the webpage to read files from the local file system and store them as a Javascript object. Next, there is a Javascript variable to store the file and the file input button is instantiated and appended to the web page.

In order for the FileReader object to work properly we need to define two functions for working with the file chosen from the local file system. The first function handleFileSelect will be executed when a file has been selected from the file choser menu. The chosen files name is logged to the Javascript console and then read using the FileReader object, in this case as a binary string. The second function reader.onload will be executed when the file has finished being read by the FileReader object. In this case it uses the method provided by Emscripten createDatafile, to add the selected file to Emscriptens virtual file system. Finally, an event listener is added to the fileInputButton to trigger the handleFileSelect function when the file has been selected.

Compiling the .csd file

When the .csd file has been uploaded to Emscriptens virtual file system it can then be compiled using Csound. Add the following code to the index.html file

...
fileInputButton.addEventListener('change', handleFileSelect, false);

function compile() {

    csound.compileCSD(file.name);
}
var compileButton = document.createElement("BUTTON");
var buttonText = document.createTextNode("Compile");
compileButton.appendChild(buttonText);
compileButton.onclick = compile;
document.body.appendChild(compileButton);

</script>
...

Here we first define the compile function which triggers the compilation of the .csd file. We then create a new button with a text label, point the onclick method to our compile function and append it to the body of the webpage.

Perform the .csd file

Finally when the .csd file has been compiled we need to start the csound performance. Similarly to the compile button, we first define a play function which starts the csound performance. We then create our play button, point the onclick method to the play function and add it to the webpage:

...
function play() {

    csound.startAudioCallback();
}
var playButton = document.createElement("BUTTON");
var buttonText = document.createTextNode("Play");
playButton.appendChild(buttonText);
playButton.onclick = play;
document.body.appendChild(playButton);
...

When the finished website is loaded, it should be possible now to select a file, compile it and play it back using CsoundEmscripten. Here is the full code for the index.html website:

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<script src="javascripts/libcsound.js"></script>
<script src="javascripts/CsoundObj.js"></script>
</head>
<body>
<script>

var csound = new CsoundObj();
var reader = new FileReader();
var file;
var fileInputButton = document.createElement("INPUT");
fileInputButton.setAttribute("type", "file");
document.body.appendChild(fileInputButton);

function handleFileSelect(evt) {

    var files = evt.target.files;
    file = files[0];
    console.log(file.name);
    reader.readAsBinaryString(file);
}

reader.onload = (function(theFile) {

    return function(e) {

        FS.createDataFile('/', file.name, e.target.result, true, false);
    };
})(file)

fileInputButton.addEventListener('change', handleFileSelect, false);

function compile() {

    csound.compileCSD(file.name);
}
var compileButton = document.createElement("BUTTON");
var buttonText = document.createTextNode("Compile");
compileButton.appendChild(buttonText);
compileButton.onclick = compile;
document.body.appendChild(compileButton);

function play() {

    csound.startAudioCallback();
}
var playButton = document.createElement("BUTTON");
var buttonText = document.createTextNode("Play");
playButton.appendChild(buttonText);
playButton.onclick = play;
document.body.appendChild(playButton);

</script>
</body>
</html>

CsoundObj.js Reference

CsoundObj.compileCSD(fileName)

This method takes as its argument the address of a CSD file fileName and compiles it for performance. The CSD file must be present in Emscripten's virtual filesystem.


CsoundObj.enableAudioInput()

This method enables audio input to the web browser. When called, it triggers a permissions dialogue in the host web browser requesting permission to allow audio input. If permission is granted, audio input is available for the running Csound instance.


CsoundObj.startAudioCallback()

This method starts the performance of a compiled CSD file.


CsoundObj.stopAudioCallback()

This method stops the performance of a compiled CSD file.


CsoundObj.addControlChannel(name, initialValue)

This method adds an object to a Javascript array that is used to update Csound's named channel values. Each object contains a string value given by name, a float value given by initialValue and additionally a boolean value indicating whether the float value has been updated.


CsoundObj.setControlChannelValue(name, value)

This method sets a named control channel given by the string name to the specified number given by the value argument.


CsoundObj.getControlChannelValue(name)

This method returns the current value of a named control channel given by the string name.