所以问题是我想从Audioclip创建一个.wav文件,但我无法弄清楚如何做到这一点。我一直在寻找.wav文件结构是如何但我无法理解它我想要的(我也不知道如何从Audioclip获取所有数据并将其转换为字节并设置它到文件)。
这是我到目前为止所尝试的内容:
public static bool ToWAV(this AudioClip audio, string path)
{
try
{
int samples = audio.samples;
int channels = audio.channels;
int sampleRate = audio.frequency;
FileStream stream = new FileStream(path, FileMode.OpenOrCreate);
BinaryWriter bw = new BinaryWriter(stream);
//RIFF HEADER
bw.Write(System.Text.Encoding.ASCII.GetBytes("RIFF"));
bw.Write(36 + samples * channels);
bw.Write(System.Text.Encoding.ASCII.GetBytes("WAVE"));
//FMT SUBCHUNK
bw.Write(System.Text.Encoding.ASCII.GetBytes("fmt "));
bw.Write(16); //Chunk size
bw.Write(1); //Compression
bw.Write(channels); //Num Channels
bw.Write(sampleRate); //SampleRate
bw.Write(sampleRate * channels); //ByteRate
bw.Write(channels); //BlockAlign
bw.Write(8); //BitsPerSample
//DATA SUBCHUNK
bw.Write(System.Text.Encoding.ASCII.GetBytes("data"));
bw.Write(samples * channels); //Chunk size
float[] data = new float[audio.samples * audio.channels];
audio.GetData(data, 0);
for (int d = 0; d < data.Length; d++)
{
bw.Write((byte)data[d]);
}
return true;
}
catch (System.Exception e)
{
Debug.LogError("Failed to create .WAV at: " + path + " - Error: " + e.Message);
return false;
}
}
答案 0 :(得分:1)
这里的问题是浮点数据的范围是-1..1,而您只是将其强制转换为每个样本8位的字节,这意味着您将主要获得零数据。您需要重新缩放以占据全部可用的数字范围,这对于8位(有符号)表示-128..127 ...
尝试在写入时乘以127并转换为sbyte。
此外,我相信PCM多通道WAV文件是交错的。因此,将来自一个通道的所有数据然后放入来自另一个通道的所有数据(因为它们存储在内存中)将不起作用。实际上,您必须在通道之间交替字节。
答案 1 :(得分:0)
我今天才把这个编码好玩了。我发现其他人也想进行转换。这就是我遇到您的帖子的方式。这可能有些棘手,但您需要遵循指南here。规范非常挑剔,您需要按照规范中要求的正确字节序写入数据。这是我的代码,将从AudioClip转换为16位PCM Wave文件格式(注意:我仅在麦克风的单通道音频上对其进行了测试;也许其他人可以仔细检查是否为多个渠道工作,因为我怀疑赔率看起来很有希望,或者您可以进行调整并相应地进行调整):
void ExportClipData(AudioClip clip)
{
var data = new float[clip.samples * clip.channels];
clip.GetData(data, 0);
var path = Path.Combine(Application.persistentDataPath, "Recording.wav");
using (var stream = new FileStream(path, FileMode.CreateNew, FileAccess.Write))
{
// The following values are based on http://soundfile.sapp.org/doc/WaveFormat/
var bitsPerSample = (ushort)16;
var chunkID = "RIFF";
var format = "WAVE";
var subChunk1ID = "fmt ";
var subChunk1Size = (uint)16;
var audioFormat = (ushort)1;
var numChannels = (ushort)clip.channels;
var sampleRate = (uint)clip.frequency;
var byteRate = (uint)(sampleRate * clip.channels * bitsPerSample / 8); // SampleRate * NumChannels * BitsPerSample/8
var blockAlign = (ushort)(numChannels * bitsPerSample / 8); // NumChannels * BitsPerSample/8
var subChunk2ID = "data";
var subChunk2Size = (uint)(data.Length * clip.channels * bitsPerSample / 8); // NumSamples * NumChannels * BitsPerSample/8
var chunkSize = (uint)(36 + subChunk2Size); // 36 + SubChunk2Size
// Start writing the file.
WriteString(stream, chunkID);
WriteInteger(stream, chunkSize);
WriteString(stream, format);
WriteString(stream, subChunk1ID);
WriteInteger(stream, subChunk1Size);
WriteShort(stream, audioFormat);
WriteShort(stream, numChannels);
WriteInteger(stream, sampleRate);
WriteInteger(stream, byteRate);
WriteShort(stream, blockAlign);
WriteShort(stream, bitsPerSample);
WriteString(stream, subChunk2ID);
WriteInteger(stream, subChunk2Size);
foreach (var sample in data)
{
// De-normalize the samples to 16 bits.
var deNormalizedSample = (short)0;
if (sample > 0)
{
var temp = sample * short.MaxValue;
if (temp > short.MaxValue)
temp = short.MaxValue;
deNormalizedSample = (short)temp;
}
if (sample < 0)
{
var temp = sample * (-short.MinValue);
if (temp < short.MinValue)
temp = short.MinValue;
deNormalizedSample = (short)temp;
}
WriteShort(stream, (ushort)deNormalizedSample);
}
}
}
void WriteString(Stream stream, string value)
{
foreach (var character in value)
stream.WriteByte((byte)character);
}
void WriteInteger(Stream stream, uint value)
{
stream.WriteByte((byte)(value & 0xFF));
stream.WriteByte((byte)((value >> 8) & 0xFF));
stream.WriteByte((byte)((value >> 16) & 0xFF));
stream.WriteByte((byte)((value >> 24) & 0xFF));
}
void WriteShort(Stream stream, ushort value)
{
stream.WriteByte((byte)(value & 0xFF));
stream.WriteByte((byte)((value >> 8) & 0xFF));
}