这是基于soundtouch写的一个实时变声的C#脚本,因为是调试版,所以可能会有BUG
核心代码:
private void OnAudioFilterRead(float[] data, int channels){if (isRecording){//根据data,一段段处理变声soundTouch.PutSamples(data, data.Length);float[] tempsample_after = new float[data.Length];soundTouch.ReceiveSamples(tempsample_after, data.Length);for (int i = 0; i < data.Length; i++){data[i] = tempsample_after[i];}}}
关于OnAudioFilterRead的问题,有兴趣的同学可以去看看它的API,我在这里就不多说了
下面直接代码:
using SoundTouch;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.IO;#if SOUNDTOUCH_INTEGER_SAMPLES
using TSampleType = System.Int16;
using TLongSampleType = System.Int64;
#else
using TSampleType = System.Single;
using TLongSampleType = System.Double;
#endifpublic class ClipChangeTest : MonoBehaviour {public AudioSource audioSource;//滑动条public Slider slider1;public Slider slider2;public Slider slider3;//输入框public InputField inputField1;public InputField inputField2;public InputField inputField3;public InputField inputField_modelName;private float tmpTempo;private float tmpPitch;private float tmpRate;private float temp_ischange1;private float temp_ischange2;private bool isRecording = false;private bool isChange_pitch = false;SoundTouch soundTouch = new SoundTouch();// Use this for initializationvoid Start (){slider1.minValue = -12f;slider1.maxValue = 12f;slider2.minValue = 0f;slider2.maxValue = 6f;slider3.minValue = 0f;slider3.maxValue = 6f;slider1.value = 0f;slider2.value = 1f;slider3.value = 1f;}// Update is called once per framevoid Update () {if (!isChange_pitch){if (slider3.value != temp_ischange2){slider2.value = 1f / slider3.value;temp_ischange1 = slider2.value;temp_ischange2 = slider3.value;}else if (slider2.value != temp_ischange1){slider3.value = 1f / slider2.value;temp_ischange1 = slider2.value;temp_ischange2 = slider3.value;}if (inputField1.isFocused){slider1.value = float.Parse(inputField1.text);}else if(inputField2.isFocused){slider2.value = float.Parse(inputField2.text);}else if (inputField3.isFocused){slider3.value = float.Parse(inputField3.text);}else{inputField1.text = slider1.value.ToString();inputField2.text = slider2.value.ToString();inputField3.text = slider3.value.ToString();}tmpPitch = slider1.value;tmpTempo = slider2.value;tmpRate = slider3.value;}}public void Mic_test(){if (Microphone.devices.Length == 0){Debug.LogWarning("找不到麦克风!");}Microphone.End(null);audioSource.clip = Microphone.Start(null, false, 100, 44100);//实时变声调整(初始化)isChange_pitch = true;soundTouch.SetTempo(tmpTempo);soundTouch.SetPitchSemiTones(tmpPitch);//噪音相对大一点soundTouch.SetRate(tmpRate);soundTouch.SetSampleRate(44100);soundTouch.SetChannels(1);soundTouch.SetSetting(SettingId.UseQuickseek, 0);soundTouch.SetSetting(SettingId.UseAntiAliasFilter, 0);soundTouch.SetSetting(SettingId.SequenceDurationMs, 40);soundTouch.SetSetting(SettingId.SeekwindowDurationMs, 15);soundTouch.SetSetting(SettingId.OverlapDurationMs, 8);isRecording = true;while (Microphone.GetPosition(null) <= 0) { }audioSource.Play();}//保存声音public void Save_test(){soundTouch.Flush();float[] saveClip_befor = new float[audioSource.timeSamples];audioSource.Stop();audioSource.clip.GetData(saveClip_befor, 0);//变声处理soundTouch.SetTempo(tmpTempo);soundTouch.SetPitchSemiTones(tmpPitch);soundTouch.SetRate(tmpRate);soundTouch.SetSampleRate(44100);soundTouch.SetChannels(1);soundTouch.SetSetting(SettingId.UseQuickseek, 0);soundTouch.SetSetting(SettingId.UseAntiAliasFilter, 0);soundTouch.SetSetting(SettingId.SequenceDurationMs, 40);soundTouch.SetSetting(SettingId.SeekwindowDurationMs, 15);soundTouch.SetSetting(SettingId.OverlapDurationMs, 8);soundTouch.PutSamples(saveClip_befor, saveClip_befor.Length);//获取变声后的数据并保存float[] saveClip_after = new float[saveClip_befor.Length];soundTouch.ReceiveSamples(saveClip_after, saveClip_befor.Length);soundTouch.Flush();audioSource.clip = AudioClip.Create("changedClip", saveClip_befor.Length, 1, 44100,false);audioSource.clip.SetData(saveClip_after, 0);SavWav.Save("test1", audioSource.clip);isChange_pitch = false;}//实时变声private void OnAudioFilterRead(float[] data, int channels){if (isRecording){//根据data,一段段处理变声soundTouch.PutSamples(data, data.Length);float[] tempsample_after = new float[data.Length];soundTouch.ReceiveSamples(tempsample_after, data.Length);for (int i = 0; i < data.Length; i++){data[i] = tempsample_after[i];}}}//控制录音时是否有声音public void ChangeController(){if (audioSource.volume == 0){audioSource.volume = 1;}else{audioSource.volume = 0;}}//测试所用//回放public void replay(){isChange_pitch = false;isRecording = true;//实时变声调整(初始化)soundTouch.SetTempo(tmpTempo);soundTouch.SetPitchSemiTones(tmpPitch);//噪音相对大一点soundTouch.SetRate(tmpRate);soundTouch.SetSampleRate(44100);soundTouch.SetChannels(1);soundTouch.SetSetting(SettingId.UseQuickseek, 0);soundTouch.SetSetting(SettingId.UseAntiAliasFilter, 0);soundTouch.SetSetting(SettingId.SequenceDurationMs, 40);soundTouch.SetSetting(SettingId.SeekwindowDurationMs, 15);soundTouch.SetSetting(SettingId.OverlapDurationMs, 8);audioSource.Play();}//保存不同的音色public void Save_changedata(){if (!File.Exists(Application.dataPath + "/Assets/Resources/speech_model.txt")){File.Create(Application.dataPath + "/Assets/Resources/speech_model.txt");Debug.LogWarning("创建文件");}FileStream fileStream = new FileStream(Application.dataPath + "/Assets/Resources/speech_model.txt",FileMode.Append);StreamWriter streamWriter = new StreamWriter(fileStream);streamWriter.Write(inputField_modelName.text + ": ");streamWriter.Write(" pitch:" + tmpPitch);streamWriter.Write(" tempo:" + tmpTempo);streamWriter.Write(" rate:" + tmpRate);streamWriter.WriteLine();streamWriter.Close();Debug.Log("保存音色数据成功!");}}
项目下载链接: http://download.csdn.net/download/weifut/9966784