4

I can easily get Tone.js to generate a tone within a Three.js world, simply by calling, e.g., oscillator = new Tone.Oscillator(440, "sine").toMaster();, but I can't work out how to connect that tone to an AudioListener in the Three.js world to make it be a positional sound. Does anybody know how to do this?

Using the oscillator built into Three.js, it works perfectly as per the Three.js audio-sandbox example, where it uses oscillator = listener.context.createOscillator(); so I assume this proves I need to connect the Tone.js output to the AudioContext of the listener, but I just can't figure out how to do that, and nor can I find anything on the web about it. Any examples I can find simply use the toMaster() approach as above, so the sounds are not positional.

Any help most appreciated!

B-30
  • 323
  • 1
  • 13

2 Answers2

6

I figured it out, posting self-answer for those searching in the future. You simply need to set the context of Tone.js to be the same as the PositionalAudio object, then setNodeSource of that object to be the Tone.js oscillator, add it to some geometry and hey presto, positional audio generated by Tone.js:

var mesh1 = new THREE.Mesh( geometry, material ); //geometry, material defined elsewhere
scene.add(mesh1);
listener = new THREE.AudioListener();
camera.add( listener );
var sound1 = new THREE.PositionalAudio( listener );
Tone.context = sound1.context;
var oscillator1 = new Tone.Oscillator(440, "sine");
sound1.setNodeSource (oscillator1);
mesh1.add( sound1 );
Guy Luz
  • 3,372
  • 20
  • 43
B-30
  • 323
  • 1
  • 13
  • Thx @B-30 very nice of you to post the solution you found. It helped me get started faster – Harrys Kavan Nov 06 '21 at 09:46
  • Trying to use this in AFRAME, but setNodeSource throws a DOMException InvalidAccessError. https://glitch.com/edit/#!/aframe-tonejs-position-audio – Ti Hausmann May 05 '22 at 11:09
  • It looks like Three.js and Tone.js have changed a lot since 2019. For example `Tone.context` does not have a setter like that anymore and is using `Tone.setContext`. Can you post updated code? – Guy Luz Mar 22 '23 at 15:02
  • 1
    @GuyLuz, I'm afraid I got out of the game after '19 (thanks Covid), but I got an alert from my still-active Stack account about this comment, thought I'd let you know you'll need to explore by yourself, presumably using Tone.setContext to set it to the sound1 context. Good luck! Great stuff, spatial audio on the web, maybe you've inspired me to get back into it. – B-30 Mar 23 '23 at 22:32
  • Thanks for answering, currently I am stuck on `sound1.setNodeSource (oscillator1);` as it does not accept this line on the typescript. Hope you are doing something that you enjoy, that is very important. – Guy Luz Mar 24 '23 at 17:52
0

for anyone looking for this in the future, I got this working with an audio file:

// declare the listener:
    const listener = new THREE.AudioListener();
    camera.add( listener );

    // set mesh (make sure to set material & geometry before
    sphere = new THREE.Mesh(geometry, material1);

    //set positional audio
    let sound1 = new THREE.PositionalAudio( listener );
    Tone.setContext(sound1.context);
    let player = new Tone.Player
    ({
            url: "sound/test2.wav",
            loop: true,
            autostart: true, //as a lot of browsers don't auto play audio
    });
    sound1.setNodeSource(player);
    sound1.setRefDistance( 3 );
    sphere.add(sound1);
flowe
  • 1