Hiromuブログ

最近はこちら(https://zenn.dev/hiromu)が本体

SpatialSoundを試す

何気に今まで一度も試したことがなかったのでSpatialSoundの動作を確認してみました。

HoloToolkitのSpatialSound配下にprefabがないので一瞬戸惑いましたがREADMEを読んだら簡単でした。


まず、メニューのEdit -> Project Settings -> Audio –> Spatializer Plugin を「MS HRTF Spatializer」にします。

spatialsound01

spatialsound01b


あとはAudioSourceを以下のようにSpatializeにチェックを入れ、Spatial Blendを1に設定するだけです。

spatialsound02

スクリプトで制御する場合は以下が参考になります。

HoloLens の空間音響を使う


試しに、タップしたらランダムに音源の位置が変わるサンプルを作成してみました。HoloLens実機で動かすと音源の位置から音が聞こえることを確認できます。

spatialsound

オブジェクトを非表示にして音探しゲームなど作っても面白いと思いました。


プロジェクトはシンプルに以下のような感じです。

spatialsound03

  • 音源位置となるSphereを一つ配置し
  • どこをタップしてもをタップしたことを検出するためにAdd ComponentでSetGlobalListenerを追加します
  • タップしたときにSphereの位置をランダムに変更するために以下のRandomPositionスクリプトを追加します
using UnityEngine;
using HoloToolkit.Unity.InputModule;

public class RandomPosition : MonoBehaviour, IInputClickHandler
{
    public void OnInputClicked(InputClickedEventData eventData)
    {
        transform.position = new Vector3(
            Random.Range(-5, 5),
            Random.Range(-5, 5),
            Random.Range(-5, 5));
    }
}


AudioSourceのAudioClipはお好みのものでよいと思いますが、サンプルでは動的に生成した音を鳴らしました。

以下がMakeSound.csのソースです。


using UnityEngine;
using System;

/// 
/// Sin波を生成します
/// 
[RequireComponent(typeof(AudioSource))]
public class MakeSound : MonoBehaviour
{
    /// 
    /// 周波数
    /// 
    public double frequency = 440;

    /// 
    /// 音量(gain倍する)
    /// 
    public double gain = 0.05;

    /// 
    /// 位相
    /// 
    private double phase = 0.0;

    /// 
    /// サンプリングレート
    /// 
    private double sample_rate = 48000;

    /// 
    /// 1サンプルにおける変化量
    /// 
    private double unit;

    /// 
    /// 音声データにフィルターをかけます
    /// 
    /// 音声データ
    /// チャンネル
    void OnAudioFilterRead(float[] data, int channels)
    {
        unit = frequency * 2 * Math.PI / sample_rate;

        for (var i = 0; i < data.Length; i = i + channels)
        {
            phase += unit;

            data[i] = (float)(gain * Math.Sin(phase));
            if (channels == 2)
            {
                data[i + 1] = data[i];
            }

            if (phase > 2 * Math.PI)
            {
                phase = 0;
            }
        }
    }
}