Ogre .sound scripts

t0tAl_mElTd0wN

09-02-2007 23:10:27

Ok, so I'm sure most of you have heard of/seen the material, particle, and compositor scripts built into Ogre. Well, of course, leave it to Ogre to be amazing, it appears to be not especially hard to write new ones.

So, one of the features I'd like to add at some point is the ability to write .sound scripts. By placing the sound scripts and media in your resource path, I'd like Ogre to parse and build these scripts automatically, and allow you to create instances of them. For instance, say you built a sound script:
load_sound gunshot.wav
This is pretty simple. It's literally the equivelant of creating a sound and loading a WAV file. You'll still have access to the mechanisms to modify things manually, but sometimes it may be better to define pre-written scripts. Take this one for example:

load_sound rumble.wav
playing
{
sin_wav
{
set_period 5s
set_amp .5
set_offset .5
set_gain sin_value
}
}

Which would basically say while the sound is playing, have the gain follow the function sin(x * 5) * .5 + .5 where one unit on the X axis is one second. Basically, it would turn your low rumble sound into a low throbbing sound.

Of course, that's just an example. The final product would have many more states you could code for, a lot more functions and modifiers, and a lot more ajustable properties. The benefit would be in code, when you could say:

OgreAL::Sound *explosion = OgreAL::SoundManager::createSoundScript("explosion", "explosions/grenade1");
And then whenever a grenade goes off, set the position of the node and call explosion->play(), and the script will run through, possibly using a combination of gain and pitch modifiers, multiple sound files, whatever you specify.

So really, what I'm asking is three things:
1) Do you like this idea
2) Is it practical and usable? (to you?)
3) What features/commands/functions/modifiers do you want?

kungfoomasta

09-02-2007 23:38:12

1) That sounds like an awesome idea! It would be useful in the sense of re-using the sound and its properties for various instances, just like materials and particle scripts.

2) I believe it is practicle. I haven't really gotten to test out sounds in my projects, but I can already see it fits in really easily. For me, my game objects could store a list of sound scripts, and play them at appropriate times.

3) Well one important thing is a serializer. Just like you can create/modify particles/materials/meshes/skeletons/etc and serialize them, you would need to be able to do this with sounds. I can't really provide any other features/commands without diving in and using sounds everywhere... I'll get there eventually! :wink:

KungFooMasta

kinggori

26-02-2007 03:28:29

t0tAl_mElTd0wN, have you tried working on this awesome idea yet?

t0tAl_mElTd0wN

26-02-2007 14:39:56

Aye. I took a look through the compiler scripts, and I think I have a rough idea as to how to actually use it.

The first step is to write the BNF notation. Strange markup language, but not super difficult.

After that, write the state machine and the callbacks for the tokenizer

Then, write the main loop frame listener, so the scripts can be updated each frame.

I'm glad you like the idea. Hopefully it'll be ready for the next release :)

CaseyB

26-02-2007 14:47:01

You may want to check out [u]This Topic[/u] on the main forum. It seems there are some changes going on with the OgreScripts, not sure what stage they're at though!

kinggori

26-02-2007 19:19:06

I basically want to have a way of changing the file names from a text/xml/script file so that anyone with no programming skills can change the files.

Apparently, this is what you're doing here, right?

Is there a beta version i can try out?

t0tAl_mElTd0wN

27-02-2007 18:10:26

Unfortunately I'm nowhere near Beta yet. I haven't even finished defining the BNF notation for the syntax ;)

Yes, the sound files will be defined in the scripts. To change the sounds, it won't take any recompiling of anything. Just change that line in the script. The most simple of scripts might look like this:


sound Example/Simple_Sound
{
load_sound beep.wav
}


That would be the direct equivalent of loading beep.wav into a wavstream object. If you wanted, you could define all these sounds like this to allow people to mod your games or something. Alternatively, however, you could take advantage of some of the more advanced and tricky automation features like the wave definitions (supporting sin, triangle, square, or sawtooth) or looping or something. It's good to see people are excited about this though :)

kinggori

28-02-2007 06:30:46

let's say i want the simplest simplest scenario

a way to change the filename of background music from some text or config file...

do you have any suggestions on how i can do that? Can you please give me a little bit of details on what i need to do to achieve this?

t0tAl_mElTd0wN

28-02-2007 13:31:04

If you just want it done now, I would suggest looking at Ogre::ConfigFile. It's basically an INI parser. Might be useful for what you're looking for.


// Load resource paths from config file
ConfigFile cf;
cf.load("resources.cfg");

// Go through all sections & settings in the file
ConfigFile::SectionIterator seci = cf.getSectionIterator();

String secName, typeName, archName;
while (seci.hasMoreElements())
{
secName = seci.peekNextKey();
ConfigFile::SettingsMultiMap *settings = seci.getNext();
ConfigFile::SettingsMultiMap::iterator i;
for (i = settings->begin(); i != settings->end(); ++i)
{
typeName = i->first;
archName = i->second;
ResourceGroupManager::getSingleton().addResourceLocation(
archName, typeName, secName);
}
}


And the file should look something like this:

[sounds]
SoundName=filename.wav
Explosion=../explosion.wav
WalkLoop=something.wav


The [sounds] bit is accessed by the ConfigFile::SectionIterator, and the assignment parts under it (SoundName=filename.wav) are accessed from the ConfigFile::SettingsMultiMap

