-
-
Save umiyuki/fe1807230532ea2678fa6d9751ea2d9a to your computer and use it in GitHub Desktop.
Record Microphone in EditMode. Need Voice Changer Filter(https://www.assetstore.unity3d.com/jp/#!/content/54963)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Runtime.InteropServices; | |
using System.IO; | |
public class RecorderManager : MonoBehaviour | |
{ | |
[DllImport("world_dll")] | |
private static extern int filter(double[] datas, int data_size, int fs, float pitch, float formant); | |
[SerializeField]string fileName = ""; | |
[SerializeField] int micDeviceID = 0; | |
[HeaderAttribute("VoiceChanger")] | |
[SerializeField]bool enableVoiceChanger = false; | |
[SerializeField,Range(0, 5)] float pitch = 1f; | |
[SerializeField,Range(0, 5)] float formant = 1f; | |
[HeaderAttribute("CutAudio")] | |
[SerializeField]bool enableCutAudio = false; | |
[SerializeField,Range(0,10)] float cutForward = 0f; | |
[SerializeField,Range(0,10)] float cutLast = 0f; | |
[SerializeField] List<string> micDevices = new List<string>(); | |
[SerializeField] AudioClip recordClip; | |
[SerializeField] AudioClip trimmedClip; | |
int freq = 44100; | |
[SerializeField] string export_path = "ExportVoices"; | |
public void UpdateMicDevices() | |
{ | |
micDevices.Clear(); | |
foreach (string str in Microphone.devices) | |
{ | |
micDevices.Add(str); | |
} | |
} | |
void SetupClip() | |
{ | |
if (recordClip == null) | |
{ return; } | |
if (!enableCutAudio && !enableVoiceChanger) | |
{ | |
GetComponent<AudioSource>().clip = recordClip; | |
return; | |
} | |
AudioSource audioSource = GetComponent<AudioSource>(); | |
if (enableCutAudio) | |
{ | |
int cutLength = Mathf.CeilToInt(freq * (cutForward + cutLast)); | |
if (cutLength > recordClip.samples) | |
{ | |
Debug.Log("Cut length too long! recordClipSamples:" + recordClip.samples + " cutLength:" + cutLength); | |
return; | |
} | |
int cutStart = Mathf.FloorToInt(freq * cutForward); | |
int newLength = recordClip.samples - cutLength; | |
float[] samples = new float[recordClip.samples]; | |
recordClip.GetData(samples, cutStart); | |
float[] clipSamples = new float[newLength]; | |
System.Array.Copy(samples, clipSamples, clipSamples.Length); | |
trimmedClip = AudioClip.Create("trimRecordClip", clipSamples.Length, 1, freq, false); | |
trimmedClip.SetData(clipSamples, 0); | |
} | |
else | |
{ | |
float[] samples = new float[recordClip.samples]; | |
recordClip.GetData(samples, 0); | |
trimmedClip = AudioClip.Create("trimRecordClip", samples.Length, 1, freq, false); | |
trimmedClip.SetData(samples, 0); | |
} | |
if (enableVoiceChanger) | |
{ | |
float[] samples = new float[trimmedClip.samples]; | |
trimmedClip.GetData(samples, 0); | |
double[] d_samples = new double[samples.Length]; | |
for (int i = 0; i < d_samples.Length; i++) | |
{ | |
d_samples[i] = samples[i]; | |
} | |
filter(d_samples, d_samples.Length, freq, pitch, formant); | |
for (int i = 0; i < d_samples.Length; i++) | |
{ | |
samples[i] = (float)d_samples[i]; | |
} | |
trimmedClip.SetData(samples, 0); | |
} | |
audioSource.clip = trimmedClip; | |
} | |
public void SaveToFile() | |
{ | |
SetupClip(); | |
string filePath = Application.dataPath + "/" + export_path + "/" + fileName + ".wav"; | |
if (fileName == null || File.Exists(filePath)) | |
{ | |
SavWav.Save(filePath, GetComponent<AudioSource>().clip); | |
} | |
else | |
{ | |
bool exist_flag = false; | |
int index = 0; | |
while (!exist_flag) | |
{ | |
filePath = Application.dataPath + "/" + export_path + "/" + index.ToString("0000") + ".wav"; | |
if (!File.Exists(filePath)) | |
{ | |
exist_flag = true; | |
} | |
else | |
{ | |
index++; | |
} | |
} | |
SavWav.Save(filePath, GetComponent<AudioSource>().clip); | |
} | |
} | |
public void PlayClip() | |
{ | |
SetupClip(); | |
GetComponent<AudioSource>().Play(); | |
} | |
public void PauseClip() | |
{ | |
GetComponent<AudioSource>().Pause(); | |
} | |
public void StopClip() | |
{ | |
GetComponent<AudioSource>().Stop(); | |
} | |
public void Record() | |
{ | |
GetComponent<AudioSource>().clip = Microphone.Start(Microphone.devices[micDeviceID], false, 300, freq); | |
} | |
public void RecodeStop() | |
{ | |
int lastTime = Microphone.GetPosition(null); | |
if (lastTime == 0) | |
{ return; } | |
Debug.Log("lastTime =" + lastTime); | |
Microphone.End(null); | |
AudioSource audioSource = GetComponent<AudioSource>(); | |
float[] samples = new float[audioSource.clip.samples]; | |
audioSource.clip.GetData(samples, 0); | |
float[] clipSamples = new float[lastTime]; | |
System.Array.Copy(samples, clipSamples, clipSamples.Length - 1); | |
recordClip = AudioClip.Create("playRecordClip", clipSamples.Length, 1, freq, false); | |
recordClip.SetData(clipSamples, 0); | |
audioSource.clip = recordClip; | |
trimmedClip = null; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
using UnityEditor; | |
[CustomEditor(typeof(RecorderManager))] | |
public class RecoderManagerEditor : Editor { | |
public override void OnInspectorGUI() | |
{ | |
RecorderManager recordManager = (RecorderManager)target; | |
if (GUILayout.Button("Play Clip")) | |
{ | |
recordManager.PlayClip(); | |
} | |
if (GUILayout.Button("Pause Clip")) | |
{ | |
recordManager.PauseClip(); | |
} | |
if (GUILayout.Button("Stop Clip")) | |
{ | |
recordManager.StopClip(); | |
} | |
if (GUILayout.Button("Record")) | |
{ | |
recordManager.Record(); | |
} | |
if (GUILayout.Button("Record Stop")) | |
{ | |
recordManager.RecodeStop(); | |
} | |
if (GUILayout.Button("Save to File")) | |
{ | |
recordManager.SaveToFile(); | |
} | |
DrawDefaultInspector(); | |
if (GUILayout.Button("Update Mic Devices")) | |
{ | |
recordManager.UpdateMicDevices(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright (c) 2012 Calvin Rien | |
// http://the.darktable.com | |
// | |
// This software is provided 'as-is', without any express or implied warranty. In | |
// no event will the authors be held liable for any damages arising from the use | |
// of this software. | |
// | |
// Permission is granted to anyone to use this software for any purpose, | |
// including commercial applications, and to alter it and redistribute it freely, | |
// subject to the following restrictions: | |
// | |
// 1. The origin of this software must not be misrepresented; you must not claim | |
// that you wrote the original software. If you use this software in a product, | |
// an acknowledgment in the product documentation would be appreciated but is not | |
// required. | |
// | |
// 2. Altered source versions must be plainly marked as such, and must not be | |
// misrepresented as being the original software. | |
// | |
// 3. This notice may not be removed or altered from any source distribution. | |
// | |
// ============================================================================= | |
// | |
// derived from Gregorio Zanon's script | |
// http://forum.unity3d.com/threads/119295-Writing-AudioListener.GetOutputData-to-wav-problem?p=806734&viewfull=1#post806734 | |
using System; | |
using System.IO; | |
using UnityEngine; | |
using System.Collections.Generic; | |
public static class SavWav | |
{ | |
const int HEADER_SIZE = 44; | |
public static bool Save(string filepath, AudioClip clip) | |
{ | |
/* | |
if (!filename.ToLower().EndsWith(".wav")) | |
{ | |
filename += ".wav"; | |
}*/ | |
//var filepath = Path.Combine(Application.persistentDataPath, filename); | |
//var filepath = filename; | |
Debug.Log(filepath); | |
// Make sure directory exists if user is saving to sub dir. | |
Directory.CreateDirectory(Path.GetDirectoryName(filepath)); | |
using (var fileStream = CreateEmpty(filepath)) | |
{ | |
ConvertAndWrite(fileStream, clip); | |
WriteHeader(fileStream, clip); | |
} | |
return true; // TODO: return false if there's a failure saving the file | |
} | |
public static AudioClip TrimSilence(AudioClip clip, float min) | |
{ | |
var samples = new float[clip.samples]; | |
clip.GetData(samples, 0); | |
return TrimSilence(new List<float>(samples), min, clip.channels, clip.frequency); | |
} | |
public static AudioClip TrimSilence(List<float> samples, float min, int channels, int hz) | |
{ | |
return TrimSilence(samples, min, channels, hz, false, false); | |
} | |
public static AudioClip TrimSilence(List<float> samples, float min, int channels, int hz, bool _3D, bool stream) | |
{ | |
int i; | |
for (i = 0; i < samples.Count; i++) | |
{ | |
if (Mathf.Abs(samples[i]) > min) | |
{ | |
break; | |
} | |
} | |
samples.RemoveRange(0, i); | |
for (i = samples.Count - 1; i > 0; i--) | |
{ | |
if (Mathf.Abs(samples[i]) > min) | |
{ | |
break; | |
} | |
} | |
samples.RemoveRange(i, samples.Count - i); | |
var clip = AudioClip.Create("TempClip", samples.Count, channels, hz, _3D, stream); | |
clip.SetData(samples.ToArray(), 0); | |
return clip; | |
} | |
static FileStream CreateEmpty(string filepath) | |
{ | |
var fileStream = new FileStream(filepath, FileMode.Create); | |
byte emptyByte = new byte(); | |
for (int i = 0; i < HEADER_SIZE; i++) //preparing the header | |
{ | |
fileStream.WriteByte(emptyByte); | |
} | |
return fileStream; | |
} | |
static void ConvertAndWrite(FileStream fileStream, AudioClip clip) | |
{ | |
var samples = new float[clip.samples]; | |
clip.GetData(samples, 0); | |
Int16[] intData = new Int16[samples.Length]; | |
//converting in 2 float[] steps to Int16[], //then Int16[] to Byte[] | |
Byte[] bytesData = new Byte[samples.Length * 2]; | |
//bytesData array is twice the size of | |
//dataSource array because a float converted in Int16 is 2 bytes. | |
int rescaleFactor = 32767; //to convert float to Int16 | |
for (int i = 0; i < samples.Length; i++) | |
{ | |
intData[i] = (short)(samples[i] * rescaleFactor); | |
Byte[] byteArr = new Byte[2]; | |
byteArr = BitConverter.GetBytes(intData[i]); | |
byteArr.CopyTo(bytesData, i * 2); | |
} | |
fileStream.Write(bytesData, 0, bytesData.Length); | |
} | |
static void WriteHeader(FileStream fileStream, AudioClip clip) | |
{ | |
var hz = clip.frequency; | |
var channels = clip.channels; | |
var samples = clip.samples; | |
fileStream.Seek(0, SeekOrigin.Begin); | |
Byte[] riff = System.Text.Encoding.UTF8.GetBytes("RIFF"); | |
fileStream.Write(riff, 0, 4); | |
Byte[] chunkSize = BitConverter.GetBytes(fileStream.Length - 8); | |
fileStream.Write(chunkSize, 0, 4); | |
Byte[] wave = System.Text.Encoding.UTF8.GetBytes("WAVE"); | |
fileStream.Write(wave, 0, 4); | |
Byte[] fmt = System.Text.Encoding.UTF8.GetBytes("fmt "); | |
fileStream.Write(fmt, 0, 4); | |
Byte[] subChunk1 = BitConverter.GetBytes(16); | |
fileStream.Write(subChunk1, 0, 4); | |
UInt16 two = 2; | |
UInt16 one = 1; | |
Byte[] audioFormat = BitConverter.GetBytes(one); | |
fileStream.Write(audioFormat, 0, 2); | |
Byte[] numChannels = BitConverter.GetBytes(channels); | |
fileStream.Write(numChannels, 0, 2); | |
Byte[] sampleRate = BitConverter.GetBytes(hz); | |
fileStream.Write(sampleRate, 0, 4); | |
Byte[] byteRate = BitConverter.GetBytes(hz * channels * 2); // sampleRate * bytesPerSample*number of channels, here 44100*2*2 | |
fileStream.Write(byteRate, 0, 4); | |
UInt16 blockAlign = (ushort)(channels * 2); | |
fileStream.Write(BitConverter.GetBytes(blockAlign), 0, 2); | |
UInt16 bps = 16; | |
Byte[] bitsPerSample = BitConverter.GetBytes(bps); | |
fileStream.Write(bitsPerSample, 0, 2); | |
Byte[] datastring = System.Text.Encoding.UTF8.GetBytes("data"); | |
fileStream.Write(datastring, 0, 4); | |
Byte[] subChunk2 = BitConverter.GetBytes(samples * channels * 2); | |
fileStream.Write(subChunk2, 0, 4); | |
// fileStream.Close(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment