Control the number of simultaneous sound effects played

Page update date :
Page creation date :

Verification environment

Windows
  • Windows 11
Unity Editor
  • 2021.3.3f1
Input System Package
  • 1.3.0

Prerequisites for this tip

The following settings have been made in advance as a premise for the description of this tip.

About the material included with the sample

Sound effects are borrowed from the following sites.

About audio files

The following audio file formats can be played with Unity's standard features: Please prepare it in advance because it will be used in these tips.

  • WAV (.wav)
  • OggVorbis (.ogg)
  • MPEG layer 3 (.mp3)

For more information, see the official Unity documentation.

About the upper limit and volume of multiple simultaneous audio playback

In the previous tips, AudioClip it is now possible to play multiple voices by playing them while preparing AudioSource.PlayOneShot audio data in . However, there is no limit to the number of games that can be played, so if you do not limit it during the game, a lot of sound may be played and a loud volume may be played.

Here I would like to create my own program and control the number of sound effects that can be played at the same time.

Create the sample

This time, the sound effect will play every time you click the button, so create the UI as shown in the figure. The details are appropriate and good.

Drop and add the audio file you want to play into your project.

Until last time, the standard function AudioSource of was added to the hierarchy, This time, we will add a script because we will put our own control. SoundPlayManager Leave the name as .

Create the script as follows:

using System.Collections.Generic;
using UnityEngine;

/// <summary>音声再生管理クラスです。</summary>
public class SoundPlayManager : MonoBehaviour
{
  /// <summary>1つの種類の音声の再生情報を保持するクラスです。</summary>
  private class PlayInfo
  {
    /// <summary>再生している AudioSource の一覧です。</summary>
    public AudioSource[] AudioSource { get; set; }

    /// <summary>現在の再生インデックスです。</summary>
    public int NowIndex { get; set; }
  }

  /// <summary>再生しようとしている音声データのキューです。</summary>
  private HashSet<AudioClip> Queue = new HashSet<AudioClip>();

  /// <summary>再生している音声を管理している一覧です。</summary>
  private Dictionary<AudioClip, PlayInfo> Sources = new Dictionary<AudioClip, PlayInfo>();

  /// <summary>
  /// 同一音声同時再生最大数。
  /// </summary>
  [SerializeField, Range(1, 32)] private int MaxSimultaneousPlayCount = 2;

  protected void Update()
  {
    foreach (var item in Queue)
    {
      AudioSource source;
      if (Sources.ContainsKey(item) == false)
      {
        // 一度も再生されていない Clip がある場合は PlayInfo を生成します
        var info = new PlayInfo()
        {
          AudioSource = new AudioSource[MaxSimultaneousPlayCount],
        };
        for (int i = 0; i < MaxSimultaneousPlayCount; i++)
        {
          var s = gameObject.AddComponent<AudioSource>();
          s.clip = item;
          info.AudioSource[i] = s;
        }
        Sources.Add(item, info);
        source = info.AudioSource[0];
      }
      else
      {
        // 再生に使用する AudioSource を順番に取得します
        var info = Sources[item];
        info.NowIndex = (info.NowIndex + 1) % MaxSimultaneousPlayCount;
        source = info.AudioSource[info.NowIndex];
      }

      source.Play();
    }
    Queue.Clear();
  }

  /// <summary>
  /// 効果音を再生します。
  /// </summary>
  public void Play(AudioClip clip)
  {
    // 同一フレームで複数再生しないようにすでにキューに入っているか確認します
    if (Queue.Contains(clip) == false)
    {
      Queue.Add(clip);
    }
  }

  public void OnDestroy()
  {
    // 不要になった参照をすべて外します
    foreach (var source in Sources)
    {
      source.Value.AudioSource = null;
    }
    Sources.Clear();
    Queue.Clear();
  }
}

Since the script is long, detailed explanation is omitted, but it has the following functions.

  • AudioClip You can play audio by passing
  • When the same type of audio is played on top of each other, if you try to play more than a certain number of voices, the old playback data stops (the initial value is up to 2 playbacks).
  • Overlapping playback at the same frame is not allowed

This prevents the volume from increasing when the same audio is played back-to-back. In terms of functionality, only the minimum is included, so please add it if you need it.

The script is attached to EventSystem.

Next, create a script for the button.

Create the script as follows:

using UnityEngine;

public class ButtonEvent : MonoBehaviour
{
  /// <summary>再生する音声データ。</summary>
  [SerializeField] private AudioClip AudioClip;

  /// <summary>自作した音声再生管理クラス。</summary>
  [SerializeField] private SoundPlayManager SoundPlayManager;

  /// <summary>ボタンをクリックしたとき。</summary>
  public void OnClick()
  {
    SoundPlayManager.Play(AudioClip);
  }
}

The playback process is done by the self-made SoundPlayManager oneself, so in the button event, just pass the audio data and play it.

The script is attached to EventSystem. Attach management is not the main topic of this Tips, so it is appropriate.

For the audio clip, set the audio file to be played. Set the Sound Play Manager to the SoundPlayManager object to which you are attaching. Since we are attaching to the EventSystem, we will set the EventSystem.

Finally, assign to the OnClick button click event.

Run the game when you're done. By default, the maximum number of simultaneous plays is set to 2, so please click the button again while two sounds are playing and make sure that the first sound disappears.

The program created this time has an upper limit on the number of playback times for each type of sound, so it sounds natural even if you interweave other sound effects. However, depending on the type of sound, the upper limit of 2 may not be enough, so it may be a good idea to be able to set an upper limit for each type of sound. Well, I don't know if there is such an opportunity to layer the sound, but ...