A sibling API to play_sound: play_music

Place to ask discuss and request the modding support of Factorio. Don't request mods here.
Quorken
Inserter
Inserter
Posts: 33
Joined: Mon Aug 18, 2025 3:53 pm
Contact:

Re: A sibling API to play_sound: play_music

Post by Quorken »

How about allowing modders to define custom "playlists" in the prototype stage (procedural music systems, like planets already have), and then at runtime, they can set which playlist to play?
Something like:
start_playlist(playlist=<playlist_name|default|nil>, where=<global|surface|surface_list>, when_to_start=<after_current|fade_now|cut_now>, loop=<int>, who=<player|force|all>, start_song=<song_name|random|nil)
Args:
playlist: what playlist to play; can be: playlist_name (name of playlist prototype) OR "default" (default playlist for surface) OR nil (no music)
where: where the playlist plays; can be: global (all surfaces) OR surface (specific surface to play on) OR surface_list (list of surfaces to play on)
when_to_start: how soon the playlist starts playing; can be: after_current (lets current song finish before new playlist starts) OR fade_now (gently fades out current song immediately before starting new playlist) OR cut_now (immediately terminates current song before starting new playlist)
loop: how many times to loop the playlist: can be: <int> (set number of times to loop; -1 means infinite)
who: who the playlist plays for; can be: player (specific player) OR force (all players on specific force) OR all (all players)
start_song: what song to start on w/in the playlist; can be: song_name (specific song w/in playlist) OR random (random song w/in playlist) OR nil (start of playlist)
When the playlist finishes, it should go back to the surface's default music.

There would be at least two new events: playlist_started and playlist_finished

This would allow for most use-cases, I think - custom playlists in vehicles, custom music during special events (like Ceres' launch), etc.

EDIT: If a mod that started a playlist playing is no longer present upon loading, the game should immediately terminate the playlist (especially if it was set to infinite loops)

You could also maintain a playlist "stack" - a list of playlists, in the order they were requested. A playlist is added to the stack when a mod starts it playing; it is removed when it finishes playing, the mod that added it is removed, or it is explicitly removed.
Then starting a playlist would have an extra options - stack_behavior=add|replace_current|clear_stack, which controls how the playlist is added to the stack - is it added on top of the stack, does it replace the top-most stack element, or does it clear the stack before adding itself? Not sure if the surface's default music should always be on the stack, nor how this would interact with the other options I suggested, like who, where, etc.

EDIT 2: You could also allow modders to define runtime-modifiable playlists, allowing modders to have fully dynamic music, without requiring other mods to handle all the nuance that comes with changing the actual available soundtracks.

EDIT 3: Music in playlists could be toggleable - each soundtrack would have a default_active that determines if it is, well, active by default; at runtime, this could then be written to by mods to enable/disable that soundtrack w/in that playlist.
mmmPI
Smart Inserter
Smart Inserter
Posts: 4802
Joined: Mon Jun 20, 2016 6:10 pm
Contact:

Re: A sibling API to play_sound: play_music

Post by mmmPI »

Quorken wrote: Mon Nov 03, 2025 10:42 pm How about allowing modders to define custom "playlists" in the prototype stage (procedural music systems, like planets already have), and then at runtime, they can set which playlist to play?
As an inexperienced modder, it doesn't appear clear to me right away how to avoid conflict if a mod specify a where for a song and another mod define a who . But otherwise i think i can follow some of it, and i would like to mention that it would be nice in such case to have an event for when a song finishes, so it's possible to check some condition to change the playlist. The goal with this would be to have "thematic" music, like check if the player is still wearing an armor with shield, or any piece of legendary equipment when a song ends, and pick or not a battle song or a "legendary" song. Maybe it shows i didn't understand something, let me know :) this is what i had in mind as use case.

Donion wrote: Mon Nov 03, 2025 5:42 pm
Eketek wrote: Mon Nov 03, 2025 4:17 pm I looked a bit more closely at variable ambient sounds ...
You're either asking to completely change what variable tracks are or asking to create an entirely new system of dynamic tracks. That's not going to happen.
Hey sorry if it's the same thing it's because i didnt understand, Would it be possible at some point to make it so different players have different playlist/music ? Correct me if i'm wrong, currently it's not possible using the ambiant music, and it's a problem because my mods add music that is loud, techno and has some AI stuff in it, which appears to all be reasons for other players to want to alter the common playlist i establish for the game somehow.

If we're talking about the goal of the API, that would be my n2, 1 => thematic music, requiring runtime check on some condition, 2=> players can have settings that are their own instead of comon for the ambiant music of a game, order is the one in which i realized i needed to explain it with word, it is subject to change :P
Check out my latest mod ! It's noisy !
Quorken
Inserter
Inserter
Posts: 33
Joined: Mon Aug 18, 2025 3:53 pm
Contact:

Re: A sibling API to play_sound: play_music

Post by Quorken »

mmmPI wrote: Tue Nov 04, 2025 3:02 am
Quorken wrote: Mon Nov 03, 2025 10:42 pm How about allowing modders to define custom "playlists" in the prototype stage (procedural music systems, like planets already have), and then at runtime, they can set which playlist to play?
As an inexperienced modder, it doesn't appear clear to me right away how to avoid conflict if a mod specify a where for a song and another mod define a who . But otherwise i think i can follow some of it, and i would like to mention that it would be nice in such case to have an event for when a song finishes, so it's possible to check some condition to change the playlist. The goal with this would be to have "thematic" music, like check if the player is still wearing an armor with shield, or any piece of legendary equipment when a song ends, and pick or not a battle song or a "legendary" song. Maybe it shows i didn't understand something, let me know :) this is what i had in mind as use case.
How it'd probably work is that each player has their own playlist that should play on a given surface, and setting the playlist for, say, a force, would set the playlist for each player w/in that force. So if you then set the playlist for a specific player in that force, their playlist would deviate from the force-wide playlist.

Or maybe you'd want the option for a force-wide playlist that supersedes the player-specific playlist.

It'd probably be a lookup table like: player -> {global: playlist|nil, per_surface: {nauvis: playlist|nil, ...}}
If the global playlist is nil, it looks up the per_surface playlist; otherwise, it uses the global playlist.

on_song_finished and on_song_started events would probably also be useful.
mmmPI
Smart Inserter
Smart Inserter
Posts: 4802
Joined: Mon Jun 20, 2016 6:10 pm
Contact:

Re: A sibling API to play_sound: play_music

Post by mmmPI »

Quorken wrote: Tue Nov 04, 2025 5:24 am How it'd probably work is that each player has their own playlist that should play on a given surface, and setting the playlist for, say, a force, would set the playlist for each player w/in that force. So if you then set the playlist for a specific player in that force, their playlist would deviate from the force-wide playlist.
ok that make sense to me, that fit the usecase "allowing other players with more delicate ears to join my games" and other similar situations :)
Quorken wrote: Tue Nov 04, 2025 5:24 am Or maybe you'd want the option for a force-wide playlist that supersedes the player-specific playlist.
It'd probably be a lookup table like: player -> {global: playlist|nil, per_surface: {nauvis: playlist|nil, ...}}
If the global playlist is nil, it looks up the per_surface playlist; otherwise, it uses the global playlist.
That's a question for more experienced modders i believe, i wouldn't use that, that's the opposite of my use case, and what i try to avoid in the future (if it's possible). I would want to respect the overide from any other mod if they have one for a specific event though. In my mind my mods would only cause some players to have the battle music if they wear 4 shield, and the funky music if they have an epic armor ( those are examples ). Not "all the time, exclusively those music", but they wouldn't be played otherwise like a hidden track. And if a player hate the funky or the battle music, they could have a per-player setting to not have the music play.
Quorken wrote: Tue Nov 04, 2025 5:24 am on_song_finished and on_song_started events would probably also be useful.
I have plenty ideas, i don't know what is possible or make sense, if you can see the HP or read the ammunition or the battery level of a player's armor, where they are located surface/ vehicule, death count, number of trains... there's probably countless way to infer what's going on for that player in their game trigger the "next music" to be "thematic" ( don't play the song "Beware of the trains" when railway isn't researched ). I think "songs" that are 1-10 minutes are of the proper time span to match how a large chunk of the players do in game , but the change in music can be more frequent than the average lengh of song due to map/remote view. It's still blurry in my mind what music should be played if the player decide to have a sneak peak at his Vucanus factory while having the battle armor and being on gleba, the map view would cause a song to finish. I am hoping those events are not "magic tool" , that it make sense in practice, it's re-assuring to read :)
Check out my latest mod ! It's noisy !
oobanooba
Burner Inserter
Burner Inserter
Posts: 19
Joined: Thu Nov 21, 2024 4:17 pm
Contact:

