Am I going crazy? Wrong AudioChannels when playing the same AudioClip twice

Started by Monsieur OUXX, Wed 23/11/2016 01:01:11

Previous topic - Next topic

Monsieur OUXX

Consider this simplified code :
(I'm not sure it's enought o reproduce my issue)
Code: ags

// let aClip1 and aClip2 be AudioClips
AudioChannel* a1a = aClip1.Play(1, eRepeat);
AudioChannel* a1b = aClip1.Play(1, eRepeat);

AudioChannel* a2a = aClip2.Play(1, eRepeat);
AudioChannel* a2b = aClip2.Play(1, eRepeat);


//Then in repeatedly_execute_always
bool a1aPlays1 = a1a.Playingclip == aClip1;
bool a1aPlays2 = a1a.Playingclip == aClip2;
bool a1bPlays1 = a1b.Playingclip == aClip1;
bool a1bPlays2 = a1b.Playingclip == aClip2;

bool a2aPlays1 = a2a.Playingclip == aClip1;
bool a2aPlays2 = a2a.Playingclip == aClip2;
bool a2bPlays1 = a2b.Playingclip == aClip1;
bool a2bPlays2 = a2b.Playingclip == aClip2;

Display("[%d, %d, %d, %d]", a1aPlays1, a1aPlays2, a1bPlays1,a1bPlays2 );
Display("[%d, %d, %d, %d]", a2aPlays1, a2aPlays2, a2bPlays1,a2bPlays2 );



Very naturally you'd expect the display to be :
[1,0,1,0]
[0,1,0,1]

...And yet in some cases I get :
[1,0,0,1]
[0,1,1,0]


In other words, half the AudioChannels appear to be magically playing the wrong clip. Not only that, but there's a pattern : the AucioClips seems to "swap" AudioChannels (aClip1 in the channel supposed to run aClip2, and vice versa).

I'm extremely confused but I've been searching for hours now and I can't explain the mystery.

I'm not claiming this is a bug, but maybe experienced people could give me a lead?

EDIT: OH, OH, WAIT. Is a Clip that's repeating itself getting a new AudioChannel each time it restarts???
 

Crimson Wizard

Some time ago I made an attempt to explain how channels work on request by Mandle:
http://www.adventuregamestudio.co.uk/forums/index.php?topic=54062.msg636546051#msg636546051

Some things should be taken into account here. There is a limit of 8 (eight) simultaneously working channels in AGS. IIRC one is given to speech exclusively, which makes it 7. Also, depending on Audio Type settings, some types may be limited even further (Max channels property).
In other words, the pointers you may be getting there, could be pointing to less actual channels than you think. (I.e. potentionally it is possible that all of your AudioChannel* pointers are referencing same channel).

You may shed more light on your case by displaying all the channels' ID property and check if they are different.



Quote from: Monsieur OUXX on Wed 23/11/2016 01:01:11
EDIT: OH, OH, WAIT. Is a Clip that's repeating itself getting a new AudioChannel each time it restarts???
No, it does not get new channel, playing clip always stays on same channel until it is stopped or replaced by another clip.

Monsieur OUXX

I've been spending over 5 hours of intense logging and debugging on this, I swear I'm 110% sure that in the end there will just be an inversion between two channel names somewhere. I'll be so gutted.
 

Crimson Wizard

Why not just iterate over all AudioChannels and log out which clips are playing on them all (or which channel certain clip plays on), instead of making those complicated boolean variables with names that are so easy to mess up?

Monsieur OUXX

That's what I've been doing from the beginning and the results are not right.
I thought maybe I was doing something wrong in my code but Ithink I've found a bug.

If the scripter plays several clips in a row, then the AudioChannel pointer returned by the earlier AudioClip.Play are still valid, but their .PlayingClip got overwritten by the newer .Play calls

This simple script shows it. With as few as 6 sounds of type "Sound" playing, the one playing last is then found in the first AudioChannel.

Unless you tell me that it's expected behaviour that the channel is still valid but its content can be overwritten???

Code: ags

AudioChannel* channels[20];
int nbChannels=0;

