A Way to Change Music File Name By Variable

can you make a way where you can modify Music file name by variable
where when you add 1 to Music File Name
it will change GameMusic01.mp3 to GameMusic02.mp3

1 Like

Why do you need this? Can you use multiple events instead?

I need it for a piano game i am trying to create. If i was to create multiple events i would have to create 61 different events to play each different sound.

Not ideal indeed - though you can create 61 events that you can trigger with a variable (or better, create a function taking the name of the sound as parameter). It’s a bit of work at first but then very easy to use with a variable or a function (which will be a custom action launching the sound)

can you tell me step by step how to create a function taking the name of the sound as parameter?

Please read the help pages on the wiki, I wrote these for this :slight_smile:

I believe there is no “Sound” parameter type that would allow us to pick a sound file to play @4ian
Using text to hand type could be painful :disappointed_relieved:

EDIT:// Actually, it doesn’t even seems to be possible to pass text parameter to a play music and sound event. It saying “resource does not exist”… So I don’t really see how such function could be done. It is just doesn’t seems to be possible to pass any text or variable expression as file name in audio event. Or am I missing something?

My idea is way more simple: you call the function with a parameter which is a string.
Then you do events like:

condition : if the string argument is = “Sound1”
action: Play Sound1
condition : if the string argument is = “Sound2”
action: Play Sound2

etc…
Is this tedious manually work? Yes - but once you’re done you have a single action to call.
Does it work? Yes :slight_smile:

Yes it does but you still need to repeat this 60+ times or as many sounds you have and add an event manually for each sound, so it doesn’t really help because the point would be to reduce that 60 or whatever number of events to 1 by using a variable

If no Sound is playing on channel then Play “Sound” + ToString(Variable(songNumber)) + “.mp3” on channel

An then during the game you could just stop the sound on the channel, change the value of songNumber programatically, manually or randomly as you prefer and the event would kick off and start playing the sound. So it would reduce 60+ events to 1 or 2 only.
Even if you add additional sounds to the list later, it would not require to add additional events for each sound. Either you have 10 or 100 or 1000 sounds it would still require only 1 or 2 event to pick and play a specific or even a random sound. I guess it would be the idea behind the request :face_with_monocle:

1 Like

I know this is a resurrection, but there was no real conclusion to this thread and I was going to make a piano keyboard as an example to test the new howler code being tested and realised we cannot use variables to play sounds unless we resort to javascript :frowning:

The easiest way I believe to make a piano keyboard is to name each key object with part of the sound file name so that its easy to code…

Pseudo code… very :slight_smile:

If touched
key = object name touched
playsound “sounds\my very long name”+str(key)+".wav"

very simple but impossible at the moment and its not clear why we cant do this

1 Like

Just bumping this conversation again. Unclear why audio resources can’t be referenced by name. Building logic around audio is cumbersome. Any insights?

I’m assuming we could add it, probably by creating a Play Audio by Name event, and giving it a GenericExpressionField parameter, similar to the scene name param in the “Change Scene” event, i.e., GDevelop/SceneNameField.js at e75d49ea5185c3128682480437a6dbb19e8e6386 · 4ian/GDevelop · GitHub

I haven’t found the code yet, but I assume there is some Resource object to point the audio engine at, which we could write a little helper for.

It’s because, like object fields, they are references to another piece of data in the project. If you rename a resource, since they are references, its occurrences will be automatically renamed in the events to the new name. Otherwise you would have to go and change it everywhere it is used each time you rename a resource (something that power-users and examples authors do a lot).

A way to use a string instead of a reference would break this guarantee of renaming not breaking resources that we had so far, I’m guessing that’s the main reason why there would be reluctance to add such a feature.

Ahhhh interesting. @arthuro555 would there be a way to come at it from the opposite direction, and make an object that represents sound/music? Then, you could perhaps put it in a group and use “pick” to isolate it and manage it.

I’m also curious about using channels as a totally different approach here. If I just started 100 channels, each with their own music file, I could stop them all, and then select one to actually play with Random(). Just seems a bit clunky to do it that way.

I think the initial idea I proposed might work, actually, since there are some protections in the worker code already for bad/missing audio names, e.g. GDevelop/ArbitraryResourceWorker.cpp at 763aa0aa258a0a5f1a5e4c419301aff88f15fcc8 · 4ian/GDevelop · GitHub

I think there could be an event not unlike “Change Scene” which just references an arbitrary string (e.g., something from a variable), which tries to grab a valid audio file, and just silently fails if it can’t. It could be “Play Audio File by Name” or something, with no guarantees that changing resource names would change corresponding event code (as you suggested would be a problem). There is already precedent for this kind of behaviour.

When I made TripleJump in GDevelop I had a lot of different music and I did what other here suggested and just made a ton of conditions for each music file… but I know better now, and the javascript is pretty simple to do here.

