• Advertisement
Sign in to follow this  

Unity Hammer/Source SDK Soundscripts

This topic is 1733 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

First off, I know very, VERY little about programming.  I'm an audio person, but my latest ambitions seem to be taking me into the realms of the unknown. I'm hoping I've found the right section of the forum get some help.


In the most basic sense, I am trying to mod Portal 2 using Hammer.  I need to be able to have full control of the audio assets, and their potions within the 3d space, and also their behaviors.  I would also be importing new sounds, particularly ambient ones, and implementing them into the game.  While there is plenty of information on this subject at the Valve Dev Community website, it is rather scattered about the place. Some kind of code/script (possibly Squirrel?) is frequently referenced where sounds entities are relevant. (Here is an example > https://developer.valvesoftware.com/wiki/Soundscripts).  I'm wondering whether to be able to implement new sounds, and events into Portal 2, I will have to create similar scripts myself.  If this is the case, I'm basically asking where to start with code/scripting, and what I need to know?


Note that in the above link, I do understand what the script is saying i.e parameters of a sound, and their values.  What I do not understand is how important the actual files containing the script are, how they are created, how they are referenced. I don't even know the basic commands.  <string>,<integer> etc are terms that frequently pop up, and I don't know what to do with them.   I'm sorry my question is a little vague, but it just goes to show why I had to ask it.





Share this post

Link to post
Share on other sites

By playing around with the scripts that already exist, you can pick it up fairly easily, and work more quickly toward your goals.

The knowledge required to program in general takes quite some time to pick up, but the knowledge required for the specific thing you asked probably isn't that much to learn.


A string is a block of text. "My name is bob" is a string. "adfasrt4wt345352" is a string. It's a group of characters/symbols (like letters, and punctuation, and numbers).

An integer is a number. 500 is an integer. -21 is an integer.

A boolean is something that is either True or False.


Learning programming entirely takes time, and will distract you from your current actual goal.

What you are wanting to do (replace the sound files) doesn't require a multi-year pursuit of programming (unless you are wanting that, which is awesome, and I'd give entirely different advice).


My suggestion: Find examples of the files that Portal 2 is already using, and post them here, and we'll explain them. I *think* they are using them more as a "markup" language rather than a full-blown programming language, when it comes to the sound files. (But they probably use it for full-on programming when it comes to enemy AI and things like that).


Post a few of the exact files you are wanting to replace (and not just the examples shown on the wiki), and I'll try and explain them.

Edited by Servant of the Lord

Share this post

Link to post
Share on other sites

A multi-year pursuit of programming?  As you say, I think this would interfere too much with my development in audio related areas.  My goal is to be a sound designer, however, I do frequently see jobs advertised called "Audio Programmer".  Not knowing how much an audio programmer would need to know, I don't know if programming is something I should add to my skill set.  The whole point of this Portal mod is to create an audio implementation/sound design demo, that will demonstrate that I can do a sound design job.  I still find the programming subject tempting, though.  It must be quite rewarding!


I did find a tutorial video last night, which helped me understand things a bit more, but for the sake of posting something code-ish...


Here is something I do understand, except for a few minor things;  There is a file path for the sound file, yet I cannot find this sound file in my windows explorer.  It is apparently a WAV file, so it should not be hidden.  Also, I'd like to know what the very first line represents ("Portal.Glados..." , and also the significance of the quotation marks. Is this the name that Hammer references the sound file + properties by?    This came from a script .txt file, and only consists of what I've shown below, repeated for different sound files, so there are no introductory instructions.  I'm wondering how the game/Hammer will know it has to read this file?



"channel" "CHAN_VOICE"
"volume" "1.0"
"soundlevel" "SNDLVL_70DB"
"wave" "vo/aperture_ai/escape_02_sphere_cakemix-19.wav"
If that wasn't enough of a challenge, this nearly gave me a heart attack.  All I know here is that "//" means comments.  From a text file called "Soundmixers", and there is no page on Valve explaining it.  If I had to guess, I'd say this details some way of determining which sounds are played over others, such as when Glados speaks, and all other sounds are reduced.  In audio, this could be called 'ducking'.  There is, as you can see, some instructions listed as comments, but it's got me too confused, at this point:
// Halflife 2 custom sound mixers.
// These Sound Mixers are referenced by name from Soundscapes, and are used to provide
// custom volume control over various sound categories, called 'mix groups'
// "GROUPRULES" specifies the rules for inclusion of a sound in a mix group.
// Rules are checked sequentially (from top to bottom). All fields must match
// in a row in order for a sound to match the group.  A sound my be included 
// in up to 8 mix groups.
// up to 64 unique mix groups
// up to 76 group rules entries
// up to 32 sound mixers
// all strings are limited to 31 characters!
// NOTE2: at runtime, you can display the classname of the sound source by
// setting snd_showclassname 1 in the console.
// NOTE3: main character dialog during critical scenes is ducked using a separate code path which, when
// active, temporarilly disables mixer ducking (prevent double ducking).  
// Lower priority sounds are ducked by higher priority sounds, if "is ducked" is enabled. 
// Only sounds with "causes ducking" enabled can cause a lower priority sound to be ducked.
// NOTE: order these from least general to most general
// directory or .wav classname Causes  Duck to  Ducker
// group name name substring substring chan sndlvl_min sndlvl_max priority Is Ducked Ducking Percent Threshold
//  --------- ------------------ --------- ----------- ---------- ---------- -------- -------- ------- ------- ---------
"voip" "?VoiceSfx" "" "" "" "" "60" "0" "0" "100" "40"
"UI" "ui/" "" "" "" "" "60" "0" "0" "100" "40"
"commentary"             "commentary/"        ""          "" ""    "" "60" "0"     "0" "100" "40"
"mstr"              "mstr/"        ""          "" ""    "" "60" "0"     "0" "100" "40"
"noDSP"              "nodsp"        ""          "" ""    "" "60" "0"     "0" "100" "40"
"potatosVO"              "vo/glados/potatos"        ""          "" ""    "" "60" "0"     "0" "100" "40"
"gladosVO"              "vo/glados/"        ""          "" ""    "" "60" "0"     "0" "100" "40"
"announcerVO"           "vo/announcer/"    ""          "" ""    "" "60" "0"     "0" "100" "40"
"wheatleyVO"           "vo/wheatley/"    ""          "" ""    "" "60" "0"     "0" "100" "40"
"caveVO"               "vo/cavejohnson/"    ""          "" ""    "" "60" "0"     "0" "100" "40"
"coreVO"               "vo/core"    ""          "" ""    "" "60" "0"     "0" "100" "40"
"inTBeam"           "player_enter_tbeam_lp"    ""          "" ""    "" "60" "0"     "0" "100" "40"
"gelBounce"           "player_bounce_jump_paint"    ""          "" ""    "" "60" "0"     "0" "100" "40"
"epilogueMusic" "music/sp_a5_x1" "" "" "" "" "60" "0" "0" "75" "40"
"Music" "music/" "" "" "" "" "60" "0" "0" "75" "40"
"beep" "xray/beep" "" "" "" "" "60" "0" "0" "75" "40"
"bullethit" "impact_bullet" "" "" "" "" "60" "0" "0" "100" "40"
"bulletmiss" "nearmiss" "" "" "" "" "60" "0" "0" "100" "40"
"Explosions" "explo" "" "" "120" "" "60" "0" "0" "100" "40"
"Player_Fall" "fall_whoosh" "" "" "" "" "60" "0" "0" "100" "40"
"Portalgun" "portalgun" "" "" "" "" "60" "0" "0" "100" "40"
"Player_Weapons_Loud" "weapon" "Player" "" "140" "" "60" "0" "0" "100" "40"
"Player_Weapons" "weapon" "Player" "" "" "" "60" "0" "0" "100" "40"
"Player" "player/" "Player" "" "" "" "60" "0" "0" "100" "40"
"turrets" "npc/turret" ""    "" "" "" "60" "0" "0" "100" "40"
"defective_turrets" "vo/turret" ""    "" "" "" "60" "0" "0" "100" "40"
"NPC_Voice" "" "NPC" "CHAN_VOICE" "" "" "60" "0" "0" "100" "40"
"NPC_Weapons_Loud" "" "NPC" "CHAN_WEAPON" "140" "" "60" "0" "0" "100" "40"
"NPC_Weapons" "" "NPC" "CHAN_WEAPON" "" "" "60" "0" "0" "100" "40"
"NPC_Body" "" "NPC" "CHAN_BODY" "" "" "60" "0" "0" "100" "40"
"NPC_Looping" "" "NPC" "CHAN_STATIC" "" "" "60" "0" "0" "100" "40"
"NPC" "" "NPC" "" "" "" "60" "0" "0" "100" "40"
"Ambient" "ambien" "" "" "" "" "60" "0" "0" "100" "40"
"Container" "container" "" "" "" "" "60" "0" "0" "100" "40"
"Robot" "robot_parts/" "" "" "" "" "60" "0" "0" "100" "40"
"Trains" "plats/" "" "" "" "" "60" "0" "0" "100" "40"
"Doors" "doors/" "" "" "" "" "60" "0" "0" "100" "40"
"Buttons" "buttons/" "" "" "" "" "60" "0" "0" "100" "40"
"Items" "items/" "" "" "" "" "60" "0" "0" "100" "40"
"Beams" "beams/" "" "" "" "" "60" "0" "0" "100" "40"
"Vehicles" "vehicles/" "" "" "" "" "60" "0" "0" "68" "40"
"Vehicles_Looping" "vehicles/" "" "CHAN_STATIC" "" "" "60" "0" "0" "68" "40"
"Physics" "physics/" "" "" "" "" "60" "0" "0" "100" "40"
"Dialog" "combined/" "" "" "" "" "60" "0" "0" "100" "20"
"Combat" "explo" "" "" "110" "" "60" "0" "0" "100" "40"
"Weapons" "weapon" "" "" "120" "" "60" "0" "0" "100" "40"
"Quiet" "" "" "" "0" "70" "60" "0" "0" "100" "40"
"Medium" "" "" "" "71" "90" "60" "0" "0" "100" "40"
"Loud" "" "" "" "91" "100" "60" "0" "0" "100" "40"
"VeryLoud" "" "" "" "101" "149" "60" "0" "0" "100" "40"
"SuperLoud" "" "" "" "150" "" "60" "0" "0" "100" "40"
"All" "" "" "" "" "" "60" "0" "0" "100" "40"
"Claw"                  "asdfasdf"    ""          "" ""    "" "60" "0"     "0" "100" "40"
"ReducedDuckingSm"    "asdfxxx" "" "" "" "" "60" "0" "0" "100" "40"
"ReducedDuckingMd"    "asdfwww" "" "" "" "" "60" "0" "0" "100" "40"
"ReducedDuckingLg"    "asdfyyy" "" "" "" "" "60" "0" "0" "100" "40"
"ReducedDuckingXl"    "asdfbbb" "" "" "" "" "60" "0" "0" "100" "40"
"ReducedDuckingXxl" "asdfhhh" "" "" "" "" "60" "0" "0" "100" "40"
"ReducedDuckingMstr" "asdfqqd" "" "" "" "" "60" "0" "0" "100" "40"
"testTBin" "asdfaef" "" "" "" "" "60" "0" "0" "100" "40"
"testGelBounce" "asxdrf" "" "" "" "" "60" "0" "0" "100" "40"
"testGelSpeed" "asxdrf" "" "" "" "" "60" "0" "0" "100" "40"
"unduckedMusic" "music/" "" "" "" "" "60" "0" "0" "75" "40"
"unTBeam"               "untbeam"    ""          "" ""    "" "60" "0"     "0" "100" "40"
"xLoud"                 "xloud"    ""          "" ""    "" "60" "0"     "0" "100" "40"
Thanks a lot for your time!smile.png

Share this post

Link to post
Share on other sites

"channel" "CHAN_VOICE"
"volume" "1.0"
"soundlevel" "SNDLVL_70DB"
"wave" "vo/aperture_ai/escape_02_sphere_cakemix-19.wav"

It's just a way to format certain information. This would be a "markup language"-type usage.

The quotation marks are optional, but are required when certain symbols that might confuse the program reading the file are used. Any spaces or tabs or symbols for example. "If a value has a space or tab character within it, wrap it in "quote marks"." (from the wiki)

My guess would be:
"Portal.Glados_core.Crazy_19"	//The name the game uses to load this.
	//<key>		<value>
	"channel"	"CHAN_VOICE"	//What sound channel to play the sound on.
	//There's usually about 8 or 16, but all of them might not be used. Valve here seems to have dedicated
	//certain channels for certain purposes. This channel is for voiceovers (almost all of Glados' dialog
	//is voiceovers, but that probably changes when she's a potato).
	"volume"	"1.0"	//The volume to use to adjust the sound file. 0.0 is silent, 1.0 is the
	//default volume. You can only decrease the volume here (if it's too loud), you can't increase it.
	//The sound volume is later modified by dozens of other things (how far you are from the sound in-game,
	//how high the player has his speaker/headphone volume adjusted, and so on). According to the wiki,
	//certain sound channels in Portal 2 aren't affected by distance. CHAN_VOICE (for voiceovers) are
	//probably one of those.
	"soundlevel"	"SNDLVL_70DB" //The wiki says it's preset levels of 'attenuation' - which, me not
	//being a audio guy, you'd understand better than me. The wiki lists the different options.
	"wave"		"vo/aperture_ai/escape_02_sphere_cakemix-19.wav" //The actual sound file.
The game internally reads these files, and looks specifically for certain names, like 'channel', 'volume', 'soundlevel', and so on. If you added a new name, like this:
myname	myvalue
In some circumstances, the game will entirely ignore unknown names and be blind to it, because it's not already looking for that value. Other times, it's expecting you to provide your own names, because you're creating new objects for the engine. It completely depends on what the engine is expecting - so the documentation has to be looked up on a case-by-case basis.

The 'name' here, is usually called a 'key', and the name and the value together is called a 'key-value pair'.
The game already has keys in mind, so it already knows about keys called 'soundlevel', and so uses the key to find and load the value from the file. It doesn't know what the value is ahead of time, and the point of the file is to provide the value so it doesn't have to be hard-coded into the game, and can be modified by developers (and modders) easier and faster during development.

The point of these files is primarily so that the audio and art people can add and modify the content of the game without having to learn programming, as well as so even the programmers can modify stuff without waiting for a dozen minutes for the game to 'recompile' before the change can be visible. It's for rapid changes for more flexible development, as well as allowing the artists and musicians and game designs to make changes without having to depend on the programmers. Programming itself is super fun though! (it often is an acquired taste and might not seem fun at first) But it's an entire project in itself - well worth pursuing, but perhaps after you've finished your Portal 2 mod.

The wiki says about the filepath of the sound file (identified by the "wave" key):
"All filepaths within a soundscript are relative to the sound folder."

However, it might be located in a special archive file where multiple folders and files are combined into a single file (similar to .zip files in Microsoft Windows). See here and here.

About the key-value thing: The value can be a collection of more key-value pairs.
The key "Portal.Glados_core.Crazy_19", is the identifier for the value that begins with '{' and contains more key-value pairs and ends with '}'. This is sometimes called a 'structure' or 'object'.

This would be valid:
    key value
    key value

        key value

    key value
An real example of this would be where they talk about rndwave.

Keys can also have more than one value:
key value1 value2 value3 etc...
Depending on how the engine handles it, only certain keys should have multiple values. The order of the values matter, so you have to look up in the documentation what each value represents.
//position x y z
position 50 150 100
If 'position' is the key, then x,y, and z are the location in 3D space. You can't mix up the orders of them, or you'd be putting it in the wrong 3D location. In this specific case, the individual multiple values are often called 'arguments'.

So in your second file:
"MixGroups" //Key
   //Key		//Multiple values
   "potatosVO"		"vo/glados/potatos" ""  ""  ""  ""  "60"  "0"  "0"  "100"  "40"
   "gladosVO"		"vo/glados/"        ""  ""  ""  ""  "60"  "0"  "0"  "100"  "40"
   "announcerVO"	"vo/announcer/"	    ""  ""  ""  ""  "60"  "0"  "0"  "100"  "40"
   "wheatleyVO"		"vo/wheatley/"      ""  ""  ""  ""  "60"  "0"  "0"  "100"  "40"
   "caveVO"		"vo/cavejohnson/"   ""  ""  ""  ""  "60"  "0"  "0"  "100"  "40"
   //...and more stuff...
So in this case, the engine is looking specifically for a key named "MixGroups".
Inside MixGroups, it actually is expecting the developers to provide their own keys.
The keys then take a specific fixed number of values/arguments, each argument having a specific purpose/meaning.
You'll have to look up the documentation or ask on Portal 2 modding forums for the meanings of each argument.
"gladosVO"  "vo/glados/"  ""  ""  ""  ""  "60"  "0"  "0"  "100"  "40"
Here, the key (gladosVO, the quotes are optional) has 10 arguments. The order of the arguments matter and each means something different.
Because they are fine with the default values for four of the arguments, they left them empty. I'm guessing that in this specific case, an empty argument means 'use the default'. The reason why they are quoted, is because this:
"gladosVO"  "vo/glados/"                  "60"  "0"  "0"  "100"  "40"
...makes it look to the engine like there are only 6 arguments, and puts them in the wrong locations (putting "60" as argument 2 instead of the correct place at position 6).
Quoting nothing is a way of providing nothing as an argument (and thus using the defaults) while not confusing the engine about the number or positions of arguments.

Share this post

Link to post
Share on other sites

Yikes, what a mind bender!  SND_LEVEL is attenuation level?  I've seen a seperate parameter called "attenuation", so that's confusing.  Attenuation normally refers to how sound gets quieter as you move away from it's source, which has an omni_directional radius.  UDK allows for the sound designer to adjust properties of the fall-off curve, but this suggests that Valve's attenuation properties are somewhat set in stone.  I can't actually move onto this yet, as I'm stuck on creating an env_soundscape that actually plays.  I believe they can be triggered, but I'm unsure how to create a trigger area.  Which tool in Hammer would be used to create trigger-able entities?

Share this post

Link to post
Share on other sites

It's been a long time since I've played with Hammer. You're likelier to find people capable of answering that kind of question on a Source Engine modding forum - there's alot of tutorials for Hammer floating around the 'net as well. Maybe this helps?

The Source Engine has alot of different trigger brushes, for when you touch, look-at, or use the activate key, on a piece of the level. There's also trigger_soundscape, which I've never used but looks promising, and other sound-specific triggers.

Edited by Servant of the Lord

Share this post

Link to post
Share on other sites

Yeah, trigger soundscape is what I need.  You're clearly a forum guru! Really appreciate your help =]  I'm going to ask, in the sound section, about audio programmers, and then I may return asking for beginners programming advice. :)

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
  • Advertisement
  • Popular Tags

  • Advertisement
  • Popular Now

  • Similar Content

    • By 3dmodelerguy
      So I am building a turn based rogue-like (think CDDA). The game is going to have a very large map (up to 1000's x 1000's) however to alleviate most of that I obviously can't render everything so there will just be render a certain radius around the player and just load in and out data as the player moves.
      The next major system I am prototyping is making interactive tiles destructible and pretty much everything will be destructible besides basic landscape (cars, doors, windows, structures, etc. will be destructible)
      While I am only rendering a certain amount of tiles around the player, I want to keep the amount of colliders active at one time to be as small as possible for performance and currently the tilemap tool I use automatically merges colliders together.
      So instead of creating a separate colliders for each of these tiles and having the destructible behavior tied to that object (which my tilemap tool would allow me to do) I was thinking that I would store an array of all the X and Y locations for the interactive tilemap layer and let the tilemap manage the colliders. 
      Then when I hit a collider on the interactive tilemap layer, instead of of getting the behavior for how to deal with the destruction for that tile from that game object, I would pull it from the array I mentioned earlier based on the tile I attempt to interact with which I already have.
      Does this sound like a good approach? Any other recommendations would be welcomed.
    • By NDraskovic
      Hey guys,
      I have a really weird problem. I'm trying to get some data from a REST service. I'm using the following code:
      private void GetTheScores() { UnityWebRequest GetCommand = UnityWebRequest.Get(url); UnityWebRequestAsyncOperation operation = GetCommand.SendWebRequest(); if (!operation.webRequest.isNetworkError) { ResultsContainer rez = JsonUtility.FromJson<ResultsContainer>(operation.webRequest.downloadHandler.text); Debug.Log("Text: " + operation.webRequest.downloadHandler.text); } } The problem is that when I'm in Unity's editor, the request doesn't return anything (operation.webRequest.downloadHandler.text is empty, the Debug.Log command just prints "Text: "), but when I enter the debug mode and insert a breakpoint on that line, then it returns the text properly. Does anyone have an idea why is this happening?
      The real problem I'm trying to solve is that when I receive the text, I can't get the data from the JSON. The markup is really simple:
      [{"id":1,"name":"Player1"},{"id":2,"name":"Player2"}] and I have an object that should accept that data:
      [System.Serializable] public class ResultScript { public int id; public string name; } There is also a class that should accept the array of these objects (which the JSON is returning):
      [System.Serializable] public class ResultsContainer { public ResultScript[] results; } But when I run the code (in the debug mode, to get any result) I get an error: ArgumentException: JSON must represent an object type. I've googled it but none of the proposed solutions work for me.
      Also (regardless if I'm in the debug mode or not) when I try to do some string operations like removing or adding characters to the GET result, the functions return an empty string as a result
      Can you help me with any of these problems?
      Thank you
    • By nihitori
      The Emotional Music Vol. I pack focuses on beautiful and esoteric orchestral music, capable of creating truly emotive and intimate moods. It features detailed chamber strings, cello and piano as the main instruments, resulting in a subtle and elegant sound never before heard in video game royalty-free music assets.

      The pack includes 5 original tracks, as well as a total of 47 loops based on these tracks (long loops for simple use and short loops for custom / complex music layering).

      Unity Asset Store link: https://www.assetstore.unity3d.com/en/#!/content/107032
      Unreal Engine Marketplace link: https://www.unrealengine.com/marketplace/emotional-music-vol-i

      A 15 seconds preview of each main track is available on Soundcloud:
    • By RoKabium Games
      Another one of our new UI for #screenshotsaturday. This is the inventory screen for showing what animal fossils you have collected so far. #gamedev #indiedev #sama
    • By eldwin11929
      We're looking for programmers for our project.
      Our project is being made in Unity
      -Skills in Unity
      We're looking for programmers who can perform a variety of functions on our project.
      Project is a top-down hack-and-slash pvp dungeon-crawler like game. Game is entirely multiplayer based, using randomized dungeons, and a unique combat system with emphasis on gameplay.
      We have a GDD to work off of, and a Lead Programmer you would work under.
      Assignments may include:
      -Creating new scripts of varying degrees specific to the project (mostly server-side, but sometimes client-side)
      -Assembling already created monsters/characters with existing or non-existing code.
      -Creating VFX
      -Assembling already created environment models
      If interested, please contact: eldwin11929@yahoo.com
      This project is unpaid, but with royalties.
      Additional Project Info:
      Bassetune Reapers is a Player-verus-Player, competitive dungeon crawler. This basically takes on aspects of dungeon crawling, but with a more aggressive setting. Players will have the option to play as the "dungeon-crawlers" (called the 'Knights', or "Knight Class", in-game) or as the "dungeon" itself (literally called the 'Bosses', or "Boss Class", in-game). What this means is that players can choose to play as the people invading the dungeon, or as the dungeon-holders themselves.
      Key Features:
      -Intense, fast-paced combat
      -Multiple skills, weapons, and ways to play the game
      -Tons of different Bosses, Minibosses, creatures and traps to utilize throughout the dungeon
      -Multiple unique environments
      -Interesting, detailed lore behind both the game and world
      -Intricate RPG system
      -Ladder and ranking system
      -Lots of customization for both classes s of customization for both classes
  • Advertisement