Skip to content

Instantly share code, notes, and snippets.

@Vanlalhriata
Created July 18, 2022 16:38
Show Gist options
  • Save Vanlalhriata/c73273ead6afd6cb7a89c2c0addfd2c5 to your computer and use it in GitHub Desktop.
Save Vanlalhriata/c73273ead6afd6cb7a89c2c0addfd2c5 to your computer and use it in GitHub Desktop.
Generate a timmed and fading audio wav file from an AudioClip in Unity3D
using System.IO;
using System.Linq;
using UnityEngine;
// Generate a preview audio file (.wav) from an AudioClip.
// This uses SavWav forked and modified from darktable:
// https://gist.github.com/Vanlalhriata/dc5b703cca6f2e885557e1c2f54c376a
public static class PreviewAudioUtil
{
private const string PREVIEW_AUDIO_FILENAME = "Preview";
private const string PREVIEW_AUDIO_EXTENSION = ".wav";
private const float PREVIEW_DURATION_SECONDS = 20f;
private const float FADE_SECONDS = 2f;
public static void GeneratePreviewAudioFile(AudioClip sourceClip, string folderPath)
{
if (null == sourceClip)
{
Debug.LogError($"PreviewAudioUtil: sourceClip is null.");
return;
}
// NOTE: Using random part of the clip for now. may want to let user choose the preview window
var startTime = getRandomPreviewStartTime(sourceClip.length);
var previewAudioClip = trimAndFade(sourceClip, startTime, PREVIEW_DURATION_SECONDS);
if (null == previewAudioClip) return;
var filePath = Path.Combine(folderPath, PREVIEW_AUDIO_FILENAME + PREVIEW_AUDIO_EXTENSION);
var isSucess = SavWav.Save(filePath, previewAudioClip);
if (!isSucess)
{
Debug.LogError("PreviewAudioUtil: Error writing preview audio to file.");
}
}
private static float getRandomPreviewStartTime(float clipLengthSeconds)
{
if (clipLengthSeconds <= PREVIEW_DURATION_SECONDS)
{
return clipLengthSeconds;
}
// Start from anywhere between 0 and preview-length seconds before the end
return Random.Range(0, clipLengthSeconds - PREVIEW_DURATION_SECONDS);
}
// Trim an audioClip into the specified duration starting from startTime. Also fades in and out
private static AudioClip trimAndFade(AudioClip sourceClip, float startTime, float durationSeconds)
{
// Get samples starting from startTime
int sampleOffset = Mathf.RoundToInt(startTime * sourceClip.frequency); // No need to multiply by channel count
var samples = new float[sourceClip.samples * sourceClip.channels];
bool isGetSuccessful = sourceClip.GetData(samples, sampleOffset);
if (!isGetSuccessful)
{
Debug.LogError("PreviewAudioUtil: Could not get samples from main AudioClip.");
return null;
}
// Get the samples making up the required duration
var samplesCount = Mathf.CeilToInt(durationSeconds * sourceClip.frequency * sourceClip.channels);
samples = samples.Take(samplesCount).ToArray();
samples = fadeSamples(samples, sourceClip.frequency, sourceClip.channels);
var previewAudioClip = AudioClip.Create(PREVIEW_AUDIO_FILENAME, samples.Length / 2, sourceClip.channels, sourceClip.frequency, false);
previewAudioClip.SetData(samples, 0);
return previewAudioClip;
}
// Apply fade-in and fade-out
private static float[] fadeSamples(float[] samples, int frequency, int channelCount)
{
// Just fade, without caring for uniform fade for each channel
var fadeInToSample = Mathf.RoundToInt(FADE_SECONDS * frequency * channelCount);
var fadeOutFromSample = samples.Length - fadeInToSample;
var fadeStep = 1f / fadeInToSample;
int i;
for (i = 0; i < fadeInToSample; i++)
{
samples[i] *= i * fadeStep; // Linear fade
}
for (i = fadeOutFromSample; i < samples.Length; i++)
{
samples[i] *= (samples.Length - i) * fadeStep; // Linear fade
}
return samples;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment