Skip to content

Instantly share code, notes, and snippets.

@micchi-fms
Last active August 26, 2018 09:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save micchi-fms/67452ed318187f964cad2ea044ab6300 to your computer and use it in GitHub Desktop.
Save micchi-fms/67452ed318187f964cad2ea044ab6300 to your computer and use it in GitHub Desktop.
Unity上で音声を録音し、録音したデータをWavファイルに保存するコードと、録音したWavデータを再生するコード
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);
}
}
}
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;
}
}
}
}
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