1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Unity] ループしていない環境音をクロスフェードしてループにする

Last updated at Posted at 2021-09-23

...というアセットの販売を開始しました。
AmbientLooper

それに含まれるスクリプトの一部を改変して公開します。
ループ音にしたいAudioSourceがあるオブジェクトに下記スクリプトをアタッチするだけでノンループの環境音がループ音になります。
動画

長い環境音などは比較的時間もかかるので、その場合はAmbientLooperでwav化して使用するのがオススメです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(AudioSource))]
public class CrossFadeLoop : MonoBehaviour
{
    [Tooltip("cross fade dulation[sec]"), Range(0.1f, 5f)] public float m_crossFadeTime = 1f;

    void Start()
    {
        AudioSource audioSrc = gameObject.GetComponent<AudioSource>();
        AudioClip ac = audioSrc.clip;
        float[] data = new float[ac.samples * ac.channels];
        ac.GetData(data, 0);
        int span = Mathf.FloorToInt(m_crossFadeTime * (float)(ac.frequency * ac.channels));
        span -= (span % ac.channels);
        float[] newData = CrossFade(data, span);
        AudioClip newAc = AudioClip.Create("_loop_" + ac.name, newData.Length / ac.channels, ac.channels, ac.frequency, false);
        newAc.SetData(newData, 0);
        audioSrc.clip = newAc;
        if (audioSrc.playOnAwake)
            audioSrc.Play();
    }

    static public float[] CrossFade(float[] data, int span)
    {
        if (data.Length < span * 2)
            return data;

        float[] retData = new float[data.Length - span];
        for (int i = 0; i < span; ++i)
        {
            float rate = (float)(i + 1) / (float)(span + 1);
            retData[i] = data[i] * rate + data[data.Length - span + i] * (1f - rate);
        }
        for (int i = span; i < data.Length - span; ++i)
            retData[i] = data[i];

        return retData;
    }
}

具体的な操作としては、自分自身をクロスフェードして頭とおしりをつないでいます。

AmbLooper.png

まずは

        float[] data = new float[ac.samples * ac.channels];
        ac.GetData(data, 0);

でclipのデータを取得します。クリップのサイズはサンプル数xチャンネル数で決まります。

次に

        int span = Mathf.FloorToInt(m_crossFadeTime * (float)(ac.frequency * ac.channels));
        span -= (span % ac.channels);

でクロスフェードさせる時間分のデータ長を設定します。
計算で求めたspanだけでは偶数/奇数になる可能性があり、
チャンネル数が2でspanが奇数だと左右逆のチャンネルのデータをフェードして繋いでしまうことになり、音の定位変化やプチノイズの原因になるため、spanをチャンネル数で割り切れる数に調整します。

あとは

        float[] newData = CrossFade(data, span);

でデータをクロスフェードさせます。出力されるデータサイズはクロスフェードの分だけ小さくなります。

        float[] retData = new float[data.Length - span];

新しく作ったAudioClipにデータを読み込ませ、AudioSourceにセットします。

        newAc.SetData(newData, 0);
        audioSrc.clip = newAc;

AudioSourceに新しいclipを読み込ませると鳴っていた音が止まってしまうので、
音が鳴っていた(PlayOnAwakeがオンになっていた)場合はPlayします

        if (audioSrc.playOnAwake)
            audioSrc.Play();
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?