Examples of using <<AudioTrack>> API or SimpleAudio API

Twine Version: Latest

Hi All! Using Sugarcube for a few months here and there and am loving the flexibility. Right now I’m stuck in researching and trying to uncover how to correctly use the AudioTrack and/or SimpleAudio APIs to control audio play from the Story JS.

I have already implemented a previous prototype using the handy macros <<audio>> <<cacheaudio>> <<masteraudio>> and etc, but a planned expansion of my story involves synchronising 3 moving parts in the audio, and it’s very unwieldy to handle that on a per passage basis. Furthermore, at least how I’ve architected it, I need to leverage a :passagedisplay event to find an element on the page to trigger the 3 way synchronisation. So anyway, if I can’t find a way to control play of the (usually around 50 individual audio files) in the StoryJS I’ll have to abandon my planned expansion. cries in wasted dev hours

For a little description, I have character audio which is synthesized using TTS, and one some passages there are multi-turn conversations. I have subtitles which are synchronised to the speech (already handled in the StoryJS). I’d like to have a carousel of images to accompany the characters, and I’m handling that by creating an empty img element and changing the img source step by step through an array of images that are already programmatically updated through the whole built html.

So, in short : Image, Subtitles are working well, and in sync (from StoryJS) on every passage that has a character multi-turn conversation. I need to handle the play of the single audio file per passage, from Story JS.

I have trawled over 50 intfiction, reddit, twinery (and other) posts, but can’t find a single example of how to reference the audio files (already set up with <<cacheaudio>> macro in StoryInit) using either <<AudioTrack>> or SimpleAudio APIs and thus manipulate them in the Story JS.

Any help or samples would be really appreciated.

Hmm… if I’m understanding correctly, you want SimpleAudio.select() for that? There are some basic usage examples in the docs:

// Return the AudioTrack instance matching "swamped" and do something with it
SimpleAudio.select("swamped").volume(1).play();

// Start playback of paused audio tracks
SimpleAudio.select(":paused").play();

// Pause playback of playing audio tracks
SimpleAudio.select(":playing").pause();

// Stop playback of playing audio tracks
SimpleAudio.select(":playing").stop();

// Stop playback of all audio tracks (not uniquely part of a playlist)
SimpleAudio.select(":all").stop();

// Stop playback of playing audio tracks except those in the ":ui" group
SimpleAudio.select(":playing:not(:ui)").stop();

// Change the volume of all audio tracks except those in the ":ui" group
// to 40%, without changing the current playback state
SimpleAudio.select(":all:not(:ui)").volume(0.40);
1 Like

Thanks so much for taking the time with a reply here!

This helps for sure. My situation is a step before this, in a way. e.g. the first line in the example (Return the AudioTrack instance matching “swamped”…) - I wasn’t sure how to instantiate/create/acquire an AudioTrack instance in the first place and was struggling with the ideal usage.

However, I realised literally an hour ago that I was nearly there but I had some other Layer8 problems.

So, for those with the same problems as me, here is some basic usage :

  1. In your StoryInit use <<cacheaudio>> as outlined in the docs
    (e.g. <<cacheaudio "audiotrackid1234" "https://media_hosting/audiotrack.mp3">> )
  2. In the passage itself where you want the audio to play, create a variable using Sugarcube macro <<set $aTrack = "audiotrackid1234">>
  3. Now that you have set up this variable, with an event handler you can play it using Story JS when the passage has finished loading.
$(document).on(':passagedisplay', function(event){
    let aTrackId = State.getVar("$aTrack");
    let aTrackInstance = SimpleAudio.tracks.get(aTrackId);
    aTrackInstance.play();
})

Of course you can set multiple audio files up in cacheaudio and set the variable as in step 2 in multiple passages. They all just play after :passagedisplay, which was something I needed.

Adding search terms for indexing so future me (just before the cyborgs overthrow us all in 2150) can find it again :slight_smile:

sugarcube audiotrack
sugarcube audiotrack examples
sugarcube audio macro or audiotrack api

oh, and include a <<masteraudio stop>> at the top of the passage to stop previous audio playing. The audio macro runs before passagedisplay so it just… works? :slight_smile: