/// <summary> /// Opens a WAV file and attemps to read the header & audio information. /// </summary> /// <param name="pFilename">The name of the file to open</param> /// <param name="pMode">The file opening mode. Only READ and READ_WRITE are valid. If you want to write only, then use Create().</param> /// <returns>A blank string on success, or a message on failure.</returns> public String Open(String pFilename, WAVFileMode pMode) { mFilename = pFilename; return (Open(pMode)); }
/// <summary> /// Opens the file specified by mFilename and reads the file header and audio information. Does not read any of the audio data. /// </summary> /// /// <param name="pMode">The file opening mode. Only READ and READ_WRITE are valid. If you want to write only, then use Create().</param> /// <returns>A blank string on success, or a message on failure.</returns> public String Open(WAVFileMode pMode) { if (mFileStream != null) { mFileStream.Close(); mFileStream.Dispose(); mFileStream = null; } String filenameBackup = mFilename; InitMembers(); // pMode should be READ or READ_WRITE. Otherwise, throw an exception. For // write-only mode, the user can call Create(). if ((pMode != WAVFileMode.READ) && (pMode != WAVFileMode.READ_WRITE)) throw new WAVFileException("File mode not supported: " + WAVFileModeStr(pMode), "WAVFile.Open()"); if (!File.Exists(filenameBackup)) return ("File does not exist: " + filenameBackup); if (!IsWaveFile(filenameBackup)) return ("File is not a WAV file: " + filenameBackup); mFilename = filenameBackup; String retval = ""; try { mFileStream = File.Open(mFilename, FileMode.Open); mFileMode = pMode; // RIFF chunk (12 bytes total) // Read the header (first 4 bytes) byte[] buffer = new byte[4]; mFileStream.Read(buffer, 0, 4); buffer.CopyTo(mWAVHeader, 0); // Read the file size (4 bytes) mFileStream.Read(buffer, 0, 4); //mFileSizeBytes = BitConverter.ToInt32(buffer, 0); // Read the RIFF type mFileStream.Read(buffer, 0, 4); buffer.CopyTo(mRIFFType, 0); // Format chunk (24 bytes total) // "fmt " (ASCII characters) mFileStream.Read(buffer, 0, 4); // Length of format chunk (always 16) mFileStream.Read(buffer, 0, 4); // 2 bytes (value always 1) mFileStream.Read(buffer, 0, 2); // # of channels (2 bytes) mFileStream.Read(buffer, 2, 2); mNumChannels = (BitConverter.IsLittleEndian ? buffer[2] : buffer[3]); // Sample rate (4 bytes) mFileStream.Read(buffer, 0, 4); if (!BitConverter.IsLittleEndian) Array.Reverse(buffer); mSampleRateHz = BitConverter.ToInt32(buffer, 0); // Bytes per second (4 bytes) mFileStream.Read(buffer, 0, 4); if (!BitConverter.IsLittleEndian) Array.Reverse(buffer); mBytesPerSec = BitConverter.ToInt32(buffer, 0); // Bytes per sample (2 bytes) mFileStream.Read(buffer, 2, 2); if (!BitConverter.IsLittleEndian) Array.Reverse(buffer, 2, 2); mBytesPerSample = BitConverter.ToInt16(buffer, 2); // Bits per sample (2 bytes) mFileStream.Read(buffer, 2, 2); if (!BitConverter.IsLittleEndian) Array.Reverse(buffer, 2, 2); mBitsPerSample = BitConverter.ToInt16(buffer, 2); // Data chunk // "data" (ASCII characters) mFileStream.Read(buffer, 0, 4); // Length of data to follow (4 bytes) mFileStream.Read(buffer, 0, 4); if (!BitConverter.IsLittleEndian) Array.Reverse(buffer); mDataSizeBytes = BitConverter.ToInt32(buffer, 0); // Total of 44 bytes read up to this point. // The data size should be file size - 36 bytes. If not, then set // it to that. if (mDataSizeBytes != FileSizeBytes - 36) mDataSizeBytes = (int)(FileSizeBytes - 36); // The rest of the file is the audio data, which // can be read by successive calls to NextSample(). mNumSamplesRemaining = NumSamples; } catch (Exception exc) { retval = exc.Message; } return (retval); }
/// <summary> /// Returns a string representation of a WAVFileMode enumeration value. /// </summary> /// <param name="pMode">A value of the WAVFileMode enumeration</param> /// <returns>A string representation of pMode</returns> public static String WAVFileModeStr(WAVFileMode pMode) { String retval = ""; switch (pMode) { case WAVFileMode.READ: retval = "READ"; break; case WAVFileMode.WRITE: retval = "WRITE"; break; case WAVFileMode.READ_WRITE: retval = "READ_WRITE"; break; default: retval = "Unknown"; break; } return retval; }
///////////////////// // Private members // ///////////////////// /// <summary> /// Initializes the data members (for the constructors). /// </summary> private void InitMembers() { mFilename = null; mFileStream = null; mWAVHeader = new char[4]; mDataSizeBytes = 0; mBytesPerSample = 0; //mFileSizeBytes = 0; mRIFFType = new char[4]; // These audio format defaults correspond to the standard for // CD audio. mNumChannels = 2; mSampleRateHz = 44100; mBytesPerSec = 176400; mBitsPerSample = 16; mFileMode = WAVFileMode.READ; mNumSamplesRemaining = 0; }
/// <summary> /// Creates a new WAV audio file. /// </summary> /// <param name="pFilename">The name of the audio file to create</param> /// <param name="pStereo">Whether or not the audio file should be stereo (if this is false, the audio file will be mono).</param> /// <param name="pSampleRate">The sample rate of the audio file (in Hz)</param> /// <param name="pBitsPerSample">The number of bits per sample (8 or 16)</param> /// <param name="pOverwrite">Whether or not to overwrite the file if it exists. If this is false, then a System.IO.IOException will be thrown if the file exists.</param> public void Create(String pFilename, bool pStereo, int pSampleRate, short pBitsPerSample, bool pOverwrite) { // In case a file is currently open, make sure it // is closed. Note: Close() calls InitMembers(). Close(); // If the sample rate is not supported, then throw an exception. if (!SupportedSampleRate(pSampleRate)) throw new WAVFileSampleRateException("Unsupported sample rate: " + pSampleRate.ToString(), "WAVFile.Create()", pSampleRate); // If the bits per sample is not supported, then throw an exception. if (!SupportedBitsPerSample(pBitsPerSample)) throw new WAVFileBitsPerSampleException("Unsupported number of bits per sample: " + pBitsPerSample.ToString(), "WAVFile.Create()", pBitsPerSample); try { // Create the file. If pOverwrite is true, then use FileMode.Create to overwrite the // file if it exists. Otherwise, use FileMode.CreateNew, which will throw a // System.IO.IOException if the file exists. if (pOverwrite) mFileStream = File.Open(pFilename, FileMode.Create); else mFileStream = File.Open(pFilename, FileMode.CreateNew); mFileMode = WAVFileMode.WRITE; // Set the member data from the parameters. mNumChannels = pStereo ? (byte)2 : (byte)1; mSampleRateHz = pSampleRate; mBitsPerSample = pBitsPerSample; // Write the parameters to the file header. // RIFF chunk (12 bytes total) // Write the chunk IDD ("RIFF", 4 bytes) byte[] buffer = StrToByteArray("RIFF"); mFileStream.Write(buffer, 0, 4); 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)); mFileStream.Write(buffer, 0, 4); // RIFF type ("WAVE") buffer = StrToByteArray("WAVE"); mFileStream.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 "); mFileStream.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); mFileStream.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); mFileStream.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); mFileStream.Write(buffer, 0, 2); // Sample rate (4 bytes) buffer = BitConverter.GetBytes(mSampleRateHz); if (!BitConverter.IsLittleEndian) Array.Reverse(buffer); mFileStream.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 (pStereo) bytesPerSample = (short)((mBitsPerSample / 8) * 2); else bytesPerSample = (short)(mBitsPerSample / 8); // Write the # of bytes per second (4 bytes) mBytesPerSec = mSampleRateHz * bytesPerSample; buffer = BitConverter.GetBytes(mBytesPerSec); if (!BitConverter.IsLittleEndian) Array.Reverse(buffer); mFileStream.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); mFileStream.Write(buffer_2bytes, 0, 2); // Bits per sample (2 bytes) buffer_2bytes = BitConverter.GetBytes(mBitsPerSample); if (!BitConverter.IsLittleEndian) Array.Reverse(buffer_2bytes); mFileStream.Write(buffer_2bytes, 0, 2); // Data chunk // "data" (ASCII characters) buffer = StrToByteArray("data"); mFileStream.Write(buffer, 0, 4); // Length of data to follow (4 bytes) - This will be 0 for now Array.Clear(buffer, 0, buffer.GetLength(0)); mFileStream.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) { throw new WAVFileException(ex.Message, "WAVFile.Create()"); } }
/// <summary> /// Opens the file specified by mFilename and reads the file header and audio information. Does not read any of the audio data. /// </summary> /// /// <param name="Mode">The file opening mode. Only READ and READ_WRITE are valid. If you want to write only, then use Create().</param> /// <returns>A blank string on success, or a message on failure.</returns> public void Open(WAVFileMode Mode) { if (this.Stream != null) { this.Stream.Close(); this.Stream.Dispose(); this.Stream = null; } String _FileName = this.Filename; this.InitMembers(); // pMode should be READ or READ_WRITE. Otherwise, throw an exception. For // write-only mode, the user can call Create(). if ((Mode != WAVFileMode.READ) && (Mode != WAVFileMode.READ_WRITE)) { throw new WAVFileException("File mode not supported: " + Mode, "WAVFile.Open()"); } if (!File.Exists(_FileName)) { throw new WAVFileException("File does not exist: " + _FileName, nameof(Open)); } if (!IsWaveFile(_FileName)) { throw new WAVFileException("File is not a WAV file: " + _FileName, nameof(Open)); } this.Filename = _FileName; try { this.Stream = File.Open(this.Filename, System.IO.FileMode.Open); this.FileOpenMode = Mode; // RIFF chunk (12 bytes total) // Read the header (first 4 bytes) byte[] buffer = new byte[4]; this.Stream.Read(buffer, 0, 4); buffer.CopyTo(WAVHeader, 0); // Read the file size (4 bytes) this.Stream.Read(buffer, 0, 4); //mFileSizeBytes = BitConverter.ToInt32(buffer, 0); // Read the RIFF type this.Stream.Read(buffer, 0, 4); buffer.CopyTo(RIFFType, 0); // Format chunk (24 bytes total) // "fmt " (ASCII characters) this.Stream.Read(buffer, 0, 4); // Length of format chunk (always 16) this.Stream.Read(buffer, 0, 4); // 2 bytes (value always 1) this.Stream.Read(buffer, 0, 2); // # of channels (2 bytes) this.Stream.Read(buffer, 2, 2); this.NumChannels = (BitConverter.IsLittleEndian ? buffer[2] : buffer[3]); // Sample rate (4 bytes) this.Stream.Read(buffer, 0, 4); if (!BitConverter.IsLittleEndian) { Array.Reverse(buffer); } this.SampleRateHz = BitConverter.ToInt32(buffer, 0); // Bytes per second (4 bytes) this.Stream.Read(buffer, 0, 4); if (!BitConverter.IsLittleEndian) { Array.Reverse(buffer); } this.BytesPerSec = BitConverter.ToInt32(buffer, 0); // Bytes per sample (2 bytes) this.Stream.Read(buffer, 2, 2); if (!BitConverter.IsLittleEndian) { Array.Reverse(buffer, 2, 2); } this.BytesPerSample = BitConverter.ToInt16(buffer, 2); // Bits per sample (2 bytes) this.Stream.Read(buffer, 2, 2); if (!BitConverter.IsLittleEndian) { Array.Reverse(buffer, 2, 2); } this.BitsPerSample = BitConverter.ToInt16(buffer, 2); // Data chunk // "data" (ASCII characters) this.Stream.Read(buffer, 0, 4); // Length of data to follow (4 bytes) this.Stream.Read(buffer, 0, 4); if (!BitConverter.IsLittleEndian) { Array.Reverse(buffer); } this.DataSizeBytes = BitConverter.ToInt32(buffer, 0); // Total of 44 bytes read up to this point. // The data size should be file size - 36 bytes. If not, then set // it to that. if (this.DataSizeBytes != (int)(FileSizeBytes - HeaderSize)) { this.DataSizeBytes = (int)(FileSizeBytes - HeaderSize); } // The rest of the file is the audio data, which // can be read by successive calls to NextSample(). this.NumSamplesRemaining = this.NumSamples; } catch (Exception exc) { throw new WAVFileException(exc.Message, "WAVFile.Open()"); } }
/// <summary> /// Opens a WAV file and attemps to read the header & audio information. /// </summary> /// <param name="FileName">The name of the file to open</param> /// <param name="Mode">The file opening mode. Only READ and READ_WRITE are valid. If you want to write only, then use Create().</param> /// <returns>A blank string on success, or a message on failure.</returns> public void Open(string FileName, WAVFileMode Mode) { this.Filename = FileName; this.Open(Mode); }