Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tsound.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef TNZCORE_LIGHT
Toshihiro Shimizu 890ddd
#include "tthread.h"
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
#include "tsop.h"
Toshihiro Shimizu 890ddd
#include <set></set>
Toshihiro Shimizu 890ddd
#include "tsystem.h"
Toshihiro Shimizu 890ddd
Shinya Kitaoka d4642c
#include <mmsystem.h></mmsystem.h>
Shinya Kitaoka d4642c
Toshihiro Shimizu 890ddd
//=========================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// forward declarations
Toshihiro Shimizu 890ddd
class TSoundOutputDeviceImp;
Toshihiro Shimizu 890ddd
class TSoundInputDeviceImp;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
void CALLBACK recordCB(HWAVEIN hwi, UINT uMsg, DWORD dwInstance, DWORD dwParam1,
Shinya Kitaoka 120a6e
                       DWORD dwParam2);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool setRecordLine(TSoundInputDevice::Source typeInput);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
MMRESULT getLineInfo(HMIXEROBJ hMixer, DWORD dwComponentType, MIXERLINE &mxl);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
MMRESULT getLineControl(MIXERCONTROL &mxc, HMIXEROBJ hMixer, DWORD dwLineID,
Shinya Kitaoka 120a6e
                        DWORD dwControlType);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
MMRESULT setControlDetails(HMIXEROBJ hMixer, DWORD dwSelectControlID,
Shinya Kitaoka 120a6e
                           DWORD dwMultipleItems,
Shinya Kitaoka 120a6e
                           MIXERCONTROLDETAILS_UNSIGNED *mxcdSelectValue);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
MMRESULT getControlDetails(HMIXEROBJ hMixer, DWORD dwSelectControlID,
Shinya Kitaoka 120a6e
                           DWORD dwMultipleItems,
Shinya Kitaoka 120a6e
                           MIXERCONTROLDETAILS_UNSIGNED *mxcdSelectValue);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
MMRESULT isaFormatSupported(int sampleRate, int channelCount, int bitPerSample,
Shinya Kitaoka 120a6e
                            bool input);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
