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