Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

SugarCube 2.18.0 — more granular control over audio play/stop/fade etc?

Bear with me on this as I'll try to explain my situation as clearly as I can —

My game has background music associated with different sections of the "world." As the narrative structure of the game isn't linear, it's possible for the player to approach different areas in different orders; to compensate this I have a macro that fades out the currently-playing audio
<<audio ":playing" fadeoverto 2 0>>

and then the background track associated with the zone comes in on top
<<audio "CharacterCreation_A" loop play>>

This works fine except that I also have audio effects associated with clicking buttons and other UI elements, and I belatedly realised that they are also impacted by the :playing catchall — because duh, of course they would be.

My question is — is there a better way that I can do this in order to fade out the background music but not disrupt the UI audio effects? The only way I can think at the moment would be to hard code all of them like
<<audio "CharacterCreation_A" fadeoverto 2 0>>
<<audio "Zone_A" fadeoverto 2 0>>
<<audio "Zone_B" fadeoverto 2 0>>
<<audio "Zone_C" fadeoverto 2 0>>

etc etc so that it covers any tracks that might happen to be playing at the moment, but that's tedious and I'm hoping there's a smarter way to manage it. Maybe with the playlists? Can, for example, I put all of the audio in a playlist and trigger a fadeoverto macro on that playlist even if the audio track is playing separately to the playlist itself?

Let me know if this makes no sense.

