C# - воспроизведение WAV-файла из потока
Эй, ребята, я немного поэкспериментировал с WAV-файлами, и мне нужно иметь возможность воспроизводить WAV-файл из потока. То, что я собираюсь сделать, - это открыть файл, получить необработанные данные wav-файла. Я делаю это с помощью этого класса, предоставленного NightFox:
http://www.codeproject.com/KB/audio-video/CSharpWAVClassAndMixing.aspx
Затем, когда у меня есть необработанные данные, я извлекаю их с помощью встроенной функции WAVFile GetNextSampleAs16Bit().
Вот класс, который я сделал:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; // I want to be able to input a list of shorts, and it will give me // a playable stream internal wav file. namespace Aurasen { class InternalWAVFile { private MemoryStream mMemoryStream; private bool mStereo; private int mSampleRateHz; private short mBitsPerSample; private int mDataSizeBytes; public InternalWAVFile(short[] samples, bool pStereo, int pSampleRateHz, short pBitsPerSample) { if (mMemoryStream != null) { mMemoryStream.Close(); mMemoryStream.Dispose(); mMemoryStream = null; } mMemoryStream = new MemoryStream(); mStereo = pStereo; mSampleRateHz = pSampleRateHz; mBitsPerSample = pBitsPerSample; Create(); foreach (short s in samples) { byte[] buffer = BitConverter.GetBytes(s); if (!BitConverter.IsLittleEndian) Array.Reverse(buffer); AddSample_ByteArray(buffer); } mMemoryStream.Close(); } public MemoryStream GetStream() { return mMemoryStream; } private void AddSample_ByteArray(byte[] pSample) { try { int numBytes = pSample.GetLength(0); mMemoryStream.Write(pSample, 0, numBytes); } catch { } } // Adds the header to the memory stream so that now I can add the data private void Create() { try { // set the member data from the params byte mNumChannels = mStereo ? (byte)2 : (byte)1; char[] mWAVHeader = new char[4]; char[] mRIFFType = new char[4]; "RIFF".CopyTo(0, mWAVHeader, 0, 4); "WAVE".CopyTo(0, mRIFFType, 0, 4); // RIFF chunk (12 bytes total) // Write the chunk IDD ("RIFF", 4 bytes) byte[] buffer = StrToByteArray("RIFF"); mMemoryStream.Write(buffer, 0, 4); // gets stuck here..won't write to the stream if (mWAVHeader == null) mWAVHeader = new char[4]; "RIFF".CopyTo(0, mWAVHeader, 0, 4); // File size size (4 bytes) - This will be 0 for now Array.Clear(buffer, 0, buffer.GetLength(0)); mMemoryStream.Write(buffer, 0, 4); // RIFF type ("WAVE") buffer = StrToByteArray("WAVE"); mMemoryStream.Write(buffer, 0, 4); if (mRIFFType == null) mRIFFType = new char[4]; "WAVE".CopyTo(0, mRIFFType, 0, 4); // Format chunk (24 bytes total) // "fmt " (ASCII characters) buffer = StrToByteArray("fmt "); mMemoryStream.Write(buffer, 0, 4); // Length of format chunk (always 16, 4 bytes) Array.Clear(buffer, 0, buffer.GetLength(0)); buffer[0] = 16; if (!BitConverter.IsLittleEndian) Array.Reverse(buffer); mMemoryStream.Write(buffer, 0, 4); // 2 bytes (always 1) Array.Clear(buffer, 0, buffer.GetLength(0)); buffer[0] = 1; if (!BitConverter.IsLittleEndian) Array.Reverse(buffer, 0, 2); mMemoryStream.Write(buffer, 0, 2); // # of channels (2 bytes) Array.Clear(buffer, 0, buffer.GetLength(0)); buffer[0] = mNumChannels; if (!BitConverter.IsLittleEndian) Array.Reverse(buffer, 0, 2); mMemoryStream.Write(buffer, 0, 2); // Sample rate (4 bytes) buffer = BitConverter.GetBytes(mSampleRateHz); if (!BitConverter.IsLittleEndian) Array.Reverse(buffer); mMemoryStream.Write(buffer, 0, 4); // Calculate the # of bytes per sample: 1=8 bit Mono, 2=8 bit Stereo or // 16 bit Mono, 4=16 bit Stereo short bytesPerSample = 0; if (mStereo) bytesPerSample = (short)((mBitsPerSample / 8) * 2); else bytesPerSample = (short)(mBitsPerSample / 8); // Write the # of bytes per second (4 bytes) int mBytesPerSec = mSampleRateHz * bytesPerSample; buffer = BitConverter.GetBytes(mBytesPerSec); if (!BitConverter.IsLittleEndian) Array.Reverse(buffer); mMemoryStream.Write(buffer, 0, 4); // Write the # of bytes per sample (2 bytes) byte[] buffer_2bytes = BitConverter.GetBytes(bytesPerSample); if (!BitConverter.IsLittleEndian) Array.Reverse(buffer_2bytes); mMemoryStream.Write(buffer_2bytes, 0, 2); // Bits per sample (2 bytes) buffer_2bytes = BitConverter.GetBytes(mBitsPerSample); if (!BitConverter.IsLittleEndian) Array.Reverse(buffer_2bytes); mMemoryStream.Write(buffer_2bytes, 0, 2); // Data chunk // "data" (ASCII characters) buffer = StrToByteArray("data"); mMemoryStream.Write(buffer, 0, 4); // Length of data to follow (4 bytes) - This will be 0 for now Array.Clear(buffer, 0, buffer.GetLength(0)); mMemoryStream.Write(buffer, 0, 4); mDataSizeBytes = 0; // Total of 44 bytes written up to this point. // The rest of the file is the audio data } catch (Exception ex) { Console.WriteLine(ex.Message); } } private static byte[] StrToByteArray(String pStr) { System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding(); return encoding.GetBytes(pStr); } } }
Но по какой-то причине, когда я использовал эту функцию для воспроизведения звука, как это:
Все, что он делает, это говорит, что информация заголовка повреждена, хотя я использую тот же метод построения содержимого wav-файла, что и создатель класса WAVFile.
У кого-нибудь есть какие-нибудь предложения?
class Program { static void Main(string[] args) { Console.WriteLine("hi"); WAVFile audioFile = new WAVFile(); string warning = audioFile.Open("11.wav", WAVFile.WAVFileMode.READ); short[] audioSample = new short[audioFile.NumSamples]; if (warning == "") { for (int sampleNum = 0; sampleNum < audioFile.NumSamples; ++sampleNum) { audioSample[sampleNum] = audioFile.GetNextSampleAs16Bit(); } } InternalWAVFile iwf = new InternalWAVFile(audioSample, audioFile.IsStereo, audioFile.SampleRateHz, audioFile.BitsPerSample); MemoryStream ms = iwf.GetStream(); if (null == ms) Console.WriteLine("stream is null"); else { Console.WriteLine("Not null"); Audio a = new Audio(); Console.WriteLine("Going to play"); a.Play(ms, Microsoft.VisualBasic.AudioPlayMode.Background); Console.WriteLine("Played"); } } }
shubhangi waghmare
Где находится класс WaveFile.Выше код дает ошибку..