//because I'm paranoid I'm checking if pointers to AudioClip* can return several false positives
String nameClip(AudioClip* c)
{
    String result = "";
    if (c==aSnow_tempest)
        result=String.Format("%s aSnow_tempest",result);
    if (c==aAmbiant_cave1)
        result=String.Format("%s aAmbiant_cave1",result);    
    if (c==aAmbiant_cave2)
        result=String.Format("%s aAmbiant_cave2",result);
    return result;
}

String listChannels()
{
    String result="";
    int i=0;
    while (i<nbChannels)
    {
        result=String.Format("%s channel\[%d]=%s[ ",result, i, nameClip(channels[i].PlayingClip));
        i++;
    }
    return result;
}

void game_start()
{
    FadeIn(64);
    channels[nbChannels] = aSnow_tempest.Play(1, eRepeat); nbChannels++;
    channels[nbChannels] = aSnow_tempest.Play(1, eRepeat); nbChannels++;
    channels[nbChannels] = aAmbiant_cave1.Play(1, eRepeat); nbChannels++;
    channels[nbChannels] = aAmbiant_cave1.Play(1, eRepeat); nbChannels++;
    channels[nbChannels] = aAmbiant_cave2.Play(1, eRepeat); nbChannels++;
    channels[nbChannels] = aAmbiant_cave2.Play(1, eRepeat); nbChannels++;
    
    Display(listChannels());
    
}




 

Snarky

Quote from: Monsieur OUXX on Wed 23/11/2016 21:33:06
Unless you tell me that it's expected behaviour that the channel is still valid but its content can be overwritten???

Yes it is, as explained in the post CW linked to:

Quote from: Crimson Wizard on Thu 20/10/2016 17:29:13
Since Audio Channels are fixed thing that always exists, the pointer to Audio Channel is the pointer to fixed, always present object. That pointer keeps working even after the clip stopped playing. So you may end up changing volume of another playback, by the way, if you keep using same pointer all the time.

Monsieur OUXX

OK, then I didn't understand all the implications of CW's post.
This is a big issue for me. If I play 2 ambient sounds in the room, multiplied by two to cross-fade them, plus one channel (or two!) for the footsteps for each character, that's already 6+ channels used. They're running out quickly...

Is the limit of 8 channels an artifical limit easily removed, or...?
 

Crimson Wizard

Quote from: Monsieur OUXX on Thu 24/11/2016 12:01:15
OK, then I didn't understand all the implications of CW's post.
Umm, implications?... I tried to write everything as explicitly as I could.


Quote from: Monsieur OUXX on Thu 24/11/2016 12:01:15
Is the limit of 8 channels an artifical limit easily removed, or...?
From the engine's perspective there is no problem of removing it, but I cannot predict whether the old sound library AGS is using will manage playing more sounds at once.
We could find out, I guess.

Monsieur OUXX

Quote from: Crimson Wizard on Thu 24/11/2016 12:27:31
everything as explicitly as I could.
I know, that was my way of saying that I'm dumb.



Quote
We could find out, I guess.
that'd be really cool. Maybe check if hardware sound is enabled or something before allowing more channels. I have no idea what's the average number of channels used in "modern" gaming systems and/or sound hardware.
 

morganw

Quote from: Monsieur OUXX on Thu 24/11/2016 12:01:15
This is a big issue for me. If I play 2 ambient sounds in the room, multiplied by two to cross-fade them, plus one channel (or two!) for the footsteps for each character, that's already 6+ channels used. They're running out quickly...
For the ambient sounds you should be able to reduce the number of channels you need, as long as you don't need to dynamically implement the crossfade.

  • load the sample into an audio editor
  • split it into two pieces where you would want to crossfade (just not too near the edge)
  • swap the position of the two pieces (left part moves to the right, right part moves to the left)
  • crossfade the two pieces (where they meet in the middle) and render that out as a new sample
You could do the same with the other ambient sample and optionally render them both together, so you would only be using 1 or 2 channels for ambient sounds. I'm pretty sure Audacity can do all of the above. MP3 format isn't good for looping sounds, but OGG should loop seamlessly between the start and end (where you made the initial split).

SMF spam blocked by CleanTalk