resonance-audio / resonance-audio-web-sdk

Resonance Audio SDK for Web
https://resonance-audio.github.io/resonance-audio/
Apache License 2.0
200 stars 56 forks source link

Confirming exactly what the "ambisonicOutput" is #25

Closed tonetechnician closed 5 years ago

tonetechnician commented 5 years ago

Hey there,

I have been playing around with the examples and it seems the "ambisonicOutput" object isn't quite working as I thought it would.

Assuming I'm using first order, when I connect the ambisonicOutput of the resonance object to my audio context destination, I expect 4 channels of B-format to be output to my soundcard (I have a multichannel soundcard).

However, when I do this, I only get 2 channels. Could someone please confirm if this behavior is expected?

I have tried playing a regular multichannel file from my browser and that works perfectly so would expect the raw B-format to output to my soundcard similarly.

Thanks!

tonetechnician commented 5 years ago

Sorry, I realized this was simply because my audioContext was not setup to handle 4 channels. This works as it should!

iooops commented 5 years ago

Hi same issue here.

So how did you get the expected output finally?

tonetechnician commented 5 years ago

I needed to change the audioContext destination channel count, for some reason it defaulted to 2. I found that I needed to ensure the channel count was set to the number of channels on the destination device, in my case 8 channels, otherwise the channel mapping would go funny. If you have a 4 channel soundcard it would need to be 4 channels.

So referring to the vs-pannernode.js example. I added in some lines that would take the raw ambisonic output from the foaScene audio processor. I have added comments next to my changes. If you'd like the full file I can upload it to my git.

function initAudio() {
  // Create <audio> streaming audio source.
  audioContext = new (window.AudioContext || window.webkitAudioContext);
  console.log(audioContext)
  audioContext.destination.channelCount = 8;  // Set the number of channels on the sound card
  let audioSource = 'resources/cube-sound.wav';
  audioElement = document.createElement('audio');
  audioElement.src = audioSource;
  audioElement.crossOrigin = 'anonymous';
  audioElement.load();
  audioElement.loop = true;
  audioElementSource =
    audioContext.createMediaElementSource(audioElement);

  // Create gain nodes.
  noneGain = audioContext.createGain();
  pannerGain = audioContext.createGain();
  foaGain = audioContext.createGain();
  toaGain = audioContext.createGain();
  ambioutGain = audioContext.createGain(); // Created RAW Ambisonic output gain node.
  ambioutGain.channelCount = 4;  // Ensure it is set to 4 channels
  // Initialize scene and create Source(s).
  // Initialize PannerNode/Listener
  foaScene = new ResonanceAudio(audioContext, {
    ambisonicOrder: 1,
    dimensions: {
      width: 0,
      height: 0,
      depth: 0,
    },
    materials: {
      left: 'transparent',
      right: 'transparent',
      front: 'transparent',
      back: 'transparent',
      up: 'transparent',
      down: 'transparent',
    }
  });
  console.log("foa")
  console.log(foaScene);
  toaScene = new ResonanceAudio(audioContext, {ambisonicOrder: 3});
  pannerNode = audioContext.createPanner();
  pannerNode.panningModel = 'HRTF';
  pannerNode.distanceModel = 'inverse';
  pannerNode.refDistance = ResonanceAudio.Utils.DEFAULT_MIN_DISTANCE;
  pannerNode.maxDistance = ResonanceAudio.Utils.DEFAULT_MAX_DISTANCE;
  foaSource = foaScene.createSource();
  toaSource = toaScene.createSource();

  // Connect audio graph.
  audioElementSource.connect(noneGain);
  audioElementSource.connect(pannerNode);
  audioElementSource.connect(foaSource.input);
  audioElementSource.connect(toaSource.input);
  pannerNode.connect(pannerGain);
  foaScene.output.connect(foaGain);
  toaScene.output.connect(toaGain);

  console.log(foaScene);
  console.log(foaScene.ambisonicOutput);

  foaScene.ambisonicOutput.connect(ambioutGain);  // Connect the 4 channel 'ambisonicOutput' from the foaScene to my ambisonic Gain node

  noneGain.connect(audioContext.destination);
  pannerGain.connect(audioContext.destination);
  foaGain.connect(audioContext.destination);
  toaGain.connect(audioContext.destination);

  ambioutGain.connect(audioContext.destination); // Connect the gain node to the soundcard

  audioReady = true;
  selectRenderingMode();
}

Hope this helps!

scriptify commented 3 years ago

@tonetechnician Nice! Do you know if the same technique could also be used to make ResonanceAudio compatible with different speaker layouts like 5.1 or 7.1?

tonetechnician commented 3 years ago

Hey there @scriptify - must be honest, it's been a little while since I looked at this code, but I believe it would support other layouts.

You'll just need to figure what the channel mapping is for your surround channels, but I don't see it any different. Just add the resonance web audio decoder, set the channel count, and let it decode. If I get a chance I'll have a quick look to check.

scriptify commented 3 years ago

Sounds logic! Would be cool if it could be used with Apple's Spatial Audio feature. I don't own AirPods myself so I need to borrow some and try it out. Thanks for your answer.

It would also be cool to look into other methods of mimicing the listener's head position, but that's beyond that thread.