質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

6009閲覧

<Unity>音声データの取得

mhmmic1

総合スコア27

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

2クリップ

投稿2018/12/26 19:45

わからないこと

1.Unity上での音声データの取得方法
・フレーム単位でリアルタイムにデータを取得できるのか?

2.AudioSource.GetOutputDataで得られる出力データはどのようなデータであるのか
・音声データのブロックとは何か? 

3.MonoBehaviour.OnAudioFilterReadはどのようなタイミングで呼び出されているのか
・フレームごとに呼び出している?

該当のソースコード

最初に試したコードです. その後試行錯誤しましたが結局うまくいきませんでした.

C#

1using UnityEngine; 2 3[RequireComponent(typeof(AudioSource))] 4[RequireComponent(typeof(LineRenderer))] 5public class Sound_Mic : MonoBehaviour 6{ 7 private LineRenderer lr; 8 private AudioSource _audio; 9 [HideInInspector] 10 public float[] data; 11 private int count; 12 13 void Conduct(float[] data) 14 { 15 count++; 16 lr.positionCount = count; 17 lr.SetPosition(count - 1, new Vector3(count * 0.01f, 100, 5)); 18 foreach(float d in data) { 19 count++; 20 lr.positionCount = count; 21 lr.SetPosition(count - 1, new Vector3(count * 0.01f, d*10, 5)); 22 } 23 } 24 25 void Start() 26 { 27 data = new float[1024]; 28 _audio = GetComponent<AudioSource>(); 29 lr = GetComponent<LineRenderer>(); 30 count = 0; 31 lr.positionCount = count; 32 } 33 34 void Update() 35 { 36 37 if (_audio.isPlaying) 38 { 39 FillAudioBuffer(); 40 } 41 42 if (!_audio.isPlaying) 43 { 44 _audio.Stop(); 45 } 46 } 47 48 void FillAudioBuffer() 49 { 50 _audio.GetOutputData(data, _audio.clip.channels); 51 Conduct(data); 52 } 53}

試したこと

AudioSourceで正弦波音源を流しGetOutputDataから取得したデータを用いて波形を生成してみたのですが
想定していた波形が得られず原因を調べている状態です.

###わかりずらい文章かもしれませんが何卒お願いします.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

  1. 音声データの取得について

これはご質問者さんのおっしゃるAudioSource.GetOutputDataMonoBehaviour.OnAudioFilterReadが妥当ではないかと思います。

  1. AudioSource.GetOutputDataのデータについて

すでにリファレンスをご覧になったかと思いますが、おそらくここで言及されている「ブロック」は単にデータの塊ということだろうと思います。サイズ1024の配列で受け取れば、今再生されている点周辺の1024個のデータ(不確かですが、「今まさに再生されている瞬間から直近1024点」とは言い切れないと思いますが...未調査です)が得られるはずです。

  1. MonoBehaviour.OnAudioFilterReadのタイミングについて

リファレンスによると...

OnAudioFilterRead is called every time a chunk of audio is sent to the filter (this happens frequently, every ~20ms depending on the sample rate and platform).

OnAudioFilterReadはオーディオのチャンクがフィルターへ送られるたびに実行されます(サンプルレートやプラットフォームにもよりますが、~20ミリ秒おきに頻繁に実行されます)。
※「チャンク」も「データの一塊」のようなとらえ方でいいように思います。オーディオファイルフォーマットの中の、各種データのためのそれぞれの領域を「チャンク」と呼んだりもしますが、そちらは文脈的にそぐわないように感じます。

Also note that OnAudioFilterRead is called on a different thread from the main thread (namely the audio thread) so calling into many Unity functions from this function is not allowed (if you try, a warning shows up at run time).

また、OnAudioFilterReadはメインスレッドとは異なるスレッド(オーディオスレッド)上で呼び出されることにご注意ください。よって、この関数内では大部分のUnity関数の呼び出しは許されません(行おうとすれば実行時に警告が表示されます)。

とのことで、Updateとは異なる周期のようですね。

波形の記録はこんな感じでいかがでしょうか?

C#

1using System.Collections.Generic; 2using UnityEngine; 3 4[RequireComponent(typeof(AudioSource))] 5[RequireComponent(typeof(LineRenderer))] 6public class Sound_Mic : MonoBehaviour 7{ 8 public int ChannelToRead; 9 10 [HideInInspector] private int count; 11 private readonly object lockObject = new object(); 12 private LineRenderer lr; 13 private bool playing; 14 private readonly List<float> recordedData = new List<float>(); 15 16 private void Start() 17 { 18 this.lr = this.GetComponent<LineRenderer>(); 19 this.count = 0; 20 this.lr.positionCount = this.count; 21 this.playing = true; 22 } 23 24 // OnAudioFilterReadは別スレッドで動作するようなので、こちらのメソッドでは 25 // データの記録のみ行い、LineRendererの操作は行わない 26 private void OnAudioFilterRead(float[] data, int channels) 27 { 28 // dataには各チャンネルのデータがインターリーブ状態で入ってくる 29 // ステレオ音声ならLRLRLRLR... 30 // (ChannelToRead >= channelsにはならないものとして範囲チェックは省略) 31 lock (this.lockObject) 32 { 33 if (this.playing) 34 { 35 for (var i = 0; i < data.Length; i += channels) 36 { 37 this.recordedData.Add(data[i + this.ChannelToRead]); 38 } 39 } 40 } 41 } 42 43 // Update内でrecordedDataを見て、新たなデータが追記されていればラインを延ばす 44 private void Update() 45 { 46 lock (this.lockObject) 47 { 48 if (!this.playing) 49 { 50 return; 51 } 52 53 // 無制限にラインを延ばし続けると、じきにハングアップするので 54 // 適当な時間でやめる 55 if (Time.timeSinceLevelLoad > 0.1f) 56 { 57 this.playing = false; 58 } 59 var newCount = this.recordedData.Count; 60 if (newCount > this.count) 61 { 62 this.lr.positionCount = newCount + 1; 63 for (var i = this.count; i < newCount; i++) 64 { 65 this.lr.SetPosition(i, new Vector3(i * 0.1f, this.recordedData[i] * 10, 5)); 66 } 67 68 this.lr.SetPosition(newCount, new Vector3(newCount * 0.1f, 100, 5)); 69 } 70 } 71 } 72}

ですが、なにぶん毎秒数万点のデータがやってきますので、LineRendererによる描画では頂点数が多すぎて、すぐに動かなくなってしまうでしょう。データを間引くなどの対策が必要かと思います。
また、パフォーマンスは考慮していませんので、再生中の音にプツプツとノイズが入るかもしれません。多少改良しても、そもそも大量のデータをリアルタイムに操作するのはやっかいですので、解消しきれない可能性があります。
それよりも、もし「今再生中の音の記録」ではなくてもいいのなら、元のオーディオクリップからデータを持ってきてグラフを描くというのも一案かと思います。

投稿2018/12/29 00:52

Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mhmmic1

2019/01/02 16:40

年末年始と忙しく返信が遅れてしまいすみません. 可能であれば, もう一つ質問よろしいでしょうか? 上記とは別にデータを取得した後に, ストリームに流し他のPCでデータの処理をしようと考えています. ・Hololens - PC 間を想定しています (Holo:送信 - PC:受信) この取得したデータを送信する場合, マイク4ch分をwaveファイルに変換することは可能でしょうか? ・ステレオ・モノラルのみ? ・データ構造のチャンネルの部分を変えるだけ? 伝わりづらいかもしれませんがお時間よろしければお願いします. ご回答いただき誠にありがとうございます. 初めての投稿で伝わりにくかったとは思いますがとても的確なアドバイスを受けさらに理解を深めることができました. 日々精進いたします. ありがとうございます.
Bongo

2019/01/02 19:39 編集

おそらく可能だとは思います(すみませんがHoloLensを持っておらず実験はできませんが...)。https://qiita.com/miyaura/items/3a4a130175d272ea85e6 の記事では、Microphoneからの入力を音声認識のために録音しようと試みている様子です。マイクのデバイス名として... _microphone = Microphone.devices[0]; を使っている部分がありますが、想像するに2、3、4番マイクからの入力もdevices[1]、devices[2]、devices[3]から取れるんじゃないでしょうか? 4基のマイクを4つのAudioSourceにそれぞれつないで、それぞれのAudioSourceの音を記録することになるんじゃないかと思います。そして、ステレオ対応のマイクならば、それぞれのAudioSourceで2チャンネルのLRLRLRLR......の形でデータを得られるように思われます。 取得したデータは単なるfloatの配列ですので、その後PC側へ送ることもできるだろうと思うのですが、ネットワーク越しではリアルタイム処理をするのはより難しそうな気はします。 といいましても、やはり実機を持っていないのでどうなるか判断しかねるところがありますね...この辺は実際にやってみてご確認いただきたいと思います。 データを得た後のWAVEフォーマットへの加工についても記事の後半に少し言及されており、ご参考になりそうですね。
mhmmic1

2019/01/03 05:18

URLとても参考になりました. 行き詰っていたところだったので早速とりかかろうと思います. 本当にありがとうございます. 実際にやってみて試行錯誤し, 理想に近づくよう精進いたします.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問