首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 讀取 WAVE 檔案標頭資訊完整程式碼:RIFF 結構、位元解析、BitConverter 應用

     編輯:關於C語言

前言

WAVE(.wav)檔案遵循 RIFF 容器格式,標頭包含音訊格式、取樣率、聲道數、位深度等關鍵資訊。本文提供完整 C# 程式碼,解析前 44 位元組標頭,使用 BinaryReader/BitConverter 處理小端序資料。

一、WAVE 標頭結構(標準 PCM,44 位元組)

偏移大小欄位說明範例值
04ChunkID"RIFF" 標識0x52494646
44ChunkSize檔案大小 - 8小端序整數
84Format"WAVE"0x57415645
124Subchunk1ID"fmt "0x666D7420
164Subchunk1SizePCM 固定 1616
202AudioFormat1=PCM, 其他=壓縮1
222NumChannels1=單聲道, 2=立體聲2
244SampleRate取樣率 (Hz)44100
284ByteRateSampleRate × NumChannels × BitsPerSample/8176400
322BlockAlignNumChannels × BitsPerSample/84
342BitsPerSample位深度 (8/16/24/32)16
364Subchunk2ID"data"0x64617461
404Subchunk2Size音訊資料大小...

二、完整解析程式碼

using System;
using System.IO;

public struct WavInfo
{
    public string ChunkID;           // "RIFF"
    public uint ChunkSize;           // 檔案大小 - 8
    public string Format;            // "WAVE"
    public string Subchunk1ID;       // "fmt "
    public uint Subchunk1Size;       // 16 for PCM
    public ushort AudioFormat;       // 1 = PCM
    public ushort NumChannels;       // 聲道數
    public uint SampleRate;          // 取樣率
    public uint ByteRate;            // 位元率
    public ushort BlockAlign;        // 區塊對齊
    public ushort BitsPerSample;     // 位深度
    public string Subchunk2ID;       // "data"
    public uint Subchunk2Size;       // 資料大小
}

public static class WavHeaderReader
{
    public static WavInfo Read(string filePath)
    {
        if (!File.Exists(filePath))
            throw new FileNotFoundException("找不到檔案", filePath);
        
        var info = new WavInfo();
        
        using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        {
            if (fs.Length < 44)
                throw new InvalidDataException("檔案太小,非有效 WAVE 檔案");
            
            byte[] header = new byte[44];
            fs.Read(header, 0, 44);
            
            // 使用 BitConverter 處理小端序(Little Endian)
            info.ChunkID = System.Text.Encoding.ASCII.GetString(header, 0, 4);
            info.ChunkSize = BitConverter.ToUInt32(header, 4);
            info.Format = System.Text.Encoding.ASCII.GetString(header, 8, 4);
            info.Subchunk1ID = System.Text.Encoding.ASCII.GetString(header, 12, 4);
            info.Subchunk1Size = BitConverter.ToUInt32(header, 16);
            info.AudioFormat = BitConverter.ToUInt16(header, 20);
            info.NumChannels = BitConverter.ToUInt16(header, 22);
            info.SampleRate = BitConverter.ToUInt32(header, 24);
            info.ByteRate = BitConverter.ToUInt32(header, 28);
            info.BlockAlign = BitConverter.ToUInt16(header, 32);
            info.BitsPerSample = BitConverter.ToUInt16(header, 34);
            info.Subchunk2ID = System.Text.Encoding.ASCII.GetString(header, 36, 4);
            info.Subchunk2Size = BitConverter.ToUInt32(header, 40);
            
            // 驗證關鍵標識
            if (info.ChunkID != "RIFF" || info.Format != "WAVE" || info.Subchunk1ID != "fmt ")
                throw new InvalidDataException("非標準 WAVE 檔案格式");
        }
        
        return info;
    }
    
    public static void PrintInfo(WavInfo info)
    {
        Console.WriteLine($"ChunkID: {info.ChunkID}");
        Console.WriteLine($"ChunkSize: {info.ChunkSize} bytes");
        Console.WriteLine($"Format: {info.Format}");
        Console.WriteLine($"Subchunk1ID: {info.Subchunk1ID}");
        Console.WriteLine($"Subchunk1Size: {info.Subchunk1Size}");
        Console.WriteLine($"AudioFormat: {info.AudioFormat} (1=PCM)");
        Console.WriteLine($"NumChannels: {info.NumChannels}");
        Console.WriteLine($"SampleRate: {info.SampleRate} Hz");
        Console.WriteLine($"ByteRate: {info.ByteRate} bytes/sec");
        Console.WriteLine($"BlockAlign: {info.BlockAlign}");
        Console.WriteLine($"BitsPerSample: {info.BitsPerSample} bits");
        Console.WriteLine($"Subchunk2ID: {info.Subchunk2ID}");
        Console.WriteLine($"Subchunk2Size: {info.Subchunk2Size} bytes");
        
        // 衍生資訊
        double duration = (double)info.Subchunk2Size / info.ByteRate;
        Console.WriteLine($"Duration: {duration:F2} seconds");
    }
}

三、使用範例

static void Main(string[] args)
{
    string path = args.Length > 0 ? args[0] : @"C:\Test\audio.wav";
    
    try
    {
        var info = WavHeaderReader.Read(path);
        WavHeaderReader.PrintInfo(info);
    }
    catch (Exception ex)
    {
        Console.WriteLine($"錯誤: {ex.Message}");
    }
}

四、關鍵技術點解析

1. 小端序與 BitConverter

WAVE 檔案採用 Little Endian(低位元組在前)。BitConverter 在 Windows (x86/x64) 上預設即為小端序,直接對應:

  • ToUInt16:2 位元組 → ushort
  • ToUInt32:4 位元組 → uint
  • ToInt16/ToInt32:有號版本

2. 字串欄位解析

RIFF 標識為 ASCII 字串,用 Encoding.ASCII.GetString(bytes, offset, count) 解析。

3. 驗證機制

檢查 RIFF、WAVE、fmt 三大標識,快速排除非 WAVE 檔案。

五、進階擴展建議

  • 支援大檔案:ChunkSize 為 uint,>4GB 需 RIFF64 (RF64) 格式
  • 多格式支援:解析 AudioFormat 判斷 PCM/IEEE Float/ADPCM/MP3 等
  • 非標準區塊:LIST、cue、smpl 等額外區塊解析
  • 串流處理:大檔案避免一次性讀入,使用 BinaryReader 逐段讀取
  • 唯讀屬性:WavInfo 設計為不可變結構

六、總結

WAVE 標頭解析核心在於:

  1. 確認 RIFF/WAVE/fmt 標識
  2. 依偏移量讀取固定長度二進位資料
  3. BitConverter 處理小端序整數轉換
  4. 結構化輸出 WavInfo 供上層應用使用

本程式碼可直接整合至音訊處理、轉檔、播放器等專案中。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved