texto - ¿Cómo puedo determinar la longitud de un archivo.wav en C#?
recorrer archivo txt c# (14)
En la situación no comprimida, sé que necesito leer el encabezado wav, extraer el número de canales, bits y frecuencia de muestreo y trabajar desde allí: (canales) * (bits) * (muestras / s) * (segundos) = (tamaño del archivo)
¿Hay una manera más simple, una biblioteca gratuita, o algo en el framework .net quizás?
¿Cómo haría esto si el archivo .wav está comprimido (con el códec mpeg, por ejemplo)?
¿Qué está haciendo exactamente tu aplicación con WAV comprimidas? Los archivos WAV comprimidos siempre son complicados: siempre trato de utilizar un formato de contenedor alternativo en este caso, como los archivos OGG o WMA. Las bibliotecas XNA tienden a estar diseñadas para trabajar con formatos específicos, aunque es posible que dentro de XACT encuentres un método de reproducción wav más genérico. Una posible alternativa es examinar el puerto SDL C #, aunque solo lo he usado para reproducir WAV sin comprimir: una vez abierto, puede consultar el número de muestras para determinar la longitud.
Descargar NAudio.dll desde el enlace http://naudio.codeplex.com/
y luego usa esta función
public static TimeSpan GetWavFileDuration(string fileName)
{
WaveFileReader wf = new WaveFileReader(fileName);
return wf.TotalTime;
}
obtendrás la Duración
Descargue "PresentationCore.dll" y "WindowsBase.dll" desde:
http://www.search-dll.com/dll-files/download/windowsbase.dll.html
Pegue los archivos en la carpeta del bin de la aplicación como referencia. Debería funcionar ahora.
En el framework .net hay una clase de reproductor de medios:
http://msdn.microsoft.com/en-us/library/system.windows.media.mediaplayer_members.aspx
Aquí hay un ejemplo:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2667714&SiteID=1&pageid=0#2685871
Hay un poco de un tutorial (con, presumiblemente, código de trabajo que puede aprovechar) en CodeProject .
Lo único que hay que tener un poco de cuidado es que es perfectamente "normal" que un archivo WAV se componga de múltiples fragmentos, por lo que debes desplazarte por todo el archivo para asegurarte de que se tengan en cuenta todos los fragmentos.
No quité nada de la respuesta ya aceptada, pero pude obtener la duración de un archivo de audio (varios formatos diferentes, incluido AC3, que es lo que necesitaba en ese momento) usando el espacio de nombres Microsoft.DirectX.AudioVideoPlayBack
. Esto es parte de DirectX 9.0 para Managed Code . Agregar una referencia a eso hizo que mi código fuera tan simple como esto ...
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
¡Y es bastante rápido, también! Aquí hay una referencia para la clase de Audio .
Pruebe el siguiente código de Cómo determinar la longitud de un archivo .wav en C #
string path = @"c:/test.wav";
WaveReader wr = new WaveReader(File.OpenRead(path));
int durationInMS = wr.GetDurationInMS();
wr.Close();
Puede considerar usar la función mciSendString (...) (la comprobación de errores se omite para mayor claridad):
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;
}
}
}
Puede encontrar que la biblioteca XNA tiene algún soporte para trabajar con WAV, etc., si está dispuesto a seguir esa ruta. Está diseñado para trabajar con C # para la programación de juegos, por lo que podría ocuparse de lo que necesita.
Sí, hay una biblioteca gratuita que se puede usar para obtener la duración del archivo de audio. Esta biblioteca también proporciona muchas más funcionalidades.
TagLib se distribuye bajo la Licencia Pública General Reducida (LGPL) de GNU y la Licencia Pública de Mozilla (MPL).
Implementé el código siguiente que devuelve la duración del tiempo en segundos.
using TagLib.Mpeg;
public static double GetSoundLength(string FilePath)
{
AudioFile ObjAF = new AudioFile(FilePath);
return ObjAF.Properties.Duration.TotalSeconds;
}
Tuve dificultades con el ejemplo de la clase MediaPlayer anterior. Podría tomar algún tiempo, antes de que el jugador haya abierto el archivo. En el "mundo real" tiene que registrarse para el evento MediaOpened, después de que se haya disparado, la NaturalDuration es válida. En una aplicación de consola solo tienes que esperar unos segundos después de la apertura.
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();
}
}
}
Voy a suponer que está familiarizado con la estructura de un archivo .WAV: contiene una estructura de encabezado WAVEFORMATEX, seguida de varias otras estructuras (o "fragmentos") que contienen varios tipos de información. Ver Wikipedia para más información sobre el formato de archivo.
Primero, itere a través del archivo .wav y sume las longitudes no acolchadas de los fragmentos de "datos" (el fragmento "datos" contiene los datos de audio para el archivo; por lo general, solo hay uno de estos, pero es posible que haya más de uno). Ahora tiene el tamaño total, en bytes, de los datos de audio.
A continuación, obtenga el miembro "promedio de bytes por segundo" de la estructura del encabezado WAVEFORMATEX del archivo.
Finalmente, divida el tamaño total de los datos de audio por el promedio de bytes por segundo; esto le dará la duración del archivo, en segundos.
Esto funciona razonablemente bien para archivos comprimidos y sin comprimir.
Voy a tener que decir MediaInfo , lo he estado utilizando durante más de un año con una aplicación de codificación de audio / video en la que estoy trabajando. Proporciona toda la información para archivos wav junto con casi cualquier otro formato.
MediaInfoDll viene con el código de muestra C # sobre cómo hacerlo funcionar.
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