Como posso determinar o comprimento (ou seja,duração) de um arquivo .wav em C#?

StackOverflow https://stackoverflow.com/questions/82319

  •  01-07-2019
  •  | 
  •  

Pergunta

Na situação descompactada, sei que preciso ler o cabeçalho wav, extrair o número de canais, bits e taxa de amostragem e calcular a partir daí:(canais) * (bits) * (amostras/s) * (segundos) = (tamanho do arquivo)

Existe uma maneira mais simples - uma biblioteca gratuita ou algo na estrutura .net, talvez?

Como eu faria isso se o arquivo .wav estivesse compactado (com o codec mpeg, por exemplo)?

Foi útil?

Solução

Você pode considerar usar a função mciSendString (...) (verificação de erros é omitida para maior clareza):

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

Outras dicas

Fazer download NAudio.dll a partir do link http://naudio.codeplex.com/

e, em seguida, usar essa função

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

você obterá o Duração

Para não tirar nada da resposta já aceitou, mas eu era capaz de conseguir a duração de um arquivo de áudio (vários formatos diferentes, incluindo AC3, que é o que eu precisava na época) usando o namespace Microsoft.DirectX.AudioVideoPlayBack. Isso faz parte do DirectX 9.0 para código gerenciado . Adicionando uma referência ao que fez o meu código tão simples como isso ...

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

E é muito rápido, muito! Aqui é uma referência para a classe Áudio .

Eu tive dificuldades com o exemplo do MediaPlayer classe acima. Ele pode levar algum tempo, antes que o jogador abriu o arquivo. No "mundo real" você tem que se inscrever para o evento MediaOpened, depois que foi disparado, o NaturalDuration é válido. Em um console app você só tem que esperar alguns segundos após o aberto.

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

Tente código abaixo de Como determinar o comprimento de um arquivo .wav em C #

    string path = @"c:\test.wav";
    WaveReader wr = new WaveReader(File.OpenRead(path));
    int durationInMS = wr.GetDurationInMS();
    wr.Close();

Sim, Há uma biblioteca livre que pode ser usado para obter tempo de duração de arquivo de áudio. Esta biblioteca também oferece muitas mais funcionalidades.

TagLib

TagLib é distribuído sob a GNU Lesser General Public License (LGPL) e Mozilla Public License (MPL).

Eu implementei o código abaixo que a duração retornos tempo em segundos.

using TagLib.Mpeg;

public static double GetSoundLength(string FilePath)
{
    AudioFile ObjAF = new AudioFile(FilePath);
    return ObjAF.Properties.Duration.TotalSeconds;
}

Você pode achar que a biblioteca XNA tem algum suporte para trabalhando com WAV da etc, se você está disposto a ir por esse caminho. Ele é projetado para trabalhar com C # para programação de jogos, por isso só poderia cuidar do que você precisa.

Há um pouco de um tutorial (com - presumivelmente - código de trabalho você pode aproveitar) sobre a CodeProject .

A única coisa que você tem que ser um pouco cuidadoso de é que é perfeitamente "normal" para um arquivo WAV a ser composto por vários pedaços - então você tem que fugir durante o arquivo inteiro para garantir que todos os pedaços são contabilizados.

O que exatamente é a sua aplicação fazendo com WAVs comprimido? WAV comprimido são sempre complicado - Eu sempre tento e usar um formato contêiner alternativa neste caso como OGG ou WMA. As bibliotecas XNA tendem a ser projetado para trabalhar com formatos específicos - embora seja possível que dentro XACT você vai encontrar um método de reprodução wav mais genérico. Uma alternativa possível é olhar para a porta SDL C #, embora eu só nunca usei-o para jogar WAVs descompactado -. Uma vez aberto você pode consultar o número de amostras para determinar o comprimento

Vou ter de dizer MediaInfo , eu tenho usado por mais de um ano com uma aplicação de codificação de áudio / vídeo que eu estou trabalhando. Ele dá todas as informações para arquivos WAV, juntamente com quase todos os outro formato.

MediaInfoDll Vem com código de exemplo C # sobre como obtê-lo de trabalho.

Eu estou indo supor que você está um pouco familiarizado com a estrutura de um arquivo .WAV: contém uma estrutura de cabeçalho WAVEFORMATEX, seguido por uma série de outras estruturas (ou "pedaços") contendo vários tipos de informação. Consulte Wikipedia para mais informações sobre o formato de arquivo.

Em primeiro lugar, percorrer os arquivos .wav e somar os comprimentos unpadded dos "dados" pedaços (os "dados" pedaço contém os dados de áudio para o arquivo, geralmente há apenas um desses, mas é possível que poderia haver mais de um). Você tem agora o tamanho total, em bytes, dos dados de áudio.

Em seguida, obter o "bytes média por segundo" membro da struct cabeçalho WAVEFORMATEX do arquivo.

Finalmente, divida o tamanho total dos dados de áudio pelas médias bytes por segundo -. Isso vai lhe dar a duração do arquivo, em segundos

Isso funciona razoavelmente bem para arquivos descompactados e compactados.

= tempo fileLength / (Classificação Amostra * Canais * bits por amostra / 8)

Eu testei soprou código falharia, formatos de arquivo são como "\\ 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;
    }
}

enquanto obras NAudio

    public static int GetSoundLength(string fileName)
     {
        using (WaveFileReader wf = new WaveFileReader(fileName))
        {
            return (int)wf.TotalTime.TotalMilliseconds;
        }
     }`
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

Fazer download "PresentationCore.dll" e "WindowsBase.dll" de:

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

Cole os arquivos em você pasta bin pedido de referência. Ele deve funcionar agora.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top