var AudioletBuffer = new Class({
    initialize: function(numberOfChannels, length) {
        this.numberOfChannels = numberOfChannels;
        this.length = length;

        this.channels = [];
        for (var i = 0; i < this.numberOfChannels; i++) {
            this.channels.push(new Float32Array(numberOfChannels * length));
        }

        this.unslicedChannels = [];
        for (var i = 0; i < this.numberOfChannels; i++) {
            this.unslicedChannels.push(this.channels[i]);
        }

        this.isEmpty = false;
        this.channelOffset = 0;
    },

    getChannelData: function(channel) {
        return (this.channels[channel]);
    },

    set: function(buffer) {
        var numberOfChannels = buffer.numberOfChannels;
        for (var i = 0; i < numberOfChannels; i++) {
            this.channels[i].set(buffer.getChannelData(i));
        }
    },

    setSection: function(buffer, length, inputOffset, outputOffset) {
        inputOffset = inputOffset || 0;
        outputOffset = outputOffset || 0;
        var numberOfChannels = buffer.numberOfChannels;
        for (var i = 0; i < numberOfChannels; i++) {
            // Begin subarray-of-subarray fix
            inputOffset += buffer.channelOffset;
            outputOffset += this.channelOffset;
            var channel1 = this.unslicedChannels[i].subarray(outputOffset,
                                                              outputOffset +
                                                              length);
            var channel2 = buffer.unslicedChannels[i].subarray(inputOffset,
                                                                inputOffset +
                                                                length);
            // End subarray-of-subarray fix
            // Uncomment the following lines when subarray-of-subarray is fixed
            /*
            var channel1 = this.getChannelData(i).subarray(outputOffset,
                                                           outputOffset +
                                                           length);
            var channel2 = buffer.getChannelData(i).subarray(inputOffset,
                                                             inputOffset +
                                                             length);
            */
            channel1.set(channel2);
        }
    },

    add: function(buffer) {
        var length = this.length;
        var numberOfChannels = buffer.numberOfChannels;
        for (var i = 0; i < numberOfChannels; i++) {
            var channel1 = this.getChannelData(i);
            var channel2 = buffer.getChannelData(i);
            for (var j = 0; j < length; j++) {
                channel1[j] += channel2[j];
            }
        }
    },

    addSection: function(buffer, length, inputOffset, outputOffset) {
        inputOffset = inputOffset || 0;
        outputOffset = outputOffset || 0;
        var numberOfChannels = buffer.numberOfChannels;
        for (var i = 0; i < numberOfChannels; i++) {
            var channel1 = this.getChannelData(i);
            var channel2 = buffer.getChannelData(i);
            for (var j = 0; j < length; j++) {
                channel1[j + outputOffset] += channel2[j + inputOffset];
            }
        }
    },

    resize: function(numberOfChannels, length, lazy, offset) {
        offset = offset || 0;
        // Local variables
        var channels = this.channels;
        var unslicedChannels = this.unslicedChannels;

        var oldLength = this.length;
        var channelOffset = this.channelOffset;

        for (var i=0; i < numberOfChannels; i++) {
            // Get the current channels
            var channel = channels[i];
            var unslicedChannel = unslicedChannels[i];

            if (length > oldLength) {
                // We are increasing the size of the buffer
                var oldChannel = channel;

                if (!lazy ||
                    !unslicedChannel ||
                    unslicedChannel.length < length) {
                    // Unsliced channel is not empty when it needs to be,
                    // does not exist, or is not large enough, so needs to be
                    // (re)created
                    unslicedChannel = new Float32Array(length);
                }

                channel = unslicedChannel.subarray(0, length);

                if (!lazy && oldChannel) {
                    channel.set(oldChannel, offset);
                }

                channelOffset = 0;
            }
            else {
                // We are decreasing the size of the buffer
                if (!unslicedChannel) {
                    // Unsliced channel does not exist
                    // We can assume that we always have at least one unsliced
                    // channel, so we can copy its length
                    var unslicedLength = unslicedChannels[0].length;
                    unslicedChannel = new Float32Array(unslicedLength);
                }
                // Begin subarray-of-subarray fix
                channelOffset += offset;
                offset = channelOffset;
                channel = unslicedChannel.subarray(offset, offset + length);
                // End subarray-of-subarray fix
                // Uncomment the following lines when subarray-of-subarray is
                // fixed.
                // TODO: Write version where subarray-of-subarray is used
            }
            channels[i] = channel;
            unslicedChannels[i] = unslicedChannel;
        }

        this.channels = channels.slice(0, numberOfChannels);
        this.unslicedChannels = unslicedChannels.slice(0, numberOfChannels);
        this.length = length;
        this.numberOfChannels = numberOfChannels;
        this.channelOffset = channelOffset;
    },

    push: function(buffer) {
        var bufferLength = buffer.length;
        this.resize(this.numberOfChannels, this.length + bufferLength);
        this.setSection(buffer, bufferLength, 0, this.length - bufferLength);
    },

    pop: function(buffer) {
        var bufferLength = buffer.length;
        var offset = this.length - bufferLength;
        buffer.setSection(this, bufferLength, offset, 0);
        this.resize(this.numberOfChannels, offset);
    },

    unshift: function(buffer) {
        var bufferLength = buffer.length;
        this.resize(this.numberOfChannels, this.length + bufferLength, false,
                    bufferLength);
        this.setSection(buffer, bufferLength, 0, 0);
    },

    shift: function(buffer) {
        var bufferLength = buffer.length;
        buffer.setSection(this, bufferLength, 0, 0);
        this.resize(this.numberOfChannels, this.length - bufferLength,
                    false, bufferLength);
    },

    zero: function() {
       var numberOfChannels = this.numberOfChannels;
        for (var i = 0; i < numberOfChannels; i++) {
            var channel = this.getChannelData(i);
            var length = this.length;
            for (var j = 0; j < length; j++) {
                channel[j] = 0;
            }
        }
    },

    combined: function() {
        var channels = this.channels;
        var numberOfChannels = this.numberOfChannels;
        var length = this.length;
        var combined = new Float32Array(numberOfChannels * length);
        for (var i = 0; i < numberOfChannels; i++) {
            combined.set(channels[i], i * length);
        }
        return combined;
    },

    interleaved: function() {
        var channels = this.channels;
        var numberOfChannels = this.numberOfChannels;
        var length = this.length;
        var interleaved = new Float32Array(numberOfChannels * length);
        for (var i = 0; i < length; i++) {
            for (var j = 0; j < numberOfChannels; j++) {
                interleaved[numberOfChannels * i + j] = channels[j][i];
            }
        }
        return interleaved;
    },

    copy: function() {
        var buffer = new AudioletBuffer(this.numberOfChannels, this.length);
        buffer.set(this);
        return buffer;
    },

    load: function(path, async) {
        var request = new AudioFileRequest(path, async);
        request.onSuccess = function(decoded) {
            this.length = decoded.length;
            this.numberOfChannels = decoded.channels.length;
            this.unslicedChannels = decoded.channels;
            this.channels = decoded.channels;
            this.channelOffset = 0;
        }.bind(this);
        
        request.onFailure = function() {
                console.error('Could not load', path);
        }.bind(this)
        
        request.send();
    }
});

@@ -294,35 +294,16 @@
 32Array(
-numberOfChannels * 
 length))
@@ -3559,16 +3559,25 @@
 elOffset
+ + offset
 ;%0A%0A     
@@ -5044,49 +5044,8 @@
 fix%0A
-                channelOffset += offset;%0A
     

Fix two bugs in AudioletBuffer, where channels would end up the wrong size.