📜  unity soundclip mix - C# (1)

📅  最后修改于: 2023-12-03 15:20:52.430000             🧑  作者: Mango

Unity SoundClip Mix - C#

Introduction

Unity SoundClip Mix is a C# program that allows you to mix multiple audio clips into a single audio clip in Unity. This program is useful for creating background music or sound effects for your games or applications.

Features
  • Mix multiple audio clips
  • Adjust the volume of each clip
  • Export the mixed audio clip as a .wav file
Usage

To use Unity SoundClip Mix, simply attach the SoundClipMix script to an empty GameObject in your Unity scene. Then, drag and drop the audio clips you want to mix into the AudioClip array in the inspector.

To adjust the volume of each clip, use the Volume array in the inspector to set the volume of each clip. The values in the Volume array should correspond to the order of the audio clips in the AudioClip array.

Once you have added your audio clips and adjusted the volumes, press the Mix button in the inspector to mix the audio clips into a single audio clip. The mixed audio clip will be saved as a .wav file in the root directory of your Unity project.

Code
using UnityEngine;
using System.IO;

public class SoundClipMix : MonoBehaviour
{
    public AudioClip[] AudioClip;  //Array to hold audio clips
    public float[] Volume;  //Array to hold volume for each clip

    [SerializeField] private string _fileName = "MixedAudioClip";  //Name of exported file

    private void Start()
    {
        Mix();
    }

    private void Mix()
    {
        if (AudioClip.Length == 0) return;

        int length = AudioClip[0].samples;  //Get sample length of first clip
        int numChannels = AudioClip[0].channels;  //Get number of channels of first clip

        //Get sample length of longest clip
        for (int i = 1; i < AudioClip.Length; i++)
        {
            if (AudioClip[i].samples > length)
            {
                length = AudioClip[i].samples;
            }
        }

        //Create float arrays to hold samples of each clip
        float[][] samples = new float[AudioClip.Length][];
        for (int i = 0; i < AudioClip.Length; i++)
        {
            samples[i] = new float[length * numChannels];
        }

        //Get samples from each clip and adjust volume
        for (int i = 0; i < AudioClip.Length; i++)
        {
            float[] tmpSamples = new float[AudioClip[i].samples * numChannels];
            AudioClip[i].GetData(tmpSamples, 0);

            for (int j = 0; j < tmpSamples.Length; j++)
            {
                samples[i][j] = tmpSamples[j] * Volume[i];
            }
        }

        //Mix samples together
        float[] mixedSamples = new float[length * numChannels];
        for (int i = 0; i < length * numChannels; i++)
        {
            float sum = 0f;
            for (int j = 0; j < samples.Length; j++)
            {
                if (i < samples[j].Length) sum += samples[j][i];
            }
            mixedSamples[i] = sum;
        }

        //Create new audio clip with mixed samples
        AudioClip mixedClip = AudioClip.Create(_fileName, 
                                                length, 
                                                numChannels, 
                                                AudioClip[0].frequency, 
                                                false);
        mixedClip.SetData(mixedSamples, 0);

        //Export mixed audio clip as .wav file
        using (FileStream fileStream = CreateEmpty(_fileName))
        {
            ConvertAndWrite(fileStream, mixedClip);
            WriteHeader(fileStream, mixedClip);
        }
    }

    //Helper function to create empty .wav file
    private FileStream CreateEmpty(string filepath)
    {
        FileStream fileStream = new FileStream(filepath + ".wav", FileMode.Create);
        byte emptyByte = new byte();

        for (int i = 0; i < 44; i++) //Write header
        {
            fileStream.WriteByte(emptyByte);
        }

        return fileStream;
    }

    //Helper function to convert audio clip to byte array
    private void ConvertAndWrite(FileStream fileStream, AudioClip clip)
    {
        float[] samples = new float[clip.samples];
        clip.GetData(samples, 0);

        Int16[] intData = new Int16[samples.Length];
        Byte[] bytesData = new Byte[samples.Length * 2];

        for (int i = 0; i < samples.Length; i++)
        {
            intData[i] = (short)(samples[i] * 32767f);
            Byte[] byteArr = new Byte[2];
            byteArr = BitConverter.GetBytes(intData[i]);
            byteArr.CopyTo(bytesData, i * 2);
        }

        fileStream.Write(bytesData, 0, bytesData.Length);
    }

    //Helper function to write .wav header
    private void WriteHeader(FileStream fileStream, AudioClip clip)
    {
        int hz = clip.frequency;
        int channels = clip.channels;
        int samples = clip.samples;

        fileStream.Seek(0, SeekOrigin.Begin);
        Byte[] riff = System.Text.Encoding.UTF8.GetBytes("RIFF");
        fileStream.Write(riff, 0, 4);
        Byte[] chunkSize = BitConverter.GetBytes(fileStream.Length - 8);
        fileStream.Write(chunkSize, 0, 4);
        Byte[] wave = System.Text.Encoding.UTF8.GetBytes("WAVE");
        fileStream.Write(wave, 0, 4);
        Byte[] fmt = System.Text.Encoding.UTF8.GetBytes("fmt ");
        fileStream.Write(fmt, 0, 4);
        Byte[] subChunk1 = BitConverter.GetBytes(16);
        fileStream.Write(subChunk1, 0, 4);
        UInt16 one = 1;
        Byte[] audioFormat = BitConverter.GetBytes(one);
        fileStream.Write(audioFormat, 0, 2);
        Byte[] numChannels = BitConverter.GetBytes(channels);
        fileStream.Write(numChannels, 0, 2);
        Byte[] sampleRate = BitConverter.GetBytes(hz);
        fileStream.Write(sampleRate, 0, 4);
        Byte[] byteRate = BitConverter.GetBytes(hz * channels * 2); // sampleRate * bytesPerSample*number of channels
        fileStream.Write(byteRate, 0, 4);
        UInt16 blockAlign = (ushort)(channels * 2);
        fileStream.Write(BitConverter.GetBytes(blockAlign), 0, 2);
        UInt16 bps = 16;
        Byte[] bitsPerSample = BitConverter.GetBytes(bps);
        fileStream.Write(bitsPerSample, 0, 2);
        Byte[] data = System.Text.Encoding.UTF8.GetBytes("data");
        fileStream.Write(data, 0, 4);
        Byte[] subChunk2 = BitConverter.GetBytes(samples * channels * 2);
        fileStream.Write(subChunk2, 0, 4);
    }
}
Conclusion

Unity SoundClip Mix is a simple yet powerful tool for mixing audio clips in Unity. With its easy-to-use interface and flexible features, you can create high quality background music and sound effects for your games and applications.