Search code examples
javascriptweb-audio-apisynthesizerscriptprocessor

scriptProcessorNode oscillator frequency


I am working on a web audio stochastic oscillator and am having trouble with the scriptProcessorNode. My algorithm uses a random walk to determine dynamic breakpoints in the waveform and then interpolates between them.

As the breakpoints move on the x axis I thought the frequency of the oscillating waveform would change, but there is just a filtering effect, and the frequency seems to just be determined by the scriptProcessorNode buffer size, which must be a power of 2 between 256 and 16384.

How do you change the frequency of a scriptProcessorNode oscillator?

Here is my synthesis code:

scriptNode.onaudioprocess = function(audioProcessingEvent) {

    walk(); //use random walk to generate new x/y position for each breakpoint

    var outputBuffer = audioProcessingEvent.outputBuffer;
    var lastPoint = 0;
    var index = 0;

    // linearly interpolate between the new breakpoint positions
    for(var i = 0; i < breakpoint.length-1; i++) {
        var y = breakpoint[lastPoint].y; 
        for(var channel = 0; channel <= 0;channel++) {
            var outputData = outputBuffer.getChannelData(channel);
            if(i != 0){
                if(y >= breakpoint[i].y) {
                    while(y >= breakpoint[i].y) {
                        y = (breakpoint[i].m*index)+breakpoint[i].b;// y = m(x)+b
                        outputData[index] = y; 
                        index++; 
                    }
                } else if(y <= breakpoint[i].y) {
                    while(y <= breakpoint[i].y) {
                        y = (breakpoint[i].m*index)+breakpoint[i].b;
                        outputData[index] = y; 
                        index++;  
                    }
                }
            } 
        }
        lastPoint = i;
    }
}

And here is a link to a working example: http://andrewbernste.in/bernie/gendy011.html

This is all based on Iannis Xenakis' GENDY stochastic synthesis program.

Thanks!


Solution

  • I solved the problem by using an index variable outside of my scriptNode.onaudioprocess function to write the waveform to the scriptNode buffer. That way the frequency at which the waveform is written to the buffer is not tied to the size of the buffer.

    Here is the final code:

    var index = 0;
    var freq = 0.8;
    
    scriptNode.onaudioprocess = function(audioProcessingEvent){
    
        var outputBuffer = audioProcessingEvent.outputBuffer;
        var outputData = outputBuffer.getChannelData(0);
        for(var j = 0; j < outputData.length;j++){
            // linearly interpolate between the new breakpoint positions
            // get the interp point by comparing index to the x distance
            var lerp = (index - breakpoint[point].x) / (breakpoint[point+1].x - breakpoint[point].x)
    
            y = nx.interp(lerp,breakpoint[point].y,breakpoint[point+1].y);
            if(point < breakpoint.length && index >= breakpoint[point+1].x) {
                point++;
            }
    
            outputData[j] = y;
            index+=freq; 
            if(index >= breakpoint[breakpoint.length-1].x){
                index = 0;
                point = 0;
                walk(); 
            }  
        }
    }