Game Development Community

Let the music play on just until I feel this misery is gone

by Zilla · in Torque X 2D · 01/04/2008 (6:06 am) · 13 replies

I have two questions about sounds:

1. Is it possible to synchronize sounds with kind of a "time stamp"?
Let me explain it: A (background-)drum loop is playing and the player hits a wall. This event should start a bass loop. No problem so far. But I want that the second sound not only starts after the wall was hit but additionally this loop should not begin until the first loop starts again or is synchronized with a "time stamp". Could I explain it clearly (because my English is rather bad)?

2. Is there a clever method to lower the volume of all the sounds (except the "last" one) that are currently playing. Example: There is a background loop, several random explosions, a motor running - all together playing simultaneously. Now the player meets a NPC and talks to him. In order that you can hear this conversation, all the other sounds should be quieter.

#1
01/04/2008 (10:16 pm)
As far as I can tell, you can not synchrobize audio in XNA based on a time index. XNA simply does not expose time indexes the game. But, from what you described, you might try a different approach. Instead, ceate a hold on to a reference to your Cue _(say backgroundCue) object that plays your background drum loop in addition to a bool variable (say _hitWall) that checks the state (if collided with wall or not). Then, in your ProcessTick() method, you can check if _hitWall == true and if _backgroundCue.IsPlaying != true, then start playing the new sound.

This also kind of ties into your next question. If you hold on to a reference to your background loop Cue, explosion Cue, and motor Cue, you should be able to use the Cue.SetVariable() method to adjust a Cue Instance Variable, defined within XACT, that is tied to volume. You should be able set that variable lower during the NPC dialogue and then raise it when the dialogue ends.

John K.
#2
01/05/2008 (12:48 am)
Thank you very much :-) I will try this!

if _backgroundCue.IsPlaying != true, then start playing the new sound

Will this condition ever be true? Because the background loop is playing infintely.
#3
01/05/2008 (9:03 am)
Ouch! Great point! I forgot that you said it was a looping sound and not a sound played once. This might be more of a problem. Maybe you can still work with Cue Instance Variables within XACT. Perhaps you can set a cue instance variable at the end of the loop within XACT, then again, in your ProcessTick() method, call _backgroundCue.GetVariable("MyEndOfLoopVaraiable") to test if the variable is reached. I'll need to double check how cue instance variables workk, but this might do it.

John K.
#4
01/06/2008 (3:17 am)
Quote:work with Cue Instance Variables within XACT

Thank you for this idea :-)
I have never worked with these variables in XACT and I will have to find out how they work.
I found an example about this subject in "XNA unleashed" but if you know another source or even have a detailed solution for my "problem", please let me know :-)
#5
01/06/2008 (7:51 am)
As it turns out, I need to do some investigation here myself. I'll post my results (probably later today).

John K.
#6
01/06/2008 (5:10 pm)
Still looking into this, but it appears that you have to do this all within XACT by creating an interactive cue, using instance variables and markers. You need to set the IsInteractive property of the cue to True and pick a cue instance variable. Then, add your sounds to the cue to build the transition table. Then, edit the variable ranges for the sounds and transition properties to define what happens when the variable changes. You probably also need to add a Marker event to the track to trigger the interactive cue. Only the markers in the first track is used for transitions within interactive cues. To play a list of .wav in order, add them to a PlayWave event on a track. Then, set the track to looping and set NewVariationOnLoop event property to True. This will make each .wav play in order.

I'm putting together a simple demo project. Once I get it working, I'll post it for download.

John K.
#7
01/07/2008 (10:24 am)
Quote:I'm putting together a simple demo project.
That would be really cool, because I didn't understand half of what you said in your last post ;-)
But nonetheless thank you very much for your detailed explanation. It gives me a perfect start to study this XACT RPC stuff.
#8
01/07/2008 (2:38 pm)
Sorry, I was hoping that the post would not be just a bunch of useless babble. The bottom line is that audio in XNA is really strict and difficult to work with. You don't really have the flexibility and freedom that you have when working with DirectAudio or OpenAL. To make things worse, I think XACT is still missing a lot of features - basically you can play/pause/stop/rewind and even change volume and pitch. But that's about it. You can't easily get playback position, pan the audio from side to side, or even distort it in real-time.

So, what you're trying to accomplish with your original question should be possible to do, just not easy. I made some good progress on a sample project last night, I just need to finish the XACT side of things. I was then side-tracked by some thoughts on the DTS problem I'm trying to work out. I'll try and get your audio project posted this evening.

John K.
#9
01/08/2008 (1:13 am)
Quote:Sorry, I was hoping that the post would not be just a bunch of useless babble.
There's absolutely no need to be sorry. I REALLY appreciate it that very experienced users like you take your time to help XNA-newbies like me. It just takes time until I can fully understand the XACTool. So: Thank you very much for your help :-))))))))))

Quote:I'll try and get your audio project posted this evening.
Cool! GarageGames and YOU really care about their users :-)
#10
01/08/2008 (12:30 pm)
Download the sample.
*To compile, you need to Add a Reference to your own Torque.dll since I removed the Torque X Pro source code

After reading your original post and tinkering around with XNA, I decided to change the approach to better match your original question. I've uploaded a sample Torque X and XACT project that does something similar. The XACT project creates a wavebank/soundbank/cues for two helicopter engines (both set to infinite looping). Then, the code in Game.cs begins one helicopter engine sound and then schedules a callback method to stop that sound. I created two callback methods for you to compare - one stops the background loop at the natural end point of the loop, whereas the other callback stops the loop immediately. In both cases, the ProcessTick() method looks out for the stop in playback and when it is found, it re-starts the original sound playback along with the new sound playback.

This should be a good start to test out your original question. Except, instead of a scheduled callback, you would stop the sound on the collision with the wall event. Since you have handles to the individual sounds, you can also determine when to stop one or both of the sound loops. It will be up to you to make sure the loop sounds are the same length in order to keep in sync... for example, if your loop2 is 3 seconds shorter than loop1, you should add some 3 seconds of filler space at the end of loop2 to keep them in sync.

As for reducing the volume, you still need to define a Cue Instance Variable within XACT and set it programmatically with the Cue.SetVariable() method.

John K.
#11
01/09/2008 (1:34 pm)
@John
Thank you very much. This is absolutely cool and I will be able to learn a lot of things from your example :-)))
#12
03/20/2008 (1:25 pm)
Quote:pan the audio from side to side

Yeah you can; check out the 3D audio tutorials on the XNA site. From what I understand you can give a cue a location in 3d space to play at and the sound will appear to be coming from that location (automatically scaled for stereo or dolby digital output on the xbox). If you set your position to the camera, but adjusted along one axis, you should get a pan from left to right.
#13
09/26/2008 (4:58 am)
Hi, John

I was experimenting with your example. I was using some other sounds (a drum loop and a gated synth) because I didn't hear if your two helicopter sounds were really in sync.
I realised that my sounds are not in sync because

_sound1.Stop(AudioStopOptions.AsAuthored);

does not stop the sound at the end but immediately. Did I miss something?

Here's whole the code example

protected override void BeginRun()
        {
            base.BeginRun();
            SceneLoader.Load(@"data\levels\levelData.txscene");
            //being audio playback
            _waveBank = new WaveBank(Engine.SFXDevice, @"data\sounds\Wave Bank.xwb");
            _soundBank = new SoundBank(Engine.SFXDevice, @"data\sounds\Sound Bank.xsb");
            _sound1 = _soundBank.GetCue("Drumloop");
            _sound2 = _soundBank.GetCue("Gated");            
            //play one sound
            _sound1.Play();


            TorqueObject obj = TorqueObjectDatabase.Instance.FindObject<TorqueObject>("Logo");
            ProcessList.Instance.AddTickCallback(obj, this);

            //setup a scheduled event to stop the sound at end of the loop
            [b]Game.Instance.Engine.GameTimeSchedule.Schedule(1000, StopSoundAtEndOfLoop);[/b]


            //setup a scheduled event to stop the sound immediately
            //Game.Instance.Engine.GameTimeSchedule.Schedule(2500, StopSoundImmediately);
        }       

        public void StopSoundAtEndOfLoop(object Sender, ScheduledEventArguments scheduleEventArguments)
        {
            [b]_sound1.Stop(AudioStopOptions.AsAuthored);[/b]
        }

        public void StopSoundImmediately(object Sender, ScheduledEventArguments scheduleEventArguments)
        {
            _sound1.Stop(AudioStopOptions.Immediate);
        }


        public void ProcessTick(Move move, float dt)
        {
            if (_sound1.IsStopping)
            {
                _sound1 = _soundBank.GetCue("Drumloop");                
                _sound1.Play();
                _sound2.Play();                
            }
        }