Skip to main content

On Sale: GamesAssetsToolsTabletopComics
Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

Queueing Multiple Audio/Music Files

A topic by LEMONPOPPYSEEDGAMES created 26 days ago Views: 117 Replies: 4
Viewing posts 1 to 4
(+3)

I've been searching through the All About Sounds deck and this forum to try and figure out how to get looping background music that is longer than 10 seconds (without disrupting navigation like buttons).

I know that you can use sleep["play"] to play multiple audio files in order quite easily, but that prevents navigation and other things being visible, it seems. Navigation is available when using the "loop" argument in the play function (i.e. play ["audio1" "loop"]) and there is an event on loop do that can execute code each time a loop finishes. I have tried using on loop do in conjunction with a counter and some if statements to achieve my goal, but so far my attempts have not worked.

Has anyone discovered a way to accomplish this? Or does anyone know of some code that may work? Thanks.

(1 edit) (+3)

I'm sure someone more familiar with sound than I am will come along in a minute, but for now I'll point you to Asteroid Run which does something along these lines. There is a downloadable unlocked version of the deck on the page.

You may find the card script on the "gamescreen" card helpful for this.

(1 edit) (+3)

Hi! Ahmwma has already linked Asteroid Run which I wrote, please feel free to take a look at the code and ask me any questions.

I'll paste a somewhat simplified version of the code below

music1:("","sound1","sound2","sound3","sound4","sound3","sound3","sound1","sound2")
on loop do
 loopcounter.text:loopcounter.text+1
 if loopcounter.text="9" loopcounter.text:1 end
 music1["%i" parse loopcounter.text]
end

So, simple explanation is I've got a counter that increments every time loop is called (which is basically every time the audio finishes) and I've got a list in the code of all the sounds I want to play, in order. When the loop goes round, it'll increment the counter and return the name of the next sound. (And no I don't remember why I have it going from 1 to 8 instead of 0 to 7, sorry lol)

Let me know if this makes sense, or if you want to share your attempt maybe we can take a look and see why it's not working for you, since from the sounds of things you're basically working on the same principle.

(I guess the other way to have background music would be with the contraption I wrote lol)

Developer (1 edit) (+3)

Just to flesh out the implied details of Millie's example, I have an experimental setup with four audio clips named "sound1" through "sound4" (I used Decker to record myself saying the numbers one through 4 to make it clear), a field named "loopcounter", a button for starting the loop with a script like this:

on click do
 loopcounter.text:0
 play["sound1" "loop"]
end

and a button for stopping it like this:

on click do
 play[0 "loop"]
end

That leaves us with the loop[] event handler, which for this setup ought to be defined on the card. If you wanted the music to keep playing across many cards, defining a handler on the deck-level script could also work, but it would then be important to specify the path to the loopcounter field as e.g. "deck.cards.thatCard.widgets.loopcounter" instead of just "loopcounter".

We can simplify Millie's example in a few ways. Firstly, by indexing from 0 instead of 1, we can use the modulus operator (%) to wrap the incremented value of loopcounter between 0 and the length of the list of audio clip names, avoid the need for a "dummy" element at the beginning of the list, and save an "if" statement. We can also coerce a string like "3" to the number 3 by adding 0 to it (or any equivalent arithmetic identity operation) instead of parsing it:

music1:("sound1","sound2","sound3","sound4","sound3","sound3","sound1","sound2")
on loop do
 loopcounter.text:(count music1)%1+loopcounter.text
 music1[0+loopcounter.text]
end

We could make the script more concise still by defining the list of pattern names as a single string that we split on pipes (|) and stashing the loop index in a temporary variable so we don't have to refer to "loopcounter.text" three times or turn the string-ified index back into a number:

on loop do
 m:"|" split "sound1|sound2|sound3|sound4|sound3|sound3|sound1|sound2"
 loopcounter.text:i:(count m)%1+loopcounter.text
 m[i]
end

Since there's a very simple pattern to the names of audio clips we want to play, we could be even more concise by only building a list of the part that varies- the number at the end of the string- and formatting that at the end of the function:

on loop do
 m:1,2,3,4,3,3,1,2
 loopcounter.text:i:(count m)%1+loopcounter.text
 "sound%i" format m[i]
end

Of course, the most important thing is always to use the approach that makes sense to you! Longer code isn't necessarily worse if you find it clearer or easier to modify.

(+3)

Ahmwma, Millie, IJ, thank you all for such detailed answers! I really appreciate it, especially as someone who is rather new to coding! I have implemented some of the code suggested by IJ in the script of my card:

music1:("menu1","menu2","menu3")
 on loop do
 loopcounter.text:(count music1)%1+loopcounter.text
 music1[0+loopcounter.text]
end
This worked quite wonderfully! Admittedly, it will take a bit for me to fully unpack and understand it all just because of my limited understanding of code. It is interesting to use a field to store the variable information! I'll keep that in mind.

---

In regards to your discussion about having audio play across multiple cards, IJ, I found that the loop would continue if I navigate to a new card, but it would stay on the same track and loop (which I suppose makes sense given that the script on the original card would no longer apply) -- I was able to stop playback by putting the following in the script of the other pages:

on loop do
 
end
If I did want playback of the whole chain of audio files across slides, I will absolutely follow your advice above, thanks.

---

Just wanted to add this bit in case anyone wanders upon this thread in the future, but part of me had also wondered if there were a way to make it so that the whole audio chain would restart when you navigate back to that page. I managed to accomplish that by adding this bit of code at the top:

on view do
 loopcounter.text:-1
end
music1:("menu1","menu2","menu3")
on loop do
 loopcounter.text:(count music1)%1+loopcounter.text
 music1[0+loopcounter.text]
end
And that seems to work for me! If anyone finds there's a more efficient method, you're welcome to suggest it!

Thank you all for the help! Now off to make some awesome stuff with Decker! <3