views:

5748

answers:

12

In the uncompressed situation I know I need to read the wav header, pull out the number of channels, bits, and sample rate and work it out from there: (channels) * (bits) * (samples/s) * (seconds) = (filesize)

Is there a simpler way - a free library, or something in the .net framework perhaps?

How would I do this if the .wav file is compressed (with the mpeg codec for example)?

A: 

You might find that the XNA library has some support for working with WAV's etc. if you are willing to go down that route. It is designed to work with C# for game programming, so might just take care of what you need.

xan
+1  A: 

There's a bit of a tutorial (with - presumably - working code you can leverage) over at CodeProject.

The only thing you have to be a little careful of is that it's perfectly "normal" for a WAV file to be composed of multiple chunks - so you have to scoot over the entire file to ensure that all chunks are accounted for.

moobaa
+1  A: 

What exactly is your application doing with compressed WAVs? Compressed WAV files are always tricky - I always try and use an alternative container format in this case such as OGG or WMA files. The XNA libraries tend to be designed to work with specific formats - although it is possible that within XACT you'll find a more generic wav playback method. A possible alternative is to look into the SDL C# port, although I've only ever used it to play uncompressed WAVs - once opened you can query the number of samples to determine the length.

+6  A: 

You may consider using the mciSendString(...) function (error checking is omitted for clarity):

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace Sound
{
    public static class SoundInfo
    {
        [DllImport("winmm.dll")]
        private static extern uint mciSendString(
            string command,
            StringBuilder returnValue,
            int returnLength,
            IntPtr winHandle);

        public static int GetSoundLength(string fileName)
        {
            StringBuilder lengthBuf = new StringBuilder(32);

            mciSendString(string.Format("open \"{0}\" type waveaudio alias wave", fileName), null, 0, IntPtr.Zero);
            mciSendString("status wave length", lengthBuf, lengthBuf.Capacity, IntPtr.Zero);
            mciSendString("close wave", null, 0, IntPtr.Zero);

            int length = 0;
            int.TryParse(lengthBuf.ToString(), out length);

            return length;
        }
    }
}
Jan Zich
I tested this and it worked with compressed a wav too - thanks +1
John Sibly
In fact I think this is the most robust solution. One of the other suggestions I tried loading a MediaPlayer object, seems to take about a second and adds a dependency on .NET 3.5
John Sibly
A: 

I'm gonna have to say MediaInfo, I have been using it for over a year with a audio/video encoding application I'm working on. It gives all the information for wav files along with almost every other format.

MediaInfoDll Comes with sample C# code on how to get it working.

sieben
A: 

In the .net framework there is a mediaplayer class:

http://msdn.microsoft.com/en-us/library/system.windows.media.mediaplayer_members.aspx

Following on from Cetra's suggestion, I wrote a test program - you'll need to add references to PresentationCore and WindowsBase. C:\test.wav is compressed using the mp3 codec.

Hopefully this will be helpful for someone else too:

using System;
using System.Text;
using System.Windows.Media;
using System.Windows;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            MediaPlayer player = new MediaPlayer();
            Uri path = new Uri(@"C:\test.wav");
            player.Open(path);
            Duration duration = player.NaturalDuration;
            if (duration.HasTimeSpan)
            {
                Console.WriteLine(player.NaturalDuration.TimeSpan.ToString());
            }
            player.Close();
        }
    }
}
John Sibly
A: 

I'm going to assume that you're somewhat familiar with the structure of a .WAV file : it contains a WAVEFORMATEX header struct, followed by a number of other structs (or "chunks") containing various kinds of information. See Wikipedia for more info on the file format.

First, iterate through the .wav file and add up the the unpadded lengths of the "data" chunks (the "data" chunk contains the audio data for the file; usually there is only one of these, but it's possible that there could be more than one). You now have the total size, in bytes, of the audio data.

Next, get the "average bytes per second" member of the WAVEFORMATEX header struct of the file.

Finally, divide the total size of the audio data by the average bytes per second - this will give you the duration of the file, in seconds.

This works reasonably well for uncompressed and compressed files.

A: 

I had difficulties with the example of the MediaPlayer-class above. It could take some time, before the player has opened the file. In the "real world" you have to register for the MediaOpened-event, after that has fired, the NaturalDuration is valid. In a console-app you just have to wait a few seconds after the open.

using System;
using System.Text;
using System.Windows.Media;
using System.Windows;

namespace ConsoleApplication2
{
  class Program
  {
    static void Main(string[] args)
    {
      if (args.Length == 0)
        return;
      Console.Write(args[0] + ": ");
      MediaPlayer player = new MediaPlayer();
      Uri path = new Uri(args[0]);
      player.Open(path);
      TimeSpan maxWaitTime = TimeSpan.FromSeconds(10);
      DateTime end = DateTime.Now + maxWaitTime;
      while (DateTime.Now < end)
      {
        System.Threading.Thread.Sleep(100);
        Duration duration = player.NaturalDuration;
        if (duration.HasTimeSpan)
        {
          Console.WriteLine(duration.TimeSpan.ToString());
          break;
        }
      }
      player.Close();
    }
  }
}
Lars
+1  A: 

Not to take anything away from the answer already accepted, but I was able to get the duration of an audio file (several different formats, including AC3, which is what I needed at the time) using the Microsoft.DirectX.AudioVideoPlayBack namespace. This is part of DirectX 9.0 for Managed Code. Adding a reference to that made my code as simple as this...

Public Shared Function GetDuration(ByVal Path As String) As Integer
    If File.Exists(Path) Then
        Return CInt(New Audio(Path, False).Duration)
    Else
        Throw New FileNotFoundException("Audio File Not Found: " & Path)
    End If
End Function

And it's pretty fast, too! Here's a reference for the Audio class.

Josh Stodola
A: 

how to add reference for PresentationCore and WindowsBase

siraj
You should not post a question as an answer. Delete this answer and ask your question by clicking "Ask a Question" up the top. I won't -1 you, but this answer doesn't belong here :)
Richard Szalay
A: 

Download "PresentationCore.dll" and "WindowsBase.dll" from:

http://www.search-dll.com/dll-files/download/windowsbase.dll.html

Paste the files in you application bin folder for reference. It should work now.

Diptesh Shrestha
Rob