GitHub项目:Epitome.Audio音频模块
使用delegate委托:音频加载完成进行回调
namespace Epitome
{
public delegate void AudioClipLoadFinish(AudioClip clip);
public static class AudioLoad
{
public static IEnumerator Load(string url, AudioClipLoadFinish finish)
{
WWW www = new WWW("file://" + url);
yield return www;
finish(www.GetAudioClip());
}
}
}
使用案列:
public AudioSource accompany;
private void Start()
{
// 加载音频
StartCoroutine(AudioLoad.Load("filepath", AudioClipLoadFinish));
}
public void AudioClipLoadFinish(AudioClip clip)
{
accompany.clip = clip;
accompany.Paly();
}
NAudio是Mark Heath编写的开源.NET音频库
GitHub:NAudio项目
NAudio是个相对成熟、开源的C#音频开发工具,它包含录音、播放录音、格式转换、混音调整等功能。
namespace Epitome
{
public static class AudioConverter
{
///
/// MP3文件转WAV文件
///
/// MP3文件读取路径
/// WAV文件保存路径
public static void MP3TurnWAV(string filePath, string savePath)
{
using (FileStream stream = File.Open(filePath, FileMode.Open))
{
Mp3FileReader reader = new Mp3FileReader(stream);
WaveFileWriter.CreateWaveFile(savePath, reader);
}
}
public static void MP3TurnWAV(string filePath, string savePath, List<string> fileNames)
{
List<string> strs = Project.DirectoryAllFileNames(filePath, new List<string>() { "mp3" });
if (strs != null)
{
string targetFilePath, saveFilePath;
for (int j = 0; j < strs.Count; j++)
{
targetFilePath = filePath + "/" + strs[j];
saveFilePath = savePath + "/" + strs[j].Substring(0, strs[j].Length - 3) + "wav";
MP3TurnWAV(targetFilePath, saveFilePath);
}
#if UNITY_EDITOR
AssetDatabase.Refresh();
#endif
}
}
}
}
使用案列:
EditorExtension.GetSelectionPath:获取编辑器选择的目标路径,获取该路径下的MP3音频文件
通过拼接音频文件路径,调用MP3TurnWAV生成WAV音频文件
///
/// MP3文件转WAV文件
///
[MenuItem("Epitome/Audio/MP3TurnWAV")]
[MenuItem("Assets/Epitome/Audio/MP3TurnWAV")]
private static void MP3TurnWAV()
{
List<string> paths = EditorExtension.GetSelectionPath();
for (int i = 0; i < paths.Count; i++)
{
if (Directory.Exists(paths[i]))
{
string rootPath = ProjectPath.GetDataPath.Substring(0, ProjectPath.GetDataPath.Length - 6);
DirectoryInfo info = new DirectoryInfo(rootPath + paths[i]);
string savePath = info.FullName + "_WAV";
Project.CreateDirectory(savePath);
List<string> strs = Project.DirectoryAllFileNames(info.FullName, new List<string>() { "mp3" });
AudioConverter.MP3TurnWAV(info.FullName, savePath, strs);
}
}
}
///
/// 剪切空白部分
///
public static AudioClip CutBlankSection(AudioClip audioClip, int time, int samplingRate)
{
float[] samples_one = new float[audioClip.samples];
audioClip.GetData(samples_one, 0);
float[] samples_two = new float[time * samplingRate];
Array.Copy(samples_one, 0, samples_two, 0, time * samplingRate);
AudioClip newAudioClip = AudioClip.Create(audioClip.name, samplingRate * time, 1, samplingRate, false);
newAudioClip.SetData(samples_two, 0);
return newAudioClip;
}
audioLength//秒单位
frequency = 44100;
AudioClip audioClip = AudioClips.CutBlankSection(recording.clip, audioLength, frequency);
///
/// 修剪Wav文件
///
/// 修剪文件路径
/// 保存文件路径
/// 开始间隔
/// 结束间隔
public static void TrimWavFile(string filePath, string savePath, TimeSpan cutFromStart, TimeSpan cutFromEnd)
{
using (WaveFileReader reader = new WaveFileReader(filePath))
{
using (WaveFileWriter writer = new WaveFileWriter(savePath, reader.WaveFormat))
{
int bytesPerMillisecond = reader.WaveFormat.AverageBytesPerSecond / 1000;
int startPos = (int)cutFromStart.TotalMilliseconds * bytesPerMillisecond;
startPos = startPos - startPos % reader.WaveFormat.BlockAlign;
int endBytes = (int)cutFromEnd.TotalMilliseconds * bytesPerMillisecond;
endBytes = endBytes - endBytes % reader.WaveFormat.BlockAlign;
int endPos = (int)reader.Length - endBytes;
TrimWavFile(reader, writer, startPos, endPos);
}
}
}
///
/// 修剪Wav文件
///
private static void TrimWavFile(WaveFileReader reader, WaveFileWriter writer, int startPos, int endPos)
{
reader.Position = startPos;
byte[] buffer = new byte[1024];
while (reader.Position < endPos)
{
int bytesRequired = (int)(endPos - reader.Position);
if (bytesRequired > 0)
{
int bytesToRead = Math.Min(bytesRequired, buffer.Length);
int bytesRead = reader.Read(buffer, 0, bytesToRead);
if (bytesRead > 0)
{
writer.Write(buffer, 0, bytesRead);
}
}
}
}
namespace Epitome
{
public static class AudioMixer
{
///
/// 音频混合(混音)
///
/// 音频文件路径
/// 音频文件路径
/// 混合音频文件路径
public static void AudioMixing(string filePath1, string filePath2,string mixedPath)
{
using (var reader1 = new AudioFileReader(filePath1))
using (var reader2 = new AudioFileReader(filePath2))
{
var mixer = new MixingSampleProvider(new[] { reader1, reader2 });
WaveFileWriter.CreateWaveFile16(mixedPath, mixer);
}
}
}
}
使用案列:
// 伴奏混合原声
AudioMixer.AudioMixing(accompanyClipPath, originalPath, finalPath);
///
/// 合并音频
///
public static AudioClip MergeAudio(int interval, params AudioClip[] clips)
{
if (clips == null || clips.Length == 0)
return null;
int channels = clips[0].channels;
int frequency = clips[0].frequency;
using (MemoryStream memoryStream = new MemoryStream())
{
for (int i = 0; i < clips.Length; i++)
{
if (clips[i] == null)
continue;
clips[i].LoadAudioData();
var buffer = clips[i].GetData();
memoryStream.Write(buffer, 0, buffer.Length);
if (clips.Length - 1 == i)
continue;
byte[] byteClips = new byte[clips[i].frequency * clips[i].channels * 4 * interval];//合并音频间的间隔
memoryStream.Write(byteClips, 0, byteClips.Length);
}
var bytes = memoryStream.ToArray();
var result = AudioClip.Create("Merge", bytes.Length / 4 / channels, channels, 44100, false);
result.SetData(bytes);
return result;
}
}