2024年1月3日发(作者:)
MemoryStream outputStream = new MemoryStream(); using (WaveFileWriter waveFileWriter = new WaveFileWriter(outputStream, rmat)) { byte[] bytes = new byte[]; on = 0; (bytes, 0, 32()); (bytes, 0, ); (); } return outputStream; }}public class WAV{ // convert two bytes to one float in the range -1 to 1 static float bytesToFloat(byte firstByte, byte secondByte) { // convert two bytes to one short (little endian) short s = (short)((secondByte << 8) | firstByte); // convert to range from -1 to (just below) 1 return s / 32768.0F; } static int bytesToInt(byte[] bytes, int offset = 0) { int value = 0; for (int i = 0; i < 4; i++) { value |= ((int)bytes[offset + i]) << (i * 8); } return value; } // properties public float[] LeftChannel { get; internal set; } public float[] RightChannel { get; internal set; } public int ChannelCount { get; internal set; } public int SampleCount { get; internal set; } public int Frequency { get; internal set; } public WAV(byte[] wav) { // Determine if mono or stereo ChannelCount = wav[22]; // Forget byte 23 as 99.999% of WAVs are 1 or 2 channels // Get the frequency Frequency = bytesToInt(wav, 24); // Get past all the other sub chunks to get to the data subchunk: int pos = 12; // First Subchunk ID from 12 to 16 // Keep iterating until we find the data chunk (i.e. 64 61 74 61 ...... (i.e. 100 97 116 97 in decimal)) while (!(wav[pos] == 100 && wav[pos + 1] == 97 && wav[pos + 2] == 116 && wav[pos + 3] == 97)) { pos += 4; int chunkSize = wav[pos] + wav[pos + 1] * 256 + wav[pos + 2] * 65536 + wav[pos + 3] * 16777216; pos += 4 + chunkSize; } pos += 8; // Pos is now positioned to start of actual sound data. SampleCount = ( - pos) / 2; // 2 bytes per sample (16 bit sound mono) if (ChannelCount == 2) SampleCount /= 2; // 4 bytes per sample (16 bit stereo)
/// ///
AudioClip audioClip = (name, , (int)channels, sampleRate, false); ("name:"+name); ("lengthSample:"+); ("Chanel"+channels); ("frequency:"+sampleRate); a (data, 0); return audioClip; } #region wav file bytes to Unity AudioClip conversion methods private static float[] Convert8BitByteArrayToAudioClipData (byte[] source, int headerOffset, int dataSize) { int wavSize = 32 (source, headerOffset); headerOffset += sizeof(int); Format (wavSize > 0 && wavSize == dataSize, "Failed to get valid 8-bit wav size: {0} from data bytes: {1} at offset: {2}", wavSize, dataSize, headerO float[] data = new float[wavSize]; sbyte maxValue = ue; int i = 0; while (i < wavSize) { data [i] = (float)source [i] / maxValue; ++i; } return data; } private static float[] Convert16BitByteArrayToAudioClipData (byte[] source, int headerOffset, int dataSize) { int wavSize = 32 (source, headerOffset); headerOffset += sizeof(int); Format (wavSize > 0 && wavSize == dataSize, "Failed to get valid 16-bit wav size: {0} from data bytes: {1} at offset: {2}", wavSize, dataSize, heade int x = sizeof(Int16); // block size = 2 int convertedSize = wavSize / x; float[] data = new float[convertedSize]; Int16 maxValue = ue; int offset = 0; int i = 0; while (i < convertedSize) { offset = i * x + headerOffset; data [i] = (float)16 (source, offset) / maxValue; ++i; } Format ( == convertedSize, "AudioClip .wav data is wrong size: {0} == {1}", , convertedSize); return data; } private static float[] Convert24BitByteArrayToAudioClipData (byte[] source, int headerOffset, int dataSize) { int wavSize = 32 (source, headerOffset); headerOffset += sizeof(int); Format (wavSize > 0 && wavSize == dataSize, "Failed to get valid 24-bit wav size: {0} from data bytes: {1} at offset: {2}", wavSize, dataSize, heade int x = 3; // block size = 3 int convertedSize = wavSize / x; int maxValue = ue;
int maxValue = ue; float[] data = new float[convertedSize]; byte[] block = new byte[sizeof(int)]; // using a 4 byte block for copying 3 bytes, then copy bytes with 1 offset int offset = 0; int i = 0; while (i < convertedSize) { offset = i * x + headerOffset; opy (source, offset, block, 1, x); data [i] = (float)32 (block, 0) / maxValue; ++i; } Format ( == convertedSize, "AudioClip .wav data is wrong size: {0} == {1}", , convertedSize); return data; } private static float[] Convert32BitByteArrayToAudioClipData (byte[] source, int headerOffset, int dataSize) { int wavSize = 32 (source, headerOffset); headerOffset += sizeof(int); Format (wavSize > 0 && wavSize == dataSize, "Failed to get valid 32-bit wav size: {0} from data bytes: {1} at offset: {2}", wavSize, dataSize, heade int x = sizeof(float); // block size = 4 int convertedSize = wavSize / x; Int32 maxValue = ue; float[] data = new float[convertedSize]; int offset = 0; int i = 0; while (i < convertedSize) { offset = i * x + headerOffset; data [i] = (float)32 (source, offset) / maxValue; ++i; } Format ( == convertedSize, "AudioClip .wav data is wrong size: {0} == {1}", , convertedSize); return data; } #endregion public static byte[] FromAudioClip (AudioClip audioClip) { string file; return FromAudioClip (audioClip, out file, false); } public static byte[] FromAudioClip (AudioClip audioClip, out string filepath, bool saveAsFile = true, string dirname = "recordings") { MemoryStream stream = new MemoryStream (); const int headerSize = 44; // get bit depth UInt16 bitDepth = 16; //BitDepth (audioClip); // NB: Only supports 16 bit //Format (bitDepth == 16, "Only converting 16 bit is currently supported. The audio clip data is {0} bit.", bitDepth);
// total file size = 44 bytes for header format and s * factor due to float to Int16 / sbyte conversion int fileSize = s * BlockSize_16Bit + headerSize; // BlockSize (bitDepth) // chunk descriptor (riff) WriteFileHeader (ref stream, fileSize); // file header (fmt) WriteFileFormat (ref stream, ls, ncy, bitDepth); // data chunks (data) WriteFileData (ref stream, audioClip, bitDepth); byte[] bytes = y (); // Validate total bytes Format ( == fileSize, "Unexpected AudioClip to wav format byte count: {0} == {1}", , fileSize); // Save file to persistant storage location if (saveAsFile) { filepath = ("{0}/{1}/{2}.{3}", tentDataPath, dirname, ng ("yyMMdd-HHmmss-fff"), "wav"); Directory (ectoryName (filepath)); llBytes (filepath, bytes); // ("Auto-saved .wav file: " + filepath); } else { filepath = null; } e (); return bytes; } #region write .wav file functions private static int WriteFileHeader (ref MemoryStream stream, int fileSize) { int count = 0; int total = 12; // riff chunk id byte[] riff = es ("RIFF"); count += WriteBytesToMemoryStream (ref stream, riff, "ID"); // riff chunk size int chunkSize = fileSize - 8; // total size - 8 for the other two fields in the header count += WriteBytesToMemoryStream (ref stream, es (chunkSize), "CHUNK_SIZE"); byte[] wave = es ("WAVE"); count += WriteBytesToMemoryStream (ref stream, wave, "FORMAT"); // Validate header Format (count == total, "Unexpected wav descriptor byte count: {0} == {1}", count, total); return count; } private static int WriteFileFormat (ref MemoryStream stream, int channels, int sampleRate, UInt16 bitDepth) { int count = 0; int total = 24; byte[] id = es ("fmt "); count += WriteBytesToMemoryStream (ref stream, id, "FMT_ID"); int subchunk1Size = 16; // 24 - 8 count += WriteBytesToMemoryStream (ref stream, es (subchunk1Size), "SUBCHUNK_SIZE");
UInt16 audioFormat = 1; count += WriteBytesToMemoryStream (ref stream, es (audioFormat), "AUDIO_FORMAT"); UInt16 numChannels = 16 (channels); count += WriteBytesToMemoryStream (ref stream, es (numChannels), "CHANNELS"); count += WriteBytesToMemoryStream (ref stream, es (sampleRate), "SAMPLE_RATE"); int byteRate = sampleRate * channels * BytesPerSample (bitDepth); count += WriteBytesToMemoryStream (ref stream, es (byteRate), "BYTE_RATE"); UInt16 blockAlign = 16 (channels * BytesPerSample (bitDepth)); count += WriteBytesToMemoryStream (ref stream, es (blockAlign), "BLOCK_ALIGN"); count += WriteBytesToMemoryStream (ref stream, es (bitDepth), "BITS_PER_SAMPLE"); // Validate format Format (count == total, "Unexpected wav fmt byte count: {0} == {1}", count, total); return count; } private static int WriteFileData (ref MemoryStream stream, AudioClip audioClip, UInt16 bitDepth) { int count = 0; int total = 8; // Copy float[] data from AudioClip float[] data = new float[s * ls]; a (data, 0); byte[] bytes = ConvertAudioClipDataToInt16ByteArray (data); byte[] id = es ("data"); count += WriteBytesToMemoryStream (ref stream, id, "DATA_ID"); int subchunk2Size = 32 (s * BlockSize_16Bit); // BlockSize (bitDepth) count += WriteBytesToMemoryStream (ref stream, es (subchunk2Size), "SAMPLES"); // Validate header Format (count == total, "Unexpected wav data id byte count: {0} == {1}", count, total); // Write bytes to stream count += WriteBytesToMemoryStream (ref stream, bytes, "DATA"); // Validate audio data Format ( == subchunk2Size, "Unexpected AudioClip to wav subchunk2 size: {0} == {1}", , subchunk2Size); return count; } private static byte[] ConvertAudioClipDataToInt16ByteArray (float[] data) { MemoryStream dataStream = new MemoryStream (); int x = sizeof(Int16); Int16 maxValue = ue; int i = 0; while (i < ) { (es (16 (data [i] * maxValue)), 0, x); ++i; } byte[] bytes = y ();
byte[] bytes = y (); // Validate converted bytes Format ( * x == , "Unexpected float[] to Int16 to byte[] size: {0} == {1}", * x, ); e (); return bytes; } private static int WriteBytesToMemoryStream (ref MemoryStream stream, byte[] bytes, string tag = "") { int count = ; (bytes, 0, count); //mat ("WAV:{0} wrote {1} bytes.", tag, count); return count; } #endregion ///
发布评论