How can I determine the length (i.e. duration) of a .wav file in C#?

后端 未结 15 2179
逝去的感伤
逝去的感伤 2020-11-30 00:26

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) *

相关标签:
15条回答
  • 2020-11-30 01:10
    Imports System.IO
    Imports System.Text
    
    Imports System.Math
    Imports System.BitConverter
    
    Public Class PulseCodeModulation
        ' Pulse Code Modulation WAV (RIFF) file layout
    
        ' Header chunk
    
        ' Type   Byte Offset  Description
        ' Dword       0       Always ASCII "RIFF"
        ' Dword       4       Number of bytes in the file after this value (= File Size - 8)
        ' Dword       8       Always ASCII "WAVE"
    
        ' Format Chunk
    
        ' Type   Byte Offset  Description
        ' Dword       12      Always ASCII "fmt "
        ' Dword       16      Number of bytes in this chunk after this value
        ' Word        20      Data format PCM = 1 (i.e. Linear quantization)
        ' Word        22      Channels Mono = 1, Stereo = 2
        ' Dword       24      Sample Rate per second e.g. 8000, 44100
        ' Dword       28      Byte Rate per second (= Sample Rate * Channels * (Bits Per Sample / 8))
        ' Word        32      Block Align (= Channels * (Bits Per Sample / 8))
        ' Word        34      Bits Per Sample e.g. 8, 16
    
        ' Data Chunk
    
        ' Type   Byte Offset  Description
        ' Dword       36      Always ASCII "data"
        ' Dword       40      The number of bytes of sound data (Samples * Channels * (Bits Per Sample / 8))
        ' Buffer      44      The sound data
    
        Dim HeaderData(43) As Byte
    
        Private AudioFileReference As String
    
        Public Sub New(ByVal AudioFileReference As String)
            Try
                Me.HeaderData = Read(AudioFileReference, 0, Me.HeaderData.Length)
            Catch Exception As Exception
                Throw
            End Try
    
            'Validate file format
    
            Dim Encoder As New UTF8Encoding()
    
            If "RIFF" <> Encoder.GetString(BlockCopy(Me.HeaderData, 0, 4)) Or _
                "WAVE" <> Encoder.GetString(BlockCopy(Me.HeaderData, 8, 4)) Or _
                "fmt " <> Encoder.GetString(BlockCopy(Me.HeaderData, 12, 4)) Or _
                "data" <> Encoder.GetString(BlockCopy(Me.HeaderData, 36, 4)) Or _
                16 <> ToUInt32(BlockCopy(Me.HeaderData, 16, 4), 0) Or _
                1 <> ToUInt16(BlockCopy(Me.HeaderData, 20, 2), 0) _
            Then
                Throw New InvalidDataException("Invalid PCM WAV file")
            End If
    
            Me.AudioFileReference = AudioFileReference
        End Sub
    
        ReadOnly Property Channels() As Integer
            Get
                Return ToUInt16(BlockCopy(Me.HeaderData, 22, 2), 0) 'mono = 1, stereo = 2
            End Get
        End Property
    
        ReadOnly Property SampleRate() As Integer
            Get
                Return ToUInt32(BlockCopy(Me.HeaderData, 24, 4), 0) 'per second
            End Get
        End Property
    
        ReadOnly Property ByteRate() As Integer
            Get
                Return ToUInt32(BlockCopy(Me.HeaderData, 28, 4), 0) 'sample rate * channels * (bits per channel / 8)
            End Get
        End Property
    
        ReadOnly Property BlockAlign() As Integer
            Get
                Return ToUInt16(BlockCopy(Me.HeaderData, 32, 2), 0) 'channels * (bits per sample / 8)
            End Get
        End Property
    
        ReadOnly Property BitsPerSample() As Integer
            Get
                Return ToUInt16(BlockCopy(Me.HeaderData, 34, 2), 0)
            End Get
        End Property
    
        ReadOnly Property Duration() As Integer
            Get
                Dim Size As Double = ToUInt32(BlockCopy(Me.HeaderData, 40, 4), 0)
                Dim ByteRate As Double = ToUInt32(BlockCopy(Me.HeaderData, 28, 4), 0)
                Return Ceiling(Size / ByteRate)
            End Get
        End Property
    
        Public Sub Play()
            Try
                My.Computer.Audio.Play(Me.AudioFileReference, AudioPlayMode.Background)
            Catch Exception As Exception
                Throw
            End Try
        End Sub
    
        Public Sub Play(playMode As AudioPlayMode)
            Try
                My.Computer.Audio.Play(Me.AudioFileReference, playMode)
            Catch Exception As Exception
                Throw
            End Try
        End Sub
    
        Private Function Read(AudioFileReference As String, ByVal Offset As Long, ByVal Bytes As Long) As Byte()
            Dim inputFile As System.IO.FileStream
    
            Try
                inputFile = IO.File.Open(AudioFileReference, IO.FileMode.Open)
            Catch Exception As FileNotFoundException
                Throw New FileNotFoundException("PCM WAV file not found")
            Catch Exception As Exception
                Throw
            End Try
    
            Dim BytesRead As Long
            Dim Buffer(Bytes - 1) As Byte
    
            Try
                BytesRead = inputFile.Read(Buffer, Offset, Bytes)
            Catch Exception As Exception
                Throw
            Finally
                Try
                    inputFile.Close()
                Catch Exception As Exception
                    'Eat the second exception so as to not mask the previous exception
                End Try
            End Try
    
            If BytesRead < Bytes Then
                Throw New InvalidDataException("PCM WAV file read failed")
            End If
    
            Return Buffer
        End Function
    
        Private Function BlockCopy(ByRef Source As Byte(), ByVal Offset As Long, ByVal Bytes As Long) As Byte()
            Dim Destination(Bytes - 1) As Byte
    
            Try
                Buffer.BlockCopy(Source, Offset, Destination, 0, Bytes)
            Catch Exception As Exception
                Throw
            End Try
    
            Return Destination
        End Function
    End Class
    
    0 讨论(0)
  • 2020-11-30 01:12

    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.

    0 讨论(0)
  • 2020-11-30 01:12

    i have tested blew code would fail,file formats are like "\\ip\dir\*.wav'

     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;
        }
    }
    

    while naudio works

        public static int GetSoundLength(string fileName)
         {
            using (WaveFileReader wf = new WaveFileReader(fileName))
            {
                return (int)wf.TotalTime.TotalMilliseconds;
            }
         }`
    
    0 讨论(0)
  • 2020-11-30 01:13

    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.

    0 讨论(0)
  • 2020-11-30 01:14

    Download NAudio.dll from the link http://naudio.codeplex.com/

    and then use this function

    public static TimeSpan GetWavFileDuration(string fileName)       
    {     
        WaveFileReader wf = new WaveFileReader(fileName);
        return wf.TotalTime; 
    }
    

    you will get the Duration

    0 讨论(0)
  • 2020-11-30 01:14

    Yes, There is a free library that can be used to get time duration of Audio file. This library also provides many more functionalities.

    TagLib

    TagLib is distributed under the GNU Lesser General Public License (LGPL) and Mozilla Public License (MPL).

    I implemented below code that returns time duration in seconds.

    using TagLib.Mpeg;
    
    public static double GetSoundLength(string FilePath)
    {
        AudioFile ObjAF = new AudioFile(FilePath);
        return ObjAF.Properties.Duration.TotalSeconds;
    }
    
    0 讨论(0)
提交回复
热议问题