Re: A sibling API to play_sound: play_music

Post by oobanooba »

The ability to play certain music tracks at a particular point in time, or being able to add or remove tracks based on game progression, would be quite useful to me. Since the mod I'm working on has a bit of story, it would be nice to allow music to play into that.
Donion
Factorio Staff
Factorio Staff
Posts: 446
Joined: Sun Aug 22, 2021 9:18 am
Contact:

Re: A sibling API to play_sound: play_music

Post by Donion »

Alright, after much procrastination deliberation, this is what I'm starting with.

As the original post suggested, I'm making siblings to play_sound:
  • LuaGameScript::play_music() will play specified music track for all players in the game
  • LuaForce::play_music() will play specified music track for all players of a given force
  • LuaPlayer::play_music() will play specified music track for that player
  • LuaSurface::play_music() will play specified music track for all players currently on (looking at) a given surface
Playing a music track using those functions will obey the transition behaviour used when switching surfaces but without the initial delay (so fade-out -> pause -> fade-in) and the specified track will be temporarily "bound" to the player's current surface for that purpose.

Those will take PlayMusicSpecification as an argument, which is a table containing:
  • name: The name of the track to play
  • transition_ticks [optional][maybe]: Override the transition timings
  • disable_transition_from [optional][maybe]: The played track will finish playing no matter what
There would be a new track_type of AmbientSound: script-track, which are not bound to any planet/platform, don't enter the regular pool of music tracks and can be played only using the play_music() functions (but regular tracks can be played using play_music() functions too).

There is a question of what to do when those functions are called while a track from previous call is currently playing. I don't want to create any elaborate queueing systems so it will either:
  • Do nothing, the previous track has priority
  • Replace the previous track, the new track has priority
I'm not sure what the better option is, this would mainly concern multiple mods conflicting on what should play.

I'm also imagining accompanying functions to check which music track is currently playing (and if it's playing as a result of one of the play_music calls) for a given player and maybe events for a music track starting/finishing.

There are some details to iron out (mostly around switching surfaces) but this is the direction I'm happy with.


Somewhat unrelated to this, I would like to improve the whole music track binding to surfaces situation. Right now it's very rigid and doesn't support stuff like planet-less surfaces or groups of surfaces. I will create a separate thread to get some feedback on this.
mmmPI
Smart Inserter
Smart Inserter
Posts: 4802
Joined: Mon Jun 20, 2016 6:10 pm
Contact:

Re: A sibling API to play_sound: play_music

Post by mmmPI »

That sounds great to me :)

I think it should "replace" the currently playing track if another play_music was called earlier, with the idea that one will know their own sound so they can interrupt only those, or interrupt any other, or none and mimick the other option. ( with more or less flexibility depending on which other functions are available or events).

The details to iron out surface transition sounds like a lot of fun fiddly things x)

Happy to hear about the possible modification for how songs are bound to surface, i had started to think about how to improve my mod to do this in a more flexible way , but i expect it to be much better when done by a profesionnal :) , and it can be used for many differents mods that interact with surfaces, will be happy to give feedback.
Check out my latest mod ! It's noisy !
Quorken
Inserter
Inserter
Posts: 33
Joined: Mon Aug 18, 2025 3:53 pm
Contact:

Re: A sibling API to play_sound: play_music

Post by Quorken »

This is reasonable. It gives the most control to modders, albeit without any higher-level API (e.g. queueing).
But it's better to have low-level control than a high-level API that is inevitably limited, as modders can construct the high-level API from the low-level features.
And someone will likely develop a library that abstracts away the per-song control, and provides some kind of conflict resolution for different mods doing dynamic music - perhaps that could serve as a model for an official high-level music API?
Post Reply

Return to “Modding interface requests”