0
0

Language: C++
Compiler: Visual Studio.net 2003

Basically my problem is that I am loading up this playlist and randomly going through it, however after it has gone through the playlist several times (32 songs worth) the playlist will not play any more songs.
The problem can be reproduced if I load a 3D sound and start it playing every frame ( I am assuming once it has played around 32 times it stops the background music as well).
The 3d sound is loaded using the following:
[code:2nsvm24k]#define _LOAD3DSOUND(path,index) result = m_pSystem->createSound(path, FMOD_3D | FMOD_HARDWARE , 0, &m_tGameSFX[index]); \
ERRCHECK(result); \
result = m_tGameSFX[index]->set3DMinMaxDistance(50.0f * DISTANCEFACTOR, 10000.0f * DISTANCEFACTOR); \
ERRCHECK(result);[/code:2nsvm24k]
This number define loads them into an array I have defined within the class containing fmod.

Background music Code:
My background sound structure:
[code:2nsvm24k]struct tSound {
FMOD::Channel *m_Channel;
unsigned int length;
};[/code:2nsvm24k]

Initialization:
[code:2nsvm24k]FMOD_RESULT result;
FMOD_SOUND_TYPE soundtype;
bool isplaylist = false;
result = FMOD::System_Create(&m_pSystem);
ERRCHECK(result);

result = m_pSystem->init(32, FMOD_INIT_NORMAL, 0);
ERRCHECK(result);

m_pSystem->setOutput(FMOD_OUTPUTTYPE_DSOUND);

result = m_pSystem->set3DSettings(1.0f, DISTANCEFACTOR, 1.0f);
ERRCHECK(result);

// loading a playlist
result = m_pSystem->createSound("assets/sounds/Music/bttw.m3u", FMOD_DEFAULT, 0, &playlist);
ERRCHECK(result);

result = playlist->getFormat(&soundtype, 0, 0, 0);
ERRCHECK(result);

isplaylist = (soundtype == FMOD_SOUND_TYPE_PLAYLIST);

if (!isplaylist)
{

if _DEBUG

LMessageBox("assets/sounds/Music/bttw.m3u is not a playlist", 0);

endif

assert(isplaylist);
}[/code:2nsvm24k]

Starting the playlist:
[code:2nsvm24k]int randomStartTrack = rand()%m_nNumberOfSongsInPlaylist;
result = m_pSystem->playSound(FMOD_CHANNEL_FREE, m_vPlayListSounds[randomStartTrack], false, &sound1.m_Channel);
m_vPlayListSounds[randomStartTrack]->getLength(&sound1.length, FMOD_TIMEUNIT_MS);
startTime1 = timeGetTime();
sound1.m_Channel->setVolume(g_fMusicVolume);
ERRCHECK(result);
randomStartTrack = rand()%m_nNumberOfSongsInPlaylist;
result = m_pSystem->playSound(FMOD_CHANNEL_FREE, m_vPlayListSounds[randomStartTrack], true, &sound2.m_Channel);
m_vPlayListSounds[randomStartTrack]->getLength(&sound2.length, FMOD_TIMEUNIT_MS);
sound2.m_Channel->setVolume(g_fMusicVolume);
ERRCHECK(result);[/code:2nsvm24k]

Updating:
[code:2nsvm24k]int newTrackToPlay = rand()%m_nNumberOfSongsInPlaylist;
FMOD_RESULT result;
unsigned int curTime = timeGetTime();

if (m_bChannel1Playing)
{
if ((curTime – startTime1) > (sound1.length))
{
sound2.m_Channel->setPaused(false);
startTime2 = curTime;
result = m_pSystem->playSound(FMOD_CHANNEL_FREE, m_vPlayListSounds[newTrackToPlay], true, &sound1.m_Channel);
m_vPlayListSounds[newTrackToPlay]->getLength(&sound1.length, FMOD_TIMEUNIT_MS);

   ERRCHECK(result);
   m_bChannel1Playing = false;

}
}
else
{
if ((curTime – startTime2) > (sound2.length))
{
sound1.m_Channel->setPaused(false);
startTime1 = curTime;
result = m_pSystem->playSound(FMOD_CHANNEL_FREE, m_vPlayListSounds[newTrackToPlay], true, &sound2.m_Channel);
m_vPlayListSounds[newTrackToPlay]->getLength(&sound2.length, FMOD_TIMEUNIT_MS);

   ERRCHECK(result);
   m_bChannel1Playing = true;
}

}
sound1.m_Channel->setVolume(g_fMusicVolume);
sound2.m_Channel->setVolume(g_fMusicVolume);[/code:2nsvm24k]

Thank you for any insight in advance.
I apologise if this question has already been answered, I checked the FAQ and the search feature but didnt see anyone with similar issues.
I have also tried using the flag to reuse channels and this did not help.

The reason for the strange way of determining when the song is over is because I tried the IsPlayig call like what the example included with FMOD was using but it caused a small pause in between the background tracks (which in this application is not acceptable because each “song” is only several seconds long and they transition from eachother to form a random background track)

  • You must to post comments
0
0

Do I have to maintain the channels that FMOD creates and actually call stop on them manually? I was just declaring a temporary one and letting it fall out of scope.
I guess I figured that they would automatically stop the channel when the sound was done playing.

… this seems like a silly question in retrospect :roll: . I will try it and see if that fixes the problem

Edit: declaring an array, keeping the pointers to the channels, and manually calling stop on them seems to keep me from running out of channels.
However it is quite memory inefficient…. is there a reccomended way of doing this?
Id rather not have to actually keep an array and manually check each channel every frame to see if it is currently playing (to stop it) and also check each index in the array to see if it is playing whenever I want to play another sound.

  • You must to post comments
0
0

Just thinking of some ideas… I would imagine you could derive a class from FMOD::Sound which would contain functionality to stop itself when a song has finished playing. Much like what a smart pointer does when no one else is using it.

  • You must to post comments
0
0

[code:3u1zwida]void CSoundManager::playSound(GameSoundFX effectToPlay, D3DXVECTOR3 *position)
{

FMOD::Channel *tmp;
FMOD_RESULT result;

if (position == NULL)

{
result = m_pSystem->playSound(FMOD_CHANNEL_FREE, m_tGameSFX[effectToPlay], false, &tmp);
ERRCHECK(result);
}
else
{
FMOD_VECTOR pos = { position->x * DISTANCEFACTOR, position->y * DISTANCEFACTOR, position->z * DISTANCEFACTOR };
FMOD_VECTOR vel = { 0.0f, 0.0f, 0.0f };

result = m_pSystem->playSound(FMOD_CHANNEL_FREE, m_tGameSFX[effectToPlay], true, &tmp);
ERRCHECK(result);
result = tmp->set3DAttributes(&pos, &vel);
tmp->setPriority(255);
tmp->setPaused(false);
ERRCHECK(result);
}
}[/code:3u1zwida]

That is my code to play basic 3d sounds. If I maintan pointers to the “tmp” variables I am creating and actually call ->stop() on them whenever ->isplaying() returns false then everything works just fine…

[quote:3u1zwida]are they looping or something? [/quote:3u1zwida]
Nope
[quote:3u1zwida]why would they be continuing?[/quote:3u1zwida]
That is what I have been asking myself

[quote:3u1zwida]just keep a handle to the new one and the old ond and stop the old one when it is finished, you don’t need to store a handle to all of them. [/quote:3u1zwida]
The problem I have conceptually with that is I have that function called “playSound” which can be called by anyone any time within the application…. potentially calling more than one track at once.
If I just store one handle and use it the next time I call playsound… the sound who was previously using it might not have finished playing yet so I cant just stop it or use the same handle (because then FMOD would over write it and I wouldnt be able to check and stop it later) The only I way I can see to do this is something like a linked list. Unless I am completely missing the point.

[quote:3u1zwida]note you were talking about a gap in your sequence but fmod already supports gapless stitching and even has an example showing how to do it.[/quote:3u1zwida]
Well Son of a…..
I guess thats another thing // TODO: for me. I saw the playlist example and said ‘ey, ‘ats what I want to do and just looked no further >.<
Thanks for the wakeup call on that one brett

[quote:3u1zwida]Just thinking of some ideas… I would imagine you could derive a class from FMOD::Sound which would contain functionality to stop itself when a song has finished playing. Much like what a smart pointer does when no one else is using it.[/quote:3u1zwida]
This might be another option I will look in to.

  • You must to post comments
0
0

Here is a complete listing of exactly what I am doing. You will have to excuse anything silly, this was dropped in my lap 2 days ago.
Again, still doing this without using the realtime stiching example, havent looked over him yet.
.h
[code:3glt6xjz]
enum GameSoundFX
{
BALL_TELEPORTER_01 = 0,
BALL_TELEPORTER_02,

...
WATER_BALL_TO_STANDARD_POLE,
NUM_OF_GAME_SOUNDFX
};
struct tSound {
FMOD::Channel *m_Channel;
unsigned int length;
};
class CSoundManager
{
private:

//  Constructor.
CSoundManager(void);

//  Destructor.
~CSoundManager(void);
void Init();
static CSoundManager *pInstance;

FMOD::Sound *m_tGameSFX[NUM_OF_GAME_SOUNDFX];

FMOD::System        *m_pSystem;
vector&lt;FMOD::Sound *&gt; m_vPlayListSounds;
FMOD::Sound         *playlist;
int m_nNumberOfSongsInPlaylist;
FMOD_TAG          m_PlayListTag;
char              m_pCurrentFilePlaying[128];
char                m_pCurrentFileTitle[128];
unsigned int startTime1;
unsigned int startTime2;

vector&lt;FMOD::Channel *&gt; m_vChannels;
//FMOD::Sound      *m_PlayListSound;
tSound sound1;
tSound sound2;
bool m_bChannel1Playing;

void LoadGameSounds();

public:
/**************************************************************
Function: GetInstance
Purpose: Acquires an instance of the singleton class.
**************************************************************/
static CSoundManager* GetInstance();
void Shutdown();
void ERRCHECK(FMOD_RESULT result);

/**************************************************************
Function:   DeleteInstance
Purpose:    Kills the instance of the singleton class.
**************************************************************/
void DeleteInstance();
void playSound(GameSoundFX effectToPlay, D3DXVECTOR3 *position = 0);
void setlistener(D3DXMATRIX *matrix = 0);

void Update();

};[/code:3glt6xjz]

.cpp
[code:3glt6xjz]#pragma comment(lib, "FMODIncludes/fmodex_vc.lib")

define DISTANCEFACTOR 1.0f

define _LOAD3DSOUND(path,index) result = m_pSystem->createSound(path, FMOD_3D | FMOD_HARDWARE , 0, &m_tGameSFX[index]); \

ERRCHECK(result); \
result = m_tGameSFX[index]->set3DMinMaxDistance(50.0f * DISTANCEFACTOR, 10000.0f * DISTANCEFACTOR); \
ERRCHECK(result);

void CSoundManager::ERRCHECK(FMOD_RESULT result)
{
if (result != FMOD_OK)
{
char errorMessage[128];
sprintf(errorMessage, "FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));

if _DEBUG

    LMessageBox(errorMessage, 0);

endif

    assert(result == FMOD_OK);
}

}
CSoundManager* CSoundManager::pInstance = 0;

CSoundManager::CSoundManager(void)
{
m_pSystem = 0;
m_nNumberOfSongsInPlaylist = 0;
playlist = 0;
m_bChannel1Playing = true;
startTime1 = 0;
startTime2 = 0;

}
CSoundManager* CSoundManager::GetInstance()
{
if(pInstance == 0)
{
pInstance = new CSoundManager;
pInstance->Init();
}
return pInstance;
}
void CSoundManager::Init()
{
FMOD_RESULT result;
FMOD_SOUND_TYPE soundtype;
bool isplaylist = false;
result = FMOD::System_Create(&m_pSystem);
ERRCHECK(result);

result = m_pSystem-&gt;init(32, FMOD_INIT_NORMAL, 0);
ERRCHECK(result);

m_pSystem-&gt;setOutput(FMOD_OUTPUTTYPE_DSOUND);

result = m_pSystem-&gt;set3DSettings(1.0f, DISTANCEFACTOR, 1.0f);
ERRCHECK(result);

result = m_pSystem-&gt;createSound(&quot;assets/sounds/Music/bttw.m3u&quot;, FMOD_DEFAULT, 0, &amp;playlist);
ERRCHECK(result);

result = playlist-&gt;getFormat(&amp;soundtype, 0, 0, 0);
ERRCHECK(result);

isplaylist = (soundtype == FMOD_SOUND_TYPE_PLAYLIST);

if (!isplaylist)
{

if _DEBUG

    LMessageBox(&quot;assets/sounds/Music/bttw.m3u is not a playlist&quot;, 0);

endif

    assert(isplaylist);
}


do {
    result = playlist-&gt;getTag(&quot;FILE&quot;, m_nNumberOfSongsInPlaylist, &amp;m_PlayListTag);
    if (result != FMOD_OK)
    {
        break;
    }
    FMOD::Sound *temp;
    result = playlist-&gt;getTag(&quot;FILE&quot;, m_nNumberOfSongsInPlaylist, &amp;m_PlayListTag);
    ERRCHECK(result);

    sprintf(m_pCurrentFilePlaying, &quot;assets/sounds/Music/%s&quot;, (char *)m_PlayListTag.data);

    result = m_pSystem-&gt;createSound(m_pCurrentFilePlaying, FMOD_DEFAULT, 0, &amp;temp);
    ERRCHECK(result);

    m_vPlayListSounds.push_back(temp);
    ++m_nNumberOfSongsInPlaylist;

} while(1);

int randomStartTrack = rand()%m_nNumberOfSongsInPlaylist;
result = m_pSystem-&gt;playSound(FMOD_CHANNEL_FREE, m_vPlayListSounds[randomStartTrack], false, &amp;sound1.m_Channel);
m_vPlayListSounds[randomStartTrack]-&gt;getLength(&amp;sound1.length, FMOD_TIMEUNIT_MS);
startTime1 = timeGetTime();
sound1.m_Channel-&gt;setVolume(g_fMusicVolume);
ERRCHECK(result);
randomStartTrack = rand()%m_nNumberOfSongsInPlaylist;
result = m_pSystem-&gt;playSound(FMOD_CHANNEL_FREE, m_vPlayListSounds[randomStartTrack], true, &amp;sound2.m_Channel);
m_vPlayListSounds[randomStartTrack]-&gt;getLength(&amp;sound2.length, FMOD_TIMEUNIT_MS);
sound2.m_Channel-&gt;setVolume(g_fMusicVolume);
ERRCHECK(result);

LoadGameSounds();

}
void CSoundManager::DeleteInstance()
{
if(pInstance)
{
delete pInstance;
pInstance = 0;
}
}

CSoundManager::~CSoundManager(void)
{
}

void CSoundManager::Update()
{
for (unsigned int i = 0; i < m_vChannels.size();++i)
{
bool isPlaying = true;
m_vChannels[i]->isPlaying(&isPlaying);
if (!isPlaying)
{
m_vChannels[i]->stop();
m_vChannels[i] = m_vChannels.back();
m_vChannels.pop_back();
}
}
/*
When sound has finished playing, play the next sound in the playlist
*/
bool isplaying = false;
int newTrackToPlay = rand()%m_nNumberOfSongsInPlaylist;
FMOD_RESULT result;
unsigned int curTime = timeGetTime();

if (m_bChannel1Playing)
{  
    if ((curTime - startTime1) &gt; (sound1.length))
    {
        sound2.m_Channel-&gt;setPaused(false);
        startTime2 = curTime;
        result = m_pSystem-&gt;playSound(FMOD_CHANNEL_REUSE, m_vPlayListSounds[newTrackToPlay], true, &amp;sound1.m_Channel);
        m_vPlayListSounds[newTrackToPlay]-&gt;getLength(&amp;sound1.length, FMOD_TIMEUNIT_MS);

        ERRCHECK(result);
        m_bChannel1Playing = false;
    }

}
else
{
    if ((curTime - startTime2) &gt; (sound2.length))
    {
        sound1.m_Channel-&gt;setPaused(false);
        startTime1 = curTime;
        result = m_pSystem-&gt;playSound(FMOD_CHANNEL_REUSE, m_vPlayListSounds[newTrackToPlay], true, &amp;sound2.m_Channel);
        m_vPlayListSounds[newTrackToPlay]-&gt;getLength(&amp;sound2.length, FMOD_TIMEUNIT_MS);

        ERRCHECK(result);
        m_bChannel1Playing = true;
    }
}

sound1.m_Channel-&gt;setVolume(g_fMusicVolume);
sound2.m_Channel-&gt;setVolume(g_fMusicVolume);

}

void CSoundManager::LoadGameSounds()
{
FMOD_RESULT result;
_LOAD3DSOUND("assets/sounds/SFX/Ball_Teleporter_01.wav", BALL_TELEPORTER_01);
_LOAD3DSOUND("assets/sounds/SFX/Ball_Teleporter_02.wav", BALL_TELEPORTER_02);
...
_LOAD3DSOUND("assets/sounds/SFX/Water_Ball_To_Standard_Block.wav", WATER_BALL_TO_STANDARD_POLE);
}

void CSoundManager::playSound(GameSoundFX effectToPlay, D3DXVECTOR3 *position)
{

FMOD::Channel *tmp;
FMOD_RESULT result;

if (position == NULL)
{
    result = m_pSystem-&gt;playSound(FMOD_CHANNEL_FREE, m_tGameSFX[effectToPlay], false, &amp;tmp);
    ERRCHECK(result);
}else{
    FMOD_VECTOR pos = { position-&gt;x * DISTANCEFACTOR, position-&gt;y * DISTANCEFACTOR, position-&gt;z * DISTANCEFACTOR };
    FMOD_VECTOR vel = {  0.0f, 0.0f, 0.0f };

    result = m_pSystem-&gt;playSound(FMOD_CHANNEL_FREE, m_tGameSFX[effectToPlay], true, &amp;tmp);
    ERRCHECK(result);
    result = tmp-&gt;set3DAttributes(&amp;pos, &amp;vel);
    tmp-&gt;setPriority(255);
    tmp-&gt;setPaused(false);
    ERRCHECK(result);
}
m_vChannels.push_back(tmp);

}

void CSoundManager::setlistener(D3DXMATRIX *matrix)
{

if (matrix != NULL)
{
    FMOD_RESULT result;
    FMOD_VECTOR pos = {matrix-&gt;_41, matrix-&gt;_42, matrix-&gt;_43};
    FMOD_VECTOR at = {matrix-&gt;_31, matrix-&gt;_32, matrix-&gt;_33};
    FMOD_VECTOR up = {matrix-&gt;_21, matrix-&gt;_22, matrix-&gt;_23};
    FMOD_VECTOR vel = {0.0f, 0.0f, 0.0f};

    result = m_pSystem-&gt;set3DListenerAttributes(0, &amp;pos, &amp;vel, &amp;at, &amp;up);
    ERRCHECK(result);
}

}
void CSoundManager::Shutdown(){
FMOD_RESULT result;
while (m_vPlayListSounds.size())
{
result = m_vPlayListSounds.back()->release();
ERRCHECK(result);
m_vPlayListSounds.pop_back();
}
for (int i = 0; i < NUM_OF_GAME_SOUNDFX-1; ++i)
{
result = m_tGameSFX[i]->release();
ERRCHECK(result);
m_tGameSFX[i] = 0;
}
result = m_pSystem->close();
ERRCHECK(result);
result = m_pSystem->release();
ERRCHECK(result);
}[/code:3glt6xjz]

  • You must to post comments
0
0

Well this method has solved the my issue, however it is (as you said) a hack.
I apologise, I didn’t mean to ask you to debug my code, merely to post it to alliveviate any questions of exactly what was going on.
I understand it clearly is an issue of how I am implementing it, not any fault of yours, I was just asking if there was a flag or function I was missing that would auto stop a sound that is no longer playing.

The desired effect was to have fmod steal channels from sounds that are too low to hear and/or no longer playing (however without the loop to stop sounds this doesn’t happen).
I will most likely leave it as is (since it works, however unoptimally that may be), try to revise the implementation of it (time permitting), or revert to the 3.x API (Used it a year or so ago and it worked like a dream)

I would like to thank you brett for your quick responce time and making such a good API, it took all of a few hours to drop in and get working.
Your insight helped me come up with a solution (hack) much more quickly.

  • You must to post comments
0
0

Update: “Problem fixed”
For the purpose of exposing how silly of an error this was, a few cheap laughs, and for future reference for others

I was in the process of converting all my code back to FMOD 3.74 (because I had used it before and was more comfortable with the API)
When I coded the update function and called FSOUND_Update()…
Then I thought to myself, wow, I never called that in the EX version of the file…

m_pSystem->Update();

symptoms of not calling this are
– All the channels seem to keep playing indefinatly
– sounds seem to not play
– sound seem to play at a lower volume (as they are being mixed in software due to lack of channels I believe)

Thank you everyone for all your help, the only reason I had this problem was I was given 48 hours to convert the code base from using DirectSound to using FMOD and just skipped an important step.

Thank you specifically to brett for his patence with me and this silly mistake on my part.
I would like to clarify, I was not ever suggesting that your API was at fault, merely that I was somehow using it incorrecly.

Hopefully this faux pas will help someone in the future.
Feel free to laugh at my expense >.<

  • You must to post comments
Showing 6 results
Your Answer

Please first to submit.