⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sound_win32.cxx

📁 pwlib源码库
💻 CXX
📖 第 1 页 / 共 3 页
字号:
BOOL PSoundChannelWin32::Write(const void * data, PINDEX size){  lastWriteCount = 0;  if (hWaveOut == NULL)    return SetErrorValues(NotOpen, EBADF, LastWriteError);  const BYTE * ptr = (const BYTE *)data;  bufferMutex.Wait();  DWORD osError = MMSYSERR_NOERROR;  while (size > 0) {    PWaveBuffer & buffer = buffers[bufferIndex];    while ((buffer.header.dwFlags&WHDR_DONE) == 0) {      bufferMutex.Signal();      // No free buffers, so wait for one      if (WaitForSingleObject(hEventDone, INFINITE) != WAIT_OBJECT_0)        return SetErrorValues(Miscellaneous, ::GetLastError()|PWIN32ErrorFlag, LastWriteError);      bufferMutex.Wait();    }    // Can't write more than a buffer full    PINDEX count = size;    if ((osError = buffer.Prepare(hWaveOut, count)) != MMSYSERR_NOERROR)      break;    memcpy(buffer.GetPointer(), ptr, count);    if ((osError = waveOutWrite(hWaveOut, &buffer.header, sizeof(WAVEHDR))) != MMSYSERR_NOERROR)      break;    bufferIndex = (bufferIndex+1)%buffers.GetSize();    lastWriteCount += count;    size -= count;    ptr += count;  }  bufferMutex.Signal();  if (size != 0)    return SetErrorValues(Miscellaneous, osError|PWIN32ErrorFlag, LastWriteError);  return TRUE;}BOOL PSoundChannelWin32::PlaySound(const PSound & sound, BOOL wait){  Abort();  BOOL ok = FALSE;  PINDEX bufferSize;  PINDEX bufferCount;  GetBuffers(bufferSize, bufferCount);  unsigned numChannels = waveFormat->nChannels;  unsigned sampleRate = waveFormat->nSamplesPerSec;  unsigned bitsPerSample = waveFormat->wBitsPerSample;  if (sound.GetEncoding() == 0)    ok = SetFormat(sound.GetChannels(), sound.GetSampleRate(), sound.GetSampleSize());  else {    waveFormat.SetFormat(sound.GetFormatInfoData(), sound.GetFormatInfoSize());    ok = OpenDevice(os_handle);  }  if (ok) {    bufferMutex.Wait();    // To avoid lots of copying of sound data, we fake the PSound buffer into    // the internal buffers and play directly from the PSound object.    buffers.SetSize(1);    PWaveBuffer & buffer = buffers[0];    buffer = sound;    DWORD osError;    PINDEX count = sound.GetSize();    if ((osError = buffer.Prepare(hWaveOut, count)) == MMSYSERR_NOERROR &&        (osError = waveOutWrite(hWaveOut, &buffer.header, sizeof(WAVEHDR))) == MMSYSERR_NOERROR) {      if (wait)        ok = WaitForPlayCompletion();    }    else {      SetErrorValues(Miscellaneous, osError|PWIN32ErrorFlag, LastWriteError);      ok = FALSE;    }    bufferMutex.Signal();  }  SetFormat(numChannels, sampleRate, bitsPerSample);  SetBuffers(bufferSize, bufferCount);  return ok;}BOOL PSoundChannelWin32::PlayFile(const PFilePath & filename, BOOL wait){  Abort();  PMultiMediaFile mmio;  PWaveFormat fileFormat;  DWORD dataSize;  if (!mmio.OpenWaveFile(filename, fileFormat, dataSize))    return SetErrorValues(NotOpen, mmio.GetLastError()|PWIN32ErrorFlag, LastWriteError);  // Save old format and set to one loaded from file.  unsigned numChannels = waveFormat->nChannels;  unsigned sampleRate = waveFormat->nSamplesPerSec;  unsigned bitsPerSample = waveFormat->wBitsPerSample;  waveFormat = fileFormat;  if (!OpenDevice(os_handle)) {    SetFormat(numChannels, sampleRate, bitsPerSample);    return FALSE;  }  bufferMutex.Wait();  DWORD osError = MMSYSERR_NOERROR;  while (dataSize > 0) {    PWaveBuffer & buffer = buffers[bufferIndex];    while ((buffer.header.dwFlags&WHDR_DONE) == 0) {      bufferMutex.Signal();      // No free buffers, so wait for one      if (WaitForSingleObject(hEventDone, INFINITE) != WAIT_OBJECT_0) {        SetFormat(numChannels, sampleRate, bitsPerSample);        return SetErrorValues(Miscellaneous, ::GetLastError()|PWIN32ErrorFlag, LastWriteError);      }      bufferMutex.Wait();    }    // Can't write more than a buffer full    PINDEX count = dataSize;    if ((osError = buffer.Prepare(hWaveOut, count)) != MMSYSERR_NOERROR)      break;    // Read the waveform data subchunk    if (!mmio.Read(buffer.GetPointer(), count)) {      osError = mmio.GetLastError();      break;    }    if ((osError = waveOutWrite(hWaveOut, &buffer.header, sizeof(WAVEHDR))) != MMSYSERR_NOERROR)      break;    bufferIndex = (bufferIndex+1)%buffers.GetSize();    dataSize -= count;  }  bufferMutex.Signal();  if (dataSize == 0 && wait)    WaitForPlayCompletion();  SetFormat(numChannels, sampleRate, bitsPerSample);  if (osError != MMSYSERR_NOERROR)    return SetErrorValues(Miscellaneous, osError|PWIN32ErrorFlag, LastWriteError);  return TRUE;}BOOL PSoundChannelWin32::HasPlayCompleted(){  PWaitAndSignal mutex(bufferMutex);  for (PINDEX i = 0; i < buffers.GetSize(); i++) {    if ((buffers[i].header.dwFlags&WHDR_DONE) == 0)      return FALSE;  }  return TRUE;}BOOL PSoundChannelWin32::WaitForPlayCompletion(){  while (!HasPlayCompleted()) {    if (WaitForSingleObject(hEventDone, INFINITE) != WAIT_OBJECT_0)      return FALSE;  }  return TRUE;}BOOL PSoundChannelWin32::StartRecording(){  PWaitAndSignal mutex(bufferMutex);  // See if has started already.  if (bufferByteOffset != P_MAX_INDEX)    return TRUE;  DWORD osError;  // Start the first read, queue all the buffers  for (PINDEX i = 0; i < buffers.GetSize(); i++) {    PWaveBuffer & buffer = buffers[i];    if ((osError = buffer.Prepare(hWaveIn)) != MMSYSERR_NOERROR)      return FALSE;    if ((osError = waveInAddBuffer(hWaveIn, &buffer.header, sizeof(WAVEHDR))) != MMSYSERR_NOERROR)      return FALSE;  }  bufferByteOffset = 0;  if ((osError = waveInStart(hWaveIn)) == MMSYSERR_NOERROR) // start recording    return TRUE;  bufferByteOffset = P_MAX_INDEX;  return SetErrorValues(Miscellaneous, osError|PWIN32ErrorFlag, LastReadError);}BOOL PSoundChannelWin32::Read(void * data, PINDEX size){  lastReadCount = 0;  if (hWaveIn == NULL)    return SetErrorValues(NotOpen, EBADF, LastReadError);  if (!WaitForRecordBufferFull())    return FALSE;  PWaitAndSignal mutex(bufferMutex);  // Check to see if Abort() was called in another thread  if (bufferByteOffset == P_MAX_INDEX)    return FALSE;  PWaveBuffer & buffer = buffers[bufferIndex];  lastReadCount = buffer.header.dwBytesRecorded - bufferByteOffset;  if (lastReadCount > size)    lastReadCount = size;  memcpy(data, &buffer[bufferByteOffset], lastReadCount);  bufferByteOffset += lastReadCount;  if (bufferByteOffset >= (PINDEX)buffer.header.dwBytesRecorded) {    DWORD osError;    if ((osError = buffer.Prepare(hWaveIn)) != MMSYSERR_NOERROR)      return SetErrorValues(Miscellaneous, osError|PWIN32ErrorFlag, LastReadError);    if ((osError = waveInAddBuffer(hWaveIn, &buffer.header, sizeof(WAVEHDR))) != MMSYSERR_NOERROR)      return SetErrorValues(Miscellaneous, osError|PWIN32ErrorFlag, LastReadError);    bufferIndex = (bufferIndex+1)%buffers.GetSize();    bufferByteOffset = 0;  }  return TRUE;}BOOL PSoundChannelWin32::RecordSound(PSound & sound){  if (!WaitForAllRecordBuffersFull())    return FALSE;  sound.SetFormat(waveFormat->nChannels,                  waveFormat->nSamplesPerSec,                  waveFormat->wBitsPerSample);  PWaitAndSignal mutex(bufferMutex);  if (buffers.GetSize() == 1 &&          (PINDEX)buffers[0].header.dwBytesRecorded == buffers[0].GetSize())    sound = buffers[0];  else {    PINDEX totalSize = 0;    PINDEX i;    for (i = 0; i < buffers.GetSize(); i++)      totalSize += buffers[i].header.dwBytesRecorded;    if (!sound.SetSize(totalSize))      return SetErrorValues(NoMemory, ENOMEM, LastReadError);    BYTE * ptr = sound.GetPointer();    for (i = 0; i < buffers.GetSize(); i++) {      PINDEX sz = buffers[i].header.dwBytesRecorded;      memcpy(ptr, buffers[i], sz);      ptr += sz;    }  }  return TRUE;}BOOL PSoundChannelWin32::RecordFile(const PFilePath & filename){  if (!WaitForAllRecordBuffersFull())    return FALSE;  PWaitAndSignal mutex(bufferMutex);  PINDEX dataSize = 0;  PINDEX i;  for (i = 0; i < buffers.GetSize(); i++)    dataSize += buffers[i].header.dwBytesRecorded;  PMultiMediaFile mmio;  if (!mmio.CreateWaveFile(filename, waveFormat, dataSize))    return SetErrorValues(Miscellaneous, mmio.GetLastError()|PWIN32ErrorFlag, LastReadError);  for (i = 0; i < buffers.GetSize(); i++) {    if (!mmio.Write(buffers[i], buffers[i].header.dwBytesRecorded))      return SetErrorValues(Miscellaneous, mmio.GetLastError()|PWIN32ErrorFlag, LastReadError);  }  return TRUE;}BOOL PSoundChannelWin32::IsRecordBufferFull(){  PWaitAndSignal mutex(bufferMutex);  return (buffers[bufferIndex].header.dwFlags&WHDR_DONE) != 0 &&          buffers[bufferIndex].header.dwBytesRecorded > 0;}BOOL PSoundChannelWin32::AreAllRecordBuffersFull(){  PWaitAndSignal mutex(bufferMutex);  for (PINDEX i = 0; i < buffers.GetSize(); i++) {    if ((buffers[i].header.dwFlags&WHDR_DONE) == 0 ||         buffers[i].header.dwBytesRecorded    == 0)      return FALSE;  }  return TRUE;}BOOL PSoundChannelWin32::WaitForRecordBufferFull(){  if (!StartRecording())  // Start the first read, queue all the buffers    return FALSE;  while (!IsRecordBufferFull()) {    if (WaitForSingleObject(hEventDone, INFINITE) != WAIT_OBJECT_0)      return FALSE;    PWaitAndSignal mutex(bufferMutex);    if (bufferByteOffset == P_MAX_INDEX)      return FALSE;  }  return TRUE;}BOOL PSoundChannelWin32::WaitForAllRecordBuffersFull(){  if (!StartRecording())  // Start the first read, queue all the buffers    return FALSE;  while (!AreAllRecordBuffersFull()) {    if (WaitForSingleObject(hEventDone, INFINITE) != WAIT_OBJECT_0)      return FALSE;    PWaitAndSignal mutex(bufferMutex);    if (bufferByteOffset == P_MAX_INDEX)      return FALSE;  }  return TRUE;}BOOL PSoundChannelWin32::Abort(){  DWORD osError = MMSYSERR_NOERROR;  if (hWaveOut != NULL)    osError = waveOutReset(hWaveOut);  if (hWaveIn != NULL)    osError = waveInReset(hWaveIn);  PWaitAndSignal mutex(bufferMutex);  if (hWaveOut != NULL || hWaveIn != NULL) {    for (PINDEX i = 0; i < buffers.GetSize(); i++) {      while (buffers[i].Release() == WAVERR_STILLPLAYING) {        if (hWaveOut != NULL)          waveOutReset(hWaveOut);        if (hWaveIn != NULL)          waveInReset(hWaveIn);      }    }  }  bufferByteOffset = P_MAX_INDEX;  bufferIndex = 0;  // Signal any threads waiting on this event, they should then check  // the bufferByteOffset variable for an abort.  SetEvent(hEventDone);  if (osError != MMSYSERR_NOERROR)    return SetErrorValues(Miscellaneous, osError|PWIN32ErrorFlag);  return TRUE;}PString PSoundChannelWin32::GetErrorText(ErrorGroup group) const{  PString str;  if ((lastErrorNumber[group]&PWIN32ErrorFlag) == 0)    return PChannel::GetErrorText(group);  DWORD osError = lastErrorNumber[group]&~PWIN32ErrorFlag;  if (direction == Recorder) {    if (waveInGetErrorText(osError, str.GetPointer(256), 256) != MMSYSERR_NOERROR)      return PChannel::GetErrorText(group);  }  else {    if (waveOutGetErrorText(osError, str.GetPointer(256), 256) != MMSYSERR_NOERROR)      return PChannel::GetErrorText(group);  }  return str;}BOOL PSoundChannelWin32::SetVolume(unsigned newVolume){   if (!IsOpen())     return SetErrorValues(NotOpen, EBADF);   DWORD rawVolume = newVolume*65536/100;   if (rawVolume > 65535)     rawVolume = 65535;   WAVEOUTCAPS caps;   if (waveOutGetDevCaps((UINT) hWaveOut, &caps, sizeof(caps)) == MMSYSERR_NOERROR) {     // If the device does not support L/R volume only the low word matters     if ((caps.dwSupport & WAVECAPS_LRVOLUME) != 0) {       // Mantain balance       DWORD oldVolume = 0;       if (waveOutGetVolume(hWaveOut, &oldVolume) == MMSYSERR_NOERROR) {         // GetVolume() is supposed to return the value we intended to set.         // So do the proper calculations         // 1. (L + R) / 2 = rawVolume      -> GetVolume() formula         // 2. L / R       = oldL / oldR    -> Unmodified balance         // Being:         // oldL = LOWORD(oldVolume)         // oldR = HIWORD(oldVolume)                  DWORD rVol, lVol;         DWORD oldL, oldR;                  // Old volume values         oldL = LOWORD(oldVolume);         oldR = HIWORD(oldVolume);                  lVol = rVol = 0;                  // First sort out extreme cases         if ( oldL == oldR )           rVol = lVol = rawVolume;         else if ( oldL == 0 )           rVol = rawVolume;         else if ( oldR == 0 )           lVol = rawVolume;         else {#ifndef _WIN32_WCE           rVol = ::MulDiv( 2 * rawVolume, oldR, oldL + oldR );           lVol = ::MulDiv( rVol, oldL, oldR );#else           rVol = 2 * rawVolume * oldR / ( oldL + oldR );           lVol = rVol * oldL / oldR;#endif         }                  rawVolume = MAKELPARAM(lVol, rVol);       }       else {         // Couldn't get current volume. Assume centered balance         rawVolume = MAKELPARAM(rawVolume, rawVolume);       }     }   }   else {     // Couldn't get device caps. Assume centered balance     // If the device does not support independant L/R volume     // the high-order word (R) is ignored     rawVolume = MAKELPARAM(rawVolume, rawVolume);   }   if (direction == Recorder) {     // Does not appear to be an input volume!!   }   else {     DWORD osError = waveOutSetVolume(hWaveOut, rawVolume);     if (osError != MMSYSERR_NOERROR)       return SetErrorValues(Miscellaneous, osError|PWIN32ErrorFlag);   }   return TRUE;}BOOL PSoundChannelWin32::GetVolume(unsigned & oldVolume){   if (!IsOpen())     return SetErrorValues(NotOpen, EBADF);   DWORD rawVolume = 0;   if (direction == Recorder) {     // Does not appear to be an input volume!!   }   else {     DWORD osError = waveOutGetVolume(hWaveOut, &rawVolume);     if (osError != MMSYSERR_NOERROR)       return SetErrorValues(Miscellaneous, osError|PWIN32ErrorFlag);   }   WAVEOUTCAPS caps;   if (waveOutGetDevCaps((UINT) hWaveOut, &caps, sizeof(caps)) == MMSYSERR_NOERROR &&                                               (caps.dwSupport & WAVECAPS_LRVOLUME) != 0)     rawVolume = (HIWORD(rawVolume) + LOWORD(rawVolume)) / 2;   oldVolume = rawVolume*100/65536;   return TRUE;}// End of File ///////////////////////////////////////////////////////////////

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -