2008-09-17 74 views
24

Trong tình huống không nén tôi biết tôi cần đọc tiêu đề wav, kéo số lượng kênh, bit và tốc độ lấy mẫu và làm việc từ đó: (kênh) * (bit) * (mẫu/s) * (seconds) = (filesize)Làm cách nào để xác định độ dài của tệp .wav trong C#?

Có cách nào đơn giản hơn - một thư viện miễn phí hay một cái gì đó trong khung .net có lẽ?

Làm cách nào để thực hiện việc này nếu tệp .wav được nén (ví dụ như codec mpeg)?

+0

Độ dài, ý của bạn là thời gian của âm thanh hoặc kích thước tệp? –

+5

dài này: | ----------------- | – nickf

Trả lời

17

Bạn có thể xem xét sử dụng (...) Hàm mciSendString (kiểm tra lỗi bị bỏ qua để rõ ràng):

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

Tôi đã thử nghiệm điều này và nó đã làm việc với nén một wav quá - nhờ +1 –

+0

Trong thực tế, tôi nghĩ rằng đây là giải pháp mạnh mẽ nhất. Một trong những gợi ý khác tôi đã thử tải một đối tượng MediaPlayer, có vẻ mất khoảng một giây và thêm phụ thuộc vào .NET 3.5 –

+0

Khi sử dụng tính năng này trong Windows 10 để mở 'D: \ Long \ Path \ To \ WavFileWithLongName.wav' I nhận được lỗi 304 từ 'mciSendString':' Tên tệp không hợp lệ.Hãy chắc chắn rằng tên tập tin không dài quá 8 ký tự, theo sau là dấu chấm và phần mở rộng.' – damian

1

Bạn có thể thấy rằng XNA library có một số hỗ trợ để làm việc với WAV, v.v. nếu bạn sẵn sàng đi xuống tuyến đường đó. Nó được thiết kế để làm việc với C# cho lập trình trò chơi, vì vậy có thể chỉ cần chăm sóc những gì bạn cần.

1

Có một chút hướng dẫn (với - có lẽ - mã làm việc mà bạn có thể tận dụng) tại số CodeProject. Điều duy nhất bạn phải cẩn thận một chút là nó hoàn toàn "bình thường" cho một tệp WAV bao gồm nhiều phần - vì vậy bạn phải quét qua toàn bộ tệp để đảm bảo rằng tất cả các khối được tính cho .

1

Ứng dụng của bạn hoạt động chính xác với WAV được nén là gì? Các tệp WAV nén luôn luôn phức tạp - tôi luôn cố gắng và sử dụng định dạng vùng chứa thay thế trong trường hợp này, chẳng hạn như tệp OGG hoặc WMA. Các thư viện XNA có xu hướng được thiết kế để làm việc với các định dạng cụ thể - mặc dù có thể là trong XACT bạn sẽ tìm thấy một phương thức phát lại wav chung hơn. Một giải pháp thay thế có thể là nhìn vào cổng SDL C#, mặc dù tôi đã từng sử dụng nó để phát các WAV không nén - khi đã mở, bạn có thể truy vấn số lượng mẫu để xác định độ dài.

1

Tôi sẽ phải nói MediaInfo, tôi đã sử dụng nó trong hơn một năm với ứng dụng mã hóa âm thanh/video mà tôi đang thực hiện. Nó cung cấp tất cả thông tin cho các tệp wav cùng với hầu hết các định dạng khác.

MediaInfoDll Đi kèm với mã C# mẫu về cách làm cho nó hoạt động.

0

Tôi sẽ giả định rằng bạn đã quen thuộc với cấu trúc của tệp .WAV: nó chứa cấu trúc đầu trang WAVEFORMATEX, theo sau là một số cấu trúc khác (hoặc "khối") chứa nhiều loại thông tin khác nhau . Xem Wikipedia để biết thêm thông tin về định dạng tệp.

Đầu tiên, lặp qua tệp .wav và thêm chiều dài không được đệm của khối "dữ liệu" (đoạn "dữ liệu" chứa dữ liệu âm thanh cho tệp; thường chỉ có một trong số này, nhưng có thể rằng có thể có nhiều hơn một). Bây giờ bạn có tổng kích thước, tính bằng byte, của dữ liệu âm thanh.

Tiếp theo, nhận thành phần "số byte trung bình mỗi giây" của cấu trúc đầu trang WAVEFORMATEX của tệp.

Cuối cùng, chia tổng kích thước của dữ liệu âm thanh cho số byte trung bình mỗi giây - điều này sẽ cho bạn thời lượng của tệp, tính bằng giây.

Tính năng này hoạt động tốt cho các tệp không nén và nén.

2

Tôi gặp khó khăn với ví dụ về lớp MediaPlayer ở trên. Có thể mất chút thời gian, trước khi người chơi mở tệp. Trong "thế giới thực", bạn phải đăng ký cho sự kiện MediaOpened, sau khi đã kích hoạt, NaturalDuration là hợp lệ. Trong giao diện điều khiển ứng dụng, bạn chỉ cần đợi vài giây sau khi mở.

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

Không để mất bất cứ điều gì ra khỏi câu trả lời đã được chấp nhận, nhưng tôi đã có thể để có được thời gian của một tập tin âm thanh (định dạng khác nhau, bao gồm cả AC3, đó là những gì tôi cần thiết vào thời điểm đó) bằng cách sử dụng Microsoft.DirectX.AudioVideoPlayBack không gian tên. Đây là một phần của DirectX 9.0 for Managed Code. Việc thêm tham chiếu vào đó đã làm cho mã của tôi đơn giản như thế này ...

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 

Và nó cũng khá nhanh! Dưới đây là tham chiếu cho lớp Audio.

-8

Tải "PresentationCore.dll" và "WindowsBase.dll" từ:

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

Dán các tập tin trong thư mục bạn bin ứng dụng để tham khảo. Nó sẽ hoạt động ngay bây giờ.

+3

-1, đây hoàn toàn là điều sai trái để làm. PresentationCore & WindowsBase là một phần của khung và nên * không * được tải xuống từ bất kỳ đâu trên t'internet. – Rob

25

Tải NAudio.dll từ liên kết http://naudio.codeplex.com/

và sau đó sử dụng chức năng này

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

bạn sẽ nhận được Thời gian

+1

Tôi nhận thấy rằng TotalTime được báo cáo của NAudio thường dài hơn mẫu thực tế. Ngay cả khi định dạng không được nén (tức là WAV) – MutantNinjaCodeMonkey

+0

Bạn cũng có thể cài đặt gói nuget 'NAudio' thay vì tải xuống DLL. –

-1
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 
+2

Um, câu hỏi được yêu cầu cho mã C#, chứ không phải VB.NET. –

1

Có, Có một thư viện miễn phí có thể được sử dụng để nhận thời lượng của tệp Âm thanh. Thư viện này cũng cung cấp nhiều chức năng hơn.

TagLib

TagLib được phân phối theo Lesser GNU General Public License (LGPL) và Giấy phép Công cộng Mozilla (MPL).

Tôi đã triển khai bên dưới mã trả về thời lượng trong vài giây.

using TagLib.Mpeg; 

public static double GetSoundLength(string FilePath) 
{ 
    AudioFile ObjAF = new AudioFile(FilePath); 
    return ObjAF.Properties.Duration.TotalSeconds; 
} 
Các vấn đề liên quan