Comments

  • edited May 12
    What about using a story variable to track which background track is 'active' and then using that when issuing the fadeoverto.
    <<set $activeBackgroundTrack to "CharacterCreation_A">>
    <<audio $activeBackgroundTrack loop play>>
    
    
    <<audio $activeBackgroundTrack fadeoverto 2 0>>
    
    note: The above has not been tested, and it assumes you can use a story variable as a parameter to the <<audio>> macro so it may not work.
  • edited May 12
    greyelf wrote: »
    note: The above has not been tested, and it assumes you can use a story variable as a parameter to the <<audio>> macro so it may not work.

    Unfortunately in my case even if you can use a variable, it won't exactly work for me — I have two tracks which play simultaneously to compensate for the fact that audio doesn't loop seamlessly in Twine/SugarCube (it has a tendency to skip for a split second on the loop, so the two tracks fade in and out and mask where the loop actually happens). So while the player only "hears" what appears to be a single audio track, there are actually two.

    I could do
    <<set $activeBackgroundTrack to "CharacterCreation_A">>
    <<set $activeBackgroundTrack2 to "CharacterCreation_B">>
    <<audio $activeBackgroundTrack loop play>>
    <<audio $activeBackgroundTrack2 loop play>>
    
    
    <<audio $activeBackgroundTrack fadeoverto 2 0>>
    <<audio $activeBackgroundTrack2 fadeoverto 2 0>>
    

    to compensate but it's still an inelegant solution to the problem.
  • I get what you mean. Unfortunately, you cannot use playlists for this—while they do provide the grouping you want, playback actions only apply to the currently active track.

    The only way to achieve what you want, currently, is to hard code each of the tracks you want to affect.


    That said. It shouldn't be too difficult to create a new macro which would allow the creation of custom audio groups. For example:
    /********************************************
    ** EXAMPLE ONLY – THIS IS NOT ACTUAL CODE! **
    ********************************************/
    
    /* Creation of a BGM group */
    <<createaudiogroup ":bgm">>
    	<<track "Zone_A">>
    	<<track "Zone_B">>
    	<<track "Zone_C">>
    <</createaudiogroup>>
    
    /* Usage */
    <<audio ":bgm" fadeoverto 2 0>>
    


    Still, that might also be unwieldy in certain cases, so it might be nice to have the ability to negate a group as well. For example:
    /********************************************
    ** EXAMPLE ONLY – THIS IS NOT ACTUAL CODE! **
    ********************************************/
    
    /* Creation of a UI group */
    <<createaudiogroup ":ui">>
    	<<track "UI_Click">>
    	<<track "UI_Beep">>
    	<<track "UI_Buzz">>
    <</createaudiogroup>>
    
    /* Usage */
    <<audio "not(:ui)" fadeoverto 2 0>>
    


    Thoughts?
  • mixvio wrote: »
    there are actually two.
    Simply change the data type of the variable to an Array and it can track as many different tracks as you want.
    <<set $activeBackgroundTracks to []>>
    
    
    <<set $activeBackgroundTracks.push("CharacterCreation_A")>>
    <<audio "CharacterCreation_A" loop play>>
    <<set $activeBackgroundTracks.push("CharacterCreation_B")>>
    <<audio "CharacterCreation_B" loop play>>
    
    
    <<for _i to 0; _i lt $activeBackgroundTracks.length; _i++>>
    	<<audio $activeBackgroundTracks[_i] fadeoverto 2 0>>
    <</for>>
    <<set $activeBackgroundTracks to []>>
    
    note: Again the above has not been tested.
  • Still, that might also be unwieldy in certain cases, so it might be nice to have the ability to negate a group as well. For example:
    /********************************************
    ** EXAMPLE ONLY – THIS IS NOT ACTUAL CODE! **
    ********************************************/
    
    /* Creation of a UI group */
    <<createaudiogroup ":ui">>
    	<<track "UI_Click">>
    	<<track "UI_Beep">>
    	<<track "UI_Buzz">>
    <</createaudiogroup>>
    
    /* Usage */
    <<audio "not(:ui)" fadeoverto 2 0>>
    

    This would actually probably be exactly what I want; allowing me to exempt the UI audio from any attempts to fadeout the background music. There's fewer UI tracks so it's easier to remove them from the "playing" issue entirely and have their presence ignored.

    Would I put the above code in the javascript part of Twine, or call it in the StoryInit passage?

    And to be sure
    <<audio "not(:ui)" fadeoverto 2 0>>
    

    will function effectively the same way as
    <<audio ":playing" fadeoverto 2 0>>
    

    except that instead of hitting all playing audio it fades every track except those in the UI group?
  • Oh, I got back to my computer and hadn't realised the createaudiogroup bit wasn't in SugarCube already, ha. Yeah — I think that would fix my issue entirely if you've got the time to implement it, TheMadExile.

    Thanks for the quick work & super helpfulness as always.
  • mixvio wrote: »
    Would I put the above code in the javascript part of Twine, or call it in the StoryInit passage?
    Whatever macro I come up with, and <<createaudiogroup>> has a good chance, it would probably be best to place it in the StoryInit special passage after all of your <<cacheaudio>> invocations.

    If you've scattered your <<cacheaudio>> invocations around for whatever reason, then at least the tracks you intend to put into the group must have been already cached.

    mixvio wrote: »
    And to be sure
    <<audio "not(:ui)" fadeoverto 2 0>>
    

    will function effectively the same way as
    <<audio ":playing" fadeoverto 2 0>>
    

    except that instead of hitting all playing audio it fades every track except those in the UI group?
    Not quite. I'm still mulling over the syntax, however, my current idea is that the negation must be applied to a group. In the absence of an explicit group, :all would be the default/implicit group.

    For instance, your first example is equivalent to the following:
    <<audio ":all:not(:ui)" fadeoverto 2 0>>
    

    Acting only upon playing tracks not in the :ui group would look like:
    <<audio ":playing:not(:ui)" fadeoverto 2 0>>
    


    That's looking vaguely CSS pseudo-class-ish to me. Not sure if that's good, bad, or just a thing. Regardless, I think I want to allow the negation to affect multiple IDs, so I may also have to allow multiple IDs to be specified period. For example:
    → Target all playing tracks, except for those in the ":ui" and ":bgm" groups.
    ":playing:not(:ui :bgm)"
    
    → Target all playing tracks, except for "swamped" and "closer".
    ":playing:not(swamped closer)"
    
    → Target all playing tracks and "swamped" and "closer", regardless of their playback state.
    ":playing swamped closer"
    
    → Target only "swamped" and "closer", regardless of their playback state.
    "swamped closer"
    


    As is currently the case, none of those will affect playlist copies of tracks—though references would continue to be fair game.
  • I don't mind whichever implementation provided that it allows me to either fadeout just the background music group, or anything except the UI group (at the moment the only audio I have is either UI elements, or background soundtrack, and I can't imagine that changing), so whichever way you feel would be more elegant.
  • Just a quick note to say that I haven't forgotten about this. I've simply been short on free time lately as I've been fighting some health issues.

    The basic functionality has been completed, I just need to polish it up a bit. I would also like to address some other QoL issues before publishing a new release, so that's an additional holdup.
  • All good, no crisis — thanks so much for your help as always.
  • edited May 23
    You have a PM—covers both recent issues.
Sign In or Register to comment.