|
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 |
}
|