狠狠色丁香婷婷综合尤物/久久精品综合一区二区三区/中国有色金属学报/国产日韩欧美在线观看 - 国产一区二区三区四区五区tv

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

.NET 音頻采集

freeflydom
2024年11月18日 10:46 本文熱度 638

本文介紹Windows下聲音數據的采集,用于本地錄音、視訊會議、投屏等場景

聲音錄制有麥克風、揚聲器以及混合錄制三類方式,麥克風和揚聲器單獨錄制的場景更多點,混合錄制更多的是用于本地錄音

我們基于NAudio實現,開源組件NAudio已經很穩定的實現了各類播放、錄制、轉碼等功能,WaveIn,WaveInEvent,WasapiCapture,WasapiLoopbackCapture, WaveOut, WaveStream, WaveFileWriter, WaveFileReader, AudioFileReader都是比較常見的類,下面詳細介紹下錄制模塊的實現

麥克風錄制

1.WaveInEvent

通過WaveInEvent類,我們可以捕獲麥克風輸入:

 1     private WaveInEvent _waveIn;
 2     private WaveFileWriter _writer;
 3     private void MainWindow_Loaded(object sender, RoutedEventArgs e)
 4     {
 5         _waveIn = new WaveInEvent();
 6         //441采樣率,單通道
 7         _waveIn.WaveFormat = new WaveFormat(44100, 1);
 8         _writer = new WaveFileWriter("recordedAudio.wav", _waveIn.WaveFormat);
 9         _waveIn.DataAvailable += (s, a) =>
10         {
11             _writer.Write(a.Buffer, 0, a.BytesRecorded);
12         };
13         // 列出所有可用的錄音設備
14         for (int i = 0; i < WaveIn.DeviceCount; i++)
15         {
16             var deviceInfo = WaveIn.GetCapabilities(i);
17             OutputTextBlock.Text += $"Device {i}: {deviceInfo.ProductName}\r\n";
18         }
19     }
20     private void StartRecordButton_OnClick(object sender, RoutedEventArgs e)
21     {
22         _waveIn.StartRecording();
23     }
24     private void StopRecordButton_OnClick(object sender, RoutedEventArgs e)
25     {
26         _waveIn.StopRecording();
27         _waveIn.Dispose();
28         _writer.Close();
29     }

在每次錄制到數據時,將數據寫入文件。上面是實現保存錄音的DEMO

2.WaveIn

還有WaveIn,和WaveInEvent是一樣接口IWaveIn。如果是Windows窗口應用,可以直接使用WaveIn,但需要傳入窗口句柄。控制臺應用是無法支持WaveIn的

WaveIn構造參數需要傳入窗口句柄,默認不傳的話NAudio會創建一個窗口:


 1     internal void Connect(WaveInterop.WaveCallback callback)
 2     {
 3       if (this.Strategy == WaveCallbackStrategy.NewWindow)
 4       {
 5         this.waveOutWindow = new WaveWindow(callback);
 6         this.waveOutWindow.CreateControl();
 7         this.Handle = this.waveOutWindow.Handle;
 8       }
 9       else
10       {
11          .........
12       }
13     }

另外這里的WaveWindow是winform窗口,internal class WaveWindow : Form

WaveIn 使用回調函數(Callback)來處理音頻數據,這種回調函數會在 Windows 收到音頻數據時通過消息機制調度。這通常意味著你需要管理并處理這些回調函數,以確保音頻數據的正確捕捉和處理。然而這也意味著需要更多的底層工作和線程安全控制。

而在控制臺這類非GUI應用,就建議使用WaveInEvent了,它未使用窗口消息,而是通過while循環監聽buffers數據,通過判斷buffer.Done是否完成來觸發輸出buffer數據事件DataAvailable。

所以性能來說WaveIn從線程處理上會占優很多,未做過對比測試(待補充

3.WasapiCapture

除了WaveIn API,還可以使用WasapiCapture, 它與WaveIn的使用方式是一致的, 可以用來錄制麥克風WaveInAPI雖然沒有獨占、共享功能,但也需要處理并發問題,即多個錄音實例訪問同一個麥克風設備的話會存在并發訪問問題。

WasapiCapture是WASAPI About WASAPI - Win32 apps | Microsoft Learn,全稱Windows Audio Session Application Programming Interface (Windows音頻會話應用編程接口) ,它在Windows Vista引入 、提供了一些關鍵的改進

比如,提供更低的音頻延遲和高性能音頻處理,可以提供共享模式和獨占模式

在共享模式下,可以與多個應用程序共享一個音頻設備;WasapiCapture.ShareMode = AudioClientShareMode.Shared;

在獨占模式下,應用程序可以完全控制音頻設備,降低延遲 AudioClientShareMode.Exclusive

看看WasapiCapture DEMO,都是基于IWaveIn接口實現,所以代碼無差別:


 1     private WaveFileWriter _writer;
 2     private WasapiCapture _capture;
 3     private void MainWindow_Loaded(object sender, RoutedEventArgs e)
 4     {
 5         _capture = new WasapiCapture();
 6         _writer = new WaveFileWriter("recordedAudio.wav", _capture.WaveFormat);
 7         _capture.DataAvailable += (s, a) =>
 8         {
 9             _writer.Write(a.Buffer, 0, a.BytesRecorded);
10         };
11         // 列出所有可用的錄音設備
12         for (int i = 0; i < WaveIn.DeviceCount; i++)
13         {
14             var deviceInfo = WaveIn.GetCapabilities(i);
15             OutputTextBlock.Text += $"Device {i}: {deviceInfo.ProductName}\r\n";
16         }
17     }

錄制麥克風音頻,WasapiCapture 是最佳選擇,專為低延遲、高性能設計

另外,如果音頻采集時需要重采樣,可以使用BufferedWaveProvider緩存DataAvailable事件過來的原始音頻數據,


 1     //創建BufferedWaveProvider,緩存原始音頻數據
 2     var bufferedProvider = new BufferedWaveProvider(provider.NAudioWaveFormat)
 3     {
 4         DiscardOnBufferOverflow = true,
 5         ReadFully = false
 6     };
 7     provider.WaveIn.DataAvailable += (s, e) =>
 8     {
 9         //將音頻數據寫入 BufferedWaveProvider
10         bufferedProvider.AddSamples(e.Buffer, 0, e.BytesRecorded);
11     };
12     //獲取采樣接口
13     var sampleProvider = bufferedProvider.ToSampleProvider();
14     sampleProvider = new WdlResamplingSampleProvider(sampleProvider, TargetFormat.SampleRate);
15     //重采樣后的音頻數據
16     _waveProvider = sampleProvider.ToWaveProvider16();

BufferedWaveProvider、SampleToWaveProvider16均是實現IWaveProvider通用接口,可提供音頻格式以及獲取數據接口


 1   public interface IWaveProvider
 2   {
 3     /// <summary>Gets the WaveFormat of this WaveProvider.</summary>
 4     /// <value>The wave format.</value>
 5     WaveFormat WaveFormat { get; }
 6 
 7     /// <summary>Fill the specified buffer with wave data.</summary>
 8     /// <param name="buffer">The buffer to fill of wave data.</param>
 9     /// <param name="offset">Offset into buffer</param>
10     /// <param name="count">The number of bytes to read</param>
11     /// <returns>the number of bytes written to the buffer.</returns>
12     int Read(byte[] buffer, int offset, int count);
13   }

將重采樣的數據寫入本地文件保存:


 1     /// <summary>
 2     /// 目標音頻格式
 3     /// </summary>
 4     public WaveFormat TargetFormat { get; }
 5     public void Save()
 6     {
 7         using var writer = new WaveFileWriter("recordedAudio.wav", TargetFormat);
 8         // 將重采樣后的數據寫入文件
 9         byte[] buffer = new byte[TargetFormat.AverageBytesPerSecond];
10         int bytesRead;
11         while ((bytesRead = _waveProvider.Read(buffer, 0, buffer.Length)) > 0)
12         {
13             writer.Write(buffer, 0, bytesRead);
14         }
15     }

這樣,我們使用 WasapiCapture 捕獲音頻數據,并將這些數據實時重采樣到指定采樣率如44.1kHz(常見的采樣率有441和480),單聲道格式。錄音結束后,重采樣后的音頻數據再被保存到一個WAV文件中。

另外如果是單通道聲音,可以轉換成多通道即立體聲:

1     // Mono to Stereo
2     if (simpleFormat.Channels == 1)
3     {
4         sampleProvider = sampleProvider.ToStereo();
5     }

ToStereo返回的MonoToStereoSampleProvider,會將單通道聲音數據,轉換為雙通道的音頻格式。但實際上,采樣器MonoToStereoSampleProvider內部只有一份source數據,在Read時外部參數Samples直接除以2即變成了1,左右聲道均輸出此音頻數據。

麥克風錄制,推薦首選WasapiCapture。

揚聲器錄制

錄制揚聲器聲音即聲卡輸出,借助WasapiLoopbackCapture可簡單實現,使用方式與WasapiCapture沒區別。部分代碼:


 1     var capture = new WasapiLoopbackCapture();
 2     var writer = new WaveFileWriter("recordedAudio.wav", capture.WaveFormat);
 3     capture.DataAvailable += (s, a) =>
 4     {
 5         writer.Write(a.Buffer, 0, a.BytesRecorded);
 6     };
 7     capture.StartRecording();
 8     // 列出所有可用的揚聲器設備
 9     for (int i = 0; i < WaveOut.DeviceCount; i++)
10     {
11         var deviceInfo = WaveOut.GetCapabilities(i);
12         OutputTextBlock.Text += $"Device {i}: {deviceInfo.ProductName}\r\n";
13     }

1. 音頻可視化

值得另外說的,揚聲器錄制有一類廠測場景,上位機工廠測試軟件測試揚聲器,需要顯示聲道的音頻曲線

音頻波形圖或者頻譜圖,可以通過DataAvailable拿到的字節數組,根據可視化圖X坐標需要顯示的點列數量,在數組中獲取數據然后映射到可視化圖表坐標Y值上。詳細的可參考這篇 [C#] 使用 NAudio 實現音頻可視化_c#聲音頻譜-CSDN博客,它實現的是曲線,也可以另外換成柱狀圖。

錄制揚聲器,有些場景需要關閉本地揚聲器外放。投屏軟件有這個場景,會將當前設備A的聲卡音頻數據傳輸到其它設備B上播放,但設備A不想重復播放聲音。因為設備A播放聲音的話,會議室會有混音,并且投屏設備A一般是筆記本、設備B是會議大屏,揚聲器質量和功率是不如專業的交互大屏的,大屏揚聲器價格會貴點。

1     var volume = playbackDevice.AudioEndpointVolume;
2     // 記錄原音量,用于結束錄制時恢復音量
3     float originalVolume = volume.MasterVolumeLevelScalar;
4     // 靜音播放設備
5     volume.MasterVolumeLevelScalar = 0;

2.保持揚聲器活躍

同時,錄制揚聲器是一個持續活動,為避免因無音頻信號導致設備自動關閉或進入低功耗狀態,在不想關閉音頻設備而又沒有實際音頻播放任務時,會用沉默音頻保持設備活躍。可以按如下操作

1).創建一個WasapiOut實例,指定使用共享模式:var wasapiOut = new WasapiOut(device, AudioClientShareMode.Shared, true, 50);

2).獲取音頻設備MMDevice的AudioClient對象

using var audioClient = device.AudioClient;
wasapiOut.Init(new SilenceProvider(audioClient.MixFormat));

3).在啟動WasapiLoopbackCapture錄制時,將此靜音波形播放對象啟動,持續生成靜音信號

混音錄制

也有必要介紹下混音錄制,雖然場景較少。

初始化多個麥克風、揚聲器錄制器,然后同上面重采樣操作,創建一個 BufferedWaveProvider (bufferedProvider),用于存儲輸入的音頻數據。

訂閱訂閱 IWaveIn 的 DataAvailable 事件,將數據都塞進緩存音頻緩存器

最后返回16位浮點波形數據存儲器,IWaveProvider數據獲取方式同上面重采樣操作。


 1     public MixAudioCapture(params IWaveIn[] audioWaveCaptures)
 2     {
 3         _audioWaveCaptures = audioWaveCaptures;
 4         var sampleProviders = new List<ISampleProvider>();
 5         foreach (var waveIn in audioWaveCaptures)
 6         {
 7             var bufferedProvider = new BufferedWaveProvider(waveIn.WaveFormat)
 8             {
 9                 DiscardOnBufferOverflow = true,
10                 ReadFully = false
11             };
12             waveIn.DataAvailable += (s, e) =>
13             {
14                 bufferedProvider.AddSamples(e.Buffer, 0, e.BytesRecorded);
15             };
16             var sampleProvider = bufferedProvider.ToSampleProvider();
17             sampleProviders.Add(sampleProvider);
18         }
19         var waveProviders = sampleProviders.Select(m => m.ToWaveProvider());
20         // 混音后的音頻數據
21         _waveProvider = new MixingWaveProvider32(waveProviders).ToSampleProvider().ToWaveProvider16();
22     }

一般混音的同時,也會重采樣。看具體場景操作吧。

上方示例代碼詳見Demo kybs00/AudioCaptureDemo: 音頻采集DEMO (github.com)

參考:

簡要介紹WASAPI播放音頻的方法 - PeacoorZomboss - 博客園 (cnblogs.com)

[C#] 使用 NAudio 實現音頻可視化_c#聲音頻譜-CSDN博客

naudio/NAudio: Audio and MIDI library for .NET (github.com)



該文章在 2024/11/18 10:46:14 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved