/// <summary> /// Read in the specified buffer. /// </summary> /// <param name="bufIndex">Index of buffer to use for the read</param> /// <returns>MMSYSERR.NOERROR if successful</returns> protected Wave.MMSYSERR ReadBuffer(int bufIndex) { uint readLength = (uint)m_bufferSize; if (bufIndex < m_numBlocks) { uint remainingDataLength = (uint)(m_rdr.BaseStream.Length - m_rdr.BaseStream.Position); if (m_bufferSize > remainingDataLength) { readLength = remainingDataLength; } } // Read in the next block of data Wave.MMSYSERR result = m_whdr[bufIndex].Read(m_rdr, readLength, m_wfmt.nBlockAlign); if (result != Wave.MMSYSERR.NOERROR) { return(result); } // If the header is not prepared then prepare it if ((m_whdr[bufIndex].dwFlags & Wave.WAVEHDR.WHDR_PREPARED) == 0) { return(waveOutPrepareHeader(m_hwo, m_whdr[bufIndex], (uint)Marshal.SizeOf(m_whdr[bufIndex]))); } return(Wave.MMSYSERR.NOERROR); }
/// <summary> /// Get the name of the specified playback device. /// </summary> /// <param name="deviceId">ID of the device</param> /// <param name="prodName">Destination string assigned the name</param> /// <returns>MMSYSERR.NOERROR if successful</returns> public Wave.MMSYSERR GetDeviceName(uint deviceId, ref string prodName) { WAVEOUTCAPS caps = new WAVEOUTCAPS(); Wave.MMSYSERR result = waveOutGetDevCaps(deviceId, caps, caps.Size); if (result != Wave.MMSYSERR.NOERROR) { return(result); } prodName = caps.szPname; return(Wave.MMSYSERR.NOERROR); }
/// <summary> /// Get the volume of this sound. /// </summary> /// <param name="volLeft">Left channel volume level</param> /// <param name="volRight">Right channel volume level</param> /// <returns>MMSYSERR.NOERROR if successful</returns> public Wave.MMSYSERR GetVolume(ref ushort volLeft, ref ushort volRight) { uint vol = 0; Wave.MMSYSERR result = waveOutGetVolume(m_hwo, ref vol); if (result != Wave.MMSYSERR.NOERROR) { return(result); } volLeft = (ushort)(vol & 0x0000ffff); volRight = (ushort)(vol >> 16); return(Wave.MMSYSERR.NOERROR); }
/// <summary> /// Create an empty buffer to append to the end of the sound. This protects /// the playback because the system will sometimes continue reading after the /// BlockDone method is called. /// </summary> /// <param name="bufIndex">Index of buffer to be created</param> /// <returns>MMSYSERR.NOERROR is successful</returns> protected Wave.MMSYSERR CreateBuffer(int bufIndex) { Wave.MMSYSERR result = m_whdr[bufIndex].Init((uint)m_bufferSize, true); if (result != Wave.MMSYSERR.NOERROR) { return(result); } if ((m_whdr[bufIndex].dwFlags & Wave.WAVEHDR.WHDR_PREPARED) == 0) { return(waveOutPrepareHeader(m_hwo, m_whdr[bufIndex], (uint)Marshal.SizeOf(m_whdr[bufIndex]))); } return(Wave.MMSYSERR.NOERROR); }
/// <summary> /// Play a wave file. /// </summary> /// <param name="curDevice">Hardware device to use for playback</param> /// <param name="fileName">Name of file to play</param> /// <param name="hwnd">Handle to a message window to use for messaging</param> /// <param name="bufferSize">Size of streaming buffers, a 0 value specifies /// that the buffer should be created big enough to fit the entire file</param> /// <param name="volLeft">Left channel volume level</param> /// <param name="volRight">Right channel volume level</param> /// <returns>MMSYSERR.NOERROR if successful</returns> public Wave.MMSYSERR Play(uint curDevice, String fileName, IntPtr hwnd, int bufferSize, ushort volLeft, ushort volRight) { if (m_playing) { return(Wave.MMSYSERR.NOERROR); } if (!File.Exists(fileName)) { return(Wave.MMSYSERR.ERROR); } FileInfo fi = new FileInfo(fileName); if ((fi.Attributes & FileAttributes.ReadOnly) != 0) { fi.Attributes -= FileAttributes.ReadOnly; } FileStream strm = new FileStream(fileName, FileMode.Open); if (strm == null) { return(Wave.MMSYSERR.ERROR); } m_rdr = new BinaryReader(strm); if (m_rdr == null) { return(Wave.MMSYSERR.ERROR); } m_wfmt = new Wave.WAVEFORMATEX(); m_wfmt.SeekTo(strm); // Read in the WAVEFORMATEX structure and attempt to open the // device for playback. m_wfmt.Read(m_rdr); Wave.MMSYSERR result = waveOutOpen(ref m_hwo, curDevice, m_wfmt, hwnd, 0, Wave.CALLBACK_WINDOW); if (result != Wave.MMSYSERR.NOERROR) { return(result); } m_dataLength = (uint)(m_rdr.BaseStream.Length - Wave.WAVEFORMATEX.WF_OFFSET_DATA); if (bufferSize == 0) { m_bufferSize = (int)m_dataLength; } else { m_bufferSize = bufferSize / 2; } if (m_bufferSize % m_wfmt.nBlockAlign != 0) { m_bufferSize += m_wfmt.nBlockAlign - (m_bufferSize % m_wfmt.nBlockAlign); } // Determine the number of buffer reads required to play the entire // file m_numBlocks = (int)(m_dataLength / m_bufferSize); if ((m_numBlocks * m_bufferSize) < m_dataLength) { m_numBlocks++; } m_whdr[0] = new Wave.WAVEHDR(); m_whdr[1] = new Wave.WAVEHDR(); // Read in the first buffer result = ReadBuffer(0); if (result != Wave.MMSYSERR.NOERROR) { return(result); } // If the entire file fits in the buffer then close the file if (m_numBlocks == 1) { m_rdr.BaseStream.Close(); m_rdr.Close(); m_rdr = null; } SetVolume(volLeft, volRight); // Start playback of the first buffer result = waveOutWrite(m_hwo, m_whdr[0], (uint)Marshal.SizeOf(m_whdr[0])); if (result != Wave.MMSYSERR.NOERROR) { return(result); } m_curBlock = 0; // Create the second buffer. If the audio is being streamed, this will // be the next audio block, otherwise it will be padding Thread loadThread = new Thread(new ThreadStart(LoadBuffer)); loadThread.Start(); m_playing = true; return(Wave.MMSYSERR.NOERROR); }