这是基于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;
#endif
public 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 initialization
void 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 frame
void 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("保存音色数据成功!");
}
}