Loading... 有些时候我们在游戏想录制游戏内部的声音,那么常用的Unity的[MicroPhone](https://docs.unity3d.com/ScriptReference/Microphone.html) API就没什么用了。 好在Unity还提供了[OnAudioFilterRead](https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnAudioFilterRead.html)这个API来完成这类需求。 这个方案来自:[http://evanxmerz.com/blog/index.php/2016/10/07/recording-in-game-audio-in-unity/](http://evanxmerz.com/blog/index.php/2016/10/07/recording-in-game-audio-in-unity/) 实现步骤: - 创建MonoBehaviour,这个脚本需要附到Unity [AudioListener](https://docs.unity3d.com/ScriptReference/AudioListener.html) 所在的GameObject才能正常工作 - 在脚本内添加代码 ``` // write the incoming audio to the output string void OnAudioFilterRead(float[] data, int channels) { if (this.Rendering) { // store the number of channels we are rendering this.channels = channels; // store the data stream this.Write(data); } } ``` - 将接收到的数据保存到字节流中 ``` /// Write a chunk of data to the output stream. public void Write(float[] audioData) { // Convert numeric audio data to bytes for (int i = 0; i < audioData.Length; i++) { // write the short to the stream this.outputWriter.Write((short) (audioData[i] * (float) Int16.MaxValue)); } } ``` - 保存成声音文件 ``` public AudioRenderer.Result Save(string filename) { Result result = new AudioRenderer.Result(); if (outputStream.Length > 0) { // add a header to the file so we can send it to the SoundPlayer this.AddHeader(); // if a filename was passed in if (filename.Length > 0) { // Save to a file. Print a warning if overwriting a file. if (File.Exists(filename)) Debug.LogWarning("Overwriting " + filename + "..."); // reset the stream pointer to the beginning of the stream outputStream.Position = 0; // write the stream to a file FileStream fs = File.OpenWrite(filename); this.outputStream.WriteTo(fs); fs.Close(); // for debugging only Debug.Log("Finished saving to " + filename + "."); } result.State = Status.SUCCESS; } else { Debug.LogWarning("There is no audio data to save!"); result.State = Status.FAIL; result.Message = "There is no audio data to save!"; } return result; } ``` 其中的`AddHeader`如下: ``` /// This generates a simple header for a canonical wave file, /// which is the simplest practical audio file format. It /// writes the header and the audio file to a new stream, then /// moves the reference to that stream. /// /// See this page for details on canonical wave files: /// http://www.lightlink.com/tjweber/StripWav/Canon.html private void AddHeader() { // reset the output stream outputStream.Position = 0; // calculate the number of samples in the data chunk long numberOfSamples = outputStream.Length / (BITS_PER_SAMPLE / 8); // create a new MemoryStream that will have both the audio data AND the header MemoryStream newOutputStream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(newOutputStream); writer.Write(0x46464952); // "RIFF" in ASCII // write the number of bytes in the entire file writer.Write((int) (HEADER_SIZE + (numberOfSamples * BITS_PER_SAMPLE * channels / 8)) - 8); writer.Write(0x45564157); // "WAVE" in ASCII writer.Write(0x20746d66); // "fmt " in ASCII writer.Write(16); // write the format tag. 1 = PCM writer.Write((short) 1); // write the number of channels. writer.Write((short) channels); // write the sample rate. 44100 in this case. The number of audio samples per second writer.Write(SAMPLE_RATE); writer.Write(SAMPLE_RATE * channels * (BITS_PER_SAMPLE / 8)); writer.Write((short) (channels * (BITS_PER_SAMPLE / 8))); // 16 bits per sample writer.Write(BITS_PER_SAMPLE); // "data" in ASCII. Start the data chunk. writer.Write(0x61746164); // write the number of bytes in the data portion writer.Write((int) (numberOfSamples * BITS_PER_SAMPLE * channels / 8)); // copy over the actual audio data this.outputStream.WriteTo(newOutputStream); // move the reference to the new stream this.outputStream = newOutputStream; } ``` - 使用`OnGUI`代码测试 ``` #if UNITY_EDITOR void OnGUI() { if (GUI.Button(new Rect(0, 0, 100, 100), "Start")) { this.Rendering = true; } if (GUI.Button(new Rect(0, 110, 100, 100), "Stop")) { this.Rendering = false; Save(Application.dataPath + "/" + "234.wav"); } } #endif ``` 最后修改:2022 年 05 月 21 日 © 允许规范转载 赞 0