UNOWN301 Ответов: 2

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.Выше код дает ошибку..

2 Ответов

Рейтинг:
2

yoldasim

привет
вы должны написать функцию close для потока. Он должен иметь размер данных.

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);
           }
           // File size: Offset 4, 4 bytes
           mMemoryStream.Seek(4, 0);
           // Note: Per the WAV file spec, we need to write file size - 8 bytes.
           // The header is 44 bytes, and 44 - 8 = 36, so we write
           // mDataBytesWritten + 36.
           // 2009-03-17: Now using FileSizeBytes - 8 (to avoid mDataBytesWritten).
           //mFileStream.Write(BitConverter.GetBytes(mDataBytesWritten+36), 0, 4);
           int size = (int)FileSizeBytes - 8;
           byte[] buffer2 = BitConverter.GetBytes(size);
           if (!BitConverter.IsLittleEndian)
               Array.Reverse(buffer2);
           mMemoryStream.Write(buffer2, 0, 4);
           // Data size: Offset 40, 4 bytes
           mMemoryStream.Seek(40, 0);
           //mFileStream.Write(BitConverter.GetBytes(mDataBytesWritten), 0, 4);
           size = (int)(FileSizeBytes - mDataStartPos);
           buffer2 = BitConverter.GetBytes(size);
           if (!BitConverter.IsLittleEndian)
               Array.Reverse(buffer2);
           mMemoryStream.Write(buffer2, 0, 4);
           mMemoryStream.Seek(0, 0);
          // mMemoryStream.Close();
       }


Рейтинг:
1

Sergey Alexandrovich Kryukov

Прежде всего, обратитесь с этой проблемой к автору статьи Nightfox. На кнопке статьи страница, щелчок "новое сообщение" - автор получит уведомление.

—СА