Unity音频剪辑工具的实现

在游戏开发中,音频是一个至关重要的元素。音频剪辑工具能够帮助开发者高效地编辑和管理音频文件。本文将解析一个基于Unity编辑器的音频剪辑工具的实现方法

效果

在这里插入图片描述

工具功能

该音频剪辑工具允许用户在Unity编辑器中加载音频片段,并通过图形化界面进行剪辑、预览和保存操作。以下是该工具的主要功能:

  • 加载音频片段:用户可以通过工具界面选择并加载音频文件。
  • 波形显示:工具会生成音频的波形图,以帮助用户可视化音频数据。
  • 剪辑操作:用户可以通过滑动条调整音频的起始和结束时间,以便进行剪辑。
  • 音量控制:提供音量滑块,用户可以调整音频播放的音量。
  • 预览播放:用户可以播放剪辑后的音频片段进行预览。
  • 保存剪辑结果:工具支持将剪辑后的音频片段保存为新的音频文件。

代码解析

1. 显示工具窗口

首先,工具通过[MenuItem(“Tools/音频剪辑工具”)]创建一个菜单项,点击该菜单项可以显示音频编辑器窗口。
[MenuItem("Tools/音频剪辑工具")]
public static void ShowWindow()
{
    GetWindow<AudioClipEditor>("音频编辑器");
}

2. 初始化音频资源

在OnEnable方法中,工具创建了一个隐藏的AudioSource用于播放音频。
private void OnEnable()
{
    audioSource = EditorUtility.CreateGameObjectWithHideFlags("AudioSource" , HideFlags.HideAndDontSave , typeof(AudioSource)).GetComponent<AudioSource>();
}

3. 用户界面

工具通过OnGUI方法绘制用户界面,用户可以选择音频文件并进行编辑操作。
private void OnGUI()
{
    EditorGUILayout.BeginVertical();

    audioClip = EditorGUILayout.ObjectField("声音片段" , audioClip , typeof(AudioClip) , false) as AudioClip;
    if (audioClipTemp != audioClip)
    {
        audioClipTemp = audioClip;
        Init();
    }

    if (audioClip)
    {
        DisplayAudioClipInfo();
        AdjustClipSection();
        DisplayVolumeControl();

        GUILayout.Space(10);

        if (GUILayout.Button("听" , GUILayout.Height(40)))
        {
            PlayTestAudio();
        }

        GUILayout.Space(10);

        if (GUILayout.Button("保存片段" , GUILayout.Height(40)))
        {
            ClipAndSave();
        }
    }

    EditorGUILayout.EndVertical();
}

4. 初始化和显示音频信息

Init方法负责加载音频数据并生成波形图,DisplayAudioClipInfo方法显示音频的基本信息。
private void Init()
{
    if (audioClip != null)
    {
        endTime = audioClip.length;
        samples = new float[audioClip.samples * audioClip.channels];
        audioClip.GetData(samples , 0);
        UpdateWaveformTexture();
    }
}

private void DisplayAudioClipInfo()
{
    EditorGUILayout.LabelField($"开始时间: {startTime:F2}s");
    EditorGUILayout.LabelField($"结束时间: {endTime:F2}s");

    GUILayout.Space(10);
}

5. 剪辑和预览功能

工具通过AdjustClipSection方法调整剪辑区间,通过PlayTestAudio方法进行预览播放。
private void AdjustClipSection()
{
    GUILayout.Label("调整剪辑片段");

    Rect waveformRect = GUILayoutUtility.GetRect(position.width , 64);
    if (waveformTexture == null || waveformTexture.width != (int)waveformRect.width)
    {
        UpdateWaveformTexture();
    }

    if (waveformTexture != null)
    {
        EditorGUI.DrawPreviewTexture(waveformRect , waveformTexture);
    }

    EditorGUILayout.MinMaxSlider("" , ref startTime , ref endTime , 0f , audioClip != null ? audioClip.length : 10f);
}

private void PlayTestAudio()
{
    if (audioClip != null)
    {
        AudioClip clippedAudioClip = ClipAudio(audioClip , startTime , endTime);
        audioSource.clip = clippedAudioClip;
        audioSource.volume = volume;
        audioSource.Play();
    }
    else
    {
        Debug.LogError("请指定一段音频");
    }
}

6. 保存剪辑后的音频

ClipAndSave方法允许用户将剪辑后的音频片段保存到文件。
private void ClipAndSave()
{
    if (audioClip != null)
    {
        AudioClip clippedAudioClip = ClipAudio(audioClip , startTime , endTime);
        string savePath = EditorUtility.SaveFilePanel("保存剪辑的音频" , "Assets" , audioClipTemp.name + "_New" , "wav");

        if (!string.IsNullOrEmpty(savePath))
        {
            SaveAudioClipToFile(clippedAudioClip , savePath);
        }
    }
    else
    {
        Debug.LogError("请指定一段音频");
    }
}

7. 波形图生成

UpdateWaveformTexture方法更新波形图,GenerateWaveformTexture方法生成音频波形图像。
private void UpdateWaveformTexture()
{
    if (samples != null)
    {
        waveformTexture = GenerateWaveformTexture(samples , audioClip.channels , (int)position.width , 64);
    }
}

private Texture2D GenerateWaveformTexture(float[] samples , int channels , int width , int height)
{
    Texture2D texture = new Texture2D(width , height , TextureFormat.RGBA32 , false);
    Color[] colors = new Color[width * height];
    for (int i = 0; i < colors.Length; i++)
    {
        colors[i] = Color.black;
    }
    texture.SetPixels(colors);

    int packSize = ( samples.Length / channels ) / width;
    for (int x = 0; x < width; x++)
    {
        float max = 0;
        for (int i = 0; i < packSize; i++)
        {
            float sampleValue = samples[( x * packSize + i ) * channels] * volume;
            if (sampleValue > max) max = sampleValue;
        }
        int heightValue = (int)( max * height );
        for (int y = 0; y < heightValue; y++)
        {
            texture.SetPixel(x , y , Color.yellow);
        }
    }
    texture.Apply();
    return texture;
}

8. 剪辑音频片段

ClipAudio方法根据用户指定的起始和结束时间剪辑音频片段,并返回新的AudioClip。
private AudioClip ClipAudio(AudioClip originalClip , float start , float end)
{
    float[] data = new float[originalClip.samples * originalClip.channels];
    originalClip.GetData(data , 0);

    int newSampleCount = (int)( ( end - start ) * originalClip.frequency );
    float[] newData = new float[newSampleCount * originalClip.channels];

    int startIndex = (int)( start * originalClip.frequency * originalClip.channels );
    for (int i = 0; i < newSampleCount * originalClip.channels; i++)
    {
        newData[i] = data[startIndex + i] * volume;
    }

    AudioClip clippedAudioClip = AudioClip.Create("ClippedAudio" , newSampleCount , originalClip.channels , originalClip.frequency , false);
    clippedAudioClip.SetData(newData , 0);

    return clippedAudioClip;
}

我为什么要使用?

  • 用户友好:工具通过图形化界面,使得音频剪辑操作直观易用,即使对非程序员用户也非常友好。
  • 实时预览:用户可以即时预览剪辑后的音频片段,方便进行调整。
  • 高效:工具内嵌于Unity编辑器中,无需切换应用程序,提升了开发效率。
  • 灵活性:提供音量控制功能,用户可以根据需求调整音量,确保最终效果符合预期。
  • 便捷保存:工具支持将剪辑后的音频片段保存为文件,便于后续使用和管理。
通过实现这个音频剪辑工具,我们可以看到在Unity中集成自定义工具的强大功能。它不仅提升了工作效率,也为开发者提供了更多的创作自由。希望本文对你理解和实现类似的工具有所帮助。

虽然文章写的已经够详细了,但是还是放出来 Demo吧,我知道大家都很忙,直接用一个工具挺好的~

有时间一定回来看看具体实现,学会写一些小工具来提升自己的开发效率,一起加油!

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