Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tfilepath.h"
Toshihiro Shimizu 890ddd
#include "tsound.h"
Toshihiro Shimizu 890ddd
#include "tsound_io.h"
Toshihiro Shimizu 890ddd
#include "tsop.h"
Toshihiro Shimizu 890ddd
#include "tthread.h"
Toshihiro Shimizu 890ddd
#include "texception.h"
Toshihiro Shimizu 890ddd
#include "tsystem.h"
Toshihiro Shimizu 890ddd
#include <iostream></iostream>
Toshihiro Shimizu 890ddd
#include <linux soundcard.h=""></linux>
Toshihiro Shimizu 890ddd
#include <set></set>
Toshihiro Shimizu 890ddd
#include <sys time.h=""></sys>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <unistd.h></unistd.h>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <fcntl.h></fcntl.h>
Toshihiro Shimizu 890ddd
#include <sys ioctl.h=""></sys>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// using namespace std;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// forward declaration
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
int openMixer();
Toshihiro Shimizu 890ddd
int getCurrentRecordSource(int mixer);
Toshihiro Shimizu 890ddd
bool writeVolume(int volume, int mixer, int indexDev);
Toshihiro Shimizu 890ddd
bool selectInputDevice(TSoundInputDevice::Source dev);
Toshihiro Shimizu 890ddd
string parseError(int error);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// bisogna interagire con /dev/dsp per il settaggio delle
Toshihiro Shimizu 890ddd
// caratteristiche della traccia tipo bit, rate, canali e
Toshihiro Shimizu 890ddd
// per effettuare lettura/scrittura ossia record/play
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// mentre bisogna interagire con /dev/mixer per modificare
Toshihiro Shimizu 890ddd
// i valori del volume e per selezionare il dispositivo da
Toshihiro Shimizu 890ddd
// cui registrare e ascoltare
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class SmartWatch {
Shinya Kitaoka 120a6e
  struct timeval m_start_tv;
Shinya Kitaoka 120a6e
  TINT32 m_totalus;
Shinya Kitaoka 120a6e
  bool m_stopped;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  SmartWatch() : m_totalus(0), m_stopped(true) { timerclear(&m_start_tv); }
Shinya Kitaoka 120a6e
  void start() {
Shinya Kitaoka 120a6e
    m_stopped = false;
Shinya Kitaoka 120a6e
    gettimeofday(&m_start_tv, 0);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  void stop() {
Shinya Kitaoka 120a6e
    m_stopped = true;
Shinya Kitaoka 120a6e
    struct timeval tv;
Shinya Kitaoka 120a6e
    gettimeofday(&tv, 0);
Shinya Kitaoka 120a6e
    m_totalus = (tv.tv_sec - m_start_tv.tv_sec) * 1000000 +
Shinya Kitaoka 120a6e
                (tv.tv_usec - m_start_tv.tv_usec);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  double getTotalTime() {
Shinya Kitaoka 120a6e
    if (!m_stopped)  // questa e' una porcata!
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      stop();
Shinya Kitaoka 120a6e
      m_stopped = false;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return m_totalus / 1000.;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void addDelay(double ms) { m_start_tv.tv_usec += (long)(ms * 1000.); }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================================
Toshihiro Shimizu 890ddd
//======================================================================
Toshihiro Shimizu 890ddd
//					CLASSI PER IL PLAYBACK
Toshihiro Shimizu 890ddd
//======================================================================
Toshihiro Shimizu 890ddd
//======================================================================
Shinya Kitaoka 120a6e
class TSoundOutputDeviceImp {
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  static int m_count;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  int m_dev;
Shinya Kitaoka 120a6e
  bool m_stopped;
Shinya Kitaoka 120a6e
  bool m_isPlaying;
Shinya Kitaoka 120a6e
  bool m_looped;
Shinya Kitaoka 120a6e
  TSoundTrackFormat m_currentFormat;
Shinya Kitaoka 120a6e
  std::set<int> m_supportedRate;</int>
Shinya Kitaoka 120a6e
  static std::multimap<tuint32, tsoundtrackformat=""> m_supportFormats;</tuint32,>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  typedef pair<tsoundtrackp, bool=""> WaitPair;</tsoundtrackp,>
Shinya Kitaoka 120a6e
  vector<waitpair> m_waitingTracks;</waitpair>
Shinya Kitaoka 120a6e
  std::set<tsoundoutputdevicelistener *=""> m_listeners;</tsoundoutputdevicelistener>
Shinya Kitaoka 120a6e
  TThread::Executor m_executor;
Shinya Kitaoka 120a6e
  TThread::Mutex m_mutex;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TSoundOutputDeviceImp()
Shinya Kitaoka 120a6e
      : m_dev(-1)
Shinya Kitaoka 120a6e
      , m_stopped(false)
Shinya Kitaoka 120a6e
      , m_isPlaying(false)
Shinya Kitaoka 120a6e
      , m_looped(false)
Shinya Kitaoka 120a6e
      , m_supportedRate() {
Shinya Kitaoka 120a6e
    /*
Shinya Kitaoka 120a6e
if (m_count != 0)
Shinya Kitaoka 120a6e
throw TException("unable to create second instance of TSoundOutputDeviceImp");
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
    ++m_count;
Shinya Kitaoka 120a6e
    checkSupportedFormat();
Shinya Kitaoka 120a6e
  };
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ~TSoundOutputDeviceImp() { --m_count; };
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool doOpenDevice();
Shinya Kitaoka 120a6e
  bool doCloseDevice();
Shinya Kitaoka 120a6e
  bool verifyRate();
Shinya Kitaoka 120a6e
  void insertAllRate();
Shinya Kitaoka 120a6e
  void checkSupportedFormat();
Shinya Kitaoka 120a6e
  bool isSupportFormat(const TSoundTrackFormat &fmt);
Shinya Kitaoka 120a6e
  void setFormat(const TSoundTrackFormat &fmt);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int TSoundOutputDeviceImp::m_count = 0;
Shinya Kitaoka 120a6e
std::multimap<tuint32, tsoundtrackformat=""></tuint32,>
Shinya Kitaoka 120a6e
    TSoundOutputDeviceImp::m_supportFormats;
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDeviceImp::doOpenDevice() {
Shinya Kitaoka 120a6e
  if (m_dev >= 0) return true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TThread::ScopedLock sl(m_mutex);
Shinya Kitaoka 120a6e
  m_dev = open("/dev/dsp", O_WRONLY, 0);
Shinya Kitaoka 120a6e
  if (m_dev < 0) {
Shinya Kitaoka 120a6e
    string errMsg = strerror(errno);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(
Shinya Kitaoka 120a6e
        TSoundDeviceException::UnableOpenDevice, errMsg + " /dev/dsp"
Shinya Kitaoka 120a6e
        /*"Unable to open device /dev/dsp; check permissions"*/);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // le chiamate a questa ioctl sono state commentate perche' pag 36 doc OSS
Shinya Kitaoka 120a6e
  //"this ioctl stop the device immadiately	and returns it to a state where
Shinya Kitaoka 38fd86
  // it
Shinya Kitaoka 120a6e
  // can accept new parameters. It Should not be called after opening the device
Shinya Kitaoka 120a6e
  // as it may cause unwanted side effect in his situation. require to abort
Shinya Kitaoka 120a6e
  // play
Shinya Kitaoka 120a6e
  // or secord.Generally recommended to open and close device after using the
Shinya Kitaoka 120a6e
  // RESET"
Shinya Kitaoka 120a6e
  // ioctl(m_dev, SNDCTL_DSP_RESET,0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // N.B. e' bene che la dimensione sia piccola cosi' l'attesa, in seguito
Shinya Kitaoka 120a6e
  // alla richiesta di stop,
Shinya Kitaoka 120a6e
  // e' minore in questo caso vogliamo 32 frammenti ognuno di 256 byte
Shinya Kitaoka 120a6e
  // Se non chiamata questa ioctl il device la calcola per conto suo
Shinya Kitaoka 120a6e
  // ma alcune volte la dimensione dei frammenti potrebbe essere eccessiva e
Shinya Kitaoka 120a6e
  // creare dei click e dei silenzi in attesi ad esempio nel playback dentro
Shinya Kitaoka 120a6e
  // zcomp, quindi e' meglio settarla. 32 rappresenta il numero di frammenti
Shinya Kitaoka 120a6e
  // di solito e' documentato che 2 siano sufficienti ma potrebbero essere pochi
Shinya Kitaoka 120a6e
  // soprattutto se si interagisce con altre console
Shinya Kitaoka 120a6e
  // int fraginfo = ( 32<<16)|8;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int fraginfo = 0xffffffff;
Shinya Kitaoka 120a6e
  if (ioctl(m_dev, SNDCTL_DSP_SETFRAGMENT, &fraginfo) == -1)
Shinya Kitaoka 120a6e
    perror("SETFRAGMENT");
Shinya Kitaoka 120a6e
  // if(fraginfo != ((32<<16)|8))
Shinya Kitaoka 120a6e
  // std::cout << std::hex << fraginfo<
Shinya Kitaoka 120a6e
  // exit(0);
Shinya Kitaoka 120a6e
  audio_buf_info info;
Shinya Kitaoka 120a6e
  if (ioctl(m_dev, SNDCTL_DSP_GETOSPACE, &info) == -1) perror("GETOSPACE");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // std::cout << info.fragments << " frammenti " << " da " << info.fragsize <<
Shinya Kitaoka 120a6e
  // "  = " << info.fragsize*info.fragments << " bytes" <
Shinya Kitaoka 120a6e
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
  if (m_dev < 0) return true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TThread::ScopedLock sl(m_mutex);
Shinya Kitaoka 120a6e
  ioctl(m_dev, SNDCTL_DSP_POST, 0);
Shinya Kitaoka 120a6e
  ioctl(m_dev, SNDCTL_DSP_RESET, 0);
Shinya Kitaoka 120a6e
  int tmpDev      = m_dev;
Shinya Kitaoka 120a6e
  bool not_closed = (close(m_dev) < 0);
Shinya Kitaoka 120a6e
  if (not_closed) {
Shinya Kitaoka 120a6e
    while (true) {
Shinya Kitaoka 120a6e
      m_dev = tmpDev;
Shinya Kitaoka 120a6e
      perror("non chiude il device :");
Shinya Kitaoka 120a6e
      not_closed = (close(m_dev) < 0);
Shinya Kitaoka 120a6e
      if (!not_closed) break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    // return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  ioctl(m_dev, SNDCTL_DSP_RESET, 0);
Shinya Kitaoka 120a6e
  m_dev = -1;
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(); ++it) {
Shinya Kitaoka 120a6e
    int sampleRate = *it;
Shinya Kitaoka 120a6e
    if (ioctl(m_dev, SNDCTL_DSP_SPEED, &sampleRate) == -1)
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(
Shinya Kitaoka 120a6e
          TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
          "Failed setting the specified sample rate  aaaa");
Shinya Kitaoka 120a6e
    if (sampleRate != *it) m_supportedRate.erase(*it);
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
void TSoundOutputDeviceImp::checkSupportedFormat() {
Shinya Kitaoka 120a6e
  if (!m_supportFormats.empty()) return;
Shinya Kitaoka 120a6e
  int test_formats[] = {
Shinya Kitaoka 120a6e
      AFMT_U8, AFMT_S8, AFMT_S16_LE, AFMT_S16_BE,
Shinya Kitaoka 120a6e
      /* // servono per supportare traccie a 24 e 32 bit ma non compaiono in
Shinya Kitaoka 120a6e
// nessun file linux/soundcard.h in distribuzione sulle macchine che abbiamo
Shinya Kitaoka 120a6e
// il che fa pensare che non sono supportati ancora
Shinya Kitaoka 120a6e
AFMT_S32_LE,
Shinya Kitaoka 120a6e
AFMT_S32_BE,
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
      0};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int test_channels[] = {1, 2, 0};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TUINT32 test_sample_rates[] = {8000,  11025, 16000, 22050,
Shinya Kitaoka 120a6e
                                 32000, 44100, 48000, 0};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Open the device nonblocking, so the open call returns immediately.
Shinya Kitaoka 120a6e
  if (m_dev)
Shinya Kitaoka 120a6e
    if ((m_dev = open("/dev/dsp", O_WRONLY | O_NONBLOCK)) == -1) {
Shinya Kitaoka 120a6e
      /*
Shinya Kitaoka 120a6e
m_dev = -1;
Shinya Kitaoka 120a6e
string errMsg = strerror(errno);
Shinya Kitaoka 120a6e
throw TSoundDeviceException(
Shinya Kitaoka 120a6e
                TSoundDeviceException::UnableOpenDevice, errMsg + " /dev/dsp\n:
Shinya Kitaoka 120a6e
impossible check supported formats");
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int mask;
Shinya Kitaoka 120a6e
  // Querying hardware supported formats.
Shinya Kitaoka 120a6e
  if (ioctl(m_dev, SNDCTL_DSP_GETFMTS, &mask) == -1) {
Shinya Kitaoka 120a6e
    /*
Shinya Kitaoka 120a6e
throw TSoundDeviceException(
Shinya Kitaoka 120a6e
            TSoundDeviceException::UnsupportedFormat,
Shinya Kitaoka 120a6e
            "Getting supported formats failed.");
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    for (int i = 0; test_formats[i] != 0; i++) {
Shinya Kitaoka 120a6e
      // Test all the formats in test_formats which are supported by the
Shinya Kitaoka 120a6e
      // hardware.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (mask & test_formats[i]) {
Shinya Kitaoka 120a6e
        // Test the format only if it is supported by the hardware.
Shinya Kitaoka 120a6e
        // Note: We also could test formats that are not supported by the
Shinya Kitaoka 120a6e
        // hardware.
Shinya Kitaoka 120a6e
        //       In some cases there exist OSS software converter, so that some
Shinya Kitaoka 120a6e
        //       formats
Shinya Kitaoka 120a6e
        //       work but are not reported by the above SNDCTL_DSP_GETFMTS.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        int fmt = test_formats[i];
Shinya Kitaoka 120a6e
        // Try to set the format...
Shinya Kitaoka 120a6e
        if (ioctl(m_dev, SNDCTL_DSP_SETFMT, &fmt) == -1)
Shinya Kitaoka 120a6e
          continue;  // gli altri formati potrebbero essere supportati
Shinya Kitaoka 120a6e
        else {
Shinya Kitaoka 120a6e
          // and always check the variable after doing an ioctl!
Shinya Kitaoka 120a6e
          if (fmt == test_formats[i]) {
Shinya Kitaoka 120a6e
            // Test the supported channel numbers for this format.
Shinya Kitaoka 120a6e
            // Note: If you need a channel that is not tested here, simply add
Shinya Kitaoka 120a6e
            // it to
Shinya Kitaoka 120a6e
            //       the definition of the array test_channels in this file.
Shinya Kitaoka 120a6e
            for (int j = 0; test_channels[j] != 0; j++) {
Shinya Kitaoka 120a6e
              int test_channel = test_channels[j];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
              // Try to set the channel number.
Shinya Kitaoka 120a6e
              if (ioctl(m_dev, SNDCTL_DSP_CHANNELS, &test_channel) == -1)
Shinya Kitaoka 120a6e
                continue;  // altri canali potrebbero essere supportati
Shinya Kitaoka 120a6e
              else {
Shinya Kitaoka 120a6e
                if (test_channel == test_channels[j]) {
Shinya Kitaoka 120a6e
                  // Last step: Test the supported sample rates for the current
Shinya Kitaoka 120a6e
                  // channel number
Shinya Kitaoka 120a6e
                  //            and format.
Shinya Kitaoka 120a6e
                  // Note: If you need a sample rate that is not tested here,
Shinya Kitaoka 120a6e
                  // simply add it to
Shinya Kitaoka 120a6e
                  //       the definition of the array test_sample_rates in this
Shinya Kitaoka 120a6e
                  //       file.
Shinya Kitaoka 120a6e
                  for (int k = 0; test_sample_rates[k] != 0; k++) {
Shinya Kitaoka 120a6e
                    TUINT32 test_rate = test_sample_rates[k];
Shinya Kitaoka 120a6e
                    if (ioctl(m_dev, SNDCTL_DSP_SPEED, &test_rate) == -1)
Shinya Kitaoka 120a6e
                      continue;  // altri rates ppotrebbero essere supportati
Shinya Kitaoka 120a6e
                    else {
Shinya Kitaoka 120a6e
                      bool sign = true;
Shinya Kitaoka 120a6e
                      int bits;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
                      if (fmt == AFMT_U8 || fmt == AFMT_S8) {
Shinya Kitaoka 120a6e
                        bits                     = 8;
Shinya Kitaoka 120a6e
                        if (fmt == AFMT_U8) sign = false;
Shinya Kitaoka 120a6e
                      } else if (fmt == AFMT_S16_LE || fmt == AFMT_S16_BE)
Shinya Kitaoka 120a6e
                        bits = 16;
Shinya Kitaoka 120a6e
                      /*// vedi commento alla variabile test_formats
Shinya Kitaoka 120a6e
else if(fmt == AFMT_S32_LE || fmt == AFMT_S32_BE)
Shinya Kitaoka 120a6e
bits = 24;
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
                      // Add it to the format in the input property.
Shinya Kitaoka 120a6e
                      // std::cout << test_rate << " " <
Shinya Kitaoka 120a6e
                      // "<
Shinya Kitaoka 120a6e
                      m_supportFormats.insert(std::make_pair(
Shinya Kitaoka 120a6e
                          test_rate, TSoundTrackFormat(test_rate, bits,
Shinya Kitaoka 120a6e
                                                       test_channel, sign)));
Shinya Kitaoka 120a6e
                    }
Shinya Kitaoka 120a6e
                  }
Shinya Kitaoka 120a6e
                }  // loop over the test_sample_rates
Shinya Kitaoka 120a6e
              }    // channel set correctly ?
Shinya Kitaoka 120a6e
            }      // ioctl for sample rate worked ?
Shinya Kitaoka 120a6e
          }        // loop over the test_channels
Shinya Kitaoka 120a6e
        }          // channel set correctly ?
Shinya Kitaoka 120a6e
      }            // ioctl for channel worked ?
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // After testing all configurations for one format, the device is closed
Shinya Kitaoka 120a6e
      // and reopened.
Shinya Kitaoka 120a6e
      // This is necessary to configure it to another format in a secure way.
Shinya Kitaoka 120a6e
      if (close(m_dev) == -1) {
Shinya Kitaoka 120a6e
        /*
Shinya Kitaoka 120a6e
throw TSoundDeviceException(
Shinya Kitaoka 120a6e
          TSoundDeviceException::UnableCloseDevice,
Shinya Kitaoka 120a6e
          "Problem to close the output device checking formats");
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
        continue;
Shinya Kitaoka 120a6e
      } else if ((m_dev = open("/dev/dsp", O_WRONLY | O_NONBLOCK)) == -1) {
Shinya Kitaoka 120a6e
        /*
Shinya Kitaoka 120a6e
m_dev = -1;
Shinya Kitaoka 120a6e
string errMsg = strerror(errno);
Shinya Kitaoka 120a6e
throw TSoundDeviceException(
Shinya Kitaoka 120a6e
            TSoundDeviceException::UnableOpenDevice, errMsg + " /dev/dsp\n:
Shinya Kitaoka 120a6e
impossible check supported formats");
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
        return;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }  // format set correctly ?
Shinya Kitaoka 120a6e
  }    // loop over the test_formats
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Close the device to make it forget the last format configurations.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (close(m_dev) == -1) {
Shinya Kitaoka 120a6e
    /*
Shinya Kitaoka 120a6e
throw TSoundDeviceException(
Shinya Kitaoka 120a6e
            TSoundDeviceException::UnableCloseDevice,
Shinya Kitaoka 120a6e
            "Problem to close the output device checking formats");
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    m_dev = -1;
Shinya Kitaoka 120a6e
  // std::cout << "FINITO " << m_supportFormats.size()<< std::endl;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDeviceImp::isSupportFormat(const TSoundTrackFormat &fmt) {
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    if (m_supportFormats.empty()) checkSupportedFormat();
Shinya Kitaoka 120a6e
  } catch (TSoundDeviceException &e) {
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::multimap<tuint32, tsoundtrackformat="">::iterator it;</tuint32,>
Shinya Kitaoka 120a6e
  pair<std::multimap<tuint32, tsoundtrackformat="">::iterator,</std::multimap<tuint32,>
Shinya Kitaoka 120a6e
       std::multimap<tuint32, tsoundtrackformat="">::iterator></tuint32,>
Shinya Kitaoka 120a6e
      findRange;
Shinya Kitaoka 120a6e
  findRange = m_supportFormats.equal_range(fmt.m_sampleRate);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  it = findRange.first;
Shinya Kitaoka 120a6e
  for (; it != findRange.second; ++it) {
Shinya Kitaoka 120a6e
    assert(it->first == fmt.m_sampleRate);
Shinya Kitaoka 120a6e
    if (it->second == fmt) {
Shinya Kitaoka 120a6e
      return true;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TSoundOutputDeviceImp::setFormat(const TSoundTrackFormat &fmt) {
Shinya Kitaoka 120a6e
  int bps, ch, status;
Shinya Kitaoka 120a6e
  TUINT32 sampleRate;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ch         = fmt.m_channelCount;
Shinya Kitaoka 120a6e
  sampleRate = fmt.m_sampleRate;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_dev == -1)
Shinya Kitaoka 120a6e
    if (!doOpenDevice()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (fmt.m_bitPerSample == 8) {
Shinya Kitaoka 120a6e
    if (fmt.m_signedSample)
Shinya Kitaoka 120a6e
      bps = AFMT_S8;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      bps = AFMT_U8;
Shinya Kitaoka 120a6e
  } else if (fmt.m_bitPerSample == 16) {
Shinya Kitaoka 120a6e
    bps = AFMT_S16_NE;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  int bitPerSample = bps;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  status = ioctl(m_dev, SNDCTL_DSP_SETFMT, &bps);
Shinya Kitaoka 120a6e
  if (status == -1) {
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
                                "Failed setting the specified number of bits");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  status = ioctl(m_dev, SNDCTL_DSP_CHANNELS, &ch);
Shinya Kitaoka 120a6e
  if (status == -1)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(
Shinya Kitaoka 120a6e
        TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
        "Failed setting the specified number of channel");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (ioctl(m_dev, SNDCTL_DSP_SPEED, &sampleRate) == -1)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
                                "Failed setting the specified sample rate");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (ch != fmt.m_channelCount || bps != bitPerSample ||
Shinya Kitaoka 120a6e
      sampleRate != fmt.m_sampleRate) {
Shinya Kitaoka 120a6e
    doCloseDevice();
Shinya Kitaoka 120a6e
    m_currentFormat = TSoundTrackFormat();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_currentFormat = fmt;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class TPlayTask : public TThread::Runnable {
Shinya Kitaoka 120a6e
  SmartWatch *m_stopWatch;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TSoundOutputDeviceImp *m_devImp;
Shinya Kitaoka 120a6e
  TSoundTrackP m_sndtrack;
Shinya Kitaoka 120a6e
  static int m_skipBytes;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPlayTask(TSoundOutputDeviceImp *devImp, const TSoundTrackP &st);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ~TPlayTask() { delete m_stopWatch; }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void run();
Shinya Kitaoka 120a6e
  void run2();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TPlayTask::TPlayTask(TSoundOutputDeviceImp *devImp, const TSoundTrackP &st)
Shinya Kitaoka 120a6e
    : Runnable()
Shinya Kitaoka 120a6e
    , m_stopWatch(new SmartWatch)
Shinya Kitaoka 120a6e
    , m_devImp(devImp)
Shinya Kitaoka 120a6e
    , m_sndtrack(st) {
Shinya Kitaoka 120a6e
  if (st->getFormat() != m_devImp->m_currentFormat)
Shinya Kitaoka 120a6e
    if (m_devImp->doCloseDevice()) m_devImp->setFormat(st->getFormat());
Shinya Kitaoka 120a6e
  m_stopWatch->start();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TPlayTask::run() {
Shinya Kitaoka 120a6e
  int bytesLeft = m_sndtrack->getSampleCount() * m_sndtrack->getSampleSize();
Shinya Kitaoka 120a6e
  char *buf     = (char *)m_sndtrack->getRawData();
Shinya Kitaoka 120a6e
  int done      = 0;
Shinya Kitaoka 120a6e
  int written   = 0;
Shinya Kitaoka 120a6e
  TINT32 sampleSize      = (TINT32)m_sndtrack->getSampleSize();
Shinya Kitaoka 120a6e
  const double msToBytes = sampleSize * m_sndtrack->getSampleRate() / 1000.;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TThread::milestone();
Shinya Kitaoka 120a6e
  double startupDelay = m_stopWatch->getTotalTime();
Shinya Kitaoka 120a6e
  // std::cout << "ritardo iniziale " << startupDelay << std::endl;
Shinya Kitaoka 120a6e
  int miss = 0;
Shinya Kitaoka 120a6e
  m_stopWatch->start();  // e' meglio ignorare il ritardo iniziale
Shinya Kitaoka 120a6e
  if (done > 0) {
Shinya Kitaoka 120a6e
    m_stopWatch->addDelay(((done / sampleSize) * 1000) /
Shinya Kitaoka 120a6e
                          double(m_sndtrack->getSampleRate()));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  int auxbuffersize   = 0;
Shinya Kitaoka 120a6e
  int preWrittenBytes = 0;
Shinya Kitaoka 120a6e
  int bytesToSkipNext;
Shinya Kitaoka 120a6e
  TSoundTrackP src    = TSoundTrack::create(m_sndtrack->getFormat(), 1);
Shinya Kitaoka 120a6e
  TSoundTrackP dst    = src;
Shinya Kitaoka 120a6e
  TSoundTrackP newSrc = src;
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    do  // gia' tracce accodate
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      bool changeSnd = false;
Shinya Kitaoka 120a6e
      do  // c'e' il flag loop settato
Shinya Kitaoka 120a6e
      {
Shinya Kitaoka 120a6e
        while ((bytesLeft > 0)) {
Shinya Kitaoka 120a6e
          TThread::milestone();
Shinya Kitaoka 120a6e
          changeSnd = false;
Shinya Kitaoka 120a6e
          audio_buf_info info;
Shinya Kitaoka 120a6e
          TINT32 bytesToWrite     = 0;
Shinya Kitaoka 120a6e
          TINT32 bytesToWriteNext = 0;
Shinya Kitaoka 120a6e
          double samplesDone      = done / (double)sampleSize;
Shinya Kitaoka 120a6e
          double trackTime =
Shinya Kitaoka 120a6e
              (samplesDone * 1000.) / m_sndtrack->getSampleRate();
Shinya Kitaoka 120a6e
          double curTime = m_stopWatch->getTotalTime();
Shinya Kitaoka 120a6e
          double delta   = curTime - trackTime;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          /*
Shinya Kitaoka 120a6e
           delta
Shinya Kitaoka 120a6e
                                           == 0 sync
Shinya Kitaoka 120a6e
                                           <	 0 audio piu' veloce del tempo
Shinya Kitaoka 120a6e
           di playback  --> simuliamo un ritardo con un continue;
Shinya Kitaoka 120a6e
                                           >  0 audio piu' lento del playback ->
Shinya Kitaoka 120a6e
           skip una porzione di audio
Shinya Kitaoka 120a6e
   */
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          const double minDelay = -10;
Shinya Kitaoka 120a6e
          const double maxDelay = 0;
Shinya Kitaoka 120a6e
          // if (delta>maxDelay)
Shinya Kitaoka 120a6e
          // std::cout << "buffer underrun:" << delta << std::endl;
Shinya Kitaoka 120a6e
          // std::cout << "buffer " <<
Shinya Kitaoka 120a6e
          // (delta<mindelay?"overrun":delta>maxDelay?"underrun":"sync")  << " "</mindelay?"overrun":delta>
Shinya Kitaoka 120a6e
          // << delta<< std::endl;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          if (delta < minDelay)  // overrun
Shinya Kitaoka 120a6e
          {
Shinya Kitaoka 120a6e
            // std::cout << "out of sync -> audio troppo veloce" << std::endl;
Shinya Kitaoka 120a6e
            continue;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          if (ioctl(m_devImp->m_dev, SNDCTL_DSP_GETOSPACE, &info) == -1) {
Shinya Kitaoka 120a6e
            miss++;
Shinya Kitaoka 120a6e
            break;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          int fragmentsFree_bytes = info.fragsize * info.fragments;
Shinya Kitaoka 120a6e
          if (fragmentsFree_bytes == 0) {
Shinya Kitaoka 120a6e
            // std::cout << "no bytes left on device" << std::endl;
Shinya Kitaoka 120a6e
            continue;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          int bytesToSkip = 0;
Shinya Kitaoka 120a6e
          bytesToSkipNext = 0;
Shinya Kitaoka 120a6e
          if (delta > maxDelay)  // underrun
Shinya Kitaoka 120a6e
          {
Shinya Kitaoka 120a6e
            // std::cout << "out of sync -> audio troppo lento"<
Shinya Kitaoka 120a6e
            // skip di una porzione... delta in ms
Shinya Kitaoka 120a6e
            bytesToSkip =
Shinya Kitaoka 120a6e
                tceil(delta * msToBytes);  // numero di bytes da skippare
Shinya Kitaoka 120a6e
            // lo arrotondo al sample size
Shinya Kitaoka 120a6e
            bytesToSkip += sampleSize - (bytesToSkip % sampleSize);
Shinya Kitaoka 120a6e
            // std::cout << "bytes skippati "<< bytesToSkip << std::endl;
Shinya Kitaoka 120a6e
          } else {  // sto fra minDelay e maxDelay
Shinya Kitaoka 120a6e
            bytesToSkip = 0;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          bytesToSkipNext = bytesToSkip;
Shinya Kitaoka 120a6e
          bytesToSkip     = tmin(bytesLeft, bytesToSkip);
Shinya Kitaoka 120a6e
          bytesToSkipNext -= bytesToSkip;  // se !=0 => la corrente traccia non
Shinya Kitaoka 120a6e
                                           // basta per avere il sync
Shinya Kitaoka 120a6e
          bytesLeft -= bytesToSkip;
Shinya Kitaoka 120a6e
          done += bytesToSkip;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          bytesToWrite     = tmin(bytesLeft, fragmentsFree_bytes);
Shinya Kitaoka 120a6e
          bytesToWriteNext = fragmentsFree_bytes - bytesToWrite;
Shinya Kitaoka 120a6e
          assert(bytesToWrite >= 0);
Shinya Kitaoka 120a6e
          assert(bytesToWriteNext >= 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          if (bytesToWrite % info.fragsize !=
Shinya Kitaoka 120a6e
              0) {  // cerco di gestire il write di un frammento non intero
Shinya Kitaoka 120a6e
            auxbuffersize =
Shinya Kitaoka 120a6e
                ((bytesToWrite / info.fragsize) + 1) * info.fragsize;
Shinya Kitaoka 120a6e
          } else
Shinya Kitaoka 120a6e
            auxbuffersize = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          //--------------write
Shinya Kitaoka 120a6e
          if (bytesToSkipNext == 0)  // la corrente traccia basta per lo skip
Shinya Kitaoka 120a6e
          {
Shinya Kitaoka 120a6e
            std::cout << " QUI 0 " << std::endl;
Shinya Kitaoka 120a6e
            dst = m_sndtrack->extract(done / sampleSize,
Shinya Kitaoka 120a6e
                                      (done + bytesToWrite) / sampleSize);
Shinya Kitaoka 120a6e
            if (bytesToSkip != 0) {
Shinya Kitaoka 120a6e
              // costruisco traccia su cui fare il crossfade
Shinya Kitaoka 120a6e
              // utilizzo il contenuto della traccia di crossfade
Shinya Kitaoka 120a6e
              dst = TSop::crossFade(0.2, src, dst);
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
            char *auxbuf = new char[fragmentsFree_bytes];
Shinya Kitaoka 120a6e
            memcpy(auxbuf, (char *)dst->getRawData(), bytesToWrite);
Shinya Kitaoka 120a6e
            if (bytesToWriteNext != 0) {
Shinya Kitaoka 120a6e
              int offset = bytesToWrite;
Shinya Kitaoka 120a6e
              if (m_devImp->m_looped) {
Shinya Kitaoka 120a6e
                offset += bytesToWriteNext;
Shinya Kitaoka 120a6e
                preWrittenBytes = bytesToWriteNext;
Shinya Kitaoka 120a6e
                memcpy(auxbuf + offset, buf, preWrittenBytes);
Shinya Kitaoka 120a6e
                newSrc = m_sndtrack->extract(preWrittenBytes / sampleSize,
Shinya Kitaoka 120a6e
                                             preWrittenBytes / sampleSize);
Shinya Kitaoka 120a6e
                std::cout << " QUI 1" << std::endl;
Shinya Kitaoka 120a6e
              } else {
Shinya Kitaoka 120a6e
                while (!m_devImp->m_waitingTracks.empty()) {
Shinya Kitaoka 120a6e
                  TSoundTrackP st = m_devImp->m_waitingTracks[0].first;
Shinya Kitaoka 120a6e
                  int count       = st->getSampleCount() * sampleSize;
Shinya Kitaoka 120a6e
                  if (bytesToWriteNext >= count) {
Shinya Kitaoka 120a6e
                    char *buffer = (char *)st->getRawData();
Shinya Kitaoka 120a6e
                    memcpy(auxbuf + offset, buffer, count);
Shinya Kitaoka 120a6e
                    bytesToWriteNext -= count;
Shinya Kitaoka 120a6e
                    offset += count;
Shinya Kitaoka 120a6e
                    std::cout << " QUI 2" << std::endl;
Shinya Kitaoka 120a6e
                    if (m_devImp->m_waitingTracks[0].second) {
Shinya Kitaoka 120a6e
                      m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
Shinya Kitaoka 120a6e
                      m_devImp->m_waitingTracks.erase(
Shinya Kitaoka 120a6e
                          m_devImp->m_waitingTracks.begin());
Shinya Kitaoka 120a6e
                      newSrc = m_sndtrack->extract(count / sampleSize,
Shinya Kitaoka 120a6e
                                                   count / sampleSize);
Shinya Kitaoka 120a6e
                      m_sndtrack      = st;
Shinya Kitaoka 120a6e
                      preWrittenBytes = 0;
Shinya Kitaoka 120a6e
                      std::cout << " QUI 3" << std::endl;
Shinya Kitaoka 120a6e
                      break;
Shinya Kitaoka 120a6e
                    }
Shinya Kitaoka 120a6e
                    m_devImp->m_waitingTracks.erase(
Shinya Kitaoka 120a6e
                        m_devImp->m_waitingTracks.begin());
Shinya Kitaoka 120a6e
                    newSrc = m_sndtrack->extract(count / sampleSize,
Shinya Kitaoka 120a6e
                                                 count / sampleSize);
Shinya Kitaoka 120a6e
                  } else {
Shinya Kitaoka 120a6e
                    m_sndtrack         = st;
Shinya Kitaoka 120a6e
                    m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
Shinya Kitaoka 120a6e
                    preWrittenBytes    = bytesToWriteNext;
Shinya Kitaoka 120a6e
                    buf                = (char *)m_sndtrack->getRawData();
Shinya Kitaoka 120a6e
                    memcpy(auxbuf + offset, buf, bytesToWriteNext);
Shinya Kitaoka 120a6e
                    m_devImp->m_waitingTracks.erase(
Shinya Kitaoka 120a6e
                        m_devImp->m_waitingTracks.begin());
Shinya Kitaoka 120a6e
                    newSrc =
Shinya Kitaoka 120a6e
                        m_sndtrack->extract((bytesToWriteNext) / sampleSize,
Shinya Kitaoka 120a6e
                                            (bytesToWriteNext) / sampleSize);
Shinya Kitaoka 120a6e
                    std::cout << " QUI 4" << std::endl;
Shinya Kitaoka 120a6e
                    break;
Shinya Kitaoka 120a6e
                  }
Shinya Kitaoka 120a6e
                }  // end while
Shinya Kitaoka 120a6e
              }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
              if (fragmentsFree_bytes > offset) {
Shinya Kitaoka 120a6e
                std::cout << " QUI 5" << std::endl;
Shinya Kitaoka 120a6e
                int val = m_sndtrack->isSampleSigned() ? 0 : 127;
Shinya Kitaoka 120a6e
                memset(auxbuf + offset, val,
Shinya Kitaoka 120a6e
                       fragmentsFree_bytes - offset);  // ci metto silenzio
Shinya Kitaoka 120a6e
                newSrc = TSoundTrack::create(m_sndtrack->getFormat(), 1);
Shinya Kitaoka 120a6e
              }
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
            written = write(m_devImp->m_dev, auxbuf, fragmentsFree_bytes);
Shinya Kitaoka 120a6e
            delete[] auxbuf;
Shinya Kitaoka 120a6e
          } else  // devo skippare anche parte di una delle seguenti
Shinya Kitaoka 120a6e
          {
Shinya Kitaoka 120a6e
            std::cout << " QUI 6a" << std::endl;
Shinya Kitaoka 120a6e
            assert(bytesToWriteNext > 0);
Shinya Kitaoka 120a6e
            assert(bytesToWriteNext == fragmentsFree_bytes - bytesToWrite);
Shinya Kitaoka 120a6e
            assert(bytesToWrite == 0);
Shinya Kitaoka 120a6e
            assert(bytesToSkip != 0);
Shinya Kitaoka 120a6e
            char *auxbuf = new char[fragmentsFree_bytes];
Shinya Kitaoka 120a6e
            // memcpy(auxbuf, buf+done, bytesToWrite);
Shinya Kitaoka 120a6e
            // TSoundTrackP subCross =
Shinya Kitaoka 120a6e
            // m_sndtrack->extract((done+bytesToWrite)/sampleSize,
Shinya Kitaoka 120a6e
            // (done+bytesToWrite)/sampleSize);
Shinya Kitaoka 120a6e
            // togli quelle da skippare
Shinya Kitaoka 120a6e
            int backupSkipNext = bytesToSkipNext;
Shinya Kitaoka 120a6e
            while (!m_devImp->m_waitingTracks.empty()) {
Shinya Kitaoka 120a6e
              TSoundTrackP st = m_devImp->m_waitingTracks[0].first;
Shinya Kitaoka 120a6e
              int count       = st->getSampleCount() * sampleSize;
Shinya Kitaoka 120a6e
              if (bytesToSkipNext >= count) {
Shinya Kitaoka 120a6e
                std::cout << " QUI 6b" << std::endl;
Shinya Kitaoka 120a6e
                m_devImp->m_waitingTracks.erase(
Shinya Kitaoka 120a6e
                    m_devImp->m_waitingTracks.begin());
Shinya Kitaoka 120a6e
                bytesToSkipNext -= count;
Shinya Kitaoka 120a6e
              } else {
Shinya Kitaoka 120a6e
                std::cout << " QUI 7" << std::endl;
Shinya Kitaoka 120a6e
                m_devImp->m_waitingTracks.erase(
Shinya Kitaoka 120a6e
                    m_devImp->m_waitingTracks.begin());
Shinya Kitaoka 120a6e
                m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
Shinya Kitaoka 120a6e
                m_sndtrack         = st;
Shinya Kitaoka 120a6e
                buf                = (char *)st->getRawData();
Shinya Kitaoka 120a6e
                break;
Shinya Kitaoka 120a6e
              }
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
            // scrivi byteWriteNext fai crossfade e cerca quella successiva
Shinya Kitaoka 120a6e
            // con cui riempire
Shinya Kitaoka 120a6e
            TINT32 displacement =
Shinya Kitaoka 120a6e
                0;  // deve essere in munero di campioni non bytes
Shinya Kitaoka 120a6e
            dst = TSoundTrack::create(
Shinya Kitaoka 120a6e
                m_sndtrack->getFormat(),
Shinya Kitaoka 120a6e
                (fragmentsFree_bytes - bytesToWrite) / sampleSize);
Shinya Kitaoka 120a6e
            int count = m_sndtrack->getSampleCount() * sampleSize;
Shinya Kitaoka 120a6e
            if (count >= bytesToSkipNext + bytesToWriteNext)  // la traccia
Shinya Kitaoka 120a6e
                                                              // trovata e' suff
Shinya Kitaoka 120a6e
                                                              // sia per
Shinya Kitaoka 120a6e
                                                              // skippare che
Shinya Kitaoka 120a6e
                                                              // per scrivere
Shinya Kitaoka 120a6e
            {
Shinya Kitaoka 120a6e
              preWrittenBytes = bytesToSkipNext + bytesToWriteNext;
Shinya Kitaoka 120a6e
              dst = m_sndtrack->extract(bytesToSkipNext / sampleSize,
Shinya Kitaoka 120a6e
                                        preWrittenBytes / sampleSize);
Shinya Kitaoka 120a6e
              newSrc = m_sndtrack->extract(preWrittenBytes / sampleSize,
Shinya Kitaoka 120a6e
                                           preWrittenBytes / sampleSize);
Shinya Kitaoka 120a6e
            } else  // non e' suff per scrivere
Shinya Kitaoka 120a6e
            {
Shinya Kitaoka 120a6e
              dst->copy(m_sndtrack->extract(bytesToSkipNext / sampleSize,
Shinya Kitaoka 120a6e
                                            m_sndtrack->getSampleCount() - 1),
Shinya Kitaoka 120a6e
                        0);
Shinya Kitaoka 120a6e
              displacement =
Shinya Kitaoka 120a6e
                  m_sndtrack->getSampleCount() - bytesToSkipNext / sampleSize;
Shinya Kitaoka 120a6e
              bytesToWriteNext -= displacement * sampleSize;
Shinya Kitaoka 120a6e
              while (!m_devImp->m_waitingTracks.empty()) {
Shinya Kitaoka 120a6e
                TSoundTrackP st = m_devImp->m_waitingTracks[0].first;
Shinya Kitaoka 120a6e
                int count       = st->getSampleCount() * sampleSize;
Shinya Kitaoka 120a6e
                if (bytesToWriteNext >= count) {
Shinya Kitaoka 120a6e
                  std::cout << " QUI 8" << std::endl;
Shinya Kitaoka 120a6e
                  dst->copy(st, displacement);
Shinya Kitaoka 120a6e
                  bytesToWriteNext -= count;
Shinya Kitaoka 120a6e
                  displacement += count;
Shinya Kitaoka 120a6e
                  if (m_devImp->m_waitingTracks[0].second) {
Shinya Kitaoka 120a6e
                    std::cout << " QUI 9" << std::endl;
Shinya Kitaoka 120a6e
                    m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
Shinya Kitaoka 120a6e
                    m_devImp->m_waitingTracks.erase(
Shinya Kitaoka 120a6e
                        m_devImp->m_waitingTracks.begin());
Shinya Kitaoka 120a6e
                    newSrc = m_sndtrack->extract(count / sampleSize,
Shinya Kitaoka 120a6e
                                                 count / sampleSize);
Shinya Kitaoka 120a6e
                    m_sndtrack = st;
Shinya Kitaoka 120a6e
                    break;
Shinya Kitaoka 120a6e
                  }
Shinya Kitaoka 120a6e
                  m_devImp->m_waitingTracks.erase(
Shinya Kitaoka 120a6e
                      m_devImp->m_waitingTracks.begin());
Shinya Kitaoka 120a6e
                  newSrc = m_sndtrack->extract(count / sampleSize,
Shinya Kitaoka 120a6e
                                               count / sampleSize);
Shinya Kitaoka 120a6e
                } else {
Shinya Kitaoka 120a6e
                  std::cout << " QUI 10" << std::endl;
Shinya Kitaoka 120a6e
                  dst->copy(st->extract(0L, bytesToWriteNext / sampleSize),
Shinya Kitaoka 120a6e
                            displacement);
Shinya Kitaoka 120a6e
                  m_sndtrack         = st;
Shinya Kitaoka 120a6e
                  m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
Shinya Kitaoka 120a6e
                  preWrittenBytes    = bytesToWriteNext;
Shinya Kitaoka 120a6e
                  done               = preWrittenBytes;
Shinya Kitaoka 120a6e
                  bytesLeft = m_sndtrack->getSampleCount() * sampleSize - done;
Shinya Kitaoka 120a6e
                  buf       = (char *)m_sndtrack->getRawData();
Shinya Kitaoka 120a6e
                  m_devImp->m_waitingTracks.erase(
Shinya Kitaoka 120a6e
                      m_devImp->m_waitingTracks.begin());
Shinya Kitaoka 120a6e
                  newSrc = m_sndtrack->extract(preWrittenBytes / sampleSize,
Shinya Kitaoka 120a6e
                                               preWrittenBytes / sampleSize);
Shinya Kitaoka 120a6e
                  break;
Shinya Kitaoka 120a6e
                }
Shinya Kitaoka 120a6e
              }
Shinya Kitaoka 120a6e
              bytesToSkipNext = backupSkipNext;
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
            TSoundTrackP st = TSop::crossFade(0.2, src, dst);
Shinya Kitaoka 120a6e
            memcpy(auxbuf + bytesToWrite, (char *)st->getRawData(),
Shinya Kitaoka 120a6e
                   fragmentsFree_bytes - bytesToWrite);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
            // devo ricercare quella giusta che non deve essere skippata
Shinya Kitaoka 120a6e
            // ma sostitutita come traccia corrente
Shinya Kitaoka 120a6e
            // devo fare un cross fade
Shinya Kitaoka 120a6e
            written = write(m_devImp->m_dev, auxbuf, fragmentsFree_bytes);
Shinya Kitaoka 120a6e
            delete[] auxbuf;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
          //----------- end write
Shinya Kitaoka 120a6e
          src = newSrc;
Shinya Kitaoka 120a6e
          if (written == -1) break;
Shinya Kitaoka 120a6e
          std::cout << written << " " << (bytesToWrite + preWrittenBytes)
Shinya Kitaoka 120a6e
                    << std::endl;
Shinya Kitaoka 120a6e
          if (written != bytesToWrite + preWrittenBytes) break;
Shinya Kitaoka 120a6e
          std::cout << " update done 2" << std::endl;
Shinya Kitaoka 120a6e
          bytesLeft -= written;
Shinya Kitaoka 120a6e
          done += written;
Shinya Kitaoka 120a6e
        }  // chiudo il while((bytesLeft > 0))
Shinya Kitaoka 120a6e
        std::cout << " QUI 11" << std::endl;
Shinya Kitaoka 120a6e
        done      = preWrittenBytes + bytesToSkipNext;
Shinya Kitaoka 120a6e
        written   = 0;
Shinya Kitaoka 120a6e
        bytesLeft = m_sndtrack->getSampleCount() * sampleSize - done;
Shinya Kitaoka 120a6e
        m_stopWatch->start();
Shinya Kitaoka 120a6e
        if (done > 0) {
Shinya Kitaoka 120a6e
          m_stopWatch->addDelay(((done / m_sndtrack->getSampleSize()) * 1000) /
Shinya Kitaoka 120a6e
                                double(m_sndtrack->getSampleRate()));
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        preWrittenBytes = 0;
Shinya Kitaoka 120a6e
      } while (m_devImp->m_looped || changeSnd);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (m_devImp->m_waitingTracks.empty()) break;
Shinya Kitaoka 120a6e
      m_sndtrack         = m_devImp->m_waitingTracks[0].first;
Shinya Kitaoka 120a6e
      m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
Shinya Kitaoka 120a6e
      m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
Shinya Kitaoka 120a6e
      bytesLeft = m_sndtrack->getSampleCount() * m_sndtrack->getSampleSize();
Shinya Kitaoka 120a6e
      buf       = (char *)m_sndtrack->getRawData();
Shinya Kitaoka 120a6e
      done      = 0;
Shinya Kitaoka 120a6e
      written   = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      m_stopWatch->start();  // ignoro il ritardo iniziale
Shinya Kitaoka 120a6e
      if (done > 0) {
Shinya Kitaoka 120a6e
        m_stopWatch->addDelay(((done / m_sndtrack->getSampleSize()) * 1000) /
Shinya Kitaoka 120a6e
                              double(m_sndtrack->getSampleRate()));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } while (true);  // ci sono gia' tracce accodate
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!m_devImp->m_waitingTracks.empty()) {
Shinya Kitaoka 120a6e
      m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
Shinya Kitaoka 120a6e
      m_devImp->m_executor.addTask(
Shinya Kitaoka 120a6e
          new TPlayTask(m_devImp, m_devImp->m_waitingTracks[0].first));
Shinya Kitaoka 120a6e
      m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
Shinya Kitaoka 120a6e
      // std::cout<<"OPS ..... erase 4"<
Shinya Kitaoka 120a6e
    } else if (m_devImp->m_dev != -1) {
Shinya Kitaoka 120a6e
      if (ioctl(m_devImp->m_dev, SNDCTL_DSP_SYNC) == -1) {
Shinya Kitaoka 120a6e
        std::cout << "unable to sync! " << std::endl;
Shinya Kitaoka 120a6e
        throw TException("unable to sync!");
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      m_devImp->m_isPlaying = false;
Shinya Kitaoka 120a6e
      m_devImp->m_stopped   = true;
Shinya Kitaoka 120a6e
      m_devImp->m_looped    = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // std::cout << "miss = " << miss << std::endl;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } catch (TThread::Interrupt &e) {
Shinya Kitaoka 120a6e
    std::cout << "Play interrupted " << e.getMessage() << std::endl;
Shinya Kitaoka 120a6e
    m_devImp->m_isPlaying = false;
Shinya Kitaoka 120a6e
    m_devImp->m_stopped   = true;
Shinya Kitaoka 120a6e
    m_devImp->m_looped    = false;
Shinya Kitaoka 120a6e
  } catch (TException &e) {
Shinya Kitaoka 120a6e
    std::cout << "esco dal play " << e.getMessage() << std::endl;
Shinya Kitaoka 120a6e
    m_devImp->m_isPlaying = false;
Shinya Kitaoka 120a6e
    m_devImp->m_stopped   = true;
Shinya Kitaoka 120a6e
    m_devImp->m_looped    = false;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TPlayTask::run2() {
Shinya Kitaoka 120a6e
  int bytesLeft = m_sndtrack->getSampleCount() * m_sndtrack->getSampleSize();
Shinya Kitaoka 120a6e
  char *buf     = (char *)m_sndtrack->getRawData();
Shinya Kitaoka 120a6e
  int done      = 0;
Shinya Kitaoka 120a6e
  int written   = 0;
Shinya Kitaoka 120a6e
  TINT32 sampleSize      = (TINT32)m_sndtrack->getSampleSize();
Shinya Kitaoka 120a6e
  const double msToBytes = sampleSize * m_sndtrack->getSampleRate() / 1000.;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TThread::milestone();
Shinya Kitaoka 120a6e
  double startupDelay = m_stopWatch->getTotalTime();
Shinya Kitaoka 120a6e
  // std::cout << "ritardo iniziale " << startupDelay << std::endl;
Shinya Kitaoka 120a6e
  int miss = 0;
Shinya Kitaoka 120a6e
  m_stopWatch->start();  // e' meglio ignorare il ritardo iniziale
Shinya Kitaoka 120a6e
  if (done > 0) {
Shinya Kitaoka 120a6e
    m_stopWatch->addDelay(((done / sampleSize) * 1000) /
Shinya Kitaoka 120a6e
                          double(m_sndtrack->getSampleRate()));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  int auxbuffersize   = 0;
Shinya Kitaoka 120a6e
  int preWrittenBytes = 0;
Shinya Kitaoka 120a6e
  TSoundTrackP src    = TSoundTrack::create(m_sndtrack->getFormat(), 1);
Shinya Kitaoka 120a6e
  TSoundTrackP dst    = src;
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    do  // gia' tracce accodate
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      bool changeSnd = false;
Shinya Kitaoka 120a6e
      do  // c'e' il flag loop settato
Shinya Kitaoka 120a6e
      {
Shinya Kitaoka 120a6e
        while ((bytesLeft > 0)) {
Shinya Kitaoka 120a6e
          changeSnd = false;
Shinya Kitaoka 120a6e
          TThread::milestone();
Shinya Kitaoka 120a6e
          audio_buf_info info;
Shinya Kitaoka 120a6e
          TINT32 bytesToWrite;
Shinya Kitaoka 120a6e
          double samplesDone = done / (double)sampleSize;
Shinya Kitaoka 120a6e
          double trackTime =
Shinya Kitaoka 120a6e
              (samplesDone * 1000.) / m_sndtrack->getSampleRate();
Shinya Kitaoka 120a6e
          double curTime = m_stopWatch->getTotalTime();
Shinya Kitaoka 120a6e
          double delta   = curTime - trackTime;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          /*
Shinya Kitaoka 120a6e
           delta
Shinya Kitaoka 120a6e
                                           == 0 sync
Shinya Kitaoka 120a6e
                                           <	 0 audio piu' veloce del tempo
Shinya Kitaoka 120a6e
           di playback  --> simuliamo un ritardo con un continue;
Shinya Kitaoka 120a6e
                                           >  0 audio piu' lento del playback ->
Shinya Kitaoka 120a6e
           skip una porzione di audio
Shinya Kitaoka 120a6e
   */
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          const double minDelay = -10;
Shinya Kitaoka 120a6e
          const double maxDelay = 0;
Shinya Kitaoka 120a6e
          // if (delta>maxDelay)
Shinya Kitaoka 120a6e
          // std::cout << "buffer underrun:" << delta << std::endl;
Shinya Kitaoka 120a6e
          // std::cout << "buffer " <<
Shinya Kitaoka 120a6e
          // (delta<mindelay?"overrun":delta>maxDelay?"underrun":"sync")  << " "</mindelay?"overrun":delta>
Shinya Kitaoka 120a6e
          // << delta<< std::endl;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          if (delta < minDelay)  // overrun
Shinya Kitaoka 120a6e
          {
Shinya Kitaoka 120a6e
            // std::cout << "out of sync -> audio troppo veloce" << std::endl;
Shinya Kitaoka 120a6e
            continue;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          if (ioctl(m_devImp->m_dev, SNDCTL_DSP_GETOSPACE, &info) == -1) {
Shinya Kitaoka 120a6e
            miss++;
Shinya Kitaoka 120a6e
            break;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          int fragmentsFree_bytes = info.fragsize * info.fragments;
Shinya Kitaoka 120a6e
          if (fragmentsFree_bytes == 0) {
Shinya Kitaoka 120a6e
            // std::cout << "no bytes left on device" << std::endl;
Shinya Kitaoka 120a6e
            continue;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          int bytesToSkip = 0;
Shinya Kitaoka 120a6e
          int bigSkip     = 0;
Shinya Kitaoka 120a6e
          if (delta > maxDelay)  // underrun
Shinya Kitaoka 120a6e
          {
Shinya Kitaoka 120a6e
            // std::cout << "out of sync -> audio troppo lento"<
Shinya Kitaoka 120a6e
            // skip di una porzione... delta in ms
Shinya Kitaoka 120a6e
            bytesToSkip =
Shinya Kitaoka 120a6e
                tceil(delta * msToBytes);  // numero di bytes da skippare
Shinya Kitaoka 120a6e
            // lo arrotondo al sample size
Shinya Kitaoka 120a6e
            bytesToSkip += sampleSize - (bytesToSkip % sampleSize);
Shinya Kitaoka 120a6e
            // std::cout << "bytes skippati "<< bytesToSkip << std::endl;
Shinya Kitaoka 120a6e
            bigSkip = bytesToSkip;
Shinya Kitaoka 120a6e
          } else {  // sto fra minDelay e maxDelay
Shinya Kitaoka 120a6e
            bytesToSkip = 0;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          bytesToSkip = tmin(bytesLeft, bytesToSkip);
Shinya Kitaoka 120a6e
          bigSkip -= bytesToSkip;
Shinya Kitaoka 120a6e
          bytesLeft -= bytesToSkip;
Shinya Kitaoka 120a6e
          done += bytesToSkip;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          bytesToWrite = tmin(bytesLeft, fragmentsFree_bytes);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          if (bytesToWrite % info.fragsize !=
Shinya Kitaoka 120a6e
              0) {  // cerco di gestire il write di un frammento non intero
Shinya Kitaoka 120a6e
            auxbuffersize =
Shinya Kitaoka 120a6e
                ((bytesToWrite / info.fragsize) + 1) * info.fragsize;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          if (bigSkip)
Shinya Kitaoka 120a6e
            while (!m_devImp->m_waitingTracks.empty()) {
Shinya Kitaoka 120a6e
              TSoundTrackP st = m_devImp->m_waitingTracks[0].first;
Shinya Kitaoka 120a6e
              int count       = st->getSampleCount() * sampleSize;
Shinya Kitaoka 120a6e
              if (bigSkip >= count) {
Shinya Kitaoka 120a6e
                m_devImp->m_waitingTracks.erase(
Shinya Kitaoka 120a6e
                    m_devImp->m_waitingTracks.begin());
Shinya Kitaoka 120a6e
                bigSkip -= count;
Shinya Kitaoka 120a6e
              } else
Shinya Kitaoka 120a6e
                break;
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          preWrittenBytes = 0;
Shinya Kitaoka 120a6e
          if (auxbuffersize == 0) {
Shinya Kitaoka 120a6e
            if (bytesToSkip != 0) {
Shinya Kitaoka 120a6e
              // costruisco traccia su cui fare il crossfade
Shinya Kitaoka 120a6e
              // utilizzo il contenuto della traccia di crossfade
Shinya Kitaoka 120a6e
              dst = m_sndtrack->extract(done / sampleSize,
Shinya Kitaoka 120a6e
                                        (done + bytesToWrite) / sampleSize);
Shinya Kitaoka 120a6e
              TSoundTrackP st = TSop::crossFade(0.2, src, dst);
Shinya Kitaoka 120a6e
              char *buffer    = (char *)st->getRawData();
Shinya Kitaoka 120a6e
              written         = write(m_devImp->m_dev, buffer, bytesToWrite);
Shinya Kitaoka 120a6e
            } else
Shinya Kitaoka 120a6e
              written = write(m_devImp->m_dev, buf + done, bytesToWrite);
Shinya Kitaoka 120a6e
            src       = m_sndtrack->extract((done + bytesToWrite) / sampleSize,
Shinya Kitaoka 120a6e
                                      (done + bytesToWrite) / sampleSize);
Shinya Kitaoka 120a6e
          } else {  // auxbuffersize != 0 sse il numero di bytes residui nella
Shinya Kitaoka 120a6e
                    // traccia e' inferiore alla dimensione del frammento
Shinya Kitaoka 120a6e
            char *auxbuf = new char[auxbuffersize];
Shinya Kitaoka 120a6e
            TSoundTrackP newSrc;
Shinya Kitaoka 120a6e
            dst = TSoundTrack::create(m_sndtrack->getFormat(),
Shinya Kitaoka 120a6e
                                      auxbuffersize / sampleSize);
Shinya Kitaoka 120a6e
            memcpy(auxbuf, buf + done, bytesToWrite);
Shinya Kitaoka 120a6e
            dst->copy(m_sndtrack->extract(done / sampleSize,
Shinya Kitaoka 120a6e
                                          (done + bytesToWrite) / sampleSize),
Shinya Kitaoka 120a6e
                      0);
Shinya Kitaoka 120a6e
            preWrittenBytes = auxbuffersize - bytesToWrite;
Shinya Kitaoka 120a6e
            if (m_devImp->m_looped) {
Shinya Kitaoka 120a6e
              memcpy(auxbuf + bytesToWrite, buf, preWrittenBytes);
Shinya Kitaoka 120a6e
              dst->copy(m_sndtrack->extract(0, preWrittenBytes / sampleSize),
Shinya Kitaoka 120a6e
                        bytesToWrite / sampleSize);
Shinya Kitaoka 120a6e
              newSrc = m_sndtrack->extract(preWrittenBytes / sampleSize,
Shinya Kitaoka 120a6e
                                           preWrittenBytes / sampleSize);
Shinya Kitaoka 120a6e
            } else {
Shinya Kitaoka 120a6e
              newSrc = TSoundTrack::create(m_sndtrack->getFormat(), 1);
Shinya Kitaoka 120a6e
              static int added = 0;
Shinya Kitaoka 120a6e
              // se non c'e' alcuna altra traccia o e di diverso format
Shinya Kitaoka 120a6e
              // riempo il frammento con del silenzio
Shinya Kitaoka 120a6e
              if (m_devImp->m_waitingTracks.empty() ||
Shinya Kitaoka 120a6e
                  (m_sndtrack->getFormat() !=
Shinya Kitaoka 120a6e
                   m_devImp->m_waitingTracks[0].first->getFormat())) {
Shinya Kitaoka 120a6e
                int val = m_sndtrack->isSampleSigned() ? 0 : 127;
Shinya Kitaoka 120a6e
                memset(auxbuf + bytesToWrite, val,
Shinya Kitaoka 120a6e
                       preWrittenBytes);  // ci metto silenzio
Shinya Kitaoka 120a6e
              } else
Shinya Kitaoka 120a6e
                while (true)  // ci sono altre tracce accodate
Shinya Kitaoka 120a6e
                {
Shinya Kitaoka 120a6e
                  TSoundTrackP st = m_devImp->m_waitingTracks[0].first;
Shinya Kitaoka 120a6e
                  int sampleBytes = st->getSampleCount() * st->getSampleSize();
Shinya Kitaoka 120a6e
                  if (sampleBytes >= preWrittenBytes - added) {
Shinya Kitaoka 120a6e
                    // La traccia ha abbastanza campioni per riempire il
Shinya Kitaoka 120a6e
                    // frammento
Shinya Kitaoka 120a6e
                    // quindi la sostituisco alla corrente del runnable e
Shinya Kitaoka 120a6e
                    // continuo
Shinya Kitaoka 120a6e
                    buf = (char *)st->getRawData();
Shinya Kitaoka 120a6e
                    memcpy(auxbuf + bytesToWrite, buf, preWrittenBytes - added);
Shinya Kitaoka 120a6e
                    m_sndtrack         = st;
Shinya Kitaoka 120a6e
                    m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
Shinya Kitaoka 120a6e
                    m_devImp->m_waitingTracks.erase(
Shinya Kitaoka 120a6e
                        m_devImp->m_waitingTracks.begin());
Shinya Kitaoka 120a6e
                    changeSnd = true;
Shinya Kitaoka 120a6e
                    dst->copy(m_sndtrack->extract(
Shinya Kitaoka 120a6e
                                  0, (preWrittenBytes - added) / sampleSize),
Shinya Kitaoka 120a6e
                              bytesToWrite / sampleSize + added);
Shinya Kitaoka 120a6e
                    newSrc = m_sndtrack->extract(
Shinya Kitaoka 120a6e
                        (preWrittenBytes - added) / sampleSize,
Shinya Kitaoka 120a6e
                        (preWrittenBytes - added) / sampleSize);
Shinya Kitaoka 120a6e
                    break;
Shinya Kitaoka 120a6e
                  } else {  // occhio al loop
Shinya Kitaoka 120a6e
                    // La traccia successiva e' piu corta del frammento da
Shinya Kitaoka 120a6e
                    // riempire quindi
Shinya Kitaoka 120a6e
                    // ce la metto tutta e se non ha il flag di loop settato
Shinya Kitaoka 120a6e
                    // cerco di aggiungere
Shinya Kitaoka 120a6e
                    // i byte della successiva
Shinya Kitaoka 120a6e
                    memcpy(auxbuf + bytesToWrite, st->getRawData(),
Shinya Kitaoka 120a6e
                           sampleBytes);
Shinya Kitaoka 120a6e
                    dst->copy(st->extract(0, st->getSampleCount() - 1),
Shinya Kitaoka 120a6e
                              bytesToWrite / sampleSize);
Shinya Kitaoka 120a6e
                    added += st->getSampleCount();
Shinya Kitaoka 120a6e
                    if (m_devImp->m_waitingTracks[0]
Shinya Kitaoka 120a6e
                            .second)  // e' quella che deve essere in loop
Shinya Kitaoka 120a6e
                    {
Shinya Kitaoka 120a6e
                      buf                = (char *)st->getRawData();
Shinya Kitaoka 120a6e
                      m_sndtrack         = st;
Shinya Kitaoka 120a6e
                      m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
Shinya Kitaoka 120a6e
                      preWrittenBytes    = 0;
Shinya Kitaoka 120a6e
                      bytesLeft          = 0;
Shinya Kitaoka 120a6e
                      m_devImp->m_waitingTracks.erase(
Shinya Kitaoka 120a6e
                          m_devImp->m_waitingTracks.begin());
Shinya Kitaoka 120a6e
                      changeSnd = true;
Shinya Kitaoka 120a6e
                      break;
Shinya Kitaoka 120a6e
                    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
                    // la elimino e vedo se esiste la successiva altrimenti
Shinya Kitaoka 120a6e
                    // metto campioni "zero"
Shinya Kitaoka 120a6e
                    m_devImp->m_waitingTracks.erase(
Shinya Kitaoka 120a6e
                        m_devImp->m_waitingTracks.begin());
Shinya Kitaoka 120a6e
                    if (!m_devImp->m_waitingTracks.empty()) {
Shinya Kitaoka 120a6e
                      st = m_devImp->m_waitingTracks[0].first;
Shinya Kitaoka 120a6e
                      std::cout
Shinya Kitaoka 120a6e
                          << " Traccia con meno campioni cerco la successiva"
Shinya Kitaoka 120a6e
                          << std::endl;
Shinya Kitaoka 120a6e
                    } else {
Shinya Kitaoka 120a6e
                      int val = m_sndtrack->isSampleSigned() ? 0 : 127;
Shinya Kitaoka 120a6e
                      memset(
Shinya Kitaoka 120a6e
                          auxbuf + bytesToWrite, val,
Shinya Kitaoka 120a6e
                          preWrittenBytes - sampleBytes);  // ci metto silenzio
Shinya Kitaoka 120a6e
                      std::cout << "OPS ..... silence" << std::endl;
Shinya Kitaoka 120a6e
                      break;
Shinya Kitaoka 120a6e
                    }
Shinya Kitaoka 120a6e
                  }
Shinya Kitaoka 120a6e
                }  // end while(true)
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
            // qui andrebbe fatto un cross-fade se c'erano da skippare campioni
Shinya Kitaoka 120a6e
            // => bytesToSkip != 0
Shinya Kitaoka 120a6e
            if (bytesToSkip != 0) {
Shinya Kitaoka 120a6e
              TSoundTrackP st = TSop::crossFade(0.2, src, dst);
Shinya Kitaoka 120a6e
              char *buffer    = (char *)st->getRawData();
Shinya Kitaoka 120a6e
              written         = write(m_devImp->m_dev, buffer, bytesToWrite);
Shinya Kitaoka 120a6e
            } else
Shinya Kitaoka 120a6e
              written     = write(m_devImp->m_dev, auxbuf, auxbuffersize);
Shinya Kitaoka 120a6e
            src           = newSrc;
Shinya Kitaoka 120a6e
            auxbuffersize = 0;
Shinya Kitaoka 120a6e
            delete[] auxbuf;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
          if (written == -1) break;
Shinya Kitaoka 120a6e
          if (written != bytesToWrite + preWrittenBytes) break;
Shinya Kitaoka 120a6e
          bytesLeft -= written;
Shinya Kitaoka 120a6e
          done += written;
Shinya Kitaoka 120a6e
        }  // chiudo il while((bytesLeft > 0))
Shinya Kitaoka 120a6e
        done    = preWrittenBytes;
Shinya Kitaoka 120a6e
        written = 0;
Shinya Kitaoka 120a6e
        bytesLeft =
Shinya Kitaoka 120a6e
            m_sndtrack->getSampleCount() * m_sndtrack->getSampleSize() - done;
Shinya Kitaoka 120a6e
        m_stopWatch->start();
Shinya Kitaoka 120a6e
        if (done > 0) {
Shinya Kitaoka 120a6e
          m_stopWatch->addDelay(((done / m_sndtrack->getSampleSize()) * 1000) /
Shinya Kitaoka 120a6e
                                double(m_sndtrack->getSampleRate()));
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      } while (m_devImp->m_looped || changeSnd);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (m_devImp->m_waitingTracks.empty()) {
Shinya Kitaoka 120a6e
        // std::cout<<"OPS ..... non accodato"<
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // std::cout<<"OPS ..... accodato"<
Shinya Kitaoka 120a6e
      m_sndtrack         = m_devImp->m_waitingTracks[0].first;
Shinya Kitaoka 120a6e
      m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
Shinya Kitaoka 120a6e
      m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
Shinya Kitaoka 120a6e
      bytesLeft = m_sndtrack->getSampleCount() * m_sndtrack->getSampleSize();
Shinya Kitaoka 120a6e
      buf       = (char *)m_sndtrack->getRawData();
Shinya Kitaoka 120a6e
      done      = 0;
Shinya Kitaoka 120a6e
      written   = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      m_stopWatch->start();  // ignoro il ritardo iniziale
Shinya Kitaoka 120a6e
      if (done > 0) {
Shinya Kitaoka 120a6e
        m_stopWatch->addDelay(((done / m_sndtrack->getSampleSize()) * 1000) /
Shinya Kitaoka 120a6e
                              double(m_sndtrack->getSampleRate()));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } while (true);  // ci sono gia' tracce accodate
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!m_devImp->m_waitingTracks.empty()) {
Shinya Kitaoka 120a6e
      m_devImp->m_looped = m_devImp->m_waitingTracks[0].second;
Shinya Kitaoka 120a6e
      m_devImp->m_executor.addTask(
Shinya Kitaoka 120a6e
          new TPlayTask(m_devImp, m_devImp->m_waitingTracks[0].first));
Shinya Kitaoka 120a6e
      m_devImp->m_waitingTracks.erase(m_devImp->m_waitingTracks.begin());
Shinya Kitaoka 120a6e
      // std::cout<<"OPS ..... erase 4"<
Shinya Kitaoka 120a6e
    } else if (m_devImp->m_dev != -1) {
Shinya Kitaoka 120a6e
      if (ioctl(m_devImp->m_dev, SNDCTL_DSP_SYNC) == -1) {
Shinya Kitaoka 120a6e
        std::cout << "unable to sync! " << std::endl;
Shinya Kitaoka 120a6e
        throw TException("unable to sync!");
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      m_devImp->m_isPlaying = false;
Shinya Kitaoka 120a6e
      m_devImp->m_stopped   = true;
Shinya Kitaoka 120a6e
      m_devImp->m_looped    = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // std::cout << "miss = " << miss << std::endl;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } catch (TThread::Interrupt &e) {
Shinya Kitaoka 120a6e
    std::cout << "Play interrupted " << e.getMessage() << std::endl;
Shinya Kitaoka 120a6e
    m_devImp->m_isPlaying = false;
Shinya Kitaoka 120a6e
    m_devImp->m_stopped   = true;
Shinya Kitaoka 120a6e
    m_devImp->m_looped    = false;
Shinya Kitaoka 120a6e
  } catch (TException &e) {
Shinya Kitaoka 120a6e
    std::cout << "esco dal play " << e.getMessage() << std::endl;
Shinya Kitaoka 120a6e
    m_devImp->m_isPlaying = false;
Shinya Kitaoka 120a6e
    m_devImp->m_stopped   = true;
Shinya Kitaoka 120a6e
    m_devImp->m_looped    = false;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TSoundOutputDevice::TSoundOutputDevice() : m_imp(new TSoundOutputDeviceImp) {
Shinya Kitaoka 120a6e
  if (m_imp->doOpenDevice()) {
Shinya Kitaoka 120a6e
    m_imp->insertAllRate();
Shinya Kitaoka 120a6e
    try {
Shinya Kitaoka 120a6e
      if (!m_imp->verifyRate())
Shinya Kitaoka 120a6e
        throw TSoundDeviceException(TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
                                    "No default samplerate are supported");
Shinya Kitaoka 120a6e
    } catch (TSoundDeviceException &e) {
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(e.getType(), e.getMessage());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    m_imp->doCloseDevice();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TSoundOutputDevice::~TSoundOutputDevice() { close(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDevice::installed() {
Shinya Kitaoka 120a6e
  bool ret = false;
Shinya Kitaoka 120a6e
  int dev  = ::open("/dev/dsp", O_WRONLY, 0);
Shinya Kitaoka 120a6e
  if (dev >= 0) {
Shinya Kitaoka 120a6e
    ret = true;
Shinya Kitaoka 120a6e
    ::close(dev);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return ret;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDevice::open(const TSoundTrackP &st) {
Shinya Kitaoka 120a6e
  m_imp->m_currentFormat = st->getFormat();
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    m_imp->doOpenDevice();
Shinya Kitaoka 120a6e
  } catch (TSoundDeviceException &e) {
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(e.getType(), e.getMessage());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDevice::close() {
Shinya Kitaoka 120a6e
  stop();
Shinya Kitaoka 120a6e
  if (m_imp->m_dev != -1) {
Shinya Kitaoka 120a6e
    bool closed = m_imp->doCloseDevice();
Shinya Kitaoka 120a6e
    if (!closed)
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(
Shinya Kitaoka 120a6e
          TSoundDeviceException::UnableCloseDevice,
Shinya Kitaoka 120a6e
          "Error during the closing of the output device");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return true;
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
Shinya Kitaoka 120a6e
  TThread::ScopedLock 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
  TSoundTrackFormat format = st->getFormat();
Shinya Kitaoka 120a6e
  if (!m_imp->isSupportFormat(format)) {
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnsupportedFormat,
Shinya Kitaoka 120a6e
                                "Unsupported format for playback");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_imp->m_isPlaying) {
Shinya Kitaoka 120a6e
    assert(s1 >= s0);
Shinya Kitaoka 120a6e
    TSoundTrackP subTrack = st->extract(s0, s1);
Shinya Kitaoka 120a6e
    m_imp->m_waitingTracks.push_back(std::make_pair(subTrack, loop));
Shinya Kitaoka 120a6e
    // std::cout<<"Sono in pushback"<
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if ((m_imp->m_dev == -1)) try {
Shinya Kitaoka 120a6e
      if (m_imp->doOpenDevice()) m_imp->setFormat(format);
Shinya Kitaoka 120a6e
    } catch (TSoundDeviceException &e) {
Shinya Kitaoka 120a6e
      m_imp->doCloseDevice();
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(e.getType(), e.getMessage());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_imp->m_isPlaying = true;
Shinya Kitaoka 120a6e
  m_imp->m_stopped   = false;
Shinya Kitaoka 120a6e
  m_imp->m_looped    = loop;
Shinya Kitaoka 120a6e
  // m_imp->m_currentFormat = st->getFormat();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(s1 >= s0);
Shinya Kitaoka 120a6e
  TSoundTrackP subTrack = st->extract(s0, s1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_imp->m_executor.addTask(new TPlayTask(m_imp, subTrack));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TSoundOutputDevice::stop() {
Shinya Kitaoka 120a6e
  TThread::ScopedLock sl(m_imp->m_mutex);
Shinya Kitaoka 120a6e
  if (!m_imp->m_isPlaying) return;
Shinya Kitaoka 120a6e
  m_imp->m_executor.cancel();
Shinya Kitaoka 120a6e
  ioctl(m_imp->m_dev, SNDCTL_DSP_POST, 0);
Shinya Kitaoka 120a6e
  m_imp->m_isPlaying = false;
Shinya Kitaoka 120a6e
  m_imp->m_stopped   = true;
Shinya Kitaoka 120a6e
  m_imp->m_looped    = false;
Shinya Kitaoka 120a6e
  m_imp->m_waitingTracks.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Shinya Kitaoka 120a6e
double TSoundOutputDevice::getVolume() {
Shinya Kitaoka 120a6e
  int mixer;
Shinya Kitaoka 120a6e
  if ((mixer = openMixer()) < 0)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Can't open the mixer device");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int devmask;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Error in ioctl with mixer device");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int recmask;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, SOUND_MIXER_READ_RECMASK, &recmask) == -1) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Error in ioctl with mixer device");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int stereo;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, SOUND_MIXER_READ_STEREODEVS, &stereo) == -1) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Error in ioctl with mixer device");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int outmask = devmask | ~recmask;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int index;
Shinya Kitaoka 120a6e
  if (outmask & (1 << SOUND_MIXER_ALTPCM))
Shinya Kitaoka 120a6e
    index = SOUND_MIXER_ALTPCM;
Shinya Kitaoka 120a6e
  else if (outmask & (1 << SOUND_MIXER_PCM))
Shinya Kitaoka 120a6e
    index = SOUND_MIXER_PCM;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int level;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, MIXER_READ(index), &level) == -1) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnableVolume,
Shinya Kitaoka 120a6e
                                "Error to read the volume");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if ((1 << index) & stereo) {
Shinya Kitaoka 120a6e
    int left  = level & 0xff;
Shinya Kitaoka 120a6e
    int right = ((level & 0xff00) >> 8);
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    return (left + right) / 20.0;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    return (level & 0xff) / 10.0;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDevice::setVolume(double volume) {
Shinya Kitaoka 120a6e
  int mixer;
Shinya Kitaoka 120a6e
  if ((mixer = openMixer()) < 0)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Can't open the mixer device");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int devmask;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Error in ioctl with mixer device");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int recmask;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &recmask) == -1) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Error in ioctl with mixer device");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int stereo;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, SOUND_MIXER_READ_STEREODEVS, &stereo) == -1) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Error in ioctl with mixer device");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int outmask = devmask | ~recmask;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (outmask & (1 << SOUND_MIXER_ALTPCM)) {
Shinya Kitaoka 120a6e
    int vol, index = SOUND_MIXER_ALTPCM;
Shinya Kitaoka 120a6e
    if ((1 << index) & stereo) {
Shinya Kitaoka 120a6e
      volume *= 10.0;
Shinya Kitaoka 120a6e
      vol = (int)volume + ((int)(volume * 256.0));
Shinya Kitaoka 120a6e
    } else
Shinya Kitaoka 120a6e
      vol = (int)(volume * 10.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!writeVolume(vol, mixer, index)) {
Shinya Kitaoka 120a6e
      ::close(mixer);
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(TSoundDeviceException::UnableVolume,
Shinya Kitaoka 120a6e
                                  "Can't write the volume");
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // metto anche l'altro ad un livello di sensibilita' adeguata
Shinya Kitaoka 120a6e
    if (outmask & (1 << SOUND_MIXER_PCM)) {
Shinya Kitaoka 120a6e
      int vol, index = SOUND_MIXER_PCM;
Shinya Kitaoka 120a6e
      double volDefault = 6.7;
Shinya Kitaoka 120a6e
      if ((1 << index) & stereo) {
Shinya Kitaoka 120a6e
        volDefault *= 10.0;
Shinya Kitaoka 120a6e
        vol = (int)volDefault + ((int)(volDefault * 256.0));
Shinya Kitaoka 120a6e
      } else
Shinya Kitaoka 120a6e
        vol = (int)(volDefault * 10.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (!writeVolume(vol, mixer, index)) {
Shinya Kitaoka 120a6e
        ::close(mixer);
Shinya Kitaoka 120a6e
        throw TSoundDeviceException(TSoundDeviceException::UnableVolume,
Shinya Kitaoka 120a6e
                                    "Can't write the volume");
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else if (outmask & (1 << SOUND_MIXER_PCM)) {
Shinya Kitaoka 120a6e
    int vol, index = SOUND_MIXER_PCM;
Shinya Kitaoka 120a6e
    if ((1 << index) & stereo) {
Shinya Kitaoka 120a6e
      volume *= 10.0;
Shinya Kitaoka 120a6e
      vol = (int)volume + ((int)(volume * 256.0));
Shinya Kitaoka 120a6e
    } else
Shinya Kitaoka 120a6e
      vol = (int)(volume * 10.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!writeVolume(vol, mixer, index)) {
Shinya Kitaoka 120a6e
      ::close(mixer);
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                  "Can't write the volume");
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ::close(mixer);
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDevice::isPlaying() const {
Shinya Kitaoka 120a6e
  TThread::ScopedLock sl(m_imp->m_mutex);
Shinya Kitaoka 120a6e
  return m_imp->m_isPlaying;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundOutputDevice::isLooping() {
Shinya Kitaoka 120a6e
  TThread::ScopedLock 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::ScopedLock 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
bool TSoundOutputDevice::supportsVolume() {
Shinya Kitaoka 120a6e
  int mixer;
Shinya Kitaoka 120a6e
  if ((mixer = openMixer()) < 0)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Can't open the mixer device");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int devmask;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Error in ioctl with mixer device");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int recmask;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &recmask) == -1) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Error in ioctl with mixer device");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int stereo;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, SOUND_MIXER_READ_STEREODEVS, &stereo) == -1) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Error in ioctl with mixer device");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int outmask = devmask | ~recmask;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if ((outmask & (1 << SOUND_MIXER_ALTPCM)) ||
Shinya Kitaoka 120a6e
      (outmask & (1 << SOUND_MIXER_PCM))) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    return true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return false;
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
  if (bitPerSample == 8)
Shinya Kitaoka 120a6e
    fmt = TSoundTrackFormat(sampleRate, channelCount, bitPerSample, false);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    fmt = TSoundTrackFormat(sampleRate, channelCount, bitPerSample);
Shinya Kitaoka 120a6e
  if (m_imp->isSupportFormat(fmt)) return fmt;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int bps, ch, status;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bps = bitPerSample;
Shinya Kitaoka 120a6e
  ch  = channelCount;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_imp->m_dev == -1) m_imp->doOpenDevice();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (bitPerSample <= 8) {
Shinya Kitaoka 120a6e
    bitPerSample       = AFMT_U8;
Shinya Kitaoka 120a6e
    fmt.m_signedSample = false;
Shinya Kitaoka 120a6e
  } else if ((bitPerSample > 8 && bitPerSample < 16) || bitPerSample >= 16) {
Shinya Kitaoka 120a6e
    bitPerSample       = AFMT_S16_NE;
Shinya Kitaoka 120a6e
    fmt.m_signedSample = true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  status = ioctl(m_imp->m_dev, SNDCTL_DSP_SETFMT, &bitPerSample);
Shinya Kitaoka 120a6e
  if (status == -1) {
Shinya Kitaoka 120a6e
    perror("CHE palle ");
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
                                "Failed setting the specified number of bits");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  fmt.m_bitPerSample = bitPerSample;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  status = ioctl(m_imp->m_dev, SNDCTL_DSP_CHANNELS, &channelCount);
Shinya Kitaoka 120a6e
  if (status == -1)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(
Shinya Kitaoka 120a6e
        TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
        "Failed setting the specified number of channel");
Shinya Kitaoka 120a6e
  fmt.m_channelCount = channelCount;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_imp->m_supportedRate.find((int)sampleRate) ==
Shinya Kitaoka 120a6e
      m_imp->m_supportedRate.end()) {
Shinya Kitaoka 120a6e
    std::set<int>::iterator it =</int>
Shinya Kitaoka 120a6e
        m_imp->m_supportedRate.lower_bound((int)sampleRate);
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 rate");
Shinya Kitaoka 120a6e
    } else
Shinya Kitaoka 120a6e
      sampleRate = *it;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (ioctl(m_imp->m_dev, SNDCTL_DSP_SPEED, &sampleRate) == -1)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
                                "Failed setting the specified sample rate");
Shinya Kitaoka 120a6e
  fmt.m_sampleRate = sampleRate;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (ch != channelCount || bps != bitPerSample) {
Shinya Kitaoka 120a6e
    m_imp->doCloseDevice();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return fmt;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
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(e.getType(), e.getMessage());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================================
Toshihiro Shimizu 890ddd
//======================================================================
Toshihiro Shimizu 890ddd
//					CLASSI PER IL RECORD
Toshihiro Shimizu 890ddd
//======================================================================
Toshihiro Shimizu 890ddd
//======================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class TSoundInputDeviceImp {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  int m_dev;
Shinya Kitaoka 120a6e
  bool m_stopped;
Shinya Kitaoka 120a6e
  bool m_isRecording;
Shinya Kitaoka 120a6e
  TSoundTrackFormat m_currentFormat;
Shinya Kitaoka 120a6e
  TSoundTrackP m_st;
Shinya Kitaoka 120a6e
  std::set<int> m_supportedRate;</int>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TINT32 m_recordedSampleCount;
Shinya Kitaoka 120a6e
  vector<char *=""> m_recordedBlocks;</char>
Shinya Kitaoka 120a6e
  vector<int> m_samplePerBlocks;</int>
Shinya Kitaoka 120a6e
  bool m_oneShotRecording;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TThread::Executor m_executor;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TSoundInputDeviceImp()
Shinya Kitaoka 120a6e
      : m_dev(-1)
Shinya Kitaoka 120a6e
      , m_stopped(false)
Shinya Kitaoka 120a6e
      , m_isRecording(false)
Shinya Kitaoka 120a6e
      , m_st(0)
Shinya Kitaoka 120a6e
      , m_supportedRate()
Shinya Kitaoka 120a6e
      , m_recordedBlocks()
Shinya Kitaoka 120a6e
      , m_samplePerBlocks()
Shinya Kitaoka 120a6e
      , m_oneShotRecording(false) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ~TSoundInputDeviceImp() {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool doOpenDevice(const TSoundTrackFormat &format,
Shinya Kitaoka 120a6e
                    TSoundInputDevice::Source devType);
Shinya Kitaoka 120a6e
  bool doCloseDevice();
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
bool TSoundInputDeviceImp::doOpenDevice(const TSoundTrackFormat &format,
Shinya Kitaoka 120a6e
                                        TSoundInputDevice::Source devType) {
Shinya Kitaoka 120a6e
  m_dev = open("/dev/dsp", O_RDONLY);
Shinya Kitaoka 120a6e
  if (m_dev < 0)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnableOpenDevice,
Shinya Kitaoka 120a6e
                                "Cannot open the dsp device");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // ioctl(m_dev, SNDCTL_DSP_RESET,0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundInputDeviceImp::doCloseDevice() {
Shinya Kitaoka 120a6e
  if (close(m_dev) < 0)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnableCloseDevice,
Shinya Kitaoka 120a6e
                                "Cannot close the dsp device");
Shinya Kitaoka 120a6e
  m_dev = -1;
Shinya Kitaoka 120a6e
  return true;
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(); ++it) {
Shinya Kitaoka 120a6e
    int sampleRate = *it;
Shinya Kitaoka 120a6e
    if (ioctl(m_dev, SNDCTL_DSP_SPEED, &sampleRate) == -1)
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
                                  "Failed setting the specified sample rate");
Shinya Kitaoka 120a6e
    if (sampleRate != *it) m_supportedRate.erase(*it);
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
class TRecordTask : public TThread::Runnable {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TSoundInputDeviceImp *m_devImp;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRecordTask(TSoundInputDeviceImp *devImp) : Runnable(), m_devImp(devImp){};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ~TRecordTask(){};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void run();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TRecordTask::run() {
Shinya Kitaoka 120a6e
  // N.B. e' bene che la dimensione sia piccola cosi' l'attesa perche' termini
Shinya Kitaoka 120a6e
  // e' minore in questo caso vogliamo 16 frammenti ognuno di 4096 byte
Shinya Kitaoka 120a6e
  int fraginfo = (16 << 16) | 12;
Shinya Kitaoka 120a6e
  if (ioctl(m_devImp->m_dev, SNDCTL_DSP_SETFRAGMENT, &fraginfo) == -1)
Shinya Kitaoka 120a6e
    perror("SETFRAGMENT");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int fragsize = 0;
Shinya Kitaoka 120a6e
  if (ioctl(m_devImp->m_dev, SNDCTL_DSP_GETBLKSIZE, &fragsize) == -1)
Shinya Kitaoka 120a6e
    perror("GETFRAGMENT");
Shinya Kitaoka 120a6e
  TINT32 byteRecordedSample = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_devImp->m_oneShotRecording) {
Shinya Kitaoka 120a6e
    TINT32 byteToSample =
Shinya Kitaoka 120a6e
        m_devImp->m_st->getSampleSize() * m_devImp->m_st->getSampleCount();
Shinya Kitaoka 120a6e
    char *buf = (char *)m_devImp->m_st->getRawData();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    while ((byteRecordedSample < byteToSample) && m_devImp->m_isRecording) {
Shinya Kitaoka 120a6e
      int sample;
Shinya Kitaoka 120a6e
      if (fragsize > (byteToSample - byteRecordedSample))
Shinya Kitaoka 120a6e
        sample = byteToSample - byteRecordedSample;
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        sample  = fragsize;
Shinya Kitaoka 120a6e
      int nread = read(m_devImp->m_dev, buf + byteRecordedSample, sample);
Shinya Kitaoka 120a6e
      if (nread == -1) break;
Shinya Kitaoka 120a6e
      if (nread != sample) break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      byteRecordedSample += nread;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    int bytePerSample = m_devImp->m_currentFormat.m_bitPerSample >> 3;
Shinya Kitaoka 120a6e
    switch (bytePerSample) {
Shinya Kitaoka 120a6e
    case 3:
Shinya Kitaoka 120a6e
      bytePerSample++;
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    default:
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    bytePerSample *= m_devImp->m_currentFormat.m_channelCount;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    while (m_devImp->m_isRecording) {
Shinya Kitaoka 120a6e
      char *dataBuffer = new char[fragsize];
Shinya Kitaoka 120a6e
      m_devImp->m_recordedBlocks.push_back(dataBuffer);
Shinya Kitaoka 120a6e
      m_devImp->m_samplePerBlocks.push_back(fragsize);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      int nread = read(m_devImp->m_dev, dataBuffer, fragsize);
Shinya Kitaoka 120a6e
      if (nread == -1) break;
Shinya Kitaoka 120a6e
      if (nread != fragsize) break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      m_devImp->m_recordedSampleCount += (fragsize / bytePerSample);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  ioctl(m_devImp->m_dev, SNDCTL_DSP_RESET, 0);
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->m_dev = open("/dev/dsp", O_RDONLY);
Shinya Kitaoka 120a6e
  if (m_imp->m_dev < 0)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnableOpenDevice,
Shinya Kitaoka 120a6e
                                "Cannot open the dsp device");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_imp->insertAllRate();
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    if (!m_imp->verifyRate())
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
                                  "No default samplerate are supported");
Shinya Kitaoka 120a6e
  } catch (TSoundDeviceException &e) {
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(e.getType(), e.getMessage());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_imp->doCloseDevice();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TSoundInputDevice::~TSoundInputDevice() {
Shinya Kitaoka 120a6e
  if (m_imp->m_dev != -1) m_imp->doCloseDevice();
Shinya Kitaoka 120a6e
  delete m_imp;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundInputDevice::installed() {
Shinya Kitaoka 120a6e
  bool ret = false;
Shinya Kitaoka 120a6e
  int dev  = ::open("/dev/dsp", O_RDONLY);
Shinya Kitaoka 120a6e
  if (dev >= 0) {
Shinya Kitaoka 120a6e
    ret = true;
Shinya Kitaoka 120a6e
    ::close(dev);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return ret;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TSoundInputDevice::record(const TSoundTrackFormat &format,
Shinya Kitaoka 120a6e
                               TSoundInputDevice::Source type) {
Shinya Kitaoka 120a6e
  m_imp->m_recordedBlocks.clear();
Shinya Kitaoka 120a6e
  m_imp->m_samplePerBlocks.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // registra creando una nuova traccia
Shinya Kitaoka 120a6e
  m_imp->m_oneShotRecording = false;
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    if (m_imp->m_dev == -1) m_imp->doOpenDevice(format, type);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!selectInputDevice(type))
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(
Shinya Kitaoka 120a6e
          TSoundDeviceException::UnableSetDevice,
Shinya Kitaoka 120a6e
          "Input device is not supported for recording");
Shinya Kitaoka 120a6e
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
  } catch (TSoundDeviceException &e) {
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(e.getType(), e.getMessage());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    if (getVolume() == 0.0) {
Shinya Kitaoka 120a6e
      double volume = 5.0;
Shinya Kitaoka 120a6e
      setVolume(volume);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } catch (TSoundDeviceException &e) {
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(e.getType(), e.getMessage());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_imp->m_currentFormat       = format;
Shinya Kitaoka 120a6e
  m_imp->m_isRecording         = true;
Shinya Kitaoka 120a6e
  m_imp->m_stopped             = false;
Shinya Kitaoka 120a6e
  m_imp->m_recordedSampleCount = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // far partire il thread
Shinya Kitaoka 120a6e
  /*TRecordThread *recordThread = new TRecordThread(m_imp);
Shinya Kitaoka 120a6e
if (!recordThread)
Shinya Kitaoka 120a6e
throw TSoundDeviceException(
Shinya Kitaoka 120a6e
TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
"Problemi per creare il thread");
Shinya Kitaoka 120a6e
recordThread->start();*/
Shinya Kitaoka 120a6e
  m_imp->m_executor.addTask(new TRecordTask(m_imp));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TSoundInputDevice::record(const TSoundTrackP &st,
Shinya Kitaoka 120a6e
                               TSoundInputDevice::Source type) {
Shinya Kitaoka 120a6e
  m_imp->m_recordedBlocks.clear();
Shinya Kitaoka 120a6e
  m_imp->m_samplePerBlocks.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    if (m_imp->m_dev == -1) m_imp->doOpenDevice(st->getFormat(), type);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!selectInputDevice(type))
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(
Shinya Kitaoka 120a6e
          TSoundDeviceException::UnableSetDevice,
Shinya Kitaoka 120a6e
          "Input device is not supported for recording");
Shinya Kitaoka 120a6e
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
    if (getVolume() == 0.0) {
Shinya Kitaoka 120a6e
      double volume = 5.0;
Shinya Kitaoka 120a6e
      setVolume(volume);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } catch (TSoundDeviceException &e) {
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(e.getType(), e.getMessage());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Sovrascive un'intera o parte di traccia gia' esistente
Shinya Kitaoka 120a6e
  m_imp->m_oneShotRecording    = true;
Shinya Kitaoka 120a6e
  m_imp->m_currentFormat       = st->getFormat();
Shinya Kitaoka 120a6e
  m_imp->m_isRecording         = true;
Shinya Kitaoka 120a6e
  m_imp->m_stopped             = false;
Shinya Kitaoka 120a6e
  m_imp->m_recordedSampleCount = 0;
Shinya Kitaoka 120a6e
  m_imp->m_st                  = st;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_imp->m_recordedBlocks.push_back((char *)st->getRawData());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // far partire il thread
Shinya Kitaoka 120a6e
  /*TRecordThread *recordThread = new TRecordThread(m_imp);
Shinya Kitaoka 120a6e
if (!recordThread)
Shinya Kitaoka 120a6e
throw TSoundDeviceException(
Shinya Kitaoka 120a6e
TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
"Problemi per creare il thread");
Shinya Kitaoka 120a6e
recordThread->start();*/
Shinya Kitaoka 120a6e
  m_imp->m_executor.addTask(new TRecordTask(m_imp));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TSoundTrackP TSoundInputDevice::stop() {
Shinya Kitaoka 120a6e
  TSoundTrackP st;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!m_imp->m_isRecording) return st;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_imp->m_isRecording = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // mettere istruzioni per fermare il rec
Shinya Kitaoka 120a6e
  ioctl(m_imp->m_dev, SNDCTL_DSP_SYNC, 0);
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    m_imp->doCloseDevice();
Shinya Kitaoka 120a6e
  } catch (TSoundDeviceException &e) {
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(e.getType(), e.getMessage());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // attendo 1/5 di secondo
Shinya Kitaoka 120a6e
  usleep(200000);
Shinya Kitaoka 120a6e
  if (m_imp->m_oneShotRecording)
Shinya Kitaoka 120a6e
    st = m_imp->m_st;
Shinya Kitaoka 120a6e
  else {
Shinya Kitaoka 120a6e
    st = TSoundTrack::create(m_imp->m_currentFormat,
Shinya Kitaoka 120a6e
                             m_imp->m_recordedSampleCount);
Shinya Kitaoka 120a6e
    TINT32 bytesCopied = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (int i = 0; i < (int)m_imp->m_recordedBlocks.size(); ++i) {
Shinya Kitaoka 120a6e
      memcpy((void *)(st->getRawData() + bytesCopied),
Shinya Kitaoka 120a6e
             m_imp->m_recordedBlocks[i], m_imp->m_samplePerBlocks[i]);
Shinya Kitaoka 120a6e
      delete[] m_imp->m_recordedBlocks[i];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      bytesCopied += m_imp->m_samplePerBlocks[i];
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    m_imp->m_samplePerBlocks.clear();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return st;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double TSoundInputDevice::getVolume() {
Shinya Kitaoka 120a6e
  int mixer;
Shinya Kitaoka 120a6e
  if ((mixer = openMixer()) < 0)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Can't have the mixer");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int index;
Shinya Kitaoka 120a6e
  if ((index = getCurrentRecordSource(mixer)) == -1) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Can't obtain information by mixer");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int stereo;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, SOUND_MIXER_READ_STEREODEVS, &stereo) == -1) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Can't obtain information by mixer");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int level;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, MIXER_READ(index), &level) == -1) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnableVolume,
Shinya Kitaoka 120a6e
                                "Can't read the volume value");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if ((1 << index) & stereo) {
Shinya Kitaoka 120a6e
    int left  = level & 0xff;
Shinya Kitaoka 120a6e
    int right = ((level & 0xff00) >> 8);
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    return (left + right) / 20.0;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    return (level & 0xff) / 10.0;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TSoundInputDevice::setVolume(double volume) {
Shinya Kitaoka 120a6e
  int mixer;
Shinya Kitaoka 120a6e
  if ((mixer = openMixer()) < 0)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Can't have the mixer");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int caps;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, SOUND_MIXER_READ_CAPS, &caps) == -1) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Can't obtain information by mixer");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!(caps & SOUND_CAP_EXCL_INPUT)) {
Shinya Kitaoka 120a6e
    int rec;
Shinya Kitaoka 120a6e
    if (ioctl(mixer, SOUND_MIXER_READ_RECMASK, &rec) == -1) {
Shinya Kitaoka 120a6e
      ::close(mixer);
Shinya Kitaoka 120a6e
      throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                  "Can't obtain information by mixer");
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    int i;
Shinya Kitaoka 120a6e
    int nosound = 0;
Shinya Kitaoka 120a6e
    for (i = 0; i < 32; ++i)
Shinya Kitaoka 120a6e
      if (rec & (1 << i))
Shinya Kitaoka 120a6e
        if (!writeVolume(nosound, mixer, i)) {
Shinya Kitaoka 120a6e
          ::close(mixer);
Shinya Kitaoka 120a6e
          throw TSoundDeviceException(TSoundDeviceException::UnableVolume,
Shinya Kitaoka 120a6e
                                      "Can't set the volume value");
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int index;
Shinya Kitaoka 120a6e
  if ((index = getCurrentRecordSource(mixer)) == -1) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Can't obtain information by mixer");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int stereo;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, SOUND_MIXER_READ_STEREODEVS, &stereo) == -1) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::NoMixer,
Shinya Kitaoka 120a6e
                                "Can't obtain information by mixer");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int vol;
Shinya Kitaoka 120a6e
  if ((1 << index) & stereo) {
Shinya Kitaoka 120a6e
    volume *= 10.0;
Shinya Kitaoka 120a6e
    vol = (int)volume + ((int)(volume * 256.0));
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    vol = (int)(volume * 10.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!writeVolume(vol, mixer, index)) {
Shinya Kitaoka 120a6e
    ::close(mixer);
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnableVolume,
Shinya Kitaoka 120a6e
                                "Can't write the volume value");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  ::close(mixer);
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
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
  int status;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (bitPerSample <= 8) {
Shinya Kitaoka 120a6e
    bitPerSample       = AFMT_U8;
Shinya Kitaoka 120a6e
    fmt.m_signedSample = false;
Shinya Kitaoka 120a6e
  } else if ((bitPerSample > 8 && bitPerSample < 16) || bitPerSample >= 16) {
Shinya Kitaoka 120a6e
    bitPerSample       = AFMT_S16_NE;
Shinya Kitaoka 120a6e
    fmt.m_signedSample = true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  status = ioctl(m_imp->m_dev, SNDCTL_DSP_SETFMT, &bitPerSample);
Shinya Kitaoka 120a6e
  if (status == -1)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
                                "Failed setting the specified number of bits");
Shinya Kitaoka 120a6e
  fmt.m_bitPerSample = bitPerSample;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  status = ioctl(m_imp->m_dev, SNDCTL_DSP_CHANNELS, &channelCount);
Shinya Kitaoka 120a6e
  if (status == -1)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(
Shinya Kitaoka 120a6e
        TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
        "Failed setting the specified number of channel");
Shinya Kitaoka 120a6e
  fmt.m_channelCount = channelCount;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_imp->m_supportedRate.find((int)sampleRate) ==
Shinya Kitaoka 120a6e
      m_imp->m_supportedRate.end()) {
Shinya Kitaoka 120a6e
    std::set<int>::iterator it =</int>
Shinya Kitaoka 120a6e
        m_imp->m_supportedRate.lower_bound((int)sampleRate);
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 rate");
Shinya Kitaoka 120a6e
    } else
Shinya Kitaoka 120a6e
      sampleRate = *it;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (ioctl(m_imp->m_dev, SNDCTL_DSP_SPEED, &sampleRate) == -1)
Shinya Kitaoka 120a6e
    throw TSoundDeviceException(TSoundDeviceException::UnablePrepare,
Shinya Kitaoka 120a6e
                                "Failed setting the specified sample rate");
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
Toshihiro Shimizu 890ddd
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(e.getType(), e.getMessage());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//******************************************************************************
Toshihiro Shimizu 890ddd
//******************************************************************************
Shinya Kitaoka d1f6c4
//						funzioni per l'interazione con
Shinya Kitaoka d1f6c4
// la
Shinya Kitaoka d1f6c4
// libreria
Shinya Kitaoka 38fd86
// OSS
Toshihiro Shimizu 890ddd
//******************************************************************************
Toshihiro Shimizu 890ddd
//******************************************************************************
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
string parseError(int error) {
Shinya Kitaoka 120a6e
  switch (error) {
Shinya Kitaoka 120a6e
  case EBADF:
Shinya Kitaoka 120a6e
    return string("Bad file descriptor");
Shinya Kitaoka 120a6e
  case EFAULT:
Shinya Kitaoka 120a6e
    return string("Pointer to/from buffer data is invalid");
Shinya Kitaoka 120a6e
  case EINTR:
Shinya Kitaoka 120a6e
    return string("Signal interrupt the signal");
Shinya Kitaoka 120a6e
  case EINVAL:
Shinya Kitaoka 120a6e
    return string("Request/arg isn't valid for this device");
Shinya Kitaoka 120a6e
  case EIO:
Shinya Kitaoka 120a6e
    return string("Some phisical I/O error has occurred");
Shinya Kitaoka 120a6e
  case ENOTTY:
Shinya Kitaoka 120a6e
    return string(
Shinya Kitaoka 120a6e
        "Fieldes isn't associated with a device that accepts control");
Shinya Kitaoka 120a6e
  case ENXIO:
Shinya Kitaoka 120a6e
    return string(
Shinya Kitaoka 120a6e
        "Request/arg  valid, but the requested cannot be performed on this "
Shinya Kitaoka 120a6e
        "subdevice");
Shinya Kitaoka 120a6e
  default:
Shinya Kitaoka 120a6e
    return string("Unknown error");
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TSoundInputDevice::Source stringToSource(string dev) {
Shinya Kitaoka 120a6e
  if (dev == "mic")
Shinya Kitaoka 120a6e
    return TSoundInputDevice::Mic;
Shinya Kitaoka 120a6e
  else if (dev == "line")
Shinya Kitaoka 120a6e
    return TSoundInputDevice::LineIn;
Shinya Kitaoka 120a6e
  else if (dev == "cd")
Shinya Kitaoka 120a6e
    return TSoundInputDevice::CdAudio;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return TSoundInputDevice::DigitalIn;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
string sourceToString(TSoundInputDevice::Source dev) {
Shinya Kitaoka 120a6e
  switch (dev) {
Shinya Kitaoka 120a6e
  case TSoundInputDevice::Mic:
Shinya Kitaoka 120a6e
    return string("mic");
Shinya Kitaoka 120a6e
  case TSoundInputDevice::LineIn:
Shinya Kitaoka 120a6e
    return string("line");
Shinya Kitaoka 120a6e
  case TSoundInputDevice::DigitalIn:
Shinya Kitaoka 120a6e
    return string("digital");
Shinya Kitaoka 120a6e
  default:
Shinya Kitaoka 120a6e
    return string("cd");
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int openMixer() {
Shinya Kitaoka 120a6e
  int mixer = open("/dev/mixer", O_RDWR);
Shinya Kitaoka 120a6e
  if (mixer == -1) return false;
Shinya Kitaoka 120a6e
  return mixer;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int getCurrentRecordSource(int mixer) {
Shinya Kitaoka 120a6e
  int recsrc;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) return -1;
Shinya Kitaoka 120a6e
  int index = -1;
Shinya Kitaoka 120a6e
  for (index = 0; index < 32; ++index)
Shinya Kitaoka 120a6e
    if (recsrc & 1 << index) break;
Shinya Kitaoka 120a6e
  return index;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool writeVolume(int volume, int mixer, int indexDev) {
Shinya Kitaoka 120a6e
  if (ioctl(mixer, MIXER_WRITE(indexDev), &volume) == -1) return false;
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool controlEnableRecord(int mixer) {
Shinya Kitaoka 120a6e
  int recmask;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, SOUND_MIXER_READ_RECMASK, &recmask) == -1) {
Shinya Kitaoka 120a6e
    perror("Read recmask");
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (recmask & (1 << SOUND_MIXER_IGAIN)) {
Shinya Kitaoka 120a6e
    int volume;
Shinya Kitaoka 120a6e
    if (ioctl(mixer, MIXER_READ(SOUND_MIXER_IGAIN), &volume) == -1)
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int app = (volume & 0xff);
Shinya Kitaoka 120a6e
    if (app <= 30) {
Shinya Kitaoka 120a6e
      volume = 80 | 80 << 8;
Shinya Kitaoka 120a6e
      if (!writeVolume(volume, mixer, SOUND_MIXER_IGAIN)) return false;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int isInputDeviceSupported(TSoundInputDevice::Source dev, int &mixer) {
Shinya Kitaoka 120a6e
  int recmask;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, SOUND_MIXER_READ_RECMASK, &recmask) == -1) {
Shinya Kitaoka 120a6e
    perror("Read recmask");
Shinya Kitaoka 120a6e
    return -1;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  string devS              = sourceToString(dev);
Shinya Kitaoka 120a6e
  const char *deviceName[] = SOUND_DEVICE_NAMES;
Shinya Kitaoka 120a6e
  for (i = 0; i < 32; ++i) {
Shinya Kitaoka 120a6e
    if (!(recmask & 1 << i)) continue;
Shinya Kitaoka 120a6e
    if (strcmp(devS.c_str(), deviceName[i]) == 0) return i;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return -1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool selectInputDevice(TSoundInputDevice::Source dev) {
Shinya Kitaoka 120a6e
  int mixer;
Shinya Kitaoka 120a6e
  if ((mixer = openMixer()) < 0) {
Shinya Kitaoka 120a6e
    close(mixer);
Shinya Kitaoka 120a6e
    return false;  // throw TException("Can't open the mixer device");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  int index = isInputDeviceSupported(dev, mixer);
Shinya Kitaoka 120a6e
  if (index == -1) return false;
Shinya Kitaoka 120a6e
  int recsrc;
Shinya Kitaoka 120a6e
  if (ioctl(mixer, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) {
Shinya Kitaoka 120a6e
    perror("Read recsrc");
Shinya Kitaoka 120a6e
    close(mixer);
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (!(recsrc & 1 << index)) {
Shinya Kitaoka 120a6e
    recsrc = 1 << index;
Shinya Kitaoka 120a6e
    if (ioctl(mixer, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1) {
Shinya Kitaoka 120a6e
      perror("Write recsrc");
Shinya Kitaoka 120a6e
      ::close(mixer);
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!controlEnableRecord(mixer)) {
Shinya Kitaoka 120a6e
    close(mixer);
Shinya Kitaoka 120a6e
    return false;  // throw TException("Can't enable recording");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  ::close(mixer);
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
}