Jump to content

[LE] Making bards play long songs, can't figure how to keep events in sync w/ music.


Recommended Posts

tl;dr I need multiple sounds to play back-to-back randomly without getting out of sync w/ script events, that I can also stop at-will.

 

This is semi complex so thanks in advance for reading through this! I'm making a completely new bard system with new bards who simply play instrumental songs for a specific duration via a package (early evening into late night.) I am using an hour of full-length classical guitar songs that are selected randomly. The first version was very simple, clean, and works great. Except one fatal flaw, which I cannot seem to work around.

 

In order to track when a song ends to select and play another one, I do a RegisterForSingleUpdate for the length of the song in seconds. I thought this was sort of clever. When the OnUpdate happens, I fire off the PlayRandomSong event again, and the bard starts playing another random song from the list (I have an array of the songs and the song lengths to easily pull from.) Songs are just very long sounds, emanating from the bard himself. The player can even tell them to stop playing, or to play a different song. Works great!

 

I have the sounds set to use the AudioCategoryPausedDuringMenu sound category, so when the player opens their inventory, containers, or other menus, and the RegisterForSingleUpdate stops counting (this function stops counting when the player has menus open) the music pauses so it stays mostly in sync with that counter. Also works great.

 

HOWEVER. When opening a trade/barter menu via dialogue, the game does not register this as a "Menu" like it does the inventory, and does not pause the sound. RegisterForSingleUpdate freezes, but the music keeps going. This makes the two out of sync dramatically, depending on how long you spend in the barter menu. If the song starts playing, and you talk to the innkeeper and spend 30 seconds selling and buying things, the song (since it continues to play) is now 30 seconds ahead of the RegisterForSingleUpdate, so there ends up being a 30 second pause before it properly counts down.

 

I tried about 17 different ways to hook into the menus and all that, but without SKSE there are no menu events. Notable workarounds included:

  • There is the PlayAndWait sound function which fires an event when a sound is finished playing, but that method removes all control of the sound (cannot stop it or anything whatsoever once it's going) so that is out of the question, because the player (nor the AI package) can tell the bard to stop playing once a song starts. It'll just emanate from their body til it finishes.
  • I thought of using the WaitMenuMode function, which DOES count down during menu modes to re-start the function each time, but that has no way to cancel like events do, so using it in a recursive way like that is sketchy. Also when requesting a new song, a new WAIT is initiated before the other one finishes, so you end up with multiple Wait events that are beyond control (unless one can cancel wait events?)

So, I re-made the whole thing using quests and scenes, using action timers in the scene phases under the assumption that those counters continued to run when the player was in a menu. Unfortunately, those too freeze exactly the same way that RegisterForSingleUpdate does, so it's the exact same problem, just with a different implementation.

 

I could make a new sound category that pauses the bard music completely during dialogue, but that ruins the atmosphere quite a bit.

 

I know this is probably hard to visualize without seeing it, but there are 10 or so components so I can't just paste a snippet of code in. This is more of an architectural problem and lack of supporting functions.

 

This is for Skyrim SE so I cannot make use of SKSE functions. If I did, I could check for any menu opening at all and pause the music, but alas, I cannot.

 

Cheers and thanks for reading if you made it this far.

Link to comment
Share on other sites

WORKAROUND SOLUTION that is good enough for now:

  • Made songs into _LPM with loop points so the songs loop to cover the potential gap when the timer and sound playback become out of sync (song gets ahead of timer)
  • Using LPM with fast envelope makes the 'tail' of where the loop ends play when stop is initiated, so songs still have a proper ending when Stop() is called, so both the "Tell bard to stop" and the PlayRandom functions that change the song make the current song end nicely using the tail
  • Worst-case scenario, someone spends the entire length of a song in a barter menu they will hear the song loop once before ending properly. They can always tell the bard to play something else for 1 Septim and kick off another song.

Not 100% perfect, but what ever is in the CK? It should be seamless to the user. :)

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...