كيف يمكنني تحديد الطول (أي؟المدة) لملف .wav في C#؟

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

  •  01-07-2019
  •  | 
  •  

سؤال

في الحالة غير المضغوطة، أعلم أنني بحاجة إلى قراءة رأس wav، وسحب عدد القنوات، والبت، ومعدل العينة، والعمل على حلها من هناك:(القنوات) * (البتات) * (العينات/العينات) * (الثواني) = (حجم الملف)

هل هناك طريقة أبسط - مكتبة مجانية، أو ربما شيء ما في إطار عمل .net؟

كيف أفعل ذلك إذا كان الملف .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

وهو سريع جدًا أيضًا!وهنا مرجع ل صوتي فصل.

لقد واجهت صعوبات مع مثال فئة 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

يتم توزيع TagLib بموجب رخصة جنو العمومية الصغرى (LGPL) وترخيص موزيلا العام (MPL).

لقد قمت بتنفيذ الكود أدناه الذي يُرجع المدة الزمنية بالثواني.

using TagLib.Mpeg;

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

قد تجد أن مكتبة XNA لديه بعض الدعم للعمل مع WAV وما إلى ذلك.إذا كنت على استعداد للذهاب في هذا الطريق.لقد تم تصميمه للعمل مع لغة C# لبرمجة الألعاب، لذا قد يعتني فقط بما تحتاجه.

يوجد القليل من البرنامج التعليمي (مع - من المفترض - كود العمل الذي يمكنك الاستفادة منه) في CodeProject.

الشيء الوحيد الذي يجب أن تكون حذرًا منه هو أنه من "الطبيعي" تمامًا أن يتكون ملف WAV من أجزاء متعددة - لذلك يتعين عليك البحث في الملف بأكمله للتأكد من احتساب جميع الأجزاء.

ما الذي يفعله تطبيقك بالضبط مع ملفات WAV المضغوطة؟تكون ملفات WAV المضغوطة صعبة دائمًا - أحاول دائمًا استخدام تنسيق حاوية بديل في هذه الحالة مثل ملفات OGG أو WMA.تميل مكتبات XNA إلى أن تكون مصممة للعمل مع تنسيقات معينة - على الرغم من أنه من الممكن أن تجد في XACT طريقة تشغيل wav أكثر عمومية.البديل المحتمل هو النظر في منفذ SDL C#، على الرغم من أنني لم أستخدمه إلا لتشغيل ملفات WAV غير المضغوطة - بمجرد فتحه، يمكنك الاستعلام عن عدد العينات لتحديد الطول.

يجب أن أقول معلومات الوسائط, ، أستخدمه منذ أكثر من عام مع تطبيق ترميز الصوت/الفيديو الذي أعمل عليه.إنه يوفر جميع المعلومات الخاصة بملفات wav بالإضافة إلى كل التنسيقات الأخرى تقريبًا.

MediaInfoDll يأتي مع نموذج كود 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

الصق الملفات في مجلد سلة التطبيقات الخاص بك كمرجع.يجب أن تعمل الآن.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top