Unity輕松實現麥克風錄音與播放

文章目錄

    • 概要
    • 錄音,播放
    • 音頻
    • 注意事項
    • 參考

概要

之前有想寫一個音樂播放的器的音頻功能,一直沒做,最近突然想寫,就寫了

錄音,播放

在語言模型中,編碼器和解碼器都是由一個個的 Transformer 組件拼接在一起形成的。、

 private bool micConnected = false;//麥克風是否連接private int minFreq, maxFreq;//最小和最大頻率public AudioClip RecordedClip;//錄音public AudioSource audioSource;//播放的音頻public Text Infotxt;//提示信息public Text Adress;//音頻保存地址private string fileName;//保存的文件名private byte[] data;private string microphoneName;private bool isPlayAudio;private int lastPosition;public Button startBtn, stopBtn,playBtn,saveBtn;void Start(){if (Microphone.devices.Length <= 0){Infotxt.text = "缺少麥克風設備!";}else{microphoneName = Microphone.devices[0].ToString();Infotxt.text = "設備名稱為:" + microphoneName + "請點擊Start開始錄音!";micConnected = true;Microphone.GetDeviceCaps(microphoneName, out minFreq, out maxFreq);if (minFreq == 0 && maxFreq == 0){maxFreq = 44100;}}startBtn.onClick.AddListener(Begin);stopBtn.onClick.AddListener(Stop);playBtn.onClick.AddListener(Player);saveBtn.onClick.AddListener(Save);}private float[] NormalizeData(float[] input){float value=0;for (int i = 0; i < input.Length; i++){if (value < input[i]){value = input[i];}}Debug.Log("Max:"+value);for (int i = 0; i < input.Length; i++){input[i] = input[i] / value;}return input;}/// <summary>/// 開始錄音/// </summary>public void Begin(){if (micConnected){if (!Microphone.IsRecording(null)){RecordedClip = Microphone.Start(microphoneName, false, 60, maxFreq);Infotxt.text = "開始錄音!";isPlayAudio = true;}else{Infotxt.text = "正在錄音中,請勿重復點擊Start!";}}else{Infotxt.text = "請確認麥克風設備是否已連接!";}}/// <summary>/// 停止錄音/// </summary>public void Stop(){data = GetRealAudio(ref RecordedClip);Microphone.End(null);Infotxt.text = "錄音結束!";isPlayAudio = false;}/// <summary>/// 播放錄音/// </summary>public void Player(){if (!Microphone.IsRecording(null)){audioSource.clip = RecordedClip;audioSource.Play();Infotxt.text = "正在播放錄音!";}else{Infotxt.text = "正在錄音中,請先停止錄音!";}}/// <summary>/// 保存錄音/// </summary>public void Save(){if (!Microphone.IsRecording(null)){fileName = DateTime.Now.ToString("yyyyMMddHHmmssffff");if (!fileName.ToLower().EndsWith(".wav")){//如果不是“.wav”格式的,加上后綴fileName += ".wav";}string path = Path.Combine(Application.persistentDataPath, fileName);//錄音保存路徑print(path);//輸出路徑Adress.text = path;using (FileStream fs = CreateEmpty(path)){fs.Write(data, 0, data.Length);WriteHeader(fs, RecordedClip); //wav文件頭}}else{Infotxt.text = "正在錄音中,請先停止錄音!";}}/// <summary>/// 獲取真正大小的錄音/// </summary>/// <param name="recordedClip"></param>/// <returns></returns>public static byte[] GetRealAudio(ref AudioClip recordedClip){int position = Microphone.GetPosition(null);if (position <= 0 || position > recordedClip.samples){position = recordedClip.samples;}float[] soundata = new float[position * recordedClip.channels];recordedClip.GetData(soundata, 0);recordedClip = AudioClip.Create(recordedClip.name, position,recordedClip.channels, recordedClip.frequency, false);recordedClip.SetData(soundata, 0);int rescaleFactor = 32767;byte[] outData = new byte[soundata.Length * 2];for (int i = 0; i < soundata.Length; i++){short temshort = (short)(soundata[i] * rescaleFactor);byte[] temdata = BitConverter.GetBytes(temshort);outData[i * 2] = temdata[0];outData[i * 2 + 1] = temdata[1];}Debug.Log("position=" + position + "  outData.leng=" + outData.Length);return outData;}/// <summary>/// 寫文件頭/// </summary>/// <param name="stream"></param>/// <param name="clip"></param>public static void WriteHeader(FileStream stream, AudioClip clip){int hz = clip.frequency;int channels = clip.channels;int samples = clip.samples;stream.Seek(0, SeekOrigin.Begin);Byte[] riff = System.Text.Encoding.UTF8.GetBytes("RIFF");stream.Write(riff, 0, 4);Byte[] chunkSize = BitConverter.GetBytes(stream.Length - 8);stream.Write(chunkSize, 0, 4);Byte[] wave = System.Text.Encoding.UTF8.GetBytes("WAVE");stream.Write(wave, 0, 4);Byte[] fmt = System.Text.Encoding.UTF8.GetBytes("fmt ");stream.Write(fmt, 0, 4);Byte[] subChunk1 = BitConverter.GetBytes(16);stream.Write(subChunk1, 0, 4);UInt16 one = 1;Byte[] audioFormat = BitConverter.GetBytes(one);stream.Write(audioFormat, 0, 2);Byte[] numChannels = BitConverter.GetBytes(channels);stream.Write(numChannels, 0, 2);Byte[] sampleRate = BitConverter.GetBytes(hz);stream.Write(sampleRate, 0, 4);Byte[] byteRate = BitConverter.GetBytes(hz * channels * 2);stream.Write(byteRate, 0, 4);UInt16 blockAlign = (ushort)(channels * 2);stream.Write(BitConverter.GetBytes(blockAlign), 0, 2);UInt16 bps = 16;Byte[] bitsPerSample = BitConverter.GetBytes(bps);stream.Write(bitsPerSample, 0, 2);Byte[] datastring = System.Text.Encoding.UTF8.GetBytes("data");stream.Write(datastring, 0, 4);Byte[] subChunk2 = BitConverter.GetBytes(samples * channels * 2);stream.Write(subChunk2, 0, 4);}/// <summary>/// 創建wav格式文件頭/// </summary>/// <param name="filepath"></param>/// <returns></returns>private FileStream CreateEmpty(string filepath){FileStream fileStream = new FileStream(filepath, FileMode.Create);byte emptyByte = new byte();for (int i = 0; i < 44; i++) //為wav文件頭留出空間{fileStream.WriteByte(emptyByte);}return fileStream;}private void LoadPCM(string filePath){/*  // 讀取PCM音頻數據byte[] pcmData = System.IO.File.ReadAllBytes(filePath);*/// 轉換PCM音頻數據為浮點數數組float[] floatData = new float[data.Length / 2];for (int i = 0; i < floatData.Length; i++){floatData[i] = (float)System.BitConverter.ToInt16(data, i * 2) / 32768f;}// 創建AudioClip,參數說明:// pcmData:PCM音頻數據// false:是否為壓縮格式,默認為false// false:是否為3D音頻,默認為false// AudioType.UNKNOWN:音頻類型,根據實際情況選擇合適的類型// 44100:采集最佳頻率AudioClip audioClip = AudioClip.Create("PCM", data.Length / 2, 1, 44100, false);audioClip.SetData(floatData, 0);}

音頻

 int numberId=0;// Update is called once per framevoid Update(){float data = 0;float[] spectrum = new float[64];//256AudioListener.GetSpectrumData(spectrum, 0, FFTWindow.Hamming);for (int i = 1; i < spectrum.Length - 1; i++){if (data < spectrum[i]){data = spectrum[i];}}Debug.Log("max: " + data);rect[numberId].sizeDelta =new Vector2(10, 100 * data);numberId++;if (numberId >= rect.Length){numberId = 0;}}

在這里插入圖片描述
在這里插入圖片描述

注意事項

  • 讀取音頻時,AudioClip不能為空
  • FFTWindow 選擇適合的類型

參考

麥克風

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/84604.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/84604.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/84604.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

七牛云圖片上傳 前后端全過程

相關網址&#xff1a;七牛開發者中心 相關網站&#xff1a; 七牛開發者中心 上傳流程概述 后端生成上傳憑證&#xff1a;服務器端使用七牛云 SDK 生成上傳憑證&#xff08;uptoken&#xff09;前端獲取憑證&#xff1a;前端通過 API 向后端請求上傳憑證前端上傳圖片&#xff1…

2025年AI生成PPT平臺推薦榜單:五大智能工具革新演示創作體驗

在數字化辦公飛速發展的當下&#xff0c;AI生成PPT平臺已成為職場人士、教育工作者和創意人群提升效率的利器。這些平臺憑借先進的人工智能技術&#xff0c;打破傳統PPT制作的局限&#xff0c;為用戶帶來便捷、高效且充滿創意的制作體驗。經過多維度測評&#xff0c;2025年AI生…

PHP框架在內容管理系統開發中的優勢:效率、安全與擴展性!

在當今快節奏的Web開發環境中&#xff0c;內容管理系統&#xff08;CMS&#xff09;已成為企業和個人建立動態網站的核心工具。傳統的手工編碼開發方式在面對復雜業務邏輯、頻繁迭代和安全要求時往往力不從心。而PHP框架&#xff08;如Laravel、ThinkPHP、Symfony&#xff09;的…

云原生安全實踐:CI/CD流水線集成DAST工具

&#x1f525;「炎碼工坊」技術彈藥已裝填&#xff01; 點擊關注 → 解鎖工業級干貨【工具實測|項目避坑|源碼燃燒指南】 ——從零掌握DevSecOps中的動態安全測試 一、基礎概念 1. DevSecOps DevSecOps 是將安全性&#xff08;Security&#xff09;融入開發&#xff08;Dev&am…

【C語言】基礎知識框架補充

前文主要介紹了C語言從零開始學習的基本框架與基礎知識導覽&#xff0c;本文主要補充此前未提及的學習內容&#xff0c;給有意精進C語言者指明一條可供參考的學習路徑。 補充一&#xff1a;動態內存管理 核心函數&#xff08;需#include <stdlib.h>&#xff09;&#xf…

垃圾識別檢測與分類數據集(貓臉碼客第244期)

目標檢測與垃圾&#xff1a;技術革新與環境管理的交匯點 在當今社會&#xff0c;城市化進程不斷加速&#xff0c;人口持續增長&#xff0c;垃圾處理問題愈發凸顯其重要性。有效管理垃圾&#xff0c;不僅關乎環境衛生狀況&#xff0c;更直接影響到城市的可持續發展以及居民的生…

【調研報告】2025年與2030年AI及AI智能體 (Agent) 市場份額分析報告

2025年與2030年AI及AI智能體 (Agent) 市場份額分析報告 摘要 本報告旨在深入分析全球人工智能&#xff08;AI&#xff09;市場及其子領域AI智能體的未來發展軌跡&#xff0c;重點關注其在2025年和2030年的市場規模及其占全球GDP和整體AI市場的比例。分析表明&#xff0c;AI市…

臺式機電腦CPU天梯圖2025年6月份更新:CPU選購指南及推薦

組裝電腦選硬件的過程中,CPU的選擇無疑是最關鍵的,因為它是最核心的硬件,關乎著一臺電腦的性能好壞。對于小白來說,CPU天梯圖方便直接判斷兩款CPU性能高低,準確的說,是多核性能。下面給大家分享一下臺式機電腦CPU天梯圖2025年6月版,來看看吧。 桌面CPU性能排行榜2025 臺…

小白學Pinia狀態管理

目錄 1. 什么是 Pinia&#xff1f; 2. 為什么需要 Pinia&#xff1f; 3. Pinia 的三個核心概念 State&#xff08;狀態&#xff09;- 存儲數據 Getters&#xff08;計算屬性&#xff09;- 處理數據 Actions&#xff08;方法&#xff09;- 修改數據 4. 創建一個簡單的 St…

Tauri2學習筆記

教程地址&#xff1a;https://www.bilibili.com/video/BV1Ca411N7mF?spm_id_from333.788.player.switch&vd_source707ec8983cc32e6e065d5496a7f79ee6 官方指引&#xff1a;https://tauri.app/zh-cn/start/ 目前Tauri2的教程視頻不多&#xff0c;我按照Tauri1的教程來學習&…

SQL進階之旅 Day 26:分庫分表環境中的SQL策略

【SQL進階之旅 Day 26】分庫分表環境中的SQL策略 文章簡述 隨著業務規模的擴大&#xff0c;單一數據庫難以承載海量數據與高并發訪問。分庫分表成為解決這一問題的關鍵手段&#xff0c;但同時也帶來了 SQL 查詢復雜度的顯著提升。本文作為“SQL進階之旅”系列的第26天內容&…

linux之 內存管理(6)-arm64 內核虛擬地址空間變化

一、新內核變動 kernel變化的真快&#xff0c;之前我記得4.x的內核的內核空間的線性映射區位于內核空間的高地址處的128TB&#xff0c;且當前的博客和一些書籍也都還是這樣介紹。可翻了翻kernel的Documentation/arm64/memory.rst文檔&#xff0c;發現最新的kernel已將這128TB移…

循環神經網絡(RNN):從理論到翻譯

循環神經網絡&#xff08;RNN&#xff09;是一種專為處理序列數據設計的神經網絡&#xff0c;如時間序列、自然語言或語音。與傳統的全連接神經網絡不同&#xff0c;RNN具有"記憶"功能&#xff0c;通過循環傳遞信息&#xff0c;使其特別適合需要考慮上下文或順序的任…

window批處理文件(.bat),用來清理git的master分支

echo off chcp 65001 > nul setlocal enabledelayedexpansionecho 正在檢查Git倉庫... git rev-parse --is-inside-work-tree >nul 2>&1 if %errorlevel% neq 0 (echo 錯誤&#xff1a;當前目錄不是Git倉庫&#xff01;pauseexit /b 1 )echo 警告&#xff1a;這將…

C#中的CLR屬性、依賴屬性與附加屬性

CLR屬性的主要特征 封裝性&#xff1a; 隱藏字段的實現細節 提供對字段的受控訪問 訪問控制&#xff1a; 可單獨設置get/set訪問器的可見性 可創建只讀或只寫屬性 計算屬性&#xff1a; 可以在getter中執行計算邏輯 不需要直接對應一個字段 驗證邏輯&#xff1a; 可以…

【mysql】聯合索引和單列索引的區別

區別核心&#xff1a;聯合索引可加速多個字段組合查詢&#xff0c;單列索引只能加速一個字段。 &#x1f539;聯合索引&#xff08;復合索引&#xff09; INDEX(col1, col2, col3)適用范圍&#xff1a; WHERE col1 ... ? WHERE col1 ... AND col2 ... ? WHERE col1 ..…

如何用 HTML 展示計算機代碼

原文&#xff1a;如何用 HTML 展示計算機代碼 | w3cschool筆記 &#xff08;請勿將文章標記為付費&#xff01;&#xff01;&#xff01;&#xff01;&#xff09; 在編程學習和文檔編寫過程中&#xff0c;清晰地展示代碼是一項關鍵技能。HTML 作為網頁開發的基礎語言&#x…

大模型筆記_模型微調

1. 大模型微調的概念 大模型微調&#xff08;Fine-tuning&#xff09;是指在預訓練大語言模型&#xff08;如GPT、BERT、LLaMA等&#xff09;的基礎上&#xff0c;針對特定任務或領域&#xff0c;使用小量的目標領域數據對模型進行進一步訓練&#xff0c;使其更好地適配具體應…

React Native UI 框架與動畫系統:打造專業移動應用界面

React Native UI 框架與動畫系統&#xff1a;打造專業移動應用界面 關鍵要點 UI 框架加速開發&#xff1a;NativeBase、React Native Paper、UI Kitten 和 Tailwind-RN 提供預構建組件&#xff0c;幫助開發者快速創建美觀、一致的界面。動畫提升體驗&#xff1a;React Native…

在QT中使用OpenGL

參考資料&#xff1a; 主頁 - LearnOpenGL CN https://blog.csdn.net/qq_40120946/category_12566573.html 由于OpenGL的大多數實現都是由顯卡廠商編寫的&#xff0c;當產生一個bug時通常可以通過升級顯卡驅動來解決。 OpenGL中的名詞解釋 OpenGL 上下文&#xff08;Conte…