I would like to play a specific range[startTime, endTime] of a sound file, is there an efficient way to do it ? I tried to setLoopPoints and setDelay but I couldn’t make them work. Of course, I could monitor the playback through callback and stop the playing, but I think there might be a better way to do it.
Per the documentation, after playing a sound its channel should be invalid, I don’t see it happens when I call hasHandle on a channel the handle seems valid. Does it make any sense?
You can scrub to a position of a playing Sound by calling Channel::setPosition on it’s Channel handle. For setLoopPoints to work the sound’s mode will need to be set to FMOD_LOOP_NORMAL or FMOD_LOOP_BIDI.
Where in the docs does it say after playing a sound the channel should be invalid? After playing a sound the channel should be valid if playSound was succesful.
Channel::setPosition will work on the “start”, but the problem is how to accurately end the playback on endTime; I thought about starting some timer, but would like to avoid managing multiple timers. Is there some more elegant way to deal with this? Maybe I could register to some callbacks? I did check the channel callback, didn’t look like it could help.
I saw it in the below book… I think I saw it also in the documentation, but not sure.
Well, it doesn’t seem like setLoopPoints is doing the trick. It does loop, but after the count is reached, the sound is playing without stopping. It looks like I will have to monitor the playback Any idea?
Yeah, that’s what I meant - that post-playback(complete/stopped) the channel’s handle cannot be re-used and should be invalid? I don’t see this happening… how do I check if the handle is valid?
You are right, sorry for the oversight there. I think your original solution of having callbacks is the best way to go, though I am finding it is off by 5-30ms which isn’t ideal. I have added a task to our backlog to implement a call for sample-accurate playback within a given time range.
Here is a rough example of you can implement such a callback:
FMOD_RESULT F_CALLBACK SyncCallback(FMOD_CHANNELCONTROL* channelcontrol, FMOD_CHANNELCONTROL_TYPE controltype, FMOD_CHANNELCONTROL_CALLBACK_TYPE callbacktype, void* commanddata1, void* commanddata2)
if (callbacktype == FMOD_CHANNELCONTROL_CALLBACK_SYNCPOINT)
FMOD::ChannelGroup *cc = (FMOD::ChannelGroup*)channelcontrol;
FMOD_RESULT FMOD_Play_Sound_Range(FMOD::System *system, FMOD::Sound *sound, int start, FMOD_TIMEUNIT starttimeunit, int end, FMOD_TIMEUNIT endtimeunit)
// Remove existing syncpoints
result = sound->getNumSyncPoints(&numsyncpoints);
for (int i = 0; i < numsyncpoints; ++i)
result = sound->getSyncPoint(i, &syncpoint);
result = sound->deleteSyncPoint(syncpoint);
// Add a single syncpoint for the end time
result = sound->addSyncPoint(end, FMOD_TIMEUNIT_MS, "END", &endpoint);
result = system->playSound(sound, 0, false, &channel);
// Set start time
result = channel->setPosition(start, FMOD_TIMEUNIT_MS);
result = channel->setCallback(SyncCallback);
void SetChannelRange(FMOD::ChannelGroup *channel, int start, int end)
int duration = stop - start;
unsigned long long time;
result = system->getSoftwareFormat(&sampleRate, 0, 0);
result = channel->getDSPClock(0, &time);
result = channel->setPosition(start * sampleRate, FMOD_TIMEUNIT_PCM);
result = channel->setDelay(0, time + duration * sampleRate);
As for the callback, I can see you are using C#, does your callback signature look like this?
I don’t have the MonoPInvokeCallback though.
this.hSystem.createChannelGroup(groupName, out this.channelGroup);
this.hSystem.playSound(this.hSound, this.channelGroup, true, out this.currentChannel);
The above is how group channel being created. Is this how it should be done? Basically in c#, fmod’s API forces me to provide channel group. The callback is set on “this.currentChannel”.
Am I missing something?