mpetroff / pannellum

Pannellum is a lightweight, free, and open source panorama viewer for the web.
https://pannellum.org/
MIT License
4.29k stars 726 forks source link

What's the best way to integrate Sound ? #964

Closed Spatial-esk closed 3 years ago

Spatial-esk commented 3 years ago

Hello

Your lightweight viewer is awesome. I've followed the examples presented on the website and have created a tour successfully, my question remains however - what code would be best to attribute sound to each 'scene' as a background sound?

Much appreciated!

S

mpetroff commented 3 years ago

You can use the viewer.on method to add an event listener to the scenechange event, e.g.,

var viewer = pannellum.viewer('panorama', {...});
viewer.on('scenechange', function(sceneid) {
    // Play the sound here
});
Spatial-esk commented 3 years ago

Thank you for your prompt response.

Using the Tour Example API for instance (below) , where would this event listener be best placed in the structure? I have an mp3 file ready to link to on the web so an indication of how this could be referenced would be greatly appreciated.

<!DOCTYPE HTML>

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tour</title>
<link rel="stylesheet"

href="https://cdn.jsdelivr.net/npm/pannellum@2.5.6/build/pannellum.css"/> <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/pannellum@2.5.6/build/pannellum.js">

On Wed, Mar 10, 2021 at 9:17 AM Matthew Petroff wrote: > You can use the viewer.on method to add an event listener to the > scenechange event, e.g., > > var viewer = pannellum.viewer('panorama', {...});viewer.on('scenechange', function(sceneid) { > // Play the sound here}); > > — > You are receiving this because you authored the thread. > Reply to this email directly, view it on GitHub > , > or unsubscribe > > . > -- Spatial-esk +44 772 5916 798 http://www.spatialesk.com
strarsis commented 3 years ago

You could add custom fields to each scene in your tour JSON and then let one single event handler use a specific scene field as the audio name/URL.

mpetroff commented 3 years ago

Using the Tour Example API for instance (below) , where would this event listener be best placed in the structure?

Replace the first line of the script, pannellum.viewer('panorama', {, with var viewer = pannellum.viewer('panorama', { to assign the Pannellum instance to a variable.

Then, add new code at the end of the script:

viewer.on('scenechange', function(sceneid) {
    // Replace this code with code to play your sounds.
    // This example will print the scene ID, e.g., `circle` or `house` in the example, to the browser
    // developer console any time the scene changes.
    console.log(sceneid);
});
epignosis567 commented 3 years ago

Hi. Is there a way to automatically stop the sound from the previous scene when a new scene loads? I'm trying to make every scene have it's own unique ambient sound playing in the background, but using the method here the sound from the first scene just keeps playing over the sound from the previous scene.

strarsis commented 3 years ago

@epignosis567: Well, store the JavaScript audio instance in a variable and in the handler that loads a new sound you can stop/destroy the old audio instance.

epignosis567 commented 3 years ago

Thanks, but I don't think that would work since I'm storing the audio in individual 'scenechange' functions, right?

strarsis commented 3 years ago

@epignosis567: You could store the audio reference in a variable named currentAudio that is global so the scene change function can access it. It checks whether the variable is initialized and then stops/destroys the audio. Then it creates the new audio and assigns it to the variable instead, for the next scene change.

Edit: Destroying an audio element: https://stackoverflow.com/a/8870315/4150808

epignosis567 commented 3 years ago

Thanks! I'll work on this. (I opened a separate issue in the meantime.) I'm not sure I understand how this could be implemented using 'scenechange' though. This is what I've been working on:

viewer.on('scenechange', function(extWindow) {
        var extWindowAmbience = document.getElementById("extWindowSound");
        extWindowAmbience.play();
        console.log(extWindow);
    });

    viewer.on('scenechange', function(hallChar) {
        var hallCharAmbience = document.getElementById("hallCharSound");
        hallCharAmbience.play();
        console.log(hallChar);
    });
strarsis commented 3 years ago

@epignosis567:

    var currentAudioElement = null; // store a reference to the current audio element for further usage

    viewer.on('scenechange', function(sceneId) {
        if(currentAudioElement) {
            // pause the current audio element (in case it is still playing)
            currentAudioElement.pause();
        }

        let newAudioId = sceneId + 'Sound'; // e.g. audio element with ID "ambienceSound" for sceneId "ambience"
        let newAudioElement = document.getElementById(newAudioId);

        currentAudioElement = newAudioElement ;
        newAudioElement.play();
    });

When the scene changes, the handler checks for a set currentAudioElement variable. If it is set, it calls pause() on that audio element in order to prevent any further audio playback. Then it gets the audio element for the new scene, also assigns it to currentAudioElement and plays it back.

epignosis567 commented 3 years ago

Thanks. I’m still working on this but I will report back.

Spatial-esk commented 3 years ago

Thanks, this has worked well for me - Great help!