Skip to content

Soundtracks Format Specification

potatoes edited this page Sep 19, 2024 · 12 revisions

Want a more beginner friendly guide? See the quickstart guide.

File Structure

Top Level

Your file structure will look as such: (Make sure Mason is installed to create the bootstrap.dll)

username-modname/
	plugins/
		resources/
			...
	boostrap.dll
	icon.png
	manifest.json
	project.yaml
	README.md

For most of this, i'll defer you to Thunderstore's packaging format.

For project.yaml, it should look as follows:

version: 1
dependencies:
    hard:
        dll.potatoes.ptnhbgml: 4.0.0
assets:
    setup:
      - path: soundtrack_manifest.yaml
        plugin: dll.potatoes.ptnhbgml
        loader: tnhbgml_soundtrack

Inside resources, it looks as follows:

resources/
	soundtrack/
	icon.png
	soundtrack_manifest.yaml

soundtrack_manifest.yaml should look as follows:

name: My Awesome Mod Name
guid: my_user_name.my_mod_name
location: soundtrack
game_mode: tnh

Soundtrack Level

soundtrack/
	hold_[timing]_[metadata]_[identifier]/
		intro_[metadata]_[identifier].ogg	[OPTIONAL]
		lo_[metadata]_[identifier].ogg
		transition_[metadata]_[identifier].ogg	[OPTIONAL]
		medhi_[metadata]_[identifier].ogg [OPTIONAL]
		end_[metadata]_[identifier].ogg	[OPTIONAL]
		endfail_[metadata]_[identifier].ogg [OPTIONAL]
		orbactivate_[identifier].ogg	[OPTIONAL]
		orbwave_[identifier].ogg	[OPTIONAL]
		orbsuccess_[identifier].ogg	[OPTIONAL]
		orbfailure_[identifier].ogg	[OPTIONAL]
	take_[timing]_[metadata]_[identifier]/
		takeintro_[metadata]_[identifier].ogg [OPTIONAL]
		take_[metadata]_[identifier].ogg
		alert_[metadata]_[identifier].ogg [OPTIONAL]
	preview_loop.ogg [OPTIONAL] *Incompatible with preview.
	preview.ogg [OPTIONAL] *Incompatible with preview_loop.

This may look intimidating, but let us break it down.

Anatomy of the Soundtrack Folder

[metadata] is optional. If you have none, simply do not include it. As an example. hold_[timing]_[metadata]_[identifier] -> hold_[timing]_[identifier].

There are two core parts to this: tracks (the ogg files) and track sets (the folders). And the preview.

Tracks are written as:

[type]_[metadata]_[identifier].ogg

And Track sets are written as:

[type]_[timing]_[metadata]_[identifier]

Type

Type identifies where this song should be played. The types are:

Take types

takeintro - Optional
	Plays at the start of the take phase.
	If this does not exist, `take` will play at the start of the take phase.

take
	Plays after the takeintro, if it exists.
	Keep this on loop.
	
alert - Optional
	Plays whenever in a fight with Sosigs during a take.
	Returns back to take whenever finished.
	By default, it will return to take at [time played take] + [time played alert], similar to seamless transition (st).
	If you want it to return to start of take track, use "restart" metadata on alert theme.
	If you want take to resume where it stopped, use "return" metadata on alert theme.

Hold types

intro - Optional
	Plays at the start of the hold phase- right after touching the orb.
	Will transition to the `lo` theme.
	If this does not exist, `lo` will be played directly after touching the orb.

lo
	Plays after the intro, for the duration of the hold except on the last phase.
	Keep this on loop.

transition - Optional
	A song that plays to transition from the `lo` to the `medhi`.
	Plays on the start of the last phase of the hold.
	If this does not exist, it will be skipped and it will simply go from `lo` to `medhi`.
	Requires `medhi` to exist.

medhi - Optional
	Plays after the transition, for the duration of the last phase of the hold.
	The only exception is the first hold, which uses `lo` for its one and only phase.
	If this does not exist, the `lo` will be used for the duration of the whole hold, including the last phase.
	`transition` requires `medhi` to exist.

end - Optional
	Plays at the end of the hold phase.
	If does not exist, it will transition directly to `takeintro`.

endfail - Optional
	Plays if time runs out in the hold phase.
	If does not exist, will use `end` instead. Requires `end` to exist in the trackset.

Orb types

orbactivate
	Replaces the sound the orb makes when you first touch the orb.

orbwave
	Replaces the sound the orb makes when you finish a phase of a hold by destroying all encryptions.

orbsuccess
	Replaces the sound the orb makes when you finish the hold

orbfailure
	Replaces the sound the orb makes when you fail the hold by running out of time.

Note that Orb sounds are different in that, while other types are played directionless (appears to have no physical source), the orb sounds are played from the orb.

Other preview - Optional Only one may exist. Incompatible with preview_loop Plays when the mod is selected from the TnH BGM selection panel in the TnH lobby. If does not exist (and preview_loop doesnt either), no song will play when your mod is selected. Plays for as long as the preview is. Try to keep it short, with a high theme to show off how your mod sounds like mid-hold. Minimum of 4 seconds. Fades in for two seconds, fades out the last two seconds. preview_loop - Optional Only one may exist. Incompatible with preview Plays when the mod is selected from the TnH BGM selection panel in the TnH lobby. If does not exist (and preview doesnt either), no song will play when your mod is selected. preview_loop will not stop. At the end of the preview, it will loop. As this is a long, looping song, try to keep the song low-energy and more "main menu" theme-y. Minimum of 2 seconds. Fades in the first two seconds.

Overlapping types

It is okay (and encouraged) to have several tracks with the same, overlapping type in a given trackset. When two tracks can both be played at a given point, the system will choose one at random to play. This offers greater variety and replayability (relistenability?) in your music mod.

Timing

The traditional 5 hold TnH timing goes as such:

TnH started
V
Take 0
V
Orb touched
V
Hold 0
V
Hold finish
V
Take 1
V
Orb touched
V
Hold 1
V
Hold finish
V
...
V
Take 4
V
Hold started
V
Hold 4
V
Hold finished
V
Victory!

You will notice despite having 5 holds, it ends at "hold 4". This is because we start counting from zero.

Timing indicates where this song may be played.

Overlapping Timings

Same with overlapping types, it is okay to have overlapping timings. When two tracksets can be played, the system will choose one at random to play.

Permitted values

Regular timings

`0` -> The first hold and the take prior to it.
`1` -> The second hold and the take prior to it.
`2` -> The third hold and the take prior to it.
...

Glob timings

`1-3` -> the second, third, and fourth hold.
`0,2,4` -> the first, third, and fifth hold.
`ge1` -> Hold 2 and above. (ge = Greater than or Equal to)
`le1` -> Hold 2 and below. (le = Lesser than or Equal to)
... you get the idea.

Please do not mix two or more globs!

EG: 0-2,4 and 1,ge3 is INVALID!

General timings

fallback
	Can be played at any opportunity, but `#` soundtracks will be prioritized. (e.g given `take_0_RedSong.ogg` vs `take_fallback_BluSong.ogg`, RedSong will always be played in the first take- never BluSong.)

all
	Can be played at any opportunity, pulled at random. `#` soundtracks will NOT be prioritized. (e.g given `take_0_RedSong.ogg` vs `take_all_BluSong.ogg`, a coinflip will be made whether to use RedSong or BluSong in the first take.)

death
	Song that plays once you die. Must be a take song (e.g take_death_AwesomeDeathMetalMusic.ogg)

win
	Song that plays once you win. Must be a take song (e.g take_win_CoolAssSong.ogg)

If you are designing your soundtrack for a traditional 5 hold, please set the final timings not to 4, but to ge4. This makes it so endless players wont error out and can use your soundtrack.

You may use numbers greater than 4 for endless players- there is no restriction.

Identifier

AKA, name.

This doesn't do much- it just makes sure two sets dont have the same name.

It is encouraged not to make two songs with the same identifier, for debugging reasons. And your own sanity. (It will still, however, work.)

Permitted values

Quite literally anything (Minus anything Windows won't let you type, obviously). Words, numbers, whatever. Please do not use the character _ in your identifier.

This can be useful if two sets have the same timings. (Example: hold_1_AwesomeBoneRiffs vs hold_1_LessAwesomeBoneRiffs)

When two soundtracks or tracks can be played, such as the example above, a random one will be picked.

Track Metadata

Metadata is for more advanced users.

This allows modders to customize more their sequences to their likings. If no metadata, skip. Write as [Base file name]_[identifier].ogg If multiple metadata is available, separate with -. EG: dnf-st

dnf - Do Not Fade
	By default, tracks start fading into the next one 1.5s before the end of the track. (Or if caused by an event, like take -> intro when starting a hold.)
	dnf, or Do Not Fade, will remove the fade into the song it is applied to. IT DOES NOT REMOVE THE FADE INTO THE NEXT SONG, UNLESS THAT NEXT SONG ALSO HAS DNF.

Example

take > fade > intro > fade > lo

take > intro_dnf > fade > lo

take > intro_dnf > lo_dnf

take > fade > intro > lo_dnf

st - Seamless Transition
	This song will start playing at the same point as the previous track.

As an example: Assume Transition.ogg does not exist. When Lo is 30s into its track and transition occurs, it will fade into MedHi at 30s. This allows for a MedHi that mirrors the Lo song but is much more badass and cool and shit, and will naturally and seamlessly transition. Applied to the track it is seamlessly transitioning TO, not FROM. Applied to the situation above, you would apply st to the MEDHI, NOT THE LO. Incompatible with fs.

loop - Loop
	Makes the song repeat when track comes to end, instead of playing next track.

The following types of songs should be looped:

  • take
  • lo
  • medhi
fs - Failure Sync
	Failure Sync: Aligns the end of the song with the failure time of the hold.
	May only be applied to `lo` and `medhi`.

NOTE: The amount of time to failure sync is VARIABLE. Be careful! Make sure your song is long enough or else it WILL throw an error if the amount of time to reach failure is longer than the length of your song.

The song preceding (usually intro or transition) must be AT LEAST 5s LONG.

Note that the track is set to finish 3 seconds after the actual failure time, for some buffer zone.

Incompatible with st.

Trackset Metadata

(Please note that the below metadata are Institution specific. They make no difference outside of Institution.)

center
	Makes the trackset play only on central in Institution.
north
	Makes the trackset play only in Government in Institution.
south
	Makes the trackset play only in Industry in Institution.
west
	Makes the trackset play only in Temple in Institution.
east
	Makes the trackset play only in Power in Institution.
anyreg - Any Region
	Makes the trackset play on any region.
	Please not *not* adding this on a trackset will make it act as a fallback trackset
	(Never played unless no other tracksets to play).
nsbr - No Switch Between Regions
	Does not switch tracks when crossing regions. When selected, will continue to play until hold.

Alternate Formats

Unified Take-Hold

Recall that the traditional soundtrack system is:

soundtrack/
	hold_[timing]_[metadata]_[identifier]/
		intro_[metadata]_[identifier].ogg	[OPTIONAL]
		lo_[metadata]_[identifier].ogg
		transition_[metadata]_[identifier].ogg	[OPTIONAL]
		medhi_[metadata]_[identifier].ogg [OPTIONAL]
		end_[metadata]_[identifier].ogg	[OPTIONAL]
		endfail_[metadata]_[identifier].ogg [OPTIONAL]
		orbactivate_[identifier].ogg	[OPTIONAL]
		orbwave_[identifier].ogg	[OPTIONAL]
		orbsuccess_[identifier].ogg	[OPTIONAL]
		orbfailure_[identifier].ogg	[OPTIONAL]
	take_[timing]_[metadata]_[identifier]/
		takeintro_[metadata]_[identifier].ogg [OPTIONAL]
		take_[metadata]_[identifier].ogg
		alert_[metadata]_[identifier].ogg [OPTIONAL]
	preview_loop.ogg [OPTIONAL] *Incompatible with preview.
	preview.ogg [OPTIONAL] *Incompatible with preview_loop.

In some situations, you may want the take to be unified with the hold. I.E, a particular take plays with a particular hold, always.

To do this, simply put all the take songs into the hold trackset and remove the take trackset, like so.

soundtrack/
	hold_[timing]_[metadata]_[identifier]/
		intro_[metadata]_[identifier].ogg	[OPTIONAL]
		lo_[metadata]_[identifier].ogg
		transition_[metadata]_[identifier].ogg	[OPTIONAL]
		medhi_[metadata]_[identifier].ogg [OPTIONAL]
		end_[metadata]_[identifier].ogg	[OPTIONAL]
		endfail_[metadata]_[identifier].ogg [OPTIONAL]
		orbactivate_[identifier].ogg	[OPTIONAL]
		orbwave_[identifier].ogg	[OPTIONAL]
		orbsuccess_[identifier].ogg	[OPTIONAL]
		orbfailure_[identifier].ogg	[OPTIONAL]
		takeintro_[metadata]_[identifier].ogg [OPTIONAL]
		take_[metadata]_[identifier].ogg
		alert_[metadata]_[identifier].ogg [OPTIONAL]
	preview_loop.ogg [OPTIONAL] *Incompatible with preview.
	preview.ogg [OPTIONAL] *Incompatible with preview_loop.

Phases

Phases is for more advanced users.

soundtrack/
	hold_[timing]_[identifier]/
		intro_[metadata]_[identifier].ogg	[OPTIONAL]
		phase0_[metadata]_[identifier].ogg
		phasetr0_[metadata]_[identifier].ogg	[OPTIONAL]
		phase1_[metadata]_[identifier].ogg
		phasetr1_[metadata]_[identifier].ogg	[OPTIONAL]
		phase2_[metadata]_[identifier].ogg
		phasetr2_[metadata]_[identifier].ogg	[OPTIONAL]
		...
		end_[metadata]_[identifier].ogg	[OPTIONAL]
		orbactivate_[identifier].ogg	[OPTIONAL]
		orbwave_[identifier].ogg	[OPTIONAL]
		orbsuccess_[identifier].ogg	[OPTIONAL]
		orbfailure_[identifier].ogg	[OPTIONAL]

Phases is an alternate way to handle songs instead of the Lo/MedHi system.

phasetr stands for Phase Transition.

The sequence is as follows:

Intro > Phase0 > Phasetr0 > Phase1 > Phasetr1 > ... > PhaseX > end

phase is expected to have the loop metadata, and phasetr is expected to not have the loop metadata. (This is not necessary, however.)

At the end of every phase of a hold, it will play the following phase transition. If there is no phase transition, it will simply play the next phase song.

If number of phases outnumbers number of phase tracks, the last phase will loop.