Save this text as soundbyname.json and import it as an extension:

{
  "author": "",
  "category": "Audio",
  "description": "",
  "extensionNamespace": "",
  "fullName": "SoundsByName",
  "helpPath": "",
  "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMy4wLjMsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iSWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgMzIgMzIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDMyIDMyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9DQoJLnN0MXtmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjEwO30NCjwvc3R5bGU+DQo8cmVjdCB4PSI2IiB5PSIzIiBjbGFzcz0ic3QxIiB3aWR0aD0iMjAiIGhlaWdodD0iMjYiLz4NCjxjaXJjbGUgY2xhc3M9InN0MSIgY3g9IjE2IiBjeT0iMTkiIHI9IjciLz4NCjxjaXJjbGUgY2xhc3M9InN0MSIgY3g9IjE2IiBjeT0iMTkiIHI9IjIiLz4NCjxjaXJjbGUgY2xhc3M9InN0MSIgY3g9IjIxIiBjeT0iOCIgcj0iMiIvPg0KPC9zdmc+DQo=",
  "name": "SoundsByName",
  "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/Line Hero Pack/Master/SVG/Music/Music_speaker_audio_sound.svg",
  "shortDescription": "Example Extension to allow playing sounds by name",
  "version": "0.0.1",
  "tags": [],
  "authorIds": [
    "Khhq7a4Lu8bt91GLLhG0QiGLpfx2"
  ],
  "dependencies": [],
  "eventsFunctions": [
    {
      "description": "Play Music on a Channel (By Name)",
      "fullName": "Play Music on a Channel By Name",
      "functionType": "Action",
      "group": "",
      "name": "PlayMusicOnChannelByName",
      "private": false,
      "sentence": "Plays _PARAM1_ on channel _PARAM2_ (Loop = _PARAM3_, Volume = _PARAM4_, Pitch = _PARAM5_)",
      "events": [
        {
          "type": "BuiltinCommonInstructions::JsCode",
          "inlineCode": "const soundManager = runtimeScene._runtimeGame._soundManager;\neventsFunctionContext.getArgument(\"version\")\nsoundManager.playMusicOnChannel(\n    eventsFunctionContext.getArgument(\"sound\"),\n    eventsFunctionContext.getArgument(\"channel\"),\n    eventsFunctionContext.getArgument(\"loop\"),\n    eventsFunctionContext.getArgument(\"volume\"),\n    eventsFunctionContext.getArgument(\"pitch\"));\n",
          "parameterObjects": "",
          "useStrict": true,
          "eventsSheetExpanded": true
        }
      ],
      "parameters": [
        {
          "codeOnly": false,
          "defaultValue": "",
          "description": "Sound Resource Name",
          "longDescription": "",
          "name": "sound",
          "optional": false,
          "supplementaryInformation": "",
          "type": "string"
        },
        {
          "codeOnly": false,
          "defaultValue": "",
          "description": "Channel Number",
          "longDescription": "",
          "name": "channel",
          "optional": false,
          "supplementaryInformation": "",
          "type": "expression"
        },
        {
          "codeOnly": false,
          "defaultValue": "no",
          "description": "Loop when done?",
          "longDescription": "",
          "name": "loop",
          "optional": true,
          "supplementaryInformation": "",
          "type": "yesorno"
        },
        {
          "codeOnly": false,
          "defaultValue": "",
          "description": "Volume (0-100)",
          "longDescription": "",
          "name": "volume",
          "optional": false,
          "supplementaryInformation": "",
          "type": "expression"
        },
        {
          "codeOnly": false,
          "defaultValue": "",
          "description": "Pitch (typically 1)",
          "longDescription": "",
          "name": "pitch",
          "optional": false,
          "supplementaryInformation": "",
          "type": "expression"
        }
      ],
      "objectGroups": []
    }
  ],
  "eventsBasedBehaviors": []
}

Example Usage:

Using what I provide there you can easily expand it to support all of the methods here:

1 Like

Ahaaaaaa yes, this is perfect. Looking forward to messing around with it. Thanks @krunkster .

So there are some underlying engine changes coming up that may make this method no longer work for some use cases.

In the interim, however, I adapted this to use the “Play sound” actions (to help with seamless looping), as well as the Preload actions.

If folks would like to mess around with it, I’ve submitted it as a community extension (giving credit to @krunkster for their original work) here: New extension: Audio by Filename · Issue #1021 · GDevelopApp/GDevelop-extensions · GitHub

It may not make it into the main extension list due to what parts of JS it accesses, but feel free to take a look. Huge kudos to krunkster for the original code.

Was wondering if this is still possible by manipulating the code, while my game had used that action as a main way to play any sound which will make it hard to reverse.