4

Is there a way, either within the Framework or by using P/Invoke to determine the duration of a wav file that's held in a MemoryStream?

I've already had a look at Managed DirectX and another similar question, but everything seems to work with paths, rather than providing any way to pass in a stream. One of the links in the question I've referenced (A simple C# Wave editor....) makes it fairly clear that I could parse the MemoryStream to determine the duration of the wav file. Ideally I'd like to not re-invent the wheel.

Community
  • 1
  • 1
Rob
  • 45,296
  • 24
  • 122
  • 150

3 Answers3

6

I agree with Alex. I took the time to put together a small program with three lines of code that prints the duration of a wav file.

        var stream=new MemoryStream(File.ReadAllBytes("test.wav"));
        var wave = new WaveFileReader(stream);
        Console.WriteLine(wave.TotalTime); // wave.TotalTime -> TimeSpan

Download NAudio library: you will find NAudio.dll in the package.

Just reference NAudio.dll in your project.

At time of writing it's release 1.3.

Like the author says on his blog, WaveFileReader accept a Stream too; not just a file path.

Remember that version 1.3 is built for x86. If you want it to work on x64 you need to force your project to x86. If you want NAudio.dll for x64 (like me) you need to recompile with 'any cpu'. For me both solutions worked like a charm.

Jako
  • 2,489
  • 3
  • 28
  • 38
0

Try following calculation

streamSize == headerSizeIfAny + playTime * sampling * singleSampleSize ->

playTime = ( streamSize[in bytes] - headerSizeIfAny ) / ( sampling [samples per second] * singleSampleSize[bytes])

  • the calculation is utterly useless to me unless I have the file parsed. As I've made fairly clear though, I'd rather `not re-invent the wheel.`. In fact, for my purposes, writing code to parse wav files is a non-starter. – Rob Sep 01 '10 at 15:10
  • @Rob: This calculation should work without any parsing, the bitrate of files has to be accessible without reading the wav itself I'm pretty sure as windows explorer can tell me the bitrate. I think you might be able to p/invoke the file properties to dig this up, maybe without p/invoke even... 500k file, no header, has 100k bitrate and that's a rate per second = 5 seconds. – Jimmy Hoffa Sep 01 '10 at 15:18
  • @Jimmy, sorry, really not what I'm after. I don't want to do *any* calculation no matter how simplistic. I'm after something I can give a memory stream to and it'll tell me the duration of the wav inside it. Calculating the duration of audio files isn't what my code's about so I'm not about to start =) As it stands, Explorer (Win7 anyway) tells me the duration, as well as the bitrate, making bitrate even more useless to me ;-) – Rob Sep 01 '10 at 17:40
0

Check this out:

http://www.sonicspot.com/guide/wavefiles.html

and this

typedef struct {
  WORD wFormatTag; 
  WORD nChannels; 
  DWORD nSamplesPerSec; 
  DWORD nAvgBytesPerSec; 
  WORD nBlockAlign; 
  WORD wBitsPerSample; 
  WORD cbSize;} WAVEFORMATEX; 

So you have your memorystream... Seek to 0x10 (to skip Riff header) + 0x08 (for format header) = 24

And you are in the structure above.

Use stream.ReadInt16() and stream.ReadInt32() to read wanted structure members.

Then, seek to 54, read one DWORD, and that many bytes is your sample data.

Then figure out your duration from this variables.

NOTE: that will work for ONLY THE SIMPLEST PCM wave files stored in your memorystream. For others, you'll have to honor headers and properly parse them, finding the data chunk and calculating duration according to it's size.

Daniel Mošmondor
  • 19,718
  • 12
  • 58
  • 99