kinggori

01-03-2007 04:16:03

thanks for your reply t0tAl_mElTd0wN :D

I found the INI parser (the first set of code you pasted). Do I need to add anything to it or change it in any way so that it supports sound to?

As for my resources.cfg, here is what it looks like

# Resource locations to be added to the 'boostrap' path
# This also contains the minimum you need to use the Ogre example framework

[Bootstrap]
FileSystem=../../media/bootstrap


[General]
# In the process of creating a new media directory
# cleaned out and only containing good things.

# Until we're sure this new media directory is good, old bits were left
# in old_media which should not be referenced here.

FileSystem=../../media/buildings
FileSystem=../../media/terrain
FileSystem=../../media/art
FileSystem=../../media/art_condemned

# How about eventually having GUI things instead of overlays? Yes!
FileSystem=../../media/overlays
FileSystem=../../media/gui

FileSystem=../../media/configurables
FileSystem=../../media/configurables/ai


FileSystem=../../media/Audio

FileSystem=../../media/Materials
FileSystem=../../media/Models



should i add

[sounds]
SoundName=filename.wav
Explosion=../explosion.wav
WalkLoop=something.wav


to the resources.cfg file?


sorry I'm slightly lost here

t0tAl_mElTd0wN

01-03-2007 12:33:02

Yes, you'll need to change that INI parser to suit your needs. You could either include it right in resources.cfg, or write your own and put your information in a different file.

I was just posting that as an example. In fact, the code I posted is a direct copy from the Ogre examples framework. You'll want to the values to suit your needs. Things like WAVStream, OGGStream, WAV, and OGG might be appropriate for the first key, and then the filename for the second (FirstKey=SecondKey).

For the most part, the loop I demonstrated will be the same - the part you're going to change is the ResourceGroupManger::getSingleton.addResourceLocation() part. I think everything else can be safely ignored for your purposes.

Big hint: archName stands for archive name, and thus for each iteration of the 'for' loop, will contain the next sound file you specified in the config file.


[secName] <-- While Loop Iteration
typeName=archName <-- For Loop Iteration
typeName=archName <-- For Loop Iteration

[secName] <-- While Loop Iteration
typeName=archName <-- For Loop Iteration
typeName=archName <-- For Loop Iteration
typeName=archName <-- For Loop Iteration


Using that format, you should be able to figure out how that code works. The while loop and the for loop are for the sections (secName) and the key/value pairs (typeName and archName) respectively.

If you're not clear on what an iterator is, I might recommend http://en.wikipedia.org/wiki/Iterator to get you started.

Let me (or anyone else) know if you need more help. There are no stupid questions ;)

kinggori

01-03-2007 18:44:09

Thanks for your reply t0tAl_mElTd0wN :D
Your instructions are nice and clear

Here's what I've done so far (if you're trying to do the same thing you might find this useful):

I created a new Configuration file called sounds.cfg and placed it in my Release and Debug folders. This file has the following:

# Sound files are defined here


[backgroundsound]
SoundName=mario.wav



Inside my ogre applicatin file I entered:


void CAXApplication::setupSound()
{
// Load resource paths from config file
ConfigFile cf;
cf.load("sounds.cfg");

// Go through all sections & settings in the file
ConfigFile::SectionIterator seci = cf.getSectionIterator();

String secName, typeName, archName;
while (seci.hasMoreElements())
{
secName = seci.peekNextKey();
ConfigFile::SettingsMultiMap *settings = seci.getNext();
ConfigFile::SettingsMultiMap::iterator i;
for (i = settings->begin(); i != settings->end(); ++i)
{
typeName = i->first;
archName = i->second;


OgreAL::SoundManager *soundManager;
soundManager = new OgreAL::SoundManager();
OgreAL::Sound *bgSound = soundManager->createSound("FinalDuel", i->second, true);
bgSound->setRelativeToListener(true);
bgSound->play();


}
}
}


and in the same file in the setup function under setupResources(); I added:

setupSound();


and in the header file I added


void setupSound();



and I built and ran the project and it worked!
and if I change the file name in the config file it works like a charm :D


Sorry for bothering you with my nonstop questions...

is there a way of defining multiple background files and playing them one after the other during gameplay (instead of continuosly looping through the same music)?

t0tAl_mElTd0wN

01-03-2007 19:40:11

Keep in mind, in your code there you're going to run into issues if you want more than one script, because it will try to create two sounds, both called "FinalDuel". What I would suggest, is in your code, change the line OgreAL::Sound *bgSound = soundManager->createSound("FinalDuel", i->second, true); to OgreAL::Sound *bgSound = soundManager->createSound(i->first, i->second, true); and in the config file, change SoundName=mario.wav to FinalDuel=mario.wav

The other problem is that the OgreAL::Sound actually goes out of scope as soon as the for loop ends. Correct me if I'm wrong, Casey, but I don't believe after that happens you'll have control over it.

Once those are fixed, though, you'll be able to define as many different sounds as you want in the config file, and both the names and the sound files themselves will be defined in the config file. This way, you'll be able to say Music1=music/track01.wav
Music2=music/track02.wav
Music3=music/track03.wav
Etc., and when the previous track stops, simply play() the next one.

And, of course, this can be extended to not only music, but any game sounds you want.

I'd also reccomend not playing it as soon as it's loaded. That would get very interesting, very fast, when you defined say, 20 different sounds ;)