Programming/creating vgui soundscape maker: Difference between revisions
WadDelz0949 (talk | contribs) m (added todo) |
WadDelz0949 (talk | contribs) |
||
Line 12: | Line 12: | ||
* [[VGUI2: Creating a panel]] | * [[VGUI2: Creating a panel]] | ||
==The main vgui | ==The main vgui panel== | ||
Before you start the tutorial you need to copy and paste both these files into your '''src/game/client/''' directory | Before you start the tutorial you need to copy and paste both these files into your '''src/game/client/''' directory | ||
Line 315: | Line 315: | ||
</source> | </source> | ||
Now the panel should be all done. to open the panel in game use the '''modbase_soundscape_panel''' command and the panel should show. | Now the panel should be all done. to open the panel in game use the '''modbase_soundscape_panel''' command and the panel should show. | ||
==How to use the panel== | ==How to use the panel== | ||
[[File:Labeled soundscape panel.png|thumb|alt=Labeled soundscape panel|Labeled soundscape panel]] | [[File:Labeled soundscape panel.png|thumb|alt=Labeled soundscape panel|Labeled soundscape panel]] |
Revision as of 07:02, 10 May 2025


This tutorial will show you how to make a vgui soundscape maker panel that allows you to modify and play soundscapes in game.
Requirements
- A mod running on Source SDK 2013
- Knowledge of C++
Have read and/or understand:
The main vgui panel
Before you start the tutorial you need to copy and paste both these files into your src/game/client/ directory

Once that is done you are almost all done. The next thing you are going to want to do is go over to client/vgui_int.cpp and at the top of the file and under
#include <vgui_controls/Controls.h>
add
#include "vgui_soundscape_maker.h"
Then in the same file find:
void VGui_CreateGlobalPanels( void )
{
VPANEL gameToolParent = enginevgui->GetPanel( PANEL_CLIENTDLL_TOOLS );
VPANEL toolParent = enginevgui->GetPanel( PANEL_TOOLS );
and under that add
g_SoundscapeMaker->Create(toolParent);
Now find
void VGui_Shutdown()
{
And under it add:
g_SoundscapeMaker->Destroy();
Now go to public\tier1\KeyValues.h and find:
private:
KeyValues( KeyValues& ); // prevent copy constructor being used
(should be around line 258) and make that be:
public:
KeyValues( KeyValues& ); // prevent copy constructor being used
Now go to client/c_soundscape.cpp and copy:
#include "c_soundscape.h"
to be under
#include "tier0/icommandline.h"
Then in the same file find:
void C_SoundscapeSystem::StartNewSoundscape( KeyValues *pSoundscape )
and just above that add:
extern bool g_IsPlayingSoundscape;
then at the very top of the function add
if (g_IsPlayingSoundscape)
return;
Then in the same file move
struct loopingsound_t
{
Vector position; // position (if !isAmbient)
const char *pWaveName; // name of the wave file
float volumeTarget; // target volume level (fading towards this)
float volumeCurrent; // current volume level
soundlevel_t soundlevel; // sound level (if !isAmbient)
int pitch; // pitch shift
int id; // Used to fade out sounds that don't belong to the most current setting
bool isAmbient; // Ambient sounds have no spatialization - they play from everywhere
};
to be under
#ifdef _WIN32
#pragma once
from c_soundscapes.cpp into the file client/c_soundscapes.h
and finally move:
struct randomsound_t
{
Vector position;
float nextPlayTime; // time to play a sound from the set
interval_t time;
interval_t volume;
interval_t pitch;
interval_t soundlevel;
float masterVolume;
int waveCount;
bool isAmbient;
bool isRandom;
KeyValues *pWaves;
void Init()
{
memset( this, 0, sizeof(*this) );
}
};
struct subsoundscapeparams_t
{
int recurseLevel; // test for infinite loops in the script / circular refs
float masterVolume;
int startingPosition;
int positionOverride; // forces all sounds to this position
int ambientPositionOverride; // forces all ambient sounds to this position
bool allowDSP;
bool wroteSoundMixer;
bool wroteDSPVolume;
};
class C_SoundscapeSystem : public CBaseGameSystemPerFrame
{
public:
virtual char const *Name() { return "C_SoundScapeSystem"; }
C_SoundscapeSystem()
{
m_nRestoreFrame = -1;
}
~C_SoundscapeSystem() {}
void OnStopAllSounds()
{
m_params.ent.Set( NULL );
m_params.soundscapeIndex = -1;
m_loopingSounds.Purge();
m_randomSounds.Purge();
}
// IClientSystem hooks, not needed
virtual void LevelInitPreEntity()
{
Shutdown();
Init();
TouchSoundFiles();
}
virtual void LevelInitPostEntity()
{
if ( !m_pSoundMixerVar )
{
m_pSoundMixerVar = (ConVar *)cvar->FindVar( "snd_soundmixer" );
}
if ( !m_pDSPVolumeVar )
{
m_pDSPVolumeVar = (ConVar *)cvar->FindVar( "dsp_volume" );
}
}
// The level is shutdown in two parts
virtual void LevelShutdownPreEntity() {}
// Entities are deleted / released here...
virtual void LevelShutdownPostEntity()
{
OnStopAllSounds();
}
virtual void OnSave() {}
virtual void OnRestore()
{
m_nRestoreFrame = gpGlobals->framecount;
}
virtual void SafeRemoveIfDesired() {}
// Called before rendering
virtual void PreRender() { }
// Called after rendering
virtual void PostRender() { }
// IClientSystem hooks used
virtual bool Init();
virtual void Shutdown();
// Gets called each frame
virtual void Update( float frametime );
void PrintDebugInfo()
{
Msg( "\n------- CLIENT SOUNDSCAPES -------\n" );
for ( int i=0; i < m_soundscapes.Count(); i++ )
{
Msg( "- %d: %s\n", i, m_soundscapes[i]->GetName() );
}
if ( m_forcedSoundscapeIndex )
{
Msg( "- PLAYING DEBUG SOUNDSCAPE: %d [%s]\n", m_forcedSoundscapeIndex, SoundscapeNameByIndex(m_forcedSoundscapeIndex) );
}
Msg( "- CURRENT SOUNDSCAPE: %d [%s]\n", m_params.soundscapeIndex.Get(), SoundscapeNameByIndex(m_params.soundscapeIndex) );
Msg( "----------------------------------\n\n" );
}
// local functions
void UpdateAudioParams( audioparams_t &audio );
void GetAudioParams( audioparams_t &out ) const { out = m_params; }
int GetCurrentSoundscape()
{
if ( m_forcedSoundscapeIndex >= 0 )
return m_forcedSoundscapeIndex;
return m_params.soundscapeIndex;
}
void DevReportSoundscapeName( int index );
void UpdateLoopingSounds( float frametime );
int AddLoopingAmbient( const char *pSoundName, float volume, int pitch );
void UpdateLoopingSound( loopingsound_t &loopSound );
void StopLoopingSound( loopingsound_t &loopSound );
int AddLoopingSound( const char *pSoundName, bool isAmbient, float volume,
soundlevel_t soundLevel, int pitch, const Vector &position );
int AddRandomSound( const randomsound_t &sound );
void PlayRandomSound( randomsound_t &sound );
void UpdateRandomSounds( float gameClock );
Vector GenerateRandomSoundPosition();
void ForceSoundscape( const char *pSoundscapeName, float radius );
int FindSoundscapeByName( const char *pSoundscapeName );
const char *SoundscapeNameByIndex( int index );
KeyValues *SoundscapeByIndex( int index );
// main-level soundscape processing, called on new soundscape
void StartNewSoundscape( KeyValues *pSoundscape );
void StartSubSoundscape( KeyValues *pSoundscape, subsoundscapeparams_t ¶ms );
// root level soundscape keys
// add a process for each new command here
// "dsp"
void ProcessDSP( KeyValues *pDSP );
// "dsp_player"
void ProcessDSPPlayer( KeyValues *pDSPPlayer );
// "playlooping"
void ProcessPlayLooping( KeyValues *pPlayLooping, const subsoundscapeparams_t ¶ms );
// "playrandom"
void ProcessPlayRandom( KeyValues *pPlayRandom, const subsoundscapeparams_t ¶ms );
// "playsoundscape"
void ProcessPlaySoundscape( KeyValues *pPlaySoundscape, subsoundscapeparams_t ¶ms );
// "soundmixer"
void ProcessSoundMixer( KeyValues *pSoundMixer, subsoundscapeparams_t ¶ms );
// "dsp_volume"
void ProcessDSPVolume( KeyValues *pKey, subsoundscapeparams_t ¶ms );
bool IsBeingRestored() const
{
return gpGlobals->framecount == m_nRestoreFrame ? true : false;
}
void AddSoundScapeFile( const char *filename );
void TouchPlayLooping( KeyValues *pAmbient );
void TouchPlayRandom( KeyValues *pPlayRandom );
void TouchWaveFiles( KeyValues *pSoundScape );
void TouchSoundFile( char const *wavefile );
void TouchSoundFiles();
int m_nRestoreFrame;
CUtlVector< KeyValues * > m_SoundscapeScripts; // The whole script file in memory
CUtlVector<KeyValues *> m_soundscapes; // Lookup by index of each root section
audioparams_t m_params; // current player audio params
CUtlVector<loopingsound_t> m_loopingSounds; // list of currently playing sounds
CUtlVector<randomsound_t> m_randomSounds; // list of random sound commands
float m_nextRandomTime; // next time to play a random sound
int m_loopingSoundId; // marks when the sound was issued
int m_forcedSoundscapeIndex;// >= 0 if this a "forced" soundscape? i.e. debug mode?
float m_forcedSoundscapeRadius;// distance to spatialized sounds
static ConVar *m_pDSPVolumeVar;
static ConVar *m_pSoundMixerVar;
};
from c_soundscape.cpp to under the code you added in the c_soundscape.h file. before anything else you need to look for
void ProcessDSPVolume(KeyValues* pKey, subsoundscapeparams_t& params);
private:
bool IsBeingRestored() const
in the .h file you just added the class to. and if you find it then make the private be public. Then under the class definition add:
extern C_SoundscapeSystem g_SoundscapeSystem;
Now the panel should be all done. to open the panel in game use the modbase_soundscape_panel command and the panel should show.
How to use the panel
Before we start, if you dont know how to use/create soundscapes then first use either of these links to get a good understanding on how to make soundscapes.
Using the sections:
This will teach you on how to create soundscapes using the soundscape maker panel.
So The soundscape panel has 4 sections.
- The Soundscapes section. This section contains the list of soundscapes for this file and is located on the right side of the panel.
- The soundscape data section. This section has all the data for a specific soundscape for this file, this is the bottom middle section on the panel.
- The random soundscape data section. This section has all the random waves that can play for a "playrandom" section for a specific soundscape, this is the bottom right section on the panel.
- The data section. this section contains all the data for the specific soundscape and/or current soundscape data like: the soundscape name, the soundscape dsp, a soundscape data's volume and more, this is the top right section of the panel.
To create a new soundscape right click on the soundscapes section and click on the Add Soundscape button. Then a new soundscape should appear with the name 'New Soundscape %d' (note %d is a number that gets incremented everytime a new soundscape button gets created). To start modifying a soundscape you need to press on the button that was just created OR press on an already existing soundscape to modify that.


Once you have selected a soundscape you can now modify the soundscapes name by typing in the Soundscape Name text entry and the soundscapes dsp by selecting a dsp option from the DSP Dropdown menu.
now you have a soundscape selected you can now modify the contents of the soundscape using the Soundscape Data Section. Usually when no soundscape is selected the Soundscape data section is empty and unusable. But when you have a soundscape selected it becomes more usefull. The soundscape data section
allows you to add the 3 different soundscape elements to the soundscape. these are: Looping Sounds, Other Soundscapes, and Random Sounds.
- Looping sounds are sounds that start playing when the soundscape starts and play the sound forever.
- Soundscape sounds are another soundscape that you can play with all the other looping and random sounds.
- Random sounds are a list of sounds that play a random sound in the list of sounds in a random (but changable) time interval.
To create a Soundscape data item you need to right click on the Soundscape data section, Then a context menu will show with 3 different elements you can choose from (the elements listed above. Remember it wont work if no soundscape is selected). Once you press on one of the buttons on the context menu , a new item will be created on the Soundscape data section. The item type will be determined by what option you pressed on the context menu (Note: when you create an item it automatically selects that item). When you press/select the newly created item in the Soundscape data section the Sound volume, Sound pitch, Sound Position, sound level, And Sound Name items at the top of the panel will all be enabled and will say/show what the data for that item is.

The Sound Name text entry and button won't show if the item pressed was a playrandom.
When modifying the sound name of an item you can choose from a sound using the Sound selector panel. This panel can be opened by pressing on the Sound List button. when opened, a panel with 4 buttons and a combo box will show. the combo box will show/allow you to choose from every single sound in the game.

There are 4 buttons on the Sound selector panel. these are:
- A play sound button. this play's the sound with the name that is in the combo box.
- A stop sound button. this will stop the current playing sound.
- An insert button. this button inserts the sound from the combo box into the Sound Name text entry in the main soundscape panel
- Reload sounds button. this button reloads all the sounds and re-adds to the combo box.
If you decide to press on one of the playrandom buttons on the Soundscape data section then every single added random sound will be shown on the Random sound section. You can now also add items to the Random section section by right clicking on the section and adding an item using the context menu (Note: The newly created item will automatically get selected once added).
When pressing on one of the random sounds the Sound name text entry and button will now show and be usable. the sound name text entry will also get set to the name of the random wave item you chose. Now when modifying the Sound name button it will change the name of the currently selected random wave.
Saving and loading the soundscape
There are 3 buttons on the bottom of the panel that have to do with saving, loading and creating new soundscape files. these buttons are:
- New Soundscape Button. This button clears all of the created soundscapes and resets everything. But dont worry it does prompt you before actually clearing everything
- Save Soundscape Button. This button saves the soundscape file to the file of your choice. NOTE: if you save it to a 'scripts' directory then it will add the filename to a soundscapes_manifest.txt file (and create the file if its not found)
- Open Soundscape File Button. This allows you to choose a file that will be opened in the soundscape maker panel.
Deleting and playing the soundscapes
On the middle of the soundscapes panel there are 3 buttons (1 of which being a check button). these buttons are:
- Play soundscapes checkbox. this checkbox, when checked, will play the current selected soundscape. And when unchecked will stop all soundscapes. It will also make it so any time you select another soundscape on the soundscape panel it will automatically start that soundscape. It also makes it so any other soundscapes from any other source will NOT be able to play until this checkbutton is unchecked.
- Reset soundscapes button. This button will restart the soundscape that is playing when pressed. It is also only enabled when the Play soundscapes checkbox is checked.
- Delete item button. This button will delete the last item that was pressed on any of the 3 data sections. So say I pressed a soundscape on the soundscape section. If I pressed the Delete Item button then it will delete that soundscape because that is what I selected last
I hope this tutorial helped you with using and creating soundscapes in your mod.