Last active
August 26, 2018 09:42
-
-
Save micchi-fms/67452ed318187f964cad2ea044ab6300 to your computer and use it in GitHub Desktop.
Unity上で音声を録音し、録音したデータをWavファイルに保存するコードと、録音したWavデータを再生するコード
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 System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using MiniJSON; | |
using System.Linq; | |
using System.IO; | |
using System.Text; | |
namespace JsonFunctions{ | |
public class jsonFunctions : MonoBehaviour { | |
private string fullFilePath; | |
private Dictionary<string,object> jsonData; | |
public IList LodingJsonData(string _FilePath){ | |
fullFilePath = Application.dataPath + _FilePath; | |
if(!File.Exists(fullFilePath)) Debug.Log(fullFilePath + "はありません。"); | |
string jsonStr= File.ReadAllText(fullFilePath); | |
jsonData=Json.Deserialize(jsonStr) as Dictionary<string,object>; | |
return (IList)jsonData["data"]; | |
} | |
public void OutLog(IList _jsonData){ | |
foreach(Dictionary<string,object> pathData in _jsonData){ | |
Debug.Log((string)pathData["path"]); | |
} | |
Debug.Log("要素数"+_jsonData.Count); | |
} | |
public void SaveJson(IList _jsonData){ | |
jsonData["data"]=_jsonData; | |
string writeData=Json.Serialize(jsonData); | |
Debug.Log(writeData); | |
File.WriteAllText(fullFilePath,writeData,Encoding.UTF8); | |
} | |
} | |
} |
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 System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using JsonFunctions; | |
[RequireComponent(typeof(AudioSource))]//AudioClipをアタッチ | |
[DisallowMultipleComponent]//複数アタッチするのを防ぐ | |
public class OutMic : MonoBehaviour { | |
private AudioSource audio;//オーディオ | |
#region json | |
private jsonFunctions jsonFunc; | |
private IList pathDatas; | |
#endregion | |
// Use this for initialization | |
void Start () { | |
InitPlay(); | |
audio.Play(); | |
StartCoroutine(Checking( ()=>{ | |
Debug.Log("END"); | |
} )); | |
} | |
void InitPlay(){ | |
jsonFunc=new jsonFunctions(); | |
pathDatas=jsonFunc.LodingJsonData("/Resources/sample.json"); | |
jsonFunc.OutLog(pathDatas); | |
var temp=(IDictionary)pathDatas[0]; | |
string PathPlaying=(string)temp["path"]; | |
Debug.Log(PathPlaying); | |
//audioSource指定 | |
audio=GetComponent<AudioSource>(); | |
AudioClip audioClip = WavUtility.ToAudioClip (PathPlaying); | |
audio.clip = audioClip; | |
} | |
public delegate void functionType(); | |
private IEnumerator Checking (functionType callback) { | |
while(true) { | |
yield return new WaitForFixedUpdate(); | |
if (!audio.isPlaying) { | |
callback(); | |
break; | |
} | |
} | |
} | |
} |
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 System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using System.Linq; | |
using JsonFunctions; | |
[RequireComponent(typeof(AudioSource))]//AudioClipをアタッチ | |
[DisallowMultipleComponent]//複数アタッチするのを防ぐ | |
public class RecordMic : MonoBehaviour { | |
// Use this for initialization | |
//外部から現在の音量を読み取る | |
public float GetLoudness() { | |
return loudness; | |
} | |
#region 音量についての変数 | |
[Tooltip("感度.音量の最大値.")] | |
public float sensitivity = 100; | |
[Tooltip("前フレームの影響度合い.")] | |
[Range(0,0.95f)] //最大1にできてしまうと全く変動しなくなる. | |
public float lastLoudnessInfluence; //前フレームの影響度合い. | |
private float loudness; //音量. | |
private float lastLoudness; //前フレームの音量. | |
#endregion | |
# region 録音 | |
private AudioSource audio;//オーディオ | |
[Tooltip("最小の録音時間(秒)")] | |
public int minDuration=2; | |
[Tooltip("最大の録音時間(秒)")] | |
public int maxDuration=60; | |
private const int sampleRate=16000;//録音のサンプリングレート | |
private string micName;//マイクのデバイス名 | |
#endregion | |
#region json | |
private jsonFunctions jsonFunc; | |
private IList pathDatas; | |
#endregion | |
private bool isRecording;//レコードを開始するかどうか | |
private bool isOnceRecord;//一回だけレコーディングする | |
//うなづきアニメーション | |
public float voiceThreshold=1.0f; | |
public Animator NodAnimator; | |
// public AudioClip distAudioClip; | |
void Start () { | |
jsonFunc=new jsonFunctions(); | |
pathDatas=jsonFunc.LodingJsonData("/Resources/sample.json"); | |
jsonFunc.OutLog(pathDatas); | |
InitRecord(); | |
isOnceRecord=true; | |
isRecording=true; | |
StartRecord(); | |
} | |
// Update is called once per frame | |
void Update () { | |
if(isOnceRecord){ | |
InputRecordKey(); | |
CalcLoudness();//音量を計算 | |
ControlRecord(); | |
} | |
} | |
void OnDestroy(){ | |
jsonFunc.SaveJson(pathDatas); | |
} | |
//レコード終了させる | |
void InputRecordKey(){ | |
if (Input.GetKeyDown(KeyCode.R)) | |
isRecording = !isRecording; | |
} | |
void ControlRecord(){ | |
if(!isRecording) | |
stopRecord(); | |
} | |
void InitRecord() { | |
//audioSource指定 | |
audio=GetComponent<AudioSource>(); | |
//マイク存在確認 | |
if (Microphone.devices.Length == 0) | |
{ | |
Debug.Log("マイクが見つかりません"); | |
return; | |
} | |
//マイク名 | |
micName = Microphone.devices[0]; | |
Debug.Log("init"); | |
Debug.Log(micName); | |
} | |
void StartRecord(){ | |
//AudioSource の AudioClip を出力先にして,録音開始. | |
//マイクで取り扱えるサンプルレートを調べて当てはめることもできますが,今回は一般的な 44100(44.1kHz) を指定しています. | |
audio.clip = Microphone.Start(micName, false, maxDuration, sampleRate); | |
//録音したデータは再生する必要がないのでミュートにします. | |
// audio.mute = true;//なんかここが怪しいぽい | |
//録音が開始されるまで待ちます. | |
while(!(Microphone.GetPosition("") > 0)){} | |
//データの中身を取得するために再生を始めます. | |
audio.Play(); | |
Debug.Log("録音開始"); | |
} | |
void stopRecord(){ | |
//マイクの録音位置を取得 | |
int position = Microphone.GetPosition(micName); | |
//マイクの録音を強制的に終了 | |
Microphone.End(micName); | |
//再生時間を確認すると、停止した時間に関わらず、maxDurationの値になっている。これは無音を含んでいる? | |
Debug.Log("修正前の録音時間: " + audio.clip.length); | |
Debug.Log("position"+position); | |
//最小の録音時間よりも小さければ修正 | |
if (position < minDuration * sampleRate) | |
{ | |
position = minDuration * sampleRate; | |
} | |
//音声データ一時退避用の領域を確保し、audioClipからのデータを格納 | |
float[] soundData = new float[audio.clip.samples * audio.clip.channels]; | |
audio.clip.GetData(soundData, 0); | |
//新しい音声データ領域を確保し、positonの分だけ格納できるサイズにする。 | |
float[] newData = new float[position * audio.clip.channels]; | |
//positionの分だけデータをコピー | |
for (int i = 0; i < newData.Length; i++) | |
{ | |
newData[i] = soundData[i]; | |
} | |
//新しいAudioClipのインスタンスを生成し、音声データをセット | |
AudioClip newClip = AudioClip.Create(audio.clip.name, position, audio.clip.channels, audio.clip.frequency, false); | |
newClip.SetData(newData, 0); | |
// AudioClip.Destroy(distAudioClip); | |
// distAudioClip=newClip; | |
Debug.Log(SaveWavFile (newClip)); | |
Debug.Log("修正後の録音時間: " + newClip.length); | |
string RecordedPath=SaveWavFile (newClip);//パス先を保存する | |
Dictionary<string,object> temp=new Dictionary<string,object>(){ | |
{"path",RecordedPath} | |
}; | |
pathDatas.Insert(0, temp); | |
jsonFunc.OutLog(pathDatas); | |
//再生時間 | |
isOnceRecord=false; | |
} | |
public string SaveWavFile (AudioClip _audioClip) | |
{ | |
string filepath; | |
byte[] bytes = WavUtility.FromAudioClip (_audioClip, out filepath, true);//filepathはApplication.persistentDataPath | |
return filepath; | |
} | |
void CalcLoudness() { | |
if(lastLoudness <= voiceThreshold && loudness<= voiceThreshold){ | |
Debug.Log("voiceThreshold"+voiceThreshold); | |
NodAnimator.SetBool("isNod",true); | |
} | |
if(NodAnimator.GetCurrentAnimatorStateInfo(0).IsName("nod") && !NodAnimator.IsInTransition(0)){ | |
Debug.Log(NodAnimator.GetCurrentAnimatorStateInfo(0).IsName("nod")); | |
NodAnimator.SetBool("isNod",false); | |
} | |
lastLoudness = loudness; | |
loudness = GetAveragedVolume() * sensitivity * ( 1 - lastLoudnessInfluence ) + lastLoudness * lastLoudnessInfluence; | |
Debug.Log("音量"+loudness); | |
} | |
//現フレームで再生されている AudioClip から平均的な音量を取得します. | |
float GetAveragedVolume() | |
{ | |
//AudioClip の情報を格納する配列. | |
//256は適当です.少なすぎれば平均的なサンプルデータが得られなくなるかもしれず, | |
//多すぎれば計算量が増えますので良い感じに... | |
float[] data = new float[256]; | |
//AudioClipからデータを抽出します. | |
audio.GetOutputData(data, 0); | |
//平均を返します. | |
return data.Select(item => Mathf.Abs(item)).Average(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment