Length in time of a wave file

3.9k views Asked by At

I have some simple code generating a wave file using TTS and then playing it:

public void TestSpeech()
{
    SpeechSynthesizer synth = new SpeechSynthesizer();
    using (MemoryStream stream = new MemoryStream())
    {
        synth.SetOutputToWaveStream(stream);
        synth.Speak("Hello world");
        stream.Seek(0, SeekOrigin.Begin);
        IWaveSource source = new WaveFileReader(stream);
        EventWaitHandle waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
        var soundOut = new WasapiOut();
        soundOut.Initialize(source);
        soundOut.Stopped += (s, e) => waitHandle.Set();
        soundOut.Play();
        waitHandle.WaitOne();
        soundOut.Dispose();
        source.Dispose();
    }
}

Everything is working fine, but I want to know before I start to play the wave file how long it will go on for. Is there some way of calculating this, or is it available somewhere?

If it is available somewhere, how is it calculated? I assume that it's related to the amount of data in the stream, but how?

3

There are 3 answers

7
Genti Saliu On BEST ANSWER

You can use CSCore or NAudio:

CSCore (extracted from this sample, current playback position and total duration are used here):

using System;
using CSCore;
using CSCore.Codecs.WAV;

IWaveSource wavSource = new WaveFileReader(stream);
TimeSpan totalTime = wavSource.GetLength();

NAudio:

using System;
using NAudio.Wave;

using (var wfr = new WaveFileReader(stream))
{
    TimeSpan totalTime = wfr.TotalTime;
}

Also see the MSDN docs for TimeSpan.

The duration is calculated from the total length of the WAVE data (which can be an estimate for compressed files) and the average bytes per second (as per the NAudio source in property TotalTime):

totalTimeInSeconds = LengthInBytes / AverageBytesPerSecond;
0
Florian On
using CSCore;

IWaveSource waveSource = new WaveFileReader(stream);
TimeSpan totalTime = waveSource.GetLength( ); //get length returns a timespan
0
Pavel Orlov On

In case someone's looking for a workaround, I've handeled it like this: (pardon my first StackOverflow comment)

  1. I created bool mouseScrewsAround = false
  2. timer event, that changes trackBar position while playing, fires only if !mouseScrewsAround
  3. trackBar_MouseDown -> mouseScrewsAround = true
  4. trackBar_MouseUp -> change track position, then mouseScrewsAround = false