How do I fade out a channel at the end of a file?

I want to fade out at the end of a sound file, but in my case it doesn’t work.

I am using the FMOD Studio low api 1.05.08 with Visual Studio 2013 coding in C# and WPF.

Here is a the code snippet that not works:

// get the length in samples
uint length;
this.sound.getLength(out length, FMOD.TIMEUNIT.PCM).ERRCHECK();

// get the reference clock, which is the parent channel group
ulong dspclock;
ulong parentclock;
channel.getDSPClock(out dspclock, out parentclock).ERRCHECK();

// get the sample rate
int samplerate;
SPEAKERMODE speakermode;
int numrawspeakers;
this.system.getSoftwareFormat(out samplerate, out speakermode, out numrawspeakers).ERRCHECK();

// add a start fade point 5 seconds before end with full volume
channel.addFadePoint(parentclock + length - (uint)samplerate * 5, 1f).ERRCHECK();

// add a fade point at the end of the track
channel.addFadePoint(parentclock + length, 0f).ERRCHECK();

// add a delayed stop command at the end ('stopchannels = true')
// maybe this is not necessary
channel.setDelay(0, parentclock + length, true).ERRCHECK();

What do you mean ‘doesnt work’. Please be more descriptive.

If it starts fading too early or too late (probably what you mean by doesnt work because you set the fade points past the end of the sound), then its because you didnt convert the sound’s sample rate to the output sample rate.

You need to divide the length by the sound’s samplerate (Sound::getFormat) then multiply it by the system output rate (System::getSoftwareFormat).

hi brett

you’re right, i forgot to convert the length to the system sample rate format.

i cange my example and now it seems to work right, but sometimes the fade out begins 5 seconds before end, then 8 seconds or on another track 25 seconds…

so what i am doing wrong? is there a calculated deviation? or something else… must i reset the dsp?

uint lenms;
this.sound.getLength(out lenms, FMOD.TIMEUNIT.MS).ERRCHECK();
this.LengthMs = lenms;

SOUND_TYPE soundType;
SOUND_FORMAT soundFormat;
int soundChannels;
int soundBits;
this.sound.getFormat(out soundType, out soundFormat, out soundChannels, out soundBits);

// get the reference clock, which is the parent channel group
ulong dspclock;
ulong parentclock;
channel.getDSPClock(out dspclock, out parentclock).ERRCHECK();

int samplerate;
SPEAKERMODE speakermode;
int numrawspeakers;
this.system.getSoftwareFormat(out samplerate, out speakermode, out numrawspeakers).ERRCHECK();

if (samplerate > 0 && soundBits > 0)
{
// add a fade point at 'now' with zero volume
channel.addFadePoint(parentclock, 0f).ERRCHECK();
// add a fade point 5 seconds later at 1 volume
channel.addFadePoint(parentclock + (ulong)(samplerate * 5), 1f).ERRCHECK();

var convertedLength = Convert.ToUInt64(Math.Round(soundChannels * lengthMs * samplerate * 0.001f / (float)soundBits));

// add a start fade point 5 seconds before end with full volume
channel.addFadePoint(parentclock + convertedLength - (ulong)samplerate * 5, 1f).ERRCHECK();
// add a fade point at the end of the track
channel.addFadePoint(parentclock + convertedLength, 0f).ERRCHECK();
// add a delayed stop command at the end of the track ('stopchannels = true')
channel.setDelay(0, parentclock + convertedLength, true).ERRCHECK();
}

or is there any bug in my positioning?

cannel.setPosition(this.currentPositionMs, FMOD.TIMEUNIT.MS).ERRCHECK(FMOD.RESULT.ERR_INVALID_HANDLE);
system.update().ERRCHECK();

if you setposition, then the fade out is not going to change, it will still do it in x milliseconds. It is based on the output clock, it doesnt care about your sound’s position.

if you call setPosition, you have to reset the fade points (delete them) and start again.

You have to get length-currentposition, then convert that to output samples as before, then add that to the current getDSPClock parent value.
You should probably pause before your setposition call, or call lockDSP, to get better accuracy.