DWORD WINAPI MyWaveOutCallbackThread(LPVOID lpParameter);
Toshihiro Shimizu 890ddd
void getAmplitude(int &litude, const TSoundTrackP st, TINT32 sample);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
//     Class to send the message that a playback is completed
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
#ifndef TNZCORE_LIGHT
Shinya Kitaoka 120a6e
class EndPlayMsg : public TThread::Message {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  EndPlayMsg(TSoundOutputDeviceListener *notifier) { m_listener = notifier; }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  TThread::Message *clone() const override { return new EndPlayMsg(*this); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void onDeliver() override { m_listener->onPlayCompleted(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  TSoundOutputDeviceListener *m_listener;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int makeDWORD(const short lo, const short hi) {
Shinya Kitaoka 120a6e
  int dw = hi << 16;
Shinya Kitaoka 120a6e
  dw |= lo;
Shinya Kitaoka 120a6e
  return dw;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
class WavehdrQueue;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class TSoundOutputDeviceImp {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  HWAVEOUT m_wout;
Shinya Kitaoka 120a6e
  WavehdrQueue *m_whdrQueue;
Shinya Kitaoka 120a6e
  TSoundTrackFormat m_currentFormat;
Shinya Kitaoka 120a6e
  std::set<int> m_supportedRate;</int>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TThread::Mutex m_mutex;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool m_stopped;
Shinya Kitaoka 120a6e
  bool m_isPlaying;
Shinya Kitaoka 120a6e
  bool m_looped;
Shinya Kitaoka 120a6e
  bool m_scrubbing;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::set<tsoundoutputdevicelistener *=""> m_listeners;</tsoundoutputdevicelistener>
Shinya Kitaoka 120a6e
  DWORD m_notifyThreadId;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  HANDLE m_closeDevice;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TSoundOutputDeviceImp();
Shinya Kitaoka 120a6e
  ~TSoundOutputDeviceImp();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool doOpenDevice(const TSoundTrackFormat &format);
Shinya Kitaoka 120a6e
  bool doPlay(WAVEHDR *whdr, const TSoundTrackFormat format);
Shinya Kitaoka 120a6e
  bool doCloseDevice();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool verifyRate();
Shinya Kitaoka 120a6e
  void insertAllRate();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class WavehdrQueue {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  WavehdrQueue(TSoundOutputDeviceImp *devImp, int slotCount)
Shinya Kitaoka 120a6e
      : m_devImp(devImp)
Shinya Kitaoka 120a6e
      , m_items()
Shinya Kitaoka 120a6e
      , m_queuedItems()
Shinya Kitaoka 120a6e
      , m_slotCount(slotCount)
Shinya Kitaoka 120a6e
      , m_mutex()
Shinya Kitaoka 120a6e
      , m_lastOffset(0) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ~WavehdrQueue() {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void put(TSoundTrackP &subTrack);
Shinya Kitaoka 120a6e
  WAVEHDR *get();
Shinya Kitaoka 120a6e
  bool popFront(int count);
Shinya Kitaoka 120a6e
  void pushBack(WAVEHDR *whdr, TSoundTrackP st);
Shinya Kitaoka 120a6e
  int size();
Shinya Kitaoka 120a6e
  void clear();
Shinya Kitaoka 120a6e
  bool isAllQueuedItemsPlayed();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  std::list<std::pair<wavehdr *,="" tsoundtrackp="">> m_items;</std::pair<wavehdr>
Shinya Kitaoka 120a6e
  std::list<wavehdr *=""> m_queuedItems;</wavehdr>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TThread::Mutex m_mutex;
Shinya Kitaoka 120a6e
  int m_slotCount;
Shinya Kitaoka 120a6e
  int m_lastOffset;
Shinya Kitaoka 120a6e
  TSoundOutputDeviceImp *m_devImp;
Shinya Kitaoka 120a6e
  TSoundTrackP m_lastTrack;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
WAVEHDR *prepareWaveHeader(HWAVEOUT wout, const TSoundTrackP &subTrack,
Shinya Kitaoka 120a6e
                           ULONG &count) {
Shinya Kitaoka 120a6e
  WAVEHDR *whdr = new WAVEHDR;
Shinya Kitaoka 120a6e
  memset(whdr, 0, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
  whdr->dwBufferLength = subTrack->getSampleSize() * subTrack->getSampleCount();
Shinya Kitaoka 120a6e
  whdr->lpData         = new char[whdr->dwBufferLength];
Shinya Kitaoka 120a6e
  whdr->dwFlags        = 0;
Shinya Kitaoka 120a6e
  whdr->dwUser         = count;
Shinya Kitaoka 120a6e
  memcpy(whdr->lpData, subTrack->getRawData(), whdr->dwBufferLength);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  MMRESULT ret = waveOutPrepareHeader(wout, whdr, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
    delete[] whdr->lpData;
Shinya Kitaoka 120a6e
    delete whdr;
Shinya Kitaoka 120a6e
    return 0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  ++count;
Shinya Kitaoka 120a6e
  return whdr;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void WavehdrQueue::put(TSoundTrackP &subTrack) {
Shinya Kitaoka 120a6e
  assert(subTrack->getRawData());
Shinya Kitaoka 120a6e
  static ULONG count = 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // codice messo per tab: facendo il play al rilascio del mouse e su piu'
Shinya Kitaoka 120a6e
  // colonne in cui le traccie potrebbe avere diversi formati siccome qui in
Shinya Kitaoka 120a6e
  // alcune situazioni si fa subito waveOutWrite c'e' bisogno di controllare
Shinya Kitaoka 120a6e
  // se il formato con cui e' stato aperto in precedenza il device e' uguale
Shinya Kitaoka 120a6e
  // a quello della traccia
Shinya Kitaoka 120a6e
  if (m_devImp->m_wout && m_devImp->m_currentFormat != subTrack->getFormat()) {
Shinya Kitaoka 120a6e
    m_devImp->doCloseDevice();
Shinya Kitaoka 120a6e
    TSystem::sleep(300);
Shinya Kitaoka 120a6e
    m_devImp->doOpenDevice(subTrack->getFormat());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TThread::MutexLocker sl(&m_mutex);
Shinya Kitaoka 120a6e
  if (!m_devImp->m_scrubbing) {
Shinya Kitaoka 120a6e
    WAVEHDR *whdr2 = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // traccia
Shinya Kitaoka 120a6e
    whdr2 = prepareWaveHeader(m_devImp->m_wout, subTrack, count);
Shinya Kitaoka 120a6e
    getAmplitude(m_lastOffset, subTrack, subTrack->getSampleCount() - 1L);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    MMRESULT ret = MMSYSERR_NOERROR;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (whdr2 && whdr2->dwFlags & WHDR_PREPARED) {
Shinya Kitaoka 120a6e
      ret = waveOutWrite(m_devImp->m_wout, whdr2, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
      if (ret == MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
        pushBack(whdr2, subTrack);
Shinya Kitaoka 120a6e
        getAmplitude(m_lastOffset, subTrack, subTrack->getSampleCount() - 1L);
Shinya Kitaoka 120a6e
        TThread::MutexLocker sl(&m_devImp->m_mutex);
Shinya Kitaoka 120a6e
        m_devImp->m_isPlaying = true;
Shinya Kitaoka 120a6e
        m_devImp->m_stopped   = false;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_queuedItems.size() == 0) {
Shinya Kitaoka 120a6e
    WAVEHDR *whdr1 = 0;
Shinya Kitaoka 120a6e
    WAVEHDR *whdr2 = 0;
Shinya Kitaoka 120a6e
    WAVEHDR *whdr3 = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    MMRESULT ret;
Shinya Kitaoka 120a6e
    TSoundTrackP riseTrack, decayTrack;
Shinya Kitaoka 120a6e
    int sampleSize = subTrack->getSampleSize();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // cresce
Shinya Kitaoka 120a6e
    riseTrack = TSop::fadeIn(subTrack, 0.9);
Shinya Kitaoka 120a6e
    whdr1     = prepareWaveHeader(m_devImp->m_wout, riseTrack, count);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // traccia
Shinya Kitaoka 120a6e
    whdr2 = prepareWaveHeader(m_devImp->m_wout, subTrack, count);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    getAmplitude(m_lastOffset, subTrack, subTrack->getSampleCount() - 1L);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // decresce
Shinya Kitaoka 120a6e
    decayTrack = 0;
Shinya Kitaoka 120a6e
    if (m_lastOffset) {
Shinya Kitaoka 120a6e
      decayTrack = TSop::fadeOut(subTrack, 0.9);
Shinya Kitaoka 120a6e
      whdr3      = prepareWaveHeader(m_devImp->m_wout, decayTrack, count);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (whdr1 && (whdr1->dwFlags & WHDR_PREPARED)) {
Shinya Kitaoka 120a6e
      ret = waveOutWrite(m_devImp->m_wout, whdr1, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
      if (ret == MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
        pushBack(whdr1, riseTrack);
Shinya Kitaoka 120a6e
        getAmplitude(m_lastOffset, riseTrack, riseTrack->getSampleCount() - 1L);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (whdr2 && (whdr2->dwFlags & WHDR_PREPARED)) {
Shinya Kitaoka 120a6e
      ret = waveOutWrite(m_devImp->m_wout, whdr2, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
      if (ret == MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
        pushBack(whdr2, subTrack);
Shinya Kitaoka 120a6e
        getAmplitude(m_lastOffset, subTrack, subTrack->getSampleCount() - 1L);
Shinya Kitaoka 120a6e
        TThread::MutexLocker sl(&m_devImp->m_mutex);
Shinya Kitaoka 120a6e
        m_devImp->m_isPlaying = true;
Shinya Kitaoka 120a6e
        m_devImp->m_stopped   = false;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (whdr3 && (whdr3->dwFlags & WHDR_PREPARED)) {
Shinya Kitaoka 120a6e
      ret = waveOutWrite(m_devImp->m_wout, whdr3, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
      if (ret == MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
        pushBack(whdr3, decayTrack);
Shinya Kitaoka 120a6e
        if (decayTrack->isSampleSigned())
Shinya Kitaoka 120a6e
          m_lastOffset = 0;
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
          m_lastOffset = 127;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_queuedItems.size() < 10) {
Shinya Kitaoka 120a6e
    WAVEHDR *whdr1 = 0;
Shinya Kitaoka 120a6e
    WAVEHDR *whdr2 = 0;
Shinya Kitaoka 120a6e
    WAVEHDR *whdr  = new WAVEHDR;
Shinya Kitaoka 120a6e
    memset(whdr, 0, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
    whdr->dwBufferLength =
Shinya Kitaoka 120a6e
        subTrack->getSampleSize() * subTrack->getSampleCount();
Shinya Kitaoka 120a6e
    whdr->lpData  = new char[whdr->dwBufferLength];
Shinya Kitaoka 120a6e
    whdr->dwFlags = 0;
Shinya Kitaoka 120a6e
    memcpy(whdr->lpData, subTrack->getRawData(), whdr->dwBufferLength);
Shinya Kitaoka 120a6e
    int sampleSize         = subTrack->getSampleSize();
Shinya Kitaoka 120a6e
    TSoundTrackP riseTrack = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_lastOffset)  /// devo fare ilcross fade
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      int offset;
Shinya Kitaoka 120a6e
      getAmplitude(offset, subTrack, 0L);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      offset = m_lastOffset - offset;
Shinya Kitaoka 120a6e
      if (offset) {
Shinya Kitaoka 120a6e
        TSoundTrackP st = TSop::crossFade(m_lastTrack, subTrack, 0.3);
Shinya Kitaoka 120a6e
        memcpy(whdr->lpData, st->getRawData(),
Shinya Kitaoka 120a6e
               st->getSampleCount() * sampleSize);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else  // e' zero ma ne metto uno che cresce faccio il fadeIn
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      riseTrack = TSop::fadeIn(subTrack, 0.3);
Shinya Kitaoka 120a6e
      whdr1     = prepareWaveHeader(m_devImp->m_wout, riseTrack, count);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    whdr->dwUser = count;
Shinya Kitaoka 120a6e
    ++count;
Shinya Kitaoka 120a6e
    MMRESULT ret =
Shinya Kitaoka 120a6e
        waveOutPrepareHeader(m_devImp->m_wout, whdr, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
    if (ret != MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
      delete[] whdr->lpData;
Shinya Kitaoka 120a6e
      delete whdr;
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    getAmplitude(m_lastOffset, subTrack, subTrack->getSampleCount() - 1L);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TSoundTrackP decayTrack = 0;
Shinya Kitaoka 120a6e
    if (m_queuedItems.size() <= 7) {
Shinya Kitaoka 120a6e
      if (m_lastOffset)  // devo fare il fadeOut
Shinya Kitaoka 120a6e
      {
Shinya Kitaoka 120a6e
        decayTrack = TSop::fadeOut(subTrack, 0.3);
Shinya Kitaoka 120a6e
        whdr2      = prepareWaveHeader(m_devImp->m_wout, decayTrack, count);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (whdr1 && whdr1->dwFlags & WHDR_PREPARED) {
Shinya Kitaoka 120a6e
      ret = waveOutWrite(m_devImp->m_wout, whdr1, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
      if (ret == MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
        pushBack(whdr1, riseTrack);
Shinya Kitaoka 120a6e
        getAmplitude(m_lastOffset, riseTrack, riseTrack->getSampleCount() - 1L);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (whdr && whdr->dwFlags & WHDR_PREPARED) {
Shinya Kitaoka 120a6e
      ret = waveOutWrite(m_devImp->m_wout, whdr, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
      if (ret == MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
        pushBack(whdr, subTrack);
Shinya Kitaoka 120a6e
        getAmplitude(m_lastOffset, subTrack, subTrack->getSampleCount() - 1L);
Shinya Kitaoka 120a6e
        {
Shinya Kitaoka 120a6e
          TThread::MutexLocker sl(&m_devImp->m_mutex);
Shinya Kitaoka 120a6e
          m_devImp->m_isPlaying = true;
Shinya Kitaoka 120a6e
          m_devImp->m_stopped   = false;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (whdr2 && whdr2->dwFlags & WHDR_PREPARED) {
Shinya Kitaoka 120a6e
      ret = waveOutWrite(m_devImp->m_wout, whdr2, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
      if (ret == MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
        pushBack(whdr2, decayTrack);
Shinya Kitaoka 120a6e
        if (decayTrack->isSampleSigned())
Shinya Kitaoka 120a6e
          m_lastOffset = 0;
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
          m_lastOffset = 127;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if ((int)m_items.size() == m_slotCount) {
Shinya Kitaoka 120a6e
    WAVEHDR *item = m_items.front().first;
Shinya Kitaoka 120a6e
    MMRESULT ret =
Shinya Kitaoka 120a6e
        waveOutUnprepareHeader(m_devImp->m_wout, item, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (ret == MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
      delete[] item->lpData;
Shinya Kitaoka 120a6e
      delete item;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_items.pop_front();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_queuedItems.size() != 0) {
Shinya Kitaoka 120a6e
      WAVEHDR *item  = m_items.front().first;
Shinya Kitaoka 120a6e
      int sampleSize = m_items.front().second->getSampleSize();
Shinya Kitaoka 120a6e
      int offset;
Shinya Kitaoka 120a6e
      getAmplitude(offset, m_items.front().second, 0L);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      offset = m_lastOffset - offset;
Shinya Kitaoka 120a6e
      if (offset) {
Shinya Kitaoka 120a6e
        TSoundTrackP st =
Shinya Kitaoka 120a6e
            TSop::crossFade(m_lastTrack, m_items.front().second, 0.3);
Shinya Kitaoka 120a6e
        memcpy(item->lpData, st->getRawData(),
Shinya Kitaoka 120a6e
               st->getSampleCount() * sampleSize);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  WAVEHDR *whdr = prepareWaveHeader(m_devImp->m_wout, subTrack, count);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(whdr && whdr->dwFlags & WHDR_PREPARED);
Shinya Kitaoka 120a6e
  m_items.push_back(std::make_pair(whdr, subTrack));
Shinya Kitaoka 120a6e
  assert((int)m_items.size() <= m_slotCount);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// restituisce il piu' vecchio WAVEHDR il cui stato e' prepared && !done
Shinya Kitaoka 120a6e
WAVEHDR *WavehdrQueue::get() {
Shinya Kitaoka 120a6e
  TThread::MutexLocker sl(&m_mutex);
Shinya Kitaoka 120a6e
  if (m_items.size() == 0) return 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  WAVEHDR *whdr = m_items.front().first;
Shinya Kitaoka 120a6e
  assert(whdr->dwFlags & WHDR_PREPARED);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  pushBack(whdr, m_items.front().second);
Shinya Kitaoka 120a6e
  getAmplitude(m_lastOffset, m_items.front().second,
Shinya Kitaoka 120a6e
               m_items.front().second->getSampleCount() - 1L);
Shinya Kitaoka 120a6e
  m_items.pop_front();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return whdr;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// rimuove dalla coda il piu' vecchio WAVEHDR il cui stato e' done
Shinya Kitaoka 120a6e
bool WavehdrQueue::popFront(int count) {
Shinya Kitaoka 120a6e
  TThread::MutexLocker sl(&m_mutex);
Shinya Kitaoka 120a6e
  // assert(m_queuedItems.size() > 0);
Shinya Kitaoka 120a6e
  if (m_queuedItems.size() <= 0) return false;
Shinya Kitaoka 120a6e
  WAVEHDR *whdr = m_queuedItems.front();
Shinya Kitaoka 120a6e
  // controllo introdotto pr via che su win2k si perde alcune
Shinya Kitaoka 120a6e
  // notifiche di WHDR_DONE
Shinya Kitaoka 120a6e
  while ((DWORD)count > whdr->dwUser) {
Shinya Kitaoka 120a6e
    MMRESULT ret =
Shinya Kitaoka 120a6e
        waveOutUnprepareHeader(m_devImp->m_wout, whdr, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
    if (ret == MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
      m_queuedItems.pop_front();
Shinya Kitaoka 120a6e
      delete[] whdr->lpData;
Shinya Kitaoka 120a6e
      delete whdr;
Shinya Kitaoka 120a6e
      whdr = m_queuedItems.front();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  assert(whdr->dwFlags & WHDR_DONE);
Shinya Kitaoka 120a6e
  m_queuedItems.pop_front();
Shinya Kitaoka 120a6e
  delete[] whdr->lpData;
Shinya Kitaoka 120a6e
  delete whdr;
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void WavehdrQueue::pushBack(WAVEHDR *whdr, TSoundTrackP st) {
Shinya Kitaoka 120a6e
  TThread::MutexLocker sl(&m_mutex);
Shinya Kitaoka 120a6e
  m_queuedItems.push_back(whdr);
Shinya Kitaoka 120a6e
  m_lastTrack = st;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int WavehdrQueue::size() {
Shinya Kitaoka 120a6e
  TThread::MutexLocker sl(&m_mutex);
Shinya Kitaoka 120a6e
  int size = m_queuedItems.size();
Shinya Kitaoka 120a6e
  return size;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void WavehdrQueue::clear() {
Shinya Kitaoka 120a6e
  TThread::MutexLocker sl(&m_mutex);
Shinya Kitaoka 120a6e
  m_items.clear();
Shinya Kitaoka 120a6e
  m_lastTrack = TSoundTrackP();
Shinya Kitaoka 120a6e
  std::list<wavehdr *="">::iterator it;</wavehdr>
Shinya Kitaoka 120a6e
  for (it = m_queuedItems.begin(); it != m_queuedItems.end(); it++) {
Shinya Kitaoka 120a6e
    WAVEHDR *wvhdr = *it;
Shinya Kitaoka 120a6e
    delete[] wvhdr->lpData;
Shinya Kitaoka 120a6e
    delete wvhdr;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_queuedItems.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool WavehdrQueue::isAllQueuedItemsPlayed() {
Shinya Kitaoka 120a6e
  std::list<wavehdr *="">::iterator it;</wavehdr>
Shinya Kitaoka 120a6e
  bool finished = true;
Shinya Kitaoka 120a6e
  for (it = m_queuedItems.begin(); it != m_queuedItems.end(); it++) {
Shinya Kitaoka 120a6e
    WAVEHDR *wvhdr = *it;
Shinya Kitaoka 120a6e
    finished       = finished && (wvhdr->dwFlags & WHDR_DONE);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return finished;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TSoundOutputDeviceImp::TSoundOutputDeviceImp()
Shinya Kitaoka 120a6e
    : m_stopped(true)
Shinya Kitaoka 120a6e
    , m_isPlaying(false)
Shinya Kitaoka 120a6e
    , m_looped(false)
Shinya Kitaoka 120a6e
    , m_scrubbing(false)
Shinya Kitaoka 120a6e
    , m_wout(0) {
Shinya Kitaoka 120a6e
  m_whdrQueue = new WavehdrQueue(this, 4);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  insertAllRate();
Shinya Kitaoka 120a6e
  if (!verifyRate())
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::FailedInit,
Shinya Kitaoka 120a6e
                                "Unable to verify supported rates");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_closeDevice = CreateEvent(NULL,   // no security attributes
Shinya Kitaoka 120a6e
                              FALSE,  // auto-reset event
Shinya Kitaoka 120a6e
                              FALSE,  // initial state is not signaled
Shinya Kitaoka 120a6e
                              NULL);  // object not named
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TSoundOutputDeviceImp::~TSoundOutputDeviceImp() { delete m_whdrQueue; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDeviceImp::doOpenDevice(const TSoundTrackFormat &format) {
Shinya Kitaoka 120a6e
  WAVEFORMATEX wf;
Shinya Kitaoka 120a6e
  wf.wFormatTag      = WAVE_FORMAT_PCM;
Shinya Kitaoka 120a6e
  wf.nChannels       = format.m_channelCount;
Shinya Kitaoka 120a6e
  wf.nSamplesPerSec  = format.m_sampleRate;
Shinya Kitaoka 120a6e
  wf.wBitsPerSample  = format.m_bitPerSample;
Shinya Kitaoka 120a6e
  wf.nBlockAlign     = (wf.nChannels * wf.wBitsPerSample) >> 3;
Shinya Kitaoka 120a6e
  wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;
Shinya Kitaoka 120a6e
  wf.cbSize          = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TThread::MutexLocker sl(&m_mutex);
Shinya Kitaoka 120a6e
  CloseHandle(CreateThread(NULL, 0, MyWaveOutCallbackThread, (LPVOID)this, 0,
Shinya Kitaoka 120a6e
                           &m_notifyThreadId));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  MMRESULT ret;
Shinya Kitaoka 120a6e
  if ((ret = waveOutOpen(&m_wout, WAVE_MAPPER, &wf, (DWORD)m_notifyThreadId,
Shinya Kitaoka 120a6e
                         (DWORD)this, CALLBACK_THREAD)) != MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
    while (!PostThreadMessage(m_notifyThreadId, WM_QUIT, 0, 0))
Shinya Kitaoka 120a6e
      ;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR) return false;
Shinya Kitaoka 120a6e
  m_currentFormat = format;
Shinya Kitaoka 120a6e
  return (ret == MMSYSERR_NOERROR);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDeviceImp::doPlay(WAVEHDR *whdr,
Shinya Kitaoka 120a6e
                                   const TSoundTrackFormat format) {
Shinya Kitaoka 120a6e
  TThread::MutexLocker sl(&m_mutex);
Shinya Kitaoka 120a6e
  if (!m_wout || (m_wout && m_currentFormat != format)) doOpenDevice(format);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  MMRESULT ret;
Shinya Kitaoka 120a6e
  ret = waveOutWrite(m_wout, whdr, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR) return false;
Shinya Kitaoka 120a6e
  m_stopped   = false;
Shinya Kitaoka 120a6e
  m_isPlaying = true;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDeviceImp::doCloseDevice() {
Shinya Kitaoka 120a6e
  TThread::MutexLocker sl(&m_mutex);
Shinya Kitaoka 120a6e
  if (m_wout) {
Shinya Kitaoka 120a6e
    MMRESULT ret = waveOutReset(m_wout);
Shinya Kitaoka 120a6e
    if (ret != MMSYSERR_NOERROR) return false;
Shinya Kitaoka 120a6e
    ret = waveOutClose(m_wout);
Shinya Kitaoka 120a6e
    if (ret != MMSYSERR_NOERROR) return false;
Shinya Kitaoka 120a6e
    m_wout      = 0;
Shinya Kitaoka 120a6e
    m_stopped   = true;
Shinya Kitaoka 120a6e
    m_isPlaying = false;
Shinya Kitaoka 120a6e
    m_looped    = false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  PostThreadMessage(m_notifyThreadId, WM_QUIT, 0, 0);
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TSoundOutputDeviceImp::insertAllRate() {
Shinya Kitaoka 120a6e
  m_supportedRate.insert(8000);
Shinya Kitaoka 120a6e
  m_supportedRate.insert(11025);
Shinya Kitaoka 120a6e
  m_supportedRate.insert(16000);
Shinya Kitaoka 120a6e
  m_supportedRate.insert(22050);
Shinya Kitaoka 120a6e
  m_supportedRate.insert(32000);
Shinya Kitaoka 120a6e
  m_supportedRate.insert(44100);
Shinya Kitaoka 120a6e
  m_supportedRate.insert(48000);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDeviceImp::verifyRate() {
Shinya Kitaoka 120a6e
  std::set<int>::iterator it;</int>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (it = m_supportedRate.begin(); it != m_supportedRate.end();) {
Shinya Kitaoka 120a6e
    MMRESULT ret;
Shinya Kitaoka 120a6e
    WAVEFORMATEX wf;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    wf.wFormatTag      = WAVE_FORMAT_PCM;
Shinya Kitaoka 120a6e
    wf.nChannels       = 1;
Shinya Kitaoka 120a6e
    wf.nSamplesPerSec  = *it;
Shinya Kitaoka 120a6e
    wf.wBitsPerSample  = 8;
Shinya Kitaoka 120a6e
    wf.nBlockAlign     = (wf.nChannels * wf.wBitsPerSample) >> 3;
Shinya Kitaoka 120a6e
    wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;
Shinya Kitaoka 120a6e
    wf.cbSize          = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ret = waveOutOpen(NULL, WAVE_MAPPER, &wf, NULL, NULL, WAVE_FORMAT_QUERY);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (ret == MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
      ++it;
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (ret == WAVERR_BADFORMAT)
Shinya Kitaoka 120a6e
      it = m_supportedRate.erase(it);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (m_supportedRate.end() == m_supportedRate.begin()) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TSoundOutputDevice::TSoundOutputDevice() : m_imp(new TSoundOutputDeviceImp()) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TSoundOutputDevice::~TSoundOutputDevice() {
Shinya Kitaoka 120a6e
  close();
Shinya Kitaoka 120a6e
  WaitForSingleObject(m_imp->m_closeDevice, INFINITE);
Shinya Kitaoka 120a6e
  CloseHandle(m_imp->m_closeDevice);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
DWORD WINAPI MyWaveOutCallbackThread(LPVOID lpParameter) {
Shinya Kitaoka 120a6e
  TSoundOutputDeviceImp *devImp = (TSoundOutputDeviceImp *)lpParameter;
Shinya Kitaoka 120a6e
  if (!devImp) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  MSG msg;
Shinya Kitaoka 120a6e
  BOOL bRet;
Shinya Kitaoka 120a6e
  while (bRet = GetMessage(&msg, NULL, 0, 0)) {
Shinya Kitaoka 120a6e
    if (bRet == -1) {
Shinya Kitaoka 120a6e
      // si e' verificato un errore
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    switch (msg.message) {
Shinya Kitaoka 120a6e
    case MM_WOM_DONE: {
Shinya Kitaoka 120a6e
      WAVEHDR *pWaveHdr = ((WAVEHDR *)msg.lParam);
Shinya Kitaoka 120a6e
      {
Shinya Kitaoka 120a6e
        TThread::MutexLocker sl(&devImp->m_mutex);
Shinya Kitaoka 120a6e
        if (devImp->m_looped) {
Shinya Kitaoka 120a6e
          devImp->doPlay(pWaveHdr, devImp->m_currentFormat);
Shinya Kitaoka 120a6e
          continue;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      WAVEHDR *whdr = 0;
Shinya Kitaoka 120a6e
      if (devImp->m_whdrQueue->popFront(pWaveHdr->dwUser)) {
Shinya Kitaoka 120a6e
        whdr = devImp->m_whdrQueue->get();
Shinya Kitaoka 120a6e
        if (whdr) devImp->doPlay(whdr, devImp->m_currentFormat);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        WaitForSingleObject(devImp->m_closeDevice, INFINITE);
Shinya Kitaoka 120a6e
        CloseHandle(devImp->m_closeDevice);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        MMRESULT ret =
Shinya Kitaoka 120a6e
            waveOutUnprepareHeader(devImp->m_wout, pWaveHdr, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
        if (ret == MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
          delete pWaveHdr->lpData;
Shinya Kitaoka 120a6e
          delete pWaveHdr;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (!whdr && devImp->m_whdrQueue->size() == 0) {
Shinya Kitaoka 120a6e
        std::set<tsoundoutputdevicelistener *="">::iterator it =</tsoundoutputdevicelistener>
Shinya Kitaoka 120a6e
            devImp->m_listeners.begin();
Shinya Kitaoka 120a6e
        for (; it != devImp->m_listeners.end(); ++it) {
Toshihiro Shimizu 890ddd
#ifndef TNZCORE_LIGHT
Shinya Kitaoka 120a6e
          EndPlayMsg *event = new EndPlayMsg(*it);
Shinya Kitaoka 120a6e
          event->send();
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
          assert(false);
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        devImp->doCloseDevice();
Shinya Kitaoka 120a6e
      }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    case MM_WOM_CLOSE:
Shinya Kitaoka 120a6e
      break;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    default:
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  SetEvent(devImp->m_closeDevice);
Shinya Kitaoka 120a6e
  return 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void getAmplitude(int &litude, const TSoundTrackP st, TINT32 sample) {
Shinya Kitaoka 120a6e
  TSoundTrackP snd = st;
Shinya Kitaoka 120a6e
  amplitude        = 0;
Shinya Kitaoka 120a6e
  int k            = 0;
Shinya Kitaoka 120a6e
  for (k = 0; k < snd->getChannelCount(); ++k)
Shinya Kitaoka 120a6e
    amplitude += (int)snd->getPressure(sample, k);
Shinya Kitaoka 120a6e
  amplitude /= k;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDevice::installed() {
Shinya Kitaoka 120a6e
  int ndev = waveOutGetNumDevs();
Shinya Kitaoka 120a6e
  if (ndev <= 0) return false;
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDevice::open(const TSoundTrackP &st) {
Shinya Kitaoka 120a6e
  return m_imp->doOpenDevice(st->getFormat());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TSoundOutputDevice::attach(TSoundOutputDeviceListener *listener) {
Shinya Kitaoka 120a6e
  m_imp->m_listeners.insert(listener);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TSoundOutputDevice::detach(TSoundOutputDeviceListener *listener) {
Shinya Kitaoka 120a6e
  m_imp->m_listeners.erase(listener);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TSoundOutputDevice::play(const TSoundTrackP &st, TINT32 s0, TINT32 s1,
Shinya Kitaoka 120a6e
                              bool loop, bool scrubbing) {
Shinya Kitaoka 120a6e
  assert((scrubbing && !loop) || !scrubbing);
Shinya Kitaoka 120a6e
  if (!st->getSampleCount()) return;
Shinya Kitaoka 120a6e
  TSoundTrackFormat format;
Shinya Kitaoka 120a6e
  TSoundTrackP subTrack;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    TThread::MutexLocker sl(&m_imp->m_mutex);
Shinya Kitaoka 120a6e
    if (m_imp->m_looped)
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(
Shinya Kitaoka 120a6e
          TSoundDeviceException::Busy,
Shinya Kitaoka 120a6e
          "Unable to queue another playback when the sound player is looping");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    format = st->getFormat();
Shinya Kitaoka 120a6e
    try {
Shinya Kitaoka 120a6e
      TSoundTrackFormat fmt = getPreferredFormat(format);
Shinya Kitaoka 120a6e
      if (fmt != format) {
Shinya Kitaoka 120a6e
        throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat,
Shinya Kitaoka 120a6e
                                    "Unsupported Format");
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } catch (TSoundDeviceException &e) {
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat,
Shinya Kitaoka 120a6e
                                  e.getMessage());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    assert(s1 >= s0);
Shinya Kitaoka 120a6e
    subTrack           = st->extract(s0, s1);
Shinya Kitaoka 120a6e
    m_imp->m_looped    = loop;
Shinya Kitaoka 120a6e
    m_imp->m_scrubbing = scrubbing;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!m_imp->m_wout) m_imp->doOpenDevice(format);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_imp->m_whdrQueue->put(subTrack);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TSoundOutputDevice::stop() {
Shinya Kitaoka 120a6e
  if ((m_imp->m_wout) && m_imp->m_isPlaying) {
Shinya Kitaoka 120a6e
    MMRESULT ret = waveOutReset(m_imp->m_wout);
Shinya Kitaoka 120a6e
    if (ret != MMSYSERR_NOERROR) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    TThread::MutexLocker sl(&m_imp->m_mutex);
Shinya Kitaoka 120a6e
    m_imp->m_looped    = false;
Shinya Kitaoka 120a6e
    m_imp->m_stopped   = true;
Shinya Kitaoka 120a6e
    m_imp->m_isPlaying = false;
Shinya Kitaoka 120a6e
    m_imp->m_whdrQueue->clear();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDevice::close() { return m_imp->doCloseDevice(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDevice::isPlaying() const { return m_imp->m_isPlaying; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDevice::isAllQueuedItemsPlayed() {
Shinya Kitaoka 120a6e
  return m_imp->m_whdrQueue->isAllQueuedItemsPlayed();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDevice::isLooping() {
Shinya Kitaoka 120a6e
  TThread::MutexLocker sl(&m_imp->m_mutex);
Shinya Kitaoka 120a6e
  return m_imp->m_looped;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TSoundOutputDevice::setLooping(bool loop) {
Shinya Kitaoka 120a6e
  TThread::MutexLocker sl(&m_imp->m_mutex);
Shinya Kitaoka 120a6e
  m_imp->m_looped = loop;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TSoundTrackFormat TSoundOutputDevice::getPreferredFormat(TUINT32 sampleRate,
Shinya Kitaoka 120a6e
                                                         int channelCount,
Shinya Kitaoka 120a6e
                                                         int bitPerSample) {
Shinya Kitaoka 120a6e
  TSoundTrackFormat fmt;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // avvvicinarsi al sample rate => dovrebbe esser OK avendo selezionato i piu'
Shinya Kitaoka 120a6e
  // vicini
Shinya Kitaoka 120a6e
  std::set<int>::iterator it = m_imp->m_supportedRate.lower_bound(sampleRate);</int>
Shinya Kitaoka 120a6e
  if (it == m_imp->m_supportedRate.end()) {
Shinya Kitaoka 120a6e
    it = std::max_element(m_imp->m_supportedRate.begin(),
Shinya Kitaoka 120a6e
                          m_imp->m_supportedRate.end());
Shinya Kitaoka 120a6e
    if (it != m_imp->m_supportedRate.end())
Shinya Kitaoka 120a6e
      sampleRate = *(m_imp->m_supportedRate.rbegin());
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat,
Shinya Kitaoka 120a6e
                                  "There isn't a supported format");
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    sampleRate = *it;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (bitPerSample <= 8)
Shinya Kitaoka 120a6e
    bitPerSample = 8;
Shinya Kitaoka 120a6e
  else if ((bitPerSample > 8 && bitPerSample < 16) || bitPerSample >= 16)
Shinya Kitaoka 120a6e
    bitPerSample = 16;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (bitPerSample >= 16)
Shinya Kitaoka 120a6e
    fmt.m_signedSample = true;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    fmt.m_signedSample = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // switch mono/stereo
Shinya Kitaoka 120a6e
  if (channelCount <= 1)
Shinya Kitaoka 120a6e
    channelCount = 1;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    channelCount = 2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  fmt.m_bitPerSample = bitPerSample;
Shinya Kitaoka 120a6e
  fmt.m_channelCount = channelCount;
Shinya Kitaoka 120a6e
  fmt.m_sampleRate   = sampleRate;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return fmt;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TSoundTrackFormat TSoundOutputDevice::getPreferredFormat(
Shinya Kitaoka 120a6e
    const TSoundTrackFormat &format) {
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    return getPreferredFormat(format.m_sampleRate, format.m_channelCount,
Shinya Kitaoka 120a6e
                              format.m_bitPerSample);
Shinya Kitaoka 120a6e
  } catch (TSoundDeviceException &e) {
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat,
Shinya Kitaoka 120a6e
                                e.getMessage());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
// Classi per la gestione della registrazione
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class WaveFormat : public WAVEFORMATEX {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  WaveFormat(){};
Shinya Kitaoka 120a6e
  WaveFormat(unsigned char channelCount, unsigned TINT32 sampleRate,
Shinya Kitaoka 120a6e
             unsigned char bitPerSample);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ~WaveFormat(){};
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
WaveFormat::WaveFormat(unsigned char channelCount, unsigned TINT32 sampleRate,
Shinya Kitaoka 120a6e
                       unsigned char bitPerSample) {
Shinya Kitaoka 120a6e
  wFormatTag      = WAVE_FORMAT_PCM;
Shinya Kitaoka 120a6e
  nChannels       = channelCount;
Shinya Kitaoka 120a6e
  nSamplesPerSec  = sampleRate;
Shinya Kitaoka 120a6e
  wBitsPerSample  = bitPerSample;
Shinya Kitaoka 120a6e
  nBlockAlign     = (channelCount * bitPerSample) >> 3;
Shinya Kitaoka 120a6e
  nAvgBytesPerSec = nBlockAlign * sampleRate;
Shinya Kitaoka 120a6e
  cbSize          = 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class WinSoundInputDevice {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  WinSoundInputDevice();
Shinya Kitaoka 120a6e
  ~WinSoundInputDevice();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void open(const WaveFormat &wf);
Shinya Kitaoka 120a6e
  void close();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void prepareHeader(char *sampleBuffer, unsigned TINT32 sampleBufferSize,
Shinya Kitaoka 120a6e
                     WAVEHDR &whdr);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void unprepareHeader(WAVEHDR &whdr);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void addBlock(WAVEHDR &whdr);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void start();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void reset();
Shinya Kitaoka 120a6e
  void stop();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  HANDLE m_hBlockDone;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  HWAVEIN m_hWaveIn;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
WinSoundInputDevice::WinSoundInputDevice() : m_hWaveIn(0) {
Shinya Kitaoka 120a6e
  m_hBlockDone = CreateEvent(NULL,   // no security attributes
Shinya Kitaoka 120a6e
                             FALSE,  // auto-reset event
Shinya Kitaoka 120a6e
                             FALSE,  // initial state is not signaled
Shinya Kitaoka 120a6e
                             NULL);  // object not named
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
WinSoundInputDevice::~WinSoundInputDevice() { CloseHandle(m_hBlockDone); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void WinSoundInputDevice::open(const WaveFormat &wf) {
Shinya Kitaoka 120a6e
  if (m_hWaveIn) close();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  MMRESULT ret = waveInOpen(&m_hWaveIn, WAVE_MAPPER, &wf, (DWORD)recordCB,
Shinya Kitaoka 120a6e
                            (DWORD)m_hBlockDone, CALLBACK_FUNCTION);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
    throw TException("Error to open the input device");
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void WinSoundInputDevice::close() {
Shinya Kitaoka 120a6e
  if (!m_hWaveIn) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  MMRESULT ret = waveInClose(m_hWaveIn);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
    throw TException("Error to close the input device");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_hWaveIn = 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void WinSoundInputDevice::prepareHeader(char *sampleBuffer,
Shinya Kitaoka 120a6e
                                        unsigned TINT32 sampleBufferSize,
Shinya Kitaoka 120a6e
                                        WAVEHDR &whdr) {
Shinya Kitaoka 120a6e
  whdr.lpData         = sampleBuffer;
Shinya Kitaoka 120a6e
  whdr.dwBufferLength = sampleBufferSize;  // numero di byte
Shinya Kitaoka 120a6e
  whdr.dwFlags        = 0;
Shinya Kitaoka 120a6e
  whdr.dwLoops        = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  MMRESULT ret = waveInPrepareHeader(m_hWaveIn, &whdr, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
    throw TException("Unable to prepare a wave header");
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void WinSoundInputDevice::unprepareHeader(WAVEHDR &whdr) {
Shinya Kitaoka 120a6e
  MMRESULT ret = waveInUnprepareHeader(m_hWaveIn, &whdr, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
    throw TException("Unable to unprepare a wave header");
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void WinSoundInputDevice::addBlock(WAVEHDR &whdr) {
Shinya Kitaoka 120a6e
  MMRESULT ret = waveInAddBuffer(m_hWaveIn, &whdr, sizeof(WAVEHDR));
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
    throw TException("Unable to add a waveheader");
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void WinSoundInputDevice::start() {
Shinya Kitaoka 120a6e
  int ret = waveInStart(m_hWaveIn);
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
    throw TException("Unable to add a waveheader");
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void WinSoundInputDevice::reset() {
Shinya Kitaoka 120a6e
  if (!m_hWaveIn) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  MMRESULT ret = waveInReset(m_hWaveIn);
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
    throw TException("Unable to add a waveheader");
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void WinSoundInputDevice::stop() {
Shinya Kitaoka 120a6e
  MMRESULT ret = waveInStop(m_hWaveIn);
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
    throw TException("Unable to add a waveheader");
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//====================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef TNZCORE_LIGHT
Shinya Kitaoka 120a6e
class RecordTask : public TThread::Runnable {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  RecordTask(std::shared_ptr<tsoundinputdeviceimp> dev)</tsoundinputdeviceimp>
Shinya Kitaoka 120a6e
      : Runnable(), m_dev(std::move(dev)) {}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ~RecordTask() {}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void run() override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::shared_ptr<tsoundinputdeviceimp> m_dev;</tsoundinputdeviceimp>
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//====================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class TSoundInputDeviceImp : public WinSoundInputDevice {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  bool m_allocateBuff;
Shinya Kitaoka 120a6e
  bool m_isRecording;
Shinya Kitaoka 120a6e
  bool m_supportVolume;
Shinya Kitaoka 120a6e
  int m_index;
Shinya Kitaoka 120a6e
  TINT32 m_byteRecorded;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TSoundTrackP m_st;
Shinya Kitaoka 120a6e
  TSoundTrackFormat m_format;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef TNZCORE_LIGHT
Shinya Kitaoka 120a6e
  TThread::Executor m_executor;
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
  std::vector<wavehdr> m_whdr;</wavehdr>
Shinya Kitaoka 120a6e
  std::vector<char *=""> m_recordedBlocks;</char>
Shinya Kitaoka 120a6e
  std::set<int> m_supportedRate;</int>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  HANDLE m_hLastBlockDone;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TSoundInputDeviceImp();
Shinya Kitaoka 120a6e
  ~TSoundInputDeviceImp();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void insertAllRate();
Shinya Kitaoka 120a6e
  bool verifyRate();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TSoundInputDeviceImp::TSoundInputDeviceImp()
Shinya Kitaoka 120a6e
    : m_allocateBuff(false)
Shinya Kitaoka 120a6e
    , m_isRecording(false)
Shinya Kitaoka 120a6e
    , m_supportVolume(false)
Shinya Kitaoka 120a6e
    , m_index(0)
Shinya Kitaoka 120a6e
    , m_byteRecorded(0)
Shinya Kitaoka 120a6e
    , m_format()
Shinya Kitaoka 120a6e
    , m_whdr(3)
Shinya Kitaoka 120a6e
    , m_recordedBlocks()
Shinya Kitaoka 120a6e
    , m_supportedRate() {
Shinya Kitaoka 120a6e
  m_hLastBlockDone = CreateEvent(NULL,   // no security attributes
Shinya Kitaoka 120a6e
                                 FALSE,  // is manual-reset event?
Shinya Kitaoka 120a6e
                                 FALSE,  // is signaled?
Shinya Kitaoka 120a6e
                                 NULL);  // object not named
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TSoundInputDeviceImp::~TSoundInputDeviceImp() {
Shinya Kitaoka 120a6e
  if (m_isRecording) {
Shinya Kitaoka 120a6e
    try {
Shinya Kitaoka 120a6e
      reset();
Shinya Kitaoka 120a6e
      WaitForSingleObject(m_hLastBlockDone, INFINITE);
Shinya Kitaoka 120a6e
      int i;
Shinya Kitaoka 120a6e
      for (i = 0; i < (int)m_recordedBlocks.size(); ++i)
Shinya Kitaoka 120a6e
        delete[] m_recordedBlocks[i];
Shinya Kitaoka 120a6e
      close();
Shinya Kitaoka 120a6e
    } catch (TException &) {
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  CloseHandle(m_hLastBlockDone);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TSoundInputDeviceImp::insertAllRate() {
Shinya Kitaoka 120a6e
  m_supportedRate.insert(8000);
Shinya Kitaoka 120a6e
  m_supportedRate.insert(11025);
Shinya Kitaoka 120a6e
  m_supportedRate.insert(16000);
Shinya Kitaoka 120a6e
  m_supportedRate.insert(22050);
Shinya Kitaoka 120a6e
  m_supportedRate.insert(32000);
Shinya Kitaoka 120a6e
  m_supportedRate.insert(44100);
Shinya Kitaoka 120a6e
  m_supportedRate.insert(48000);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundInputDeviceImp::verifyRate() {
Shinya Kitaoka 120a6e
  std::set<int>::iterator it;</int>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (it = m_supportedRate.begin(); it != m_supportedRate.end();) {
Shinya Kitaoka 120a6e
    MMRESULT ret;
Shinya Kitaoka 120a6e
    WAVEFORMATEX wf;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    wf.wFormatTag      = WAVE_FORMAT_PCM;
Shinya Kitaoka 120a6e
    wf.nChannels       = 1;
Shinya Kitaoka 120a6e
    wf.nSamplesPerSec  = *it;
Shinya Kitaoka 120a6e
    wf.wBitsPerSample  = 8;
Shinya Kitaoka 120a6e
    wf.nBlockAlign     = (wf.nChannels * wf.wBitsPerSample) >> 3;
Shinya Kitaoka 120a6e
    wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;
Shinya Kitaoka 120a6e
    wf.cbSize          = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ret = waveInOpen(NULL, WAVE_MAPPER, &wf, NULL, NULL, WAVE_FORMAT_QUERY);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (ret == MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
      ++it;
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (ret == WAVERR_BADFORMAT)
Shinya Kitaoka 120a6e
      it = m_supportedRate.erase(it);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (m_supportedRate.end() == m_supportedRate.begin()) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//====================================================================
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
void CALLBACK recordCB(HWAVEIN hwi, UINT uMsg, DWORD dwInstance, DWORD dwParam1,
Shinya Kitaoka 120a6e
                       DWORD dwParam2) {
Shinya Kitaoka 120a6e
  WAVEHDR *whdr     = (WAVEHDR *)dwParam1;
Shinya Kitaoka 120a6e
  HANDLE *blockDone = (HANDLE *)dwInstance;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (uMsg != MM_WIM_DATA) return;
Shinya Kitaoka 120a6e
  SetEvent(blockDone);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TSoundInputDevice::TSoundInputDevice() : m_imp(new TSoundInputDeviceImp()) {
Shinya Kitaoka 120a6e
  m_imp->insertAllRate();
Shinya Kitaoka 120a6e
  if (!m_imp->verifyRate())
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::FailedInit,
Shinya Kitaoka 120a6e
                                "Unable to verify supported rates");
Shinya Kitaoka 120a6e
  if (supportsVolume()) m_imp->m_supportVolume = true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TSoundInputDevice::~TSoundInputDevice() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundInputDevice::installed() {
Shinya Kitaoka 120a6e
  int ndev = waveInGetNumDevs();
Shinya Kitaoka 120a6e
  if (ndev <= 0) return false;
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef TNZCORE_LIGHT
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TSoundInputDevice::record(const TSoundTrackFormat &format,
Shinya Kitaoka 120a6e
                               Source devtype) {
Shinya Kitaoka 120a6e
  if (m_imp->m_isRecording)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::Busy,
Shinya Kitaoka 120a6e
                                "Just another recoding is in progress");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /*if ((format.m_bitPerSample == 8 && format.m_signedSample) ||
Shinya Kitaoka 120a6e
(format.m_bitPerSample == 24))
Shinya Kitaoka 120a6e
throw TException("This format is not supported for recording");*/
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    TSoundTrackFormat fmt = getPreferredFormat(format);
Shinya Kitaoka 120a6e
    if (fmt != format) {
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat,
Shinya Kitaoka 120a6e
                                  "Unsupported Format");
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } catch (TSoundDeviceException &e) {
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat,
Shinya Kitaoka 120a6e
                                e.getMessage());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!setRecordLine(devtype))
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnableSetDevice,
Shinya Kitaoka 120a6e
                                "Problems to set input source line to record");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_imp->m_format = format;
Shinya Kitaoka 120a6e
  m_imp->m_st     = 0;
Shinya Kitaoka 120a6e
  ResetEvent(m_imp->m_hLastBlockDone);
Shinya Kitaoka 120a6e
  ResetEvent(m_imp->m_hBlockDone);
Shinya Kitaoka 120a6e
  m_imp->m_allocateBuff = true;
Shinya Kitaoka 120a6e
  m_imp->m_isRecording  = true;
Shinya Kitaoka 120a6e
  m_imp->m_index        = 0;
Shinya Kitaoka 120a6e
  m_imp->m_recordedBlocks.clear();
Shinya Kitaoka 120a6e
  m_imp->m_byteRecorded = 0;
Shinya Kitaoka 120a6e
  TINT32 bytePerSec     = format.m_sampleRate *
Shinya Kitaoka 120a6e
                      ((format.m_bitPerSample * format.m_channelCount) >> 3);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    WaveFormat wf(m_imp->m_format.m_channelCount, m_imp->m_format.m_sampleRate,
Shinya Kitaoka 120a6e
                  m_imp->m_format.m_bitPerSample);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_imp->open(wf);
Shinya Kitaoka 120a6e
  } catch (TException &e) {
Shinya Kitaoka 120a6e
    m_imp->m_isRecording = false;
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnableOpenDevice,
Shinya Kitaoka 120a6e
                                e.getMessage());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  for (; m_imp->m_index < (int)(m_imp->m_whdr.size() - 1); ++m_imp->m_index) {
Shinya Kitaoka 120a6e
    try {
Shinya Kitaoka 120a6e
      m_imp->prepareHeader(new char[bytePerSec], bytePerSec,
Shinya Kitaoka 120a6e
                           m_imp->m_whdr[m_imp->m_index]);
Shinya Kitaoka 120a6e
      m_imp->addBlock(m_imp->m_whdr[m_imp->m_index]);
Shinya Kitaoka 120a6e
    } catch (TException &e) {
Shinya Kitaoka 120a6e
      m_imp->m_isRecording = false;
Shinya Kitaoka 120a6e
      for (int j = 0; j < (int)(m_imp->m_whdr.size() - 1); ++j) {
Shinya Kitaoka 120a6e
        if (m_imp->m_whdr[j].dwFlags & WHDR_PREPARED) {
Shinya Kitaoka 120a6e
          try {
Shinya Kitaoka 120a6e
            m_imp->unprepareHeader(m_imp->m_whdr[j]);
Shinya Kitaoka 120a6e
          } catch (TException &e) {
Shinya Kitaoka 120a6e
            throw TSoundDeviceException(
Shinya Kitaoka 120a6e
                TSoundDeviceException::UnableCloseDevice, e.getMessage());
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
          delete[] m_imp->m_whdr[j].lpData;
Shinya Kitaoka 120a6e
        } else if (j == m_imp->m_index)
Shinya Kitaoka 120a6e
          delete[] m_imp->m_whdr[j].lpData;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
                                  e.getMessage());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_imp->m_executor.addTask(new RecordTask(m_imp));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TSoundInputDevice::record(const TSoundTrackP &st, Source devtype) {
Shinya Kitaoka 120a6e
  if (m_imp->m_isRecording)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::Busy,
Shinya Kitaoka 120a6e
                                "Just another recoding is in progress");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_imp->m_format = st->getFormat();
Shinya Kitaoka 120a6e
  /*if ((m_imp->m_format.m_bitPerSample == 8 && m_imp->m_format.m_signedSample)
Shinya Kitaoka 120a6e
||
Shinya Kitaoka 120a6e
(m_imp->m_format.m_bitPerSample == 24))
Shinya Kitaoka 120a6e
throw TException("This format is not supported for recording");*/
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    TSoundTrackFormat fmt = getPreferredFormat(st->getFormat());
Shinya Kitaoka 120a6e
    if (fmt != st->getFormat()) {
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat,
Shinya Kitaoka 120a6e
                                  "Unsupported Format");
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } catch (TSoundDeviceException &e) {
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat,
Shinya Kitaoka 120a6e
                                e.getMessage());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!setRecordLine(devtype))
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnableSetDevice,
Shinya Kitaoka 120a6e
                                "Problems to set input source line to record");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_imp->m_st           = st;
Shinya Kitaoka 120a6e
  m_imp->m_allocateBuff = false;
Shinya Kitaoka 120a6e
  m_imp->m_isRecording  = true;
Shinya Kitaoka 120a6e
  ResetEvent(m_imp->m_hLastBlockDone);
Shinya Kitaoka 120a6e
  ResetEvent(m_imp->m_hBlockDone);
Shinya Kitaoka 120a6e
  m_imp->m_index = 0;
Shinya Kitaoka 120a6e
  m_imp->m_recordedBlocks.clear();
Shinya Kitaoka 120a6e
  m_imp->m_byteRecorded = 0;
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    WaveFormat wf(m_imp->m_format.m_channelCount, m_imp->m_format.m_sampleRate,
Shinya Kitaoka 120a6e
                  m_imp->m_format.m_bitPerSample);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_imp->open(wf);
Shinya Kitaoka 120a6e
    m_imp->prepareHeader(
Shinya Kitaoka 120a6e
        (char *)st->getRawData(),
Shinya Kitaoka 120a6e
        st->getSampleCount() *
Shinya Kitaoka 120a6e
            ((st->getBitPerSample() * st->getChannelCount()) >> 3),
Shinya Kitaoka 120a6e
        m_imp->m_whdr[m_imp->m_index]);
Shinya Kitaoka 120a6e
    m_imp->addBlock(m_imp->m_whdr[m_imp->m_index]);
Shinya Kitaoka 120a6e
  } catch (TException &e) {
Shinya Kitaoka 120a6e
    m_imp->m_isRecording = false;
Shinya Kitaoka 120a6e
    if (m_imp->m_whdr[m_imp->m_index].dwFlags & WHDR_PREPARED)
Shinya Kitaoka 120a6e
      m_imp->unprepareHeader(m_imp->m_whdr[m_imp->m_index]);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
                                e.getMessage());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_imp->m_executor.addTask(new RecordTask(m_imp));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TSoundTrackP TSoundInputDevice::stop() {
Shinya Kitaoka 120a6e
  if (!m_imp->m_isRecording) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_imp->m_isRecording = false;
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    m_imp->reset();
Shinya Kitaoka 120a6e
  } catch (TException &e) {
Shinya Kitaoka 120a6e
    for (int j = 0; j < (int)m_imp->m_whdr.size(); ++j) {
Shinya Kitaoka 120a6e
      if (m_imp->m_whdr[j].dwFlags & WHDR_PREPARED) {
Shinya Kitaoka 120a6e
        try {
Shinya Kitaoka 120a6e
          m_imp->unprepareHeader(m_imp->m_whdr[j]);
Shinya Kitaoka 120a6e
        } catch (TException &e) {
Shinya Kitaoka 120a6e
          throw TSoundDeviceException(TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
                                      e.getMessage());
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        delete[] m_imp->m_whdr[j].lpData;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnableCloseDevice,
Shinya Kitaoka 120a6e
                                e.getMessage());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_imp->m_allocateBuff) {
Shinya Kitaoka 120a6e
    WaitForSingleObject(m_imp->m_hLastBlockDone, INFINITE);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TSoundTrackP st = TSoundTrack::create(
Shinya Kitaoka 120a6e
        m_imp->m_format,
Shinya Kitaoka 120a6e
        m_imp->m_byteRecorded / ((m_imp->m_format.m_bitPerSample *
Shinya Kitaoka 120a6e
                                  m_imp->m_format.m_channelCount) >>
Shinya Kitaoka 120a6e
                                 3));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TINT32 bytePerSec =
Shinya Kitaoka 120a6e
        m_imp->m_format.m_sampleRate *
Shinya Kitaoka 120a6e
        ((m_imp->m_format.m_bitPerSample * m_imp->m_format.m_channelCount) >>
Shinya Kitaoka 120a6e
         3);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int i;
Shinya Kitaoka 120a6e
    for (i = 0; i < (int)(m_imp->m_recordedBlocks.size() - 1); ++i) {
Shinya Kitaoka 120a6e
      memcpy((void *)(st->getRawData() + bytePerSec * i),
Shinya Kitaoka 120a6e
             m_imp->m_recordedBlocks[i], bytePerSec);
Shinya Kitaoka 120a6e
      delete[] m_imp->m_recordedBlocks[i];
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TINT32 lastBlockSize = m_imp->m_byteRecorded - (bytePerSec * i);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (lastBlockSize != 0) {
Shinya Kitaoka 120a6e
      memcpy((void *)(st->getRawData() + bytePerSec * i),
Shinya Kitaoka 120a6e
             m_imp->m_recordedBlocks[i], lastBlockSize);
Shinya Kitaoka 120a6e
      delete[] m_imp->m_recordedBlocks[i];
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    try {
Shinya Kitaoka 120a6e
      m_imp->close();
Shinya Kitaoka 120a6e
    } catch (TException &e) {
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(TSoundDeviceException::UnableCloseDevice,
Shinya Kitaoka 120a6e
                                  e.getMessage());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return st;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    WaitForSingleObject(m_imp->m_hLastBlockDone, INFINITE);
Shinya Kitaoka 120a6e
    try {
Shinya Kitaoka 120a6e
      m_imp->close();
Shinya Kitaoka 120a6e
    } catch (TException &e) {
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(TSoundDeviceException::UnableCloseDevice,
Shinya Kitaoka 120a6e
                                  e.getMessage());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return m_imp->m_st;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
#ifndef TNZCORE_LIGHT
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void RecordTask::run() {
Shinya Kitaoka 120a6e
  m_dev->start();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_dev->m_allocateBuff) {
Shinya Kitaoka 120a6e
    TINT32 bytePerSec =
Shinya Kitaoka 120a6e
        m_dev->m_format.m_sampleRate *
Shinya Kitaoka 120a6e
        ((m_dev->m_format.m_bitPerSample * m_dev->m_format.m_channelCount) >>
Shinya Kitaoka 120a6e
         3);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    while (m_dev->m_whdr[(m_dev->m_index + 1) % m_dev->m_whdr.size()].dwFlags &
Shinya Kitaoka 120a6e
           WHDR_PREPARED) {
Shinya Kitaoka 120a6e
      if (m_dev->m_isRecording)
Shinya Kitaoka 120a6e
        WaitForSingleObject(m_dev->m_hBlockDone, INFINITE);
Shinya Kitaoka 120a6e
      int indexToPrepare = m_dev->m_index;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // calcolo l'indice successivo per far l'unprepare
Shinya Kitaoka 120a6e
      m_dev->m_index = (m_dev->m_index + 1) % m_dev->m_whdr.size();
Shinya Kitaoka 120a6e
      if (m_dev->m_whdr[m_dev->m_index].dwFlags & WHDR_DONE) {
Shinya Kitaoka 120a6e
        TINT32 byteRecorded = m_dev->m_whdr[m_dev->m_index].dwBytesRecorded;
Shinya Kitaoka 120a6e
        if (byteRecorded) {
Shinya Kitaoka 120a6e
          m_dev->m_recordedBlocks.push_back(
Shinya Kitaoka 120a6e
              m_dev->m_whdr[m_dev->m_index].lpData);
Shinya Kitaoka 120a6e
          m_dev->m_byteRecorded += byteRecorded;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        try {
Shinya Kitaoka 120a6e
          m_dev->unprepareHeader(m_dev->m_whdr[m_dev->m_index]);
Shinya Kitaoka 120a6e
        } catch (TException &) {
Shinya Kitaoka 120a6e
          for (int i = 0; i < (int)m_dev->m_recordedBlocks.size(); ++i)
Shinya Kitaoka 120a6e
            delete[] m_dev->m_recordedBlocks[i];
Shinya Kitaoka 120a6e
          return;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (byteRecorded == 0) {
Shinya Kitaoka 120a6e
          delete[] m_dev->m_whdr[m_dev->m_index].lpData;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // con questo controllo si evita che vengano accodati nuovi blocchi
Shinya Kitaoka 120a6e
        // dopo che e' stata chiamata la waveInReset
Shinya Kitaoka 120a6e
        if (m_dev->m_isRecording) {
Shinya Kitaoka 120a6e
          try {
Shinya Kitaoka 120a6e
            m_dev->prepareHeader(new char[bytePerSec], bytePerSec,
Shinya Kitaoka 120a6e
                                 m_dev->m_whdr[indexToPrepare]);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
            m_dev->addBlock(m_dev->m_whdr[indexToPrepare]);
Shinya Kitaoka 120a6e
          } catch (TException &) {
Shinya Kitaoka 120a6e
            m_dev->m_isRecording = false;
Shinya Kitaoka 120a6e
            for (int i = 0; i < (int)m_dev->m_recordedBlocks.size(); ++i)
Shinya Kitaoka 120a6e
              delete[] m_dev->m_recordedBlocks[i];
Shinya Kitaoka 120a6e
            return;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      } else
Shinya Kitaoka 120a6e
        m_dev->m_index = indexToPrepare;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    if (m_dev->m_isRecording)
Shinya Kitaoka 120a6e
      WaitForSingleObject(m_dev->m_hBlockDone, INFINITE);
Shinya Kitaoka 120a6e
    try {
Shinya Kitaoka 120a6e
      m_dev->unprepareHeader(m_dev->m_whdr[m_dev->m_index]);
Shinya Kitaoka 120a6e
      m_dev->m_isRecording = false;
Shinya Kitaoka 120a6e
    } catch (TException &) {
Shinya Kitaoka 120a6e
      m_dev->m_isRecording = false;
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  SetEvent(m_dev->m_hLastBlockDone);
Shinya Kitaoka 120a6e
  return;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double TSoundInputDevice::getVolume() {
Shinya Kitaoka 120a6e
  DWORD dwVolumeControlID;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  UINT nNumMixers;
Shinya Kitaoka 120a6e
  MMRESULT ret;
Shinya Kitaoka 120a6e
  MIXERLINE mxl;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  nNumMixers = mixerGetNumDevs();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (nNumMixers == 0)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Doesn't exist a audio mixer device");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // get dwLineID
Shinya Kitaoka 120a6e
  ret = getLineInfo((HMIXEROBJ)0, MIXERLINE_COMPONENTTYPE_DST_WAVEIN, mxl);
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnableVolume,
Shinya Kitaoka 120a6e
                                "Error to obtain info by mixer");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // get dwControlID
Shinya Kitaoka 120a6e
  MIXERCONTROL mxc;
Shinya Kitaoka 120a6e
  ret = getLineControl(mxc, (HMIXEROBJ)0, mxl.dwLineID,
Shinya Kitaoka 120a6e
                       MIXERCONTROL_CONTROLTYPE_VOLUME);
Shinya Kitaoka 120a6e
  if (ret == MIXERR_INVALCONTROL)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(
Shinya Kitaoka 120a6e
        TSoundDeviceException::UnableVolume,
Shinya Kitaoka 120a6e
        "Is not possible to obtain info of volume by mixer");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnableVolume,
Shinya Kitaoka 120a6e
                                "Error to obtain info by mixer");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  dwVolumeControlID = mxc.dwControlID;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  MIXERCONTROLDETAILS_UNSIGNED mxcdVolume;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ret = getControlDetails((HMIXEROBJ)0, dwVolumeControlID, mxc.cMultipleItems,
Shinya Kitaoka 120a6e
                          &mxcdVolume);
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnableVolume,
Shinya Kitaoka 120a6e
                                "Error to obtain info by mixer");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  DWORD dwVal = mxcdVolume.dwValue;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return (double)dwVal * 10.0 / (double)mxc.Bounds.dwMaximum;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundInputDevice::setVolume(double value) {
Shinya Kitaoka 120a6e
  DWORD dwVolumeControlID, dwMaximum;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  UINT nNumMixers;
Shinya Kitaoka 120a6e
  MMRESULT ret;
Shinya Kitaoka 120a6e
  MIXERLINE mxl;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  nNumMixers = mixerGetNumDevs();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (nNumMixers == 0)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Doesn't exist a audio mixer device");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // get dwLineID
Shinya Kitaoka 120a6e
  ret = getLineInfo((HMIXEROBJ)0, MIXERLINE_COMPONENTTYPE_DST_WAVEIN, mxl);
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR)
Shinya Kitaoka 120a6e
    throw TException("Error to obtain info by mixer");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // get dwControlID
Shinya Kitaoka 120a6e
  MIXERCONTROL mxc;
Shinya Kitaoka 120a6e
  ret = getLineControl(mxc, (HMIXEROBJ)0, mxl.dwLineID,
Shinya Kitaoka 120a6e
                       MIXERCONTROL_CONTROLTYPE_VOLUME);
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnableVolume,
Shinya Kitaoka 120a6e
                                "Error to obtain info by mixer");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  dwMaximum         = mxc.Bounds.dwMaximum;
Shinya Kitaoka 120a6e
  dwVolumeControlID = mxc.dwControlID;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int newValue;
Shinya Kitaoka 120a6e
  double fattProp = ((double)(mxc.Metrics.cSteps - 1) * value) / 10;
Shinya Kitaoka 120a6e
  double delta    = (double)(dwMaximum / (mxc.Metrics.cSteps - 1));
Shinya Kitaoka 120a6e
  newValue        = (int)(tround(fattProp) * delta);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  MIXERCONTROLDETAILS_UNSIGNED mxcdVolume = {newValue};
Shinya Kitaoka 120a6e
  ret = setControlDetails((HMIXEROBJ)0, dwVolumeControlID, mxc.cMultipleItems,
Shinya Kitaoka 120a6e
                          &mxcdVolume);
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnableVolume,
Shinya Kitaoka 120a6e
                                "Error to obtain info by mixer");
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundInputDevice::supportsVolume() {
Shinya Kitaoka 120a6e
  UINT nNumMixers;
Shinya Kitaoka 120a6e
  MMRESULT ret;
Shinya Kitaoka 120a6e
  MIXERLINE mxl;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  nNumMixers = mixerGetNumDevs();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (nNumMixers == 0)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Doesn't exist a audio mixer device");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // get dwLineID
Shinya Kitaoka 120a6e
  ret = getLineInfo((HMIXEROBJ)0, MIXERLINE_COMPONENTTYPE_DST_WAVEIN, mxl);
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnableVolume,
Shinya Kitaoka 120a6e
                                "Error to obtain info by mixer");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // get dwControlID
Shinya Kitaoka 120a6e
  MIXERCONTROL mxc;
Shinya Kitaoka 120a6e
  ret = getLineControl(mxc, (HMIXEROBJ)0, mxl.dwLineID,
Shinya Kitaoka 120a6e
                       MIXERCONTROL_CONTROLTYPE_VOLUME);
Shinya Kitaoka 120a6e
  if (ret == MIXERR_INVALCONTROL) return false;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnableVolume,
Shinya Kitaoka 120a6e
                                "Error to obtain info by mixer");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundInputDevice::isRecording() { return m_imp->m_isRecording; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*TSoundTrackFormat TSoundInputDevice::getPreferredFormat(
Toshihiro Shimizu 890ddd
      ULONG sampleRate, int channelCount, int bitPerSample)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
  MMRESULT ret;
Toshihiro Shimizu 890ddd
  TSoundTrackFormat fmt;
Shinya Kitaoka 120a6e
Toshihiro Shimizu 890ddd
  ret = isaFormatSupported(sampleRate, channelCount, bitPerSample, true);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  if (ret == MMSYSERR_NOERROR)
Toshihiro Shimizu 890ddd
  {
Toshihiro Shimizu 890ddd
    fmt.m_bitPerSample = bitPerSample;
Toshihiro Shimizu 890ddd
    fmt.m_channelCount = channelCount;
Toshihiro Shimizu 890ddd
    fmt.m_sampleRate = sampleRate;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
    if (bitPerSample >= 16)
Toshihiro Shimizu 890ddd
      fmt.m_signedSample = true;
Toshihiro Shimizu 890ddd
    else
Toshihiro Shimizu 890ddd
      fmt.m_signedSample = false;
Toshihiro Shimizu 890ddd
    return fmt;
Toshihiro Shimizu 890ddd
  }
Toshihiro Shimizu 890ddd
  if (ret == WAVERR_BADFORMAT)
Toshihiro Shimizu 890ddd
  {
Shinya Kitaoka 120a6e
    //avvvicinarsi al sample rate => dovrebbe esser OK avendo selezionato i piu'
Shinya Kitaoka 120a6e
vicini
Toshihiro Shimizu 890ddd
    std::set<int>::iterator it = m_imp->m_supportedRate.lower_bound(sampleRate);</int>
Toshihiro Shimizu 890ddd
    if (it == m_imp->m_supportedRate.end())
Toshihiro Shimizu 890ddd
    {
Shinya Kitaoka 120a6e
                  it = std::max_element(m_imp->m_supportedRate.begin(),
Shinya Kitaoka 120a6e
                                         m_imp->m_supportedRate.end());
Shinya Kitaoka 120a6e
                        if (it != m_imp->m_supportedRate.end())
Shinya Kitaoka 120a6e
                  sampleRate = *(m_imp->m_supportedRate.rbegin());
Toshihiro Shimizu 890ddd
      else
Toshihiro Shimizu 890ddd
        throw TSoundDeviceException(
Toshihiro Shimizu 890ddd
          TSoundDeviceException::UnsupportedFormat,
Toshihiro Shimizu 890ddd
          "There isn't a supported format");
Toshihiro Shimizu 890ddd
    }
Toshihiro Shimizu 890ddd
    else
Toshihiro Shimizu 890ddd
      sampleRate = *it;
Toshihiro Shimizu 890ddd
    ret = isaFormatSupported(sampleRate, channelCount, bitPerSample, true);
Toshihiro Shimizu 890ddd
    if (ret == MMSYSERR_NOERROR)
Toshihiro Shimizu 890ddd
    {
Toshihiro Shimizu 890ddd
      fmt.m_bitPerSample = bitPerSample;
Toshihiro Shimizu 890ddd
      fmt.m_channelCount = channelCount;
Toshihiro Shimizu 890ddd
      fmt.m_sampleRate = sampleRate;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
      if (bitPerSample >= 16)
Toshihiro Shimizu 890ddd
        fmt.m_signedSample = true;
Toshihiro Shimizu 890ddd
      else
Toshihiro Shimizu 890ddd
        fmt.m_signedSample = false;
Toshihiro Shimizu 890ddd
      return fmt;
Toshihiro Shimizu 890ddd
    }
Toshihiro Shimizu 890ddd
    if (ret == WAVERR_BADFORMAT)
Toshihiro Shimizu 890ddd
    {
Toshihiro Shimizu 890ddd
      //cambiare bps
Toshihiro Shimizu 890ddd
      if (bitPerSample <= 8)
Toshihiro Shimizu 890ddd
        bitPerSample = 8;
Toshihiro Shimizu 890ddd
      else if ((bitPerSample > 8 && bitPerSample < 16) || bitPerSample >= 16)
Toshihiro Shimizu 890ddd
        bitPerSample = 16;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
      ret = isaFormatSupported(sampleRate, channelCount, bitPerSample, true);
Toshihiro Shimizu 890ddd
      if (ret == MMSYSERR_NOERROR)
Toshihiro Shimizu 890ddd
      {
Toshihiro Shimizu 890ddd
        fmt.m_bitPerSample = bitPerSample;
Toshihiro Shimizu 890ddd
        fmt.m_channelCount = channelCount;
Toshihiro Shimizu 890ddd
        fmt.m_sampleRate = sampleRate;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
        if (bitPerSample >= 16)
Toshihiro Shimizu 890ddd
          fmt.m_signedSample = true;
Toshihiro Shimizu 890ddd
        else
Toshihiro Shimizu 890ddd
          fmt.m_signedSample = false;
Toshihiro Shimizu 890ddd
        return fmt;
Toshihiro Shimizu 890ddd
      }
Toshihiro Shimizu 890ddd
      if (ret == WAVERR_BADFORMAT)
Toshihiro Shimizu 890ddd
      {
Toshihiro Shimizu 890ddd
        //switch mono/stereo
Toshihiro Shimizu 890ddd
        if (channelCount <= 1)
Toshihiro Shimizu 890ddd
          channelCount = 1;
Shinya Kitaoka 120a6e
        else
Toshihiro Shimizu 890ddd
          channelCount = 2;
Shinya Kitaoka 120a6e
Toshihiro Shimizu 890ddd
        ret = isaFormatSupported(sampleRate, channelCount, bitPerSample, true);
Toshihiro Shimizu 890ddd
        if (ret == MMSYSERR_NOERROR)
Toshihiro Shimizu 890ddd
        {
Toshihiro Shimizu 890ddd
          fmt.m_bitPerSample = bitPerSample;
Toshihiro Shimizu 890ddd
          fmt.m_channelCount = channelCount;
Toshihiro Shimizu 890ddd
          fmt.m_sampleRate = sampleRate;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
          if (bitPerSample >= 16)
Toshihiro Shimizu 890ddd
            fmt.m_signedSample = true;
Toshihiro Shimizu 890ddd
          else
Toshihiro Shimizu 890ddd
            fmt.m_signedSample = false;
Toshihiro Shimizu 890ddd
          return fmt;
Toshihiro Shimizu 890ddd
        }
Toshihiro Shimizu 890ddd
        if (ret == WAVERR_BADFORMAT)
Toshihiro Shimizu 890ddd
        {
Toshihiro Shimizu 890ddd
          throw TSoundDeviceException(
Toshihiro Shimizu 890ddd
            TSoundDeviceException::UnsupportedFormat,
Toshihiro Shimizu 890ddd
            "Doesn't exist a preferred format");
Toshihiro Shimizu 890ddd
        }
Toshihiro Shimizu 890ddd
      }
Toshihiro Shimizu 890ddd
    }
Toshihiro Shimizu 890ddd
  }
Toshihiro Shimizu 890ddd
  throw TSoundDeviceException(
Toshihiro Shimizu 890ddd
    TSoundDeviceException::UnsupportedFormat,
Toshihiro Shimizu 890ddd
    "Error to query supported format");
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
TSoundTrackFormat TSoundInputDevice::getPreferredFormat(TUINT32 sampleRate,
Shinya Kitaoka 120a6e
                                                        int channelCount,
Shinya Kitaoka 120a6e
                                                        int bitPerSample) {
Shinya Kitaoka 120a6e
  TSoundTrackFormat fmt;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // avvvicinarsi al sample rate => dovrebbe esser OK avendo selezionato i piu'
Shinya Kitaoka 120a6e
  // vicini
Shinya Kitaoka 120a6e
  std::set<int>::iterator it = m_imp->m_supportedRate.lower_bound(sampleRate);</int>
Shinya Kitaoka 120a6e
  if (it == m_imp->m_supportedRate.end()) {
Shinya Kitaoka 120a6e
    it = std::max_element(m_imp->m_supportedRate.begin(),
Shinya Kitaoka 120a6e
                          m_imp->m_supportedRate.end());
Shinya Kitaoka 120a6e
    if (it != m_imp->m_supportedRate.end())
Shinya Kitaoka 120a6e
      sampleRate = *(m_imp->m_supportedRate.rbegin());
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat,
Shinya Kitaoka 120a6e
                                  "There isn't a supported format");
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    sampleRate = *it;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (bitPerSample <= 8)
Shinya Kitaoka 120a6e
    bitPerSample = 8;
Shinya Kitaoka 120a6e
  else if ((bitPerSample > 8 && bitPerSample < 16) || bitPerSample >= 16)
Shinya Kitaoka 120a6e
    bitPerSample = 16;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (bitPerSample >= 16)
Shinya Kitaoka 120a6e
    fmt.m_signedSample = true;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    fmt.m_signedSample = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // switch mono/stereo
Shinya Kitaoka 120a6e
  if (channelCount <= 1)
Shinya Kitaoka 120a6e
    channelCount = 1;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    channelCount = 2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  fmt.m_bitPerSample = bitPerSample;
Shinya Kitaoka 120a6e
  fmt.m_channelCount = channelCount;
Shinya Kitaoka 120a6e
  fmt.m_sampleRate   = sampleRate;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return fmt;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TSoundTrackFormat TSoundInputDevice::getPreferredFormat(
Shinya Kitaoka 120a6e
    const TSoundTrackFormat &format) {
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    return getPreferredFormat(format.m_sampleRate, format.m_channelCount,
Shinya Kitaoka 120a6e
                              format.m_bitPerSample);
Shinya Kitaoka 120a6e
  } catch (TSoundDeviceException &e) {
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat,
Shinya Kitaoka 120a6e
                                e.getMessage());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
// Funzioni per l'interazione con il mixer device
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// restituisce dentro la struttura mxc le informazioni relative
Toshihiro Shimizu 890ddd
// al controllo di tipo dwControlType associato alla linea
Toshihiro Shimizu 890ddd
// identificata da dwLineID
Shinya Kitaoka 120a6e
MMRESULT getLineControl(MIXERCONTROL &mxc, HMIXEROBJ hMixer, DWORD dwLineID,
Shinya Kitaoka 120a6e
                        DWORD dwControlType) {
Shinya Kitaoka 120a6e
  MIXERLINECONTROLS mxlc;
Shinya Kitaoka 120a6e
  mxlc.cbStruct      = sizeof(MIXERLINECONTROLS);
Shinya Kitaoka 120a6e
  mxlc.dwLineID      = dwLineID;
Shinya Kitaoka 120a6e
  mxlc.dwControlType = dwControlType;
Shinya Kitaoka 120a6e
  mxlc.cControls     = 1;
Shinya Kitaoka 120a6e
  mxlc.cbmxctrl      = sizeof(MIXERCONTROL);
Shinya Kitaoka 120a6e
  mxlc.pamxctrl      = &mxc;
Shinya Kitaoka 120a6e
  MMRESULT ret       = mixerGetLineControls(
Shinya Kitaoka 120a6e
      (HMIXEROBJ)hMixer, &mxlc,
Shinya Kitaoka 120a6e
      MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE);
Shinya Kitaoka 120a6e
  return ret;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// restituisce nella struttura mxl le informazioni relative alla linea
Toshihiro Shimizu 890ddd
// sorgente individuata dagli estremi destination e source
Shinya Kitaoka 120a6e
MMRESULT getLineInfo(HMIXEROBJ hMixer, MIXERLINE &mxl, DWORD destination,
Shinya Kitaoka 120a6e
                     DWORD source) {
Shinya Kitaoka 120a6e
  MMRESULT ret;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  mxl.cbStruct      = sizeof(mxl);
Shinya Kitaoka 120a6e
  mxl.dwDestination = destination;
Shinya Kitaoka 120a6e
  mxl.dwSource      = source;
Shinya Kitaoka 120a6e
  ret               = mixerGetLineInfo(0, &mxl,
Shinya Kitaoka 120a6e
                         MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_SOURCE);
Shinya Kitaoka 120a6e
  return ret;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// restituisce nella struttura mxl le informazioni relative alla linea
Toshihiro Shimizu 890ddd
// individuata da dwLineID
Shinya Kitaoka 120a6e
MMRESULT getLineInfo(HMIXEROBJ hMixer, MIXERLINE &mxl, DWORD dwLineID) {
Shinya Kitaoka 120a6e
  MMRESULT ret;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  mxl.cbStruct = sizeof(mxl);
Shinya Kitaoka 120a6e
  mxl.dwLineID = dwLineID;
Shinya Kitaoka 120a6e
  ret          = mixerGetLineInfo((HMIXEROBJ)hMixer, &mxl,
Shinya Kitaoka 120a6e
                         MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_LINEID);
Shinya Kitaoka 120a6e
  return ret;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// restituisce nella struttura mxl le informazioni relative alla linea
Toshihiro Shimizu 890ddd
// individuata dal tipo specificato in dwComponentType
Shinya Kitaoka 120a6e
MMRESULT getLineInfo(HMIXEROBJ hMixer, DWORD dwComponentType, MIXERLINE &mxl) {
Shinya Kitaoka 120a6e
  MMRESULT ret;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  mxl.cbStruct        = sizeof(MIXERLINE);
Shinya Kitaoka 120a6e
  mxl.dwComponentType = dwComponentType;
Shinya Kitaoka 120a6e
  ret =
Shinya Kitaoka 120a6e
      mixerGetLineInfo((HMIXEROBJ)hMixer, &mxl,
Shinya Kitaoka 120a6e
                       MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE);
Shinya Kitaoka 120a6e
  return ret;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// consente di settare il valore booleano specificato in mxcdSelectValue
Toshihiro Shimizu 890ddd
// relativo al controllo specificato in dwSelectControlID
Shinya Kitaoka 120a6e
MMRESULT setControlDetails(HMIXEROBJ hMixer, DWORD dwSelectControlID,
Shinya Kitaoka 120a6e
                           DWORD dwMultipleItems,
Shinya Kitaoka 120a6e
                           MIXERCONTROLDETAILS_BOOLEAN *mxcdSelectValue) {
Shinya Kitaoka 120a6e
  MMRESULT ret;
Shinya Kitaoka 120a6e
  MIXERCONTROLDETAILS mxcd;
Shinya Kitaoka 120a6e
  mxcd.cbStruct       = sizeof(MIXERCONTROLDETAILS);
Shinya Kitaoka 120a6e
  mxcd.dwControlID    = dwSelectControlID;
Shinya Kitaoka 120a6e
  mxcd.cChannels      = 1;
Shinya Kitaoka 120a6e
  mxcd.cMultipleItems = dwMultipleItems;
Shinya Kitaoka 120a6e
  mxcd.cbDetails      = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
Shinya Kitaoka 120a6e
  mxcd.paDetails      = mxcdSelectValue;
Shinya Kitaoka 120a6e
  ret                 = mixerSetControlDetails(
Shinya Kitaoka 120a6e
      (HMIXEROBJ)hMixer, &mxcd,
Shinya Kitaoka 120a6e
      MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);
Shinya Kitaoka 120a6e
  return ret;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// consente di settare il valore UNSIGNED specificato in mxcdSelectValue
Toshihiro Shimizu 890ddd
// relativo al controllo specificato in dwSelectControlID
Shinya Kitaoka 120a6e
MMRESULT setControlDetails(HMIXEROBJ hMixer, DWORD dwSelectControlID,
Shinya Kitaoka 120a6e
                           DWORD dwMultipleItems,
Shinya Kitaoka 120a6e
                           MIXERCONTROLDETAILS_UNSIGNED *mxcdSelectValue) {
Shinya Kitaoka 120a6e
  MMRESULT ret;
Shinya Kitaoka 120a6e
  MIXERCONTROLDETAILS mxcd;
Shinya Kitaoka 120a6e
  mxcd.cbStruct       = sizeof(MIXERCONTROLDETAILS);
Shinya Kitaoka 120a6e
  mxcd.dwControlID    = dwSelectControlID;
Shinya Kitaoka 120a6e
  mxcd.cChannels      = 1;
Shinya Kitaoka 120a6e
  mxcd.cMultipleItems = dwMultipleItems;
Shinya Kitaoka 120a6e
  mxcd.cbDetails      = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
Shinya Kitaoka 120a6e
  mxcd.paDetails      = mxcdSelectValue;
Shinya Kitaoka 120a6e
  ret                 = mixerSetControlDetails(
Shinya Kitaoka 120a6e
      (HMIXEROBJ)hMixer, &mxcd,
Shinya Kitaoka 120a6e
      MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);
Shinya Kitaoka 120a6e
  return ret;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// consente di ottenere il valore UNSIGNED specificato in mxcdSelectValue
Toshihiro Shimizu 890ddd
// relativo al controllo specificato in dwSelectControlID
Shinya Kitaoka 120a6e
MMRESULT getControlDetails(HMIXEROBJ hMixer, DWORD dwSelectControlID,
Shinya Kitaoka 120a6e
                           DWORD dwMultipleItems,
Shinya Kitaoka 120a6e
                           MIXERCONTROLDETAILS_UNSIGNED *mxcdSelectValue) {
Shinya Kitaoka 120a6e
  MMRESULT ret;
Shinya Kitaoka 120a6e
  MIXERCONTROLDETAILS mxcd;
Shinya Kitaoka 120a6e
  mxcd.cbStruct       = sizeof(MIXERCONTROLDETAILS);
Shinya Kitaoka 120a6e
  mxcd.dwControlID    = dwSelectControlID;
Shinya Kitaoka 120a6e
  mxcd.cChannels      = 1;
Shinya Kitaoka 120a6e
  mxcd.cMultipleItems = dwMultipleItems;
Shinya Kitaoka 120a6e
  mxcd.cbDetails      = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
Shinya Kitaoka 120a6e
  mxcd.paDetails      = mxcdSelectValue;
Shinya Kitaoka 120a6e
  ret                 = mixerGetControlDetails(
Shinya Kitaoka 120a6e
      (HMIXEROBJ)hMixer, &mxcd,
Shinya Kitaoka 120a6e
      MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);
Shinya Kitaoka 120a6e
  return ret;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// consente di ottenere la lista di informazioni in pmxcdSelectText
Toshihiro Shimizu 890ddd
// relativo al controllo specificato in dwSelectControlID
Shinya Kitaoka 120a6e
MMRESULT getControlDetails(HMIXEROBJ hMixer, DWORD dwSelectControlID,
Shinya Kitaoka 120a6e
                           DWORD dwMultipleItems,
Shinya Kitaoka 120a6e
                           MIXERCONTROLDETAILS_LISTTEXT *pmxcdSelectText) {
Shinya Kitaoka 120a6e
  MMRESULT ret;
Shinya Kitaoka 120a6e
  MIXERCONTROLDETAILS mxcd;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  mxcd.cbStruct       = sizeof(MIXERCONTROLDETAILS);
Shinya Kitaoka 120a6e
  mxcd.dwControlID    = dwSelectControlID;
Shinya Kitaoka 120a6e
  mxcd.cChannels      = 1;
Shinya Kitaoka 120a6e
  mxcd.cMultipleItems = dwMultipleItems;
Shinya Kitaoka 120a6e
  mxcd.cbDetails      = sizeof(MIXERCONTROLDETAILS_LISTTEXT);
Shinya Kitaoka 120a6e
  mxcd.paDetails      = pmxcdSelectText;
Shinya Kitaoka 120a6e
  ret                 = mixerGetControlDetails((HMIXEROBJ)0, &mxcd,
Shinya Kitaoka 120a6e
                               MIXER_GETCONTROLDETAILSF_LISTTEXT);
Shinya Kitaoka 120a6e
  return ret;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// restituiscei l nome della linea identificata da lineID
Shinya Kitaoka 120a6e
std::string getMixerLineName(DWORD lineID) {
Shinya Kitaoka 120a6e
  MIXERLINE mxl;
Shinya Kitaoka 120a6e
  MMRESULT ret;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ret = getLineInfo((HMIXEROBJ)0, mxl, lineID);
Toshihiro Shimizu 890ddd
#ifdef TNZCORE_LIGHT
Shinya Kitaoka 120a6e
  assert(false);
Shinya Kitaoka 120a6e
  return "";
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
  return std::string(mxl.szName);
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// restituisce la lista degli identificativi delle linee sorgente associate
Toshihiro Shimizu 890ddd
// alla destinazione di tipo dstComponentType
Shinya Kitaoka 120a6e
std::list<dword> getMixerSrcLines(DWORD dstComponentType) {</dword>
Shinya Kitaoka 120a6e
  std::list<dword> srcList;</dword>
Shinya Kitaoka 120a6e
  MMRESULT ret;
Shinya Kitaoka 120a6e
  MIXERLINE mxl;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ret = getLineInfo((HMIXEROBJ)0, MIXERLINE_COMPONENTTYPE_DST_WAVEIN, mxl);
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR)
Shinya Kitaoka 120a6e
    // forse bisognerebbe lanciare un'eccezione
Shinya Kitaoka 120a6e
    return srcList;  // non ha linea di dst per la registrazione
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int v;
Shinya Kitaoka 120a6e
  for (v = 0; v < (int)mxl.cConnections; v++) {
Shinya Kitaoka 120a6e
    MIXERLINE mxl1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    ret = getLineInfo((HMIXEROBJ)0, mxl1, mxl.dwDestination, v);
Shinya Kitaoka 120a6e
    if (ret == MMSYSERR_NOERROR) srcList.push_back(mxl1.dwLineID);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return srcList;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// restituisce la lista degli identificativi delle linee sorgente di tipo
Toshihiro Shimizu 890ddd
// srcComponentType associate alla destinazione di tipo dstComponentType
Shinya Kitaoka 120a6e
std::list<dword> getMixerSrcLines(DWORD dstComponentType,</dword>
Shinya Kitaoka 120a6e
                                  DWORD srcComponentType) {
Shinya Kitaoka 120a6e
  std::list<dword> srcList;</dword>
Shinya Kitaoka 120a6e
  MMRESULT ret;
Shinya Kitaoka 120a6e
  MIXERLINE mxl;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ret = getLineInfo((HMIXEROBJ)0, MIXERLINE_COMPONENTTYPE_DST_WAVEIN, mxl);
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR)
Shinya Kitaoka 120a6e
    // forse bisognerebbe lanciare un'eccezione
Shinya Kitaoka 120a6e
    return srcList;  // non ha linea di dst per la registrazione
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int v;
Shinya Kitaoka 120a6e
  for (v = 0; v < (int)mxl.cConnections; v++) {
Shinya Kitaoka 120a6e
    MIXERLINE mxl1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    ret = getLineInfo((HMIXEROBJ)0, mxl1, mxl.dwDestination, v);
Shinya Kitaoka 120a6e
    if (ret == MMSYSERR_NOERROR)
Shinya Kitaoka 120a6e
      if (mxl1.dwComponentType == srcComponentType)
Shinya Kitaoka 120a6e
        srcList.push_back(mxl1.dwLineID);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return srcList;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// restituisce true sse la linea destinazione di tipo dstComponentType
Toshihiro Shimizu 890ddd
// supporta una linea sorgente di tipo srcComponentType
Shinya Kitaoka 120a6e
bool isSrcLineSupported(DWORD dstComponentType, DWORD srcComponentType) {
Shinya Kitaoka 120a6e
  // ci possono essere piu' linee sorgente dello stesso tipo in
Shinya Kitaoka 120a6e
  // corrispondenza di una data linea destinazione ?
Shinya Kitaoka 120a6e
  MMRESULT ret;
Shinya Kitaoka 120a6e
  MIXERLINE mxl;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ret = getLineInfo((HMIXEROBJ)0, MIXERLINE_COMPONENTTYPE_DST_WAVEIN, mxl);
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR)
Shinya Kitaoka 120a6e
    return false;  // non ha linea di dst per la registrazione
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int v;
Shinya Kitaoka 120a6e
  for (v = 0; v < (int)mxl.cConnections; v++) {
Shinya Kitaoka 120a6e
    MIXERLINE mxl1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    ret = getLineInfo((HMIXEROBJ)0, mxl1, mxl.dwDestination, v);
Shinya Kitaoka 120a6e
    if (ret == MMSYSERR_NOERROR)
Shinya Kitaoka 120a6e
      if (mxl1.dwComponentType == srcComponentType) return true;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool activateSrcLine(const MIXERLINE &mxlDst, DWORD componentTypeSrc) {
Shinya Kitaoka 120a6e
  if (!isSrcLineSupported(mxlDst.dwComponentType, componentTypeSrc))
Shinya Kitaoka 120a6e
    return false;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool bRetVal = true;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (DWORD v = 0; v < mxlDst.cConnections; v++) {
Shinya Kitaoka 120a6e
    MIXERLINE mxlSrc;
Shinya Kitaoka 120a6e
    MMRESULT ret = getLineInfo((HMIXEROBJ)0, mxlSrc, mxlDst.dwDestination, v);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (ret == MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
      // chiedo il controllo di tipo MUTE della linea sorgente
Shinya Kitaoka 120a6e
      MIXERCONTROL mxc;
Shinya Kitaoka 120a6e
      ret = getLineControl(mxc, (HMIXEROBJ)0, mxlSrc.dwLineID,
Shinya Kitaoka 120a6e
                           MIXERCONTROL_CONTROLTYPE_MUTE);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      if (ret == MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
        MIXERCONTROLDETAILS_BOOLEAN mxcdSelectValue;
Shinya Kitaoka 120a6e
        mxcdSelectValue.fValue =
Shinya Kitaoka 120a6e
            mxlSrc.dwComponentType == componentTypeSrc ? 0L : 1L;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        ret = setControlDetails((HMIXEROBJ)0, mxc.dwControlID,
Shinya Kitaoka 120a6e
                                mxc.cMultipleItems, &mxcdSelectValue);
Shinya Kitaoka 120a6e
        if (ret != MMSYSERR_NOERROR) bRetVal = false;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return bRetVal;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool setSrcMixMuxControl(MIXERCONTROL mxc, DWORD componentTypeSrc) {
Shinya Kitaoka 120a6e
  MMRESULT ret;
Shinya Kitaoka 120a6e
  DWORD dwIndexLine;
Shinya Kitaoka 120a6e
  bool found = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // mantengo nota del ID del controllo dsst individuato e
Shinya Kitaoka 120a6e
  // del numero di linee src ad esso associate
Shinya Kitaoka 120a6e
  DWORD dwSelectControlID = mxc.dwControlID;
Shinya Kitaoka 120a6e
  DWORD dwMultipleItems   = mxc.cMultipleItems;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (dwMultipleItems == 0) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // determino l'indice dell'item corrispondente alla linea sorgente
Shinya Kitaoka 120a6e
  // di tipo componentTypeSrc
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::unique_ptr<mixercontroldetails_listtext[]> pmxcdSelectText(</mixercontroldetails_listtext[]>
Shinya Kitaoka 120a6e
      new MIXERCONTROLDETAILS_LISTTEXT[dwMultipleItems]);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (pmxcdSelectText) {
Shinya Kitaoka 120a6e
    // estraggo le info su tutte le linee associate al controllo
Shinya Kitaoka 120a6e
    ret = getControlDetails((HMIXEROBJ)0, dwSelectControlID, dwMultipleItems,
Shinya Kitaoka 120a6e
                            pmxcdSelectText.get());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (ret == MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
      for (DWORD dwi = 0; dwi < dwMultipleItems; dwi++) {
Shinya Kitaoka 120a6e
        // prendo le info su ogni linea e verifico se e' del giusto tipo
Shinya Kitaoka 120a6e
        MIXERLINE mxl;
Shinya Kitaoka 120a6e
        ret = getLineInfo((HMIXEROBJ)0, mxl, pmxcdSelectText[dwi].dwParam1);
Shinya Kitaoka 120a6e
        if (ret == MMSYSERR_NOERROR &&
Shinya Kitaoka 120a6e
            mxl.dwComponentType == componentTypeSrc) {
Shinya Kitaoka 120a6e
          dwIndexLine = dwi;
Shinya Kitaoka 120a6e
          found       = true;
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!found) return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (dwIndexLine >= dwMultipleItems) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool bRetVal = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::unique_ptr<mixercontroldetails_boolean[]> pmxcdSelectValue(</mixercontroldetails_boolean[]>
Shinya Kitaoka 120a6e
      new MIXERCONTROLDETAILS_BOOLEAN[dwMultipleItems]);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (pmxcdSelectValue) {
Shinya Kitaoka 120a6e
    ::ZeroMemory(pmxcdSelectValue.get(),
Shinya Kitaoka 120a6e
                 dwMultipleItems * sizeof(MIXERCONTROLDETAILS_BOOLEAN));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // impostazione del valore
Shinya Kitaoka 120a6e
    pmxcdSelectValue[dwIndexLine].fValue =
Shinya Kitaoka 120a6e
        (TINT32)1;  // lVal; //dovrebbe esser uno
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ret = setControlDetails((HMIXEROBJ)0, dwSelectControlID, dwMultipleItems,
Shinya Kitaoka 120a6e
                            pmxcdSelectValue.get());
Shinya Kitaoka 120a6e
    if (ret == MMSYSERR_NOERROR) bRetVal = true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return bRetVal;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool setRecordLine(TSoundInputDevice::Source typeInput) {
Shinya Kitaoka 120a6e
  DWORD dwComponentTypeSrc;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  UINT nNumMixers;
Shinya Kitaoka 120a6e
  MMRESULT ret;
Shinya Kitaoka 120a6e
  MIXERLINE mxl = {0};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  switch (typeInput) {
Shinya Kitaoka 120a6e
  case TSoundInputDevice::LineIn:
Shinya Kitaoka 120a6e
    dwComponentTypeSrc = MIXERLINE_COMPONENTTYPE_SRC_LINE /*|
Toshihiro Shimizu 890ddd
                             MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY |
Toshihiro Shimizu 890ddd
                             MIXERLINE_COMPONENTTYPE_SRC_ANALOG*/;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case TSoundInputDevice::DigitalIn:
Shinya Kitaoka 120a6e
    dwComponentTypeSrc = MIXERLINE_COMPONENTTYPE_SRC_DIGITAL;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case TSoundInputDevice::CdAudio:
Shinya Kitaoka 120a6e
    dwComponentTypeSrc = MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  default:
Shinya Kitaoka 120a6e
    dwComponentTypeSrc = MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  nNumMixers = mixerGetNumDevs();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (nNumMixers == 0) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // utilizziamo il MIXER di default identificato dall'indice 0
Shinya Kitaoka 120a6e
  // vedo se il device ha una linea dst per il wave_input
Shinya Kitaoka 120a6e
  ret = getLineInfo((HMIXEROBJ)0, MIXERLINE_COMPONENTTYPE_DST_WAVEIN, mxl);
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR)
Shinya Kitaoka 120a6e
    return false;  // non ha linea di dst per la registrazione
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // vediamo che tipo controllo ha questa linea dst
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // sara' un MIXER?
Shinya Kitaoka 120a6e
  MIXERCONTROL mxc = {0};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ret = getLineControl(mxc, (HMIXEROBJ)0, mxl.dwLineID,
Shinya Kitaoka 120a6e
                       MIXERCONTROL_CONTROLTYPE_MIXER);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (ret != MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
    // no mixer, try MUX
Shinya Kitaoka 120a6e
    ret = getLineControl(mxc, (HMIXEROBJ)0, mxl.dwLineID,
Shinya Kitaoka 120a6e
                         MIXERCONTROL_CONTROLTYPE_MUX);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (ret != MMSYSERR_NOERROR) {
Shinya Kitaoka 120a6e
      // vediamo se e' uno di quei device ne' MIXER ne' MUX
Shinya Kitaoka 120a6e
      return activateSrcLine(mxl, dwComponentTypeSrc);
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      // la linea ha un controllo di tipo MUX
Shinya Kitaoka 120a6e
      return setSrcMixMuxControl(mxc, dwComponentTypeSrc);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // la linea ha un controllo di tipo MIXER
Shinya Kitaoka 120a6e
    return setSrcMixMuxControl(mxc, dwComponentTypeSrc);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
MMRESULT isaFormatSupported(int sampleRate, int channelCount, int bitPerSample,
Shinya Kitaoka 120a6e
                            bool input) {
Shinya Kitaoka 120a6e
  WAVEFORMATEX wf;
Shinya Kitaoka 120a6e
  MMRESULT ret;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  wf.wFormatTag      = WAVE_FORMAT_PCM;
Shinya Kitaoka 120a6e
  wf.nChannels       = channelCount;
Shinya Kitaoka 120a6e
  wf.nSamplesPerSec  = sampleRate;
Shinya Kitaoka 120a6e
  wf.wBitsPerSample  = bitPerSample;
Shinya Kitaoka 120a6e
  wf.nBlockAlign     = (wf.nChannels * wf.wBitsPerSample) >> 3;
Shinya Kitaoka 120a6e
  wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;
Shinya Kitaoka 120a6e
  wf.cbSize          = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (input)
Shinya Kitaoka 120a6e
    ret = waveInOpen(NULL, WAVE_MAPPER, &wf, NULL, NULL, WAVE_FORMAT_QUERY);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    ret = waveOutOpen(NULL, WAVE_MAPPER, &wf, NULL, NULL, WAVE_FORMAT_QUERY);
Shinya Kitaoka 120a6e
  return ret;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
}