Как я могу определить длину (т. е.длительность) файла .wav на C #?
-
01-07-2019 - |
Вопрос
В несжатой ситуации я знаю, что мне нужно прочитать заголовок wav, извлечь количество каналов, бит и частоту дискретизации и обработать это оттуда:(каналы) * (биты) * (сэмплы в секунду) * (секунды) = (размер файла)
Есть ли более простой способ - возможно, бесплатная библиотека или что-то в .net Framework?
Как мне это сделать, если файл .wav сжат (например, с помощью mpeg-кодека)?
Решение
Вы можете рассмотреть возможность использования функции mciSendString(...) (проверка ошибок опущена для наглядности).:
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;
}
}
}
Другие советы
Скачать NAudio.dll можно по ссылке http://naudio.codeplex.com/
а затем используйте эту функцию
public static TimeSpan GetWavFileDuration(string fileName)
{
WaveFileReader wf = new WaveFileReader(fileName);
return wf.TotalTime;
}
вы получите продолжительность
Чтобы ничего не отнимать от уже принятого ответа, но я смог получить длительность аудиофайла (несколько разных форматов, включая AC3, что мне было нужно в то время), используя Microsoft.DirectX.AudioVideoPlayBack
пространство имен.Это часть DirectX 9.0 для управляемого кода.Добавление ссылки на это сделало мой код таким простым, как этот...
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
И к тому же это довольно быстро!Вот ссылка на Аудио класс.
В .net Framework есть класс mediaplayer:
http://msdn.microsoft.com/en-us/library/system.windows.media.mediaplayer_members.aspx
Вот такой пример:
http://forums.microsoft.com/MSDN/ShowPost.aspx ?postID=2667714&SiteID=1&pageid=0#2685871
У меня возникли трудности с приведенным выше примером класса MediaPlayer.Это может занять некоторое время, прежде чем проигрыватель откроет файл.В "реальном мире" вы должны зарегистрироваться для MediaOpened-события, после того как оно сработало, действительна NaturalDuration.В консольном приложении вам просто нужно подождать несколько секунд после открытия.
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();
}
}
}
Попробуйте использовать приведенный ниже код из Как определить длину файла .wav на C#
string path = @"c:\test.wav";
WaveReader wr = new WaveReader(File.OpenRead(path));
int durationInMS = wr.GetDurationInMS();
wr.Close();
Да, существует бесплатная библиотека, которую можно использовать для получения временной длительности аудиофайла.Эта библиотека также предоставляет множество других функциональных возможностей.
TagLib распространяется под GNU Lesser General Public License (LGPL) и Mozilla Public License (MPL).
Я реализовал приведенный ниже код, который возвращает продолжительность времени в секундах.
using TagLib.Mpeg;
public static double GetSoundLength(string FilePath)
{
AudioFile ObjAF = new AudioFile(FilePath);
return ObjAF.Properties.Duration.TotalSeconds;
}
Вы могли бы обнаружить, что Библиотека XNA имеет некоторую поддержку для работы с WAV и т.д.если вы готовы пойти по этому пути.Он предназначен для работы с C # при программировании игр, поэтому может просто позаботиться о том, что вам нужно.
Есть небольшой учебник (с предположительно работающим кодом, который вы можете использовать) по адресу Кодпроект.
Единственное, с чем вам нужно быть немного осторожным, это с тем, что совершенно "нормально", когда WAV-файл состоит из нескольких фрагментов, поэтому вам нужно просмотреть весь файл, чтобы убедиться, что все фрагменты учтены.
Что именно ваше приложение делает со сжатыми WAV-файлами?Сжатые файлы WAV всегда сложны - в данном случае я всегда стараюсь использовать альтернативный формат контейнера, такой как файлы OGG или WMA.Библиотеки XNA, как правило, предназначены для работы с определенными форматами, хотя возможно, что в XACT вы найдете более общий метод воспроизведения wav.Возможной альтернативой является просмотр порта SDL C #, хотя я когда-либо использовал его только для воспроизведения несжатых файлов WAV - после открытия вы можете запросить количество сэмплов, чтобы определить длину.
Я должен сказать МедиаИнфо, я использую его уже больше года с приложением для кодирования аудио / видео, над которым я работаю.Он предоставляет всю информацию для файлов wav наряду практически со всеми другими форматами.
МедиаИнфоДлл Поставляется с примером кода на C # о том, как заставить его работать.
Я собираюсь предположить, что вы в некоторой степени знакомы со структурой файла .WAV :он содержит структуру заголовка WAVEFORMATEX, за которой следует ряд других структур (или "фрагментов"), содержащих различные виды информации.Видишь Википедия для получения дополнительной информации о формате файла.
Сначала выполните итерацию по файлу .wav и сложите длины фрагментов "данных" без добавления дополнений (фрагмент "данных" содержит аудиоданные для файла;обычно существует только один из них, но вполне возможно, что их может быть больше одного).Теперь у вас есть общий размер аудиоданных в байтах.
Затем получите элемент "среднее значение байт в секунду" структуры заголовка WAVEFORMATEX файла.
Наконец, разделите общий размер аудиоданных на среднее количество байт в секунду - это даст вам продолжительность файла в секундах.
Это достаточно хорошо работает для несжатых и компрессированных файлов.
время = Длина файла / (Частота дискретизации * Каналы * Биты на выборку / 8)
я тестировал, что код не сработает, форматы файлов будут такими "\\ 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;
}
}
пока 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
Загрузить "PresentationCore.dll" и "WindowsBase.dll" с:
http://www.search-dll.com/dll-files/download/windowsbase.dll.html
Вставьте файлы в папку вашего приложения bin для справки.Теперь это должно сработать.