Search code examples
typescriptangular2-routingangular2-servicesweb-audio-api

WebAudio's ScriptProcessor in Angular 2


I would need to generate audio on the fly in Angular 2 and I found a working sample I had with WebAudio but in JS. Everything worked well in JS and I could make some sounds play today (for example random noise) for TS (Angular 2). The thing is that I would need to access to a variable I have in my service but from the script processor event (onaudioprocess). There is a sample code below.

Would this be possible? In JS, I had global variables and worked well.

imports...

@Injectable()
export class SomeService {
    variable: any;
  constructor()
  {
    this.variable = new Variable();
    this.initWebAudio();
  }

   initWebAudio(): void
    {
         try {
            this.context = new ((<any>window).AudioContext || (<any>window).webkitAudioContext)();
            this.context.SampleRate = this.sample_rate;

            this.masterGainNode = this.context.createGain();
            this.masterGainNode.gain.value = 0.5;
            this.masterGainNode.connect(this.context.destination);

            this.startJSProcessor();
          }
          catch(e) {
            alert('Web Audio API is not supported in this browser');
          }     
    }

    startJSProcessor(): void
     {      
        if(this.context.createScriptProcessor)
        {
            this.jsProcessor = this.context.createScriptProcessor(4096, 1, 2);
            //alert("Chrome Desktop/Android");
        }
         else if(this.context.createJavaScriptNode)
         {
            this.jsProcessor= this.context.createJavaScriptNode(4096,1,2);
            //alert("Safari");
        }
         else
        {
            alert("No way");
        }           
        this.jsProcessor.onaudioprocess = this.generateSounds;
        this.jsProcessor.connect(this.masterGainNode);
     }

     generateSounds(event: any): void
     {       
        var outputR = event.outputBuffer.getChannelData(0);
        var outputL = event.outputBuffer.getChannelData(1);     

        //"this" is undefined here...       
        var something = this.variable.something;
      }

Solution

  • This is the same problem that's been flummoxing people in JS for years. You can't use this.generateSounds as a callback directly because it will lose the this binding. Try this:

    this.jsProcessor.onaudioprocess = this.generateSounds.bind(this);
    

    or (equivalent):

    this.jsProcessor.onaudioprocess = (event: any) => {
      this.generateSounds(event);
    };