00001 #include "Shared/Config.h"
00002 #include "Shared/debuget.h"
00003 #include "Shared/MarkScope.h"
00004 #include "Events/EventRouter.h"
00005
00006 #include "SoundManager.h"
00007 #include "WAV.h"
00008
00009 #include <sys/types.h>
00010 #include <sys/stat.h>
00011 #include <fcntl.h>
00012 #include <unistd.h>
00013 #include <stdio.h>
00014 #include <fstream>
00015 #include <stdexcept>
00016
00017 #ifdef PLATFORM_APERIOS
00018 # include <OPENR/OSubject.h>
00019 # include <OPENR/ObjcommEvent.h>
00020 #else
00021 # ifndef __APPLE__
00022 # include "MaryClient.h"
00023 # else
00024 # include <ApplicationServices/ApplicationServices.h>
00025
00026 void speechDoneCleanup(long playid) { MarkScope autolock(sndman->lock); sndman->endPlay(playid); }
00027
00028
00029
00030 static void speechDoneCleanupCallback(SpeechChannel, long playid) { speechDoneCleanup(playid); }
00031
00032
00033 struct MacSpeechState {
00034
00035 MacSpeechState(const std::string& toSpeak) : chan(), text(toSpeak), id(SoundManager::invalid_Play_ID) {
00036 if(noErr != NewSpeechChannel(NULL,&chan))
00037 throw std::runtime_error("could not open speech channel");
00038 if(noErr != SetSpeechInfo(chan, soSpeechDoneCallBack, (void*)speechDoneCleanupCallback))
00039 throw std::runtime_error("could not set completion callback for speech channel");
00040 }
00041
00042 ~MacSpeechState() {
00043 if(noErr != DisposeSpeechChannel(chan)) {
00044 std::cerr << "SoundManager::speechDoneCleanup, error in DisposeSpeechChannel" << std::endl;
00045 }
00046 }
00047
00048 void setPlayID(SoundManager::Play_ID playid) {
00049 id=playid;
00050 if(noErr != SetSpeechInfo(chan, soRefCon, (void*)playid))
00051 throw std::runtime_error("could not set playid context for speech channel");
00052 }
00053 SpeechChannel chan;
00054 const std::string text;
00055 SoundManager::Play_ID id;
00056 private:
00057 MacSpeechState(MacSpeechState&);
00058 MacSpeechState& operator=(MacSpeechState&);
00059 };
00060 # endif
00061 #endif
00062
00063 using namespace std;
00064
00065 SoundManager * sndman=NULL;
00066
00067
00068 typedef MarkScope AutoLock;
00069
00070 SoundManager::SoundManager() :
00071 mixerBuffer(0), mixerBufferSize(0), sndlist(),playlist(),chanlist(),
00072 mix_mode(Fast),queue_mode(Override),max_chan(4),lock(),sn(0)
00073 { }
00074
00075 #ifdef PLATFORM_APERIOS
00076 void
00077 SoundManager::InitAccess(OSubject* subj) {
00078 subjs[ProcessID::getID()]=subj;
00079 }
00080 #else //PLATFORM_LOCAL
00081 void
00082 SoundManager::InitAccess(MessageQueueBase& sndbufq) {
00083 subjs[ProcessID::getID()]=&sndbufq;
00084 }
00085 #endif //PLATFORM-specific initialization
00086
00087 SoundManager::~SoundManager() {
00088 stopPlay();
00089 if(!sndlist.empty())
00090 cerr << "Warning: SoundManager was deleted with active sound buffer references" << endl;
00091 while(!sndlist.empty()) {
00092 sndlist_t::index_t it=sndlist.begin();
00093 if(sndlist[it].rcr==NULL)
00094 cerr << sndlist[it].name << " was still inflight (IPC), with " << sndlist[it].ref << " sound references" << endl;
00095 else {
00096 cerr << sndlist[it].name << " was deleted, with " << sndlist[it].ref << " sound references and " << sndlist[it].rcr->NumberOfReference() << " region references (one will be removed)" << endl;
00097 sndlist[it].rcr->RemoveReference();
00098 }
00099 sndlist.erase(it);
00100 }
00101 delete[] mixerBuffer;
00102 }
00103
00104
00105 SoundManager::Snd_ID
00106 SoundManager::loadFile(std::string const &name) {
00107 AutoLock autolock(lock);
00108 if (name.size() == 0) {
00109 cerr << "SoundManager::loadFile() null filename" << endl;
00110 return invalid_Snd_ID;
00111 };
00112 std::string path(config->sound.makePath(name));
00113 Snd_ID id=lookupPath(path);
00114 if(id!=invalid_Snd_ID) {
00115
00116 sndlist[id].ref++;
00117 } else {
00118
00119 struct stat buf;
00120 if(stat(path.c_str(),&buf)==-1) {
00121 cerr << "SoundManager::loadFile(): Sound file not found: " << path << endl;
00122 return invalid_Snd_ID;
00123 }
00124 byte * sndbuf=new byte[buf.st_size];
00125 std::ifstream file(path.c_str());
00126 file.read(reinterpret_cast<char*>(sndbuf),(std::streamsize)buf.st_size);
00127 WAV wav;
00128 WAVError error = wav.Set(sndbuf);
00129 if (error != WAV_SUCCESS) {
00130 printf("%s : %s %d: '%s'","SoundManager::loadFile()","wav.Set() FAILED",error, path.c_str());
00131 return invalid_Snd_ID;
00132 }
00133 if(wav.GetSamplingRate()!=config->sound.sample_rate || wav.GetBitsPerSample()!=config->sound.sample_bits) {
00134 printf("%s : %s %d","SoundManager::loadFile()","bad sample rate/bits", error);
00135 return invalid_Snd_ID;
00136 }
00137 if(config->sound.verbose>=3)
00138 cout << "Loading " << name << endl;
00139 id=loadBuffer(reinterpret_cast<char*>(wav.GetDataStart()),wav.GetDataEnd()-wav.GetDataStart());
00140 delete [] sndbuf;
00141 if(path.size()>=MAX_NAME_LEN)
00142 strncpy(sndlist[id].name,path.substr(path.size()-MAX_NAME_LEN+1).c_str(),MAX_NAME_LEN);
00143 else
00144 strncpy(sndlist[id].name,path.c_str(),MAX_NAME_LEN);
00145 }
00146 return id;
00147 }
00148
00149 SoundManager::Snd_ID
00150 SoundManager::loadBuffer(const char buf[], unsigned int len) {
00151
00152 if(buf==NULL || len==0)
00153 return invalid_Snd_ID;
00154 AutoLock autolock(lock);
00155
00156 RCRegion * region=initRegion(len+MSG_SIZE);
00157
00158 SoundManagerMsg * msg=new (reinterpret_cast<SoundManagerMsg*>(region->Base())) SoundManagerMsg;
00159 Snd_ID msgid=sndlist.new_front();
00160 msg->setAdd(msgid,sn);
00161
00162 sndlist[msg->getID()].rcr=NULL;
00163 sndlist[msg->getID()].data=NULL;
00164 sndlist[msg->getID()].ref=1;
00165 sndlist[msg->getID()].len=len;
00166 sndlist[msg->getID()].sn=sn;
00167
00168 const byte* src=reinterpret_cast<const byte*>(buf);
00169 byte* dest=reinterpret_cast<byte*>(region->Base())+MSG_SIZE;
00170 byte* end=dest+len;
00171 if (config->sound.sample_bits==8u)
00172 while (dest < end)
00173 *dest++ = *src++ ^ 0x80;
00174 else
00175 while (dest < end)
00176 *dest++ = *src++;
00177
00178
00179 if(ProcessID::getID()==ProcessID::SoundProcess) {
00180
00181 sndlist[msg->getID()].rcr=region;
00182 sndlist[msg->getID()].data=reinterpret_cast<byte*>(region->Base()+MSG_SIZE);
00183 } else {
00184 #ifdef PLATFORM_APERIOS
00185
00186 subjs[ProcessID::getID()]->SetData(region);
00187 subjs[ProcessID::getID()]->NotifyObservers();
00188
00189 #else
00190 subjs[ProcessID::getID()]->sendMessage(region);
00191 region->RemoveReference();
00192 #endif
00193 }
00194 return msgid;
00195 }
00196
00197 void
00198 SoundManager::releaseFile(std::string const &name) {
00199 AutoLock autolock(lock);
00200 release(lookupPath(config->sound.makePath(name)));
00201 }
00202
00203 void
00204 SoundManager::release(Snd_ID id) {
00205 if(id==invalid_Snd_ID)
00206 return;
00207 if(sndlist[id].ref==0) {
00208 cerr << "SoundManager::release() " << id << " extra release" << endl;
00209 return;
00210 }
00211 AutoLock autolock(lock);
00212 sndlist[id].ref--;
00213 if(sndlist[id].ref==0) {
00214 if(config->sound.verbose>=3 && sndlist[id].name[0]!='\0' && sndlist[id].sn!=0) {
00215 char * name = strrchr(sndlist[id].name, '/');
00216 name = (name==NULL) ? sndlist[id].name : name+1;
00217 cout << "Releasing " << name << endl;
00218 }
00219 if(sndlist[id].rcr!=NULL) {
00220
00221
00222
00223
00224 if(ProcessID::getID()==ProcessID::SoundProcess) {
00225
00226 sndlist[id].rcr->RemoveReference();
00227 sndlist[id].rcr=NULL;
00228 } else {
00229
00230
00231 RCRegion * region=initRegion(MSG_SIZE);
00232
00233 SoundManagerMsg * msg=new (reinterpret_cast<SoundManagerMsg*>(region->Base())) SoundManagerMsg;
00234 msg->setDelete(sndlist[id].rcr);
00235
00236
00237 #ifdef PLATFORM_APERIOS
00238
00239 subjs[ProcessID::getID()]->SetData(region);
00240 subjs[ProcessID::getID()]->NotifyObservers();
00241
00242 #else
00243 subjs[ProcessID::getID()]->sendMessage(region);
00244 region->RemoveReference();
00245 #endif
00246 }
00247 }
00248
00249 sndlist[id].sn=0;
00250 #ifdef __APPLE__
00251 if(sndlist[id].macSpeech)
00252 lock.completed(sndlist[id].macSpeech);
00253 #endif
00254 sndlist.erase(id);
00255 }
00256 }
00257
00258 SoundManager::Play_ID
00259 SoundManager::playFile(std::string const &name) {
00260 if(playlist.size()>=playlist_t::MAX_ENTRIES)
00261 return invalid_Play_ID;
00262 AutoLock autolock(lock);
00263 Snd_ID sndid=loadFile(name);
00264 if(sndid==invalid_Snd_ID)
00265 return invalid_Play_ID;
00266 sndlist[sndid].ref--;
00267 if(config->sound.verbose>=1)
00268 cout << "Playing " << name << endl;
00269 return play(sndid);
00270 }
00271
00272 SoundManager::Play_ID
00273 SoundManager::playBuffer(const char buf[], unsigned int len) {
00274 if(playlist.size()>=playlist_t::MAX_ENTRIES || buf==NULL || len==0)
00275 return invalid_Play_ID;
00276 AutoLock autolock(lock);
00277 Snd_ID sndid=loadBuffer(buf,len);
00278 if(sndid==invalid_Snd_ID)
00279 return invalid_Play_ID;
00280 sndlist[sndid].ref--;
00281 return play(sndid);
00282 }
00283
00284 SoundManager::Play_ID
00285 SoundManager::play(Snd_ID id) {
00286
00287 if(id==invalid_Snd_ID)
00288 return invalid_Play_ID;
00289 AutoLock autolock(lock);
00290 Play_ID playid=playlist.new_front();
00291 if(playid==invalid_Play_ID)
00292 return playid;
00293
00294 sndlist[id].ref++;
00295 playlist[playid].snd_id=id;
00296 playlist[playid].offset=0;
00297
00298 #ifdef __APPLE__
00299 if(MacSpeechState* mss = sndlist[id].macSpeech) {
00300 try {
00301 mss->setPlayID(playid);
00302 lock.initiated(mss);
00303 } catch(const std::exception& ex) {
00304 std::cerr << "ERROR SoundManager: " << ex.what() << std::endl;
00305 playlist.erase(playid);
00306 release(id);
00307 return SoundManager::invalid_Play_ID;
00308 }
00309 const char * name=sndlist[playlist[playid].snd_id].name;
00310 if(name[0]!='\0')
00311 erouter->postEvent(EventBase::audioEGID,playid,EventBase::activateETID,0,name,1);
00312 else
00313 erouter->postEvent(EventBase::audioEGID,playid,EventBase::activateETID,0);
00314 return playid;
00315 }
00316 #endif
00317
00318
00319
00320 chanlist.push_front(playid);
00321
00322
00323
00324
00325 if(ProcessID::getID()!=ProcessID::SoundProcess) {
00326 RCRegion * region=initRegion(MSG_SIZE);
00327 ASSERT(region!=NULL,"initRegion returned NULL");
00328 SoundManagerMsg * msg=new (reinterpret_cast<SoundManagerMsg*>(region->Base())) SoundManagerMsg;
00329 msg->setWakeup();
00330 #ifdef PLATFORM_APERIOS
00331
00332 subjs[ProcessID::getID()]->SetData(region);
00333 subjs[ProcessID::getID()]->NotifyObservers();
00334
00335 #else
00336 subjs[ProcessID::getID()]->sendMessage(region);
00337 region->RemoveReference();
00338 #endif
00339 }
00340
00341
00342 if(sndlist[id].rcr!=NULL) {
00343 const char * name=sndlist[playlist[playid].snd_id].name;
00344 if(name[0]!='\0')
00345 erouter->postEvent(EventBase::audioEGID,playid,EventBase::activateETID,0,name,1);
00346 else
00347 erouter->postEvent(EventBase::audioEGID,playid,EventBase::activateETID,0);
00348 }
00349 return playid;
00350 }
00351
00352 SoundManager::Play_ID
00353 SoundManager::chainFile(Play_ID base, std::string const &next) {
00354 if(base==invalid_Play_ID)
00355 return playFile(next);
00356 if(playlist[base].snd_id==invalid_Snd_ID) {
00357 std::cerr << "WARNING SoundManager: chaining on play " << base << " already stopped" << std::endl;
00358 return invalid_Play_ID;
00359 }
00360 Play_ID orig=base;
00361 while(playlist[base].next_id!=invalid_Play_ID)
00362 base=playlist[base].next_id;
00363 Play_ID nplay=playlist.new_front();
00364 if(nplay==invalid_Play_ID)
00365 return nplay;
00366 Snd_ID nsnd=loadFile(next);
00367 if(nsnd==invalid_Snd_ID) {
00368 playlist.pop_front();
00369 return invalid_Play_ID;
00370 }
00371 playlist[nplay].snd_id=nsnd;
00372 playlist[base].next_id=nplay;
00373 return orig;
00374 }
00375
00376 SoundManager::Play_ID
00377 SoundManager::chainBuffer(Play_ID base, const char buf[], unsigned int len) {
00378 if(base==invalid_Play_ID || buf==NULL || len==0)
00379 return playBuffer(buf,len);
00380 if(playlist[base].snd_id==invalid_Snd_ID) {
00381 std::cerr << "WARNING SoundManager: chaining on play " << base << " already stopped" << std::endl;
00382 return invalid_Play_ID;
00383 }
00384 Play_ID orig=base;
00385 while(playlist[base].next_id!=invalid_Play_ID)
00386 base=playlist[base].next_id;
00387 Play_ID nplay=playlist.new_front();
00388 if(nplay==invalid_Play_ID)
00389 return nplay;
00390 Snd_ID nsnd=loadBuffer(buf,len);
00391 if(nsnd==invalid_Snd_ID) {
00392 playlist.pop_front();
00393 return invalid_Play_ID;
00394 }
00395 playlist[nplay].snd_id=nsnd;
00396 playlist[base].next_id=nplay;
00397 return orig;
00398 }
00399
00400 SoundManager::Play_ID
00401 SoundManager::chain(Play_ID base, Snd_ID next) {
00402 if(base==invalid_Play_ID || next==invalid_Snd_ID)
00403 return play(next);
00404 if(playlist[base].snd_id==invalid_Snd_ID) {
00405 std::cerr << "WARNING SoundManager: chaining on play " << base << " already stopped" << std::endl;
00406 return invalid_Play_ID;
00407 }
00408 Play_ID orig=base;
00409 while(playlist[base].next_id!=invalid_Play_ID)
00410 base=playlist[base].next_id;
00411 Play_ID nplay=playlist.new_front();
00412 if(nplay==invalid_Play_ID)
00413 return nplay;
00414 playlist[nplay].snd_id=next;
00415 playlist[base].next_id=nplay;
00416 return orig;
00417 }
00418
00419 #ifdef PLATFORM_APERIOS
00420
00421 SoundManager::Play_ID
00422 SoundManager::speak(const std::string& text, bool showText, const std::string& voice) {
00423 sout->printf("Speak: %s\n",text.c_str());
00424 return SoundManager::invalid_Play_ID;
00425 }
00426
00427
00428 #elif defined(__APPLE__)
00429
00430 SoundManager::Play_ID
00431 SoundManager:: speak(const std::string& text, bool showText, const std::string& ) {
00432
00433
00434 if ( showText )
00435 std::cout << "Speak: \"" << text << "\"" << std::endl;
00436
00437 MacSpeechState * mss;
00438 try {
00439 mss = new MacSpeechState(text);
00440 } catch(const std::exception& ex) {
00441 std::cerr << "ERROR SoundManager::speak " << ex.what() << std::endl;
00442 return invalid_Play_ID;
00443 }
00444
00445 AutoLock autolock(lock);
00446 Snd_ID sndid=sndlist.new_front();
00447 sndlist[sndid].rcr=NULL;
00448 sndlist[sndid].data=NULL;
00449 sndlist[sndid].ref=0;
00450 sndlist[sndid].len=0;
00451 sndlist[sndid].sn=++sn;
00452 sndlist[sndid].macSpeech=mss;
00453 std::string name = "Speech:"+text;
00454 strncpy(sndlist[sndid].name,name.c_str(),MAX_NAME_LEN-1);
00455 sndlist[sndid].name[MAX_NAME_LEN-1]='\0';
00456
00457 return play(sndid);
00458 }
00459
00460 #else // linux and friends
00461
00462 SoundManager::Play_ID
00463 SoundManager::speak(const std::string& text, bool showText, const std::string& voice) {
00464 if ( showText )
00465 std::cout << "Speak: \"" << text << "\"" << std::endl;
00466
00467 string result;
00468 maryQuery(result, text, voice);
00469
00470 if (result.length() == 0) {
00471 std::cout << "SoundManager::speak(): Error, no response from mary server." << std::endl;
00472 return SoundManager::invalid_Play_ID;
00473 }
00474
00475
00476 std::stringstream ss("");
00477 int randomTag = rand();
00478 ss << "/tmp/" << randomTag;
00479
00480 std::string basename = ss.str();
00481 std::string filename = basename + ".wav";
00482 std::ofstream ofs(config->sound.makePath(filename).c_str(), std::ofstream::out);
00483 ofs << result;
00484 ofs.flush();
00485 ofs.close();
00486
00487
00488 std::string loudname = basename + "-loud.wav";
00489 std::string command = "sox -v 3.0 " + config->sound.makePath(filename) + " " + config->sound.makePath(loudname);
00490 system(command.c_str());
00491
00492
00493 SoundManager::Play_ID id = playFile(loudname);
00494
00495
00496 remove(config->sound.makePath(filename).c_str());
00497 remove(config->sound.makePath(loudname).c_str());
00498
00499 return id;
00500 }
00501
00502 #endif
00503
00504 void
00505 SoundManager::stopPlay() {
00506 AutoLock autolock(lock);
00507 while(!playlist.empty())
00508 stopPlay(playlist.begin());
00509 }
00510
00511 void
00512 SoundManager::stopPlay(Play_ID id) {
00513 if(id==invalid_Play_ID)
00514 return;
00515 if(playlist[id].snd_id==invalid_Snd_ID) {
00516 std::cerr << "WARNING SoundManager: Stopping play " << id << " already stopped" << std::endl;
00517 return;
00518 }
00519 AutoLock autolock(lock);
00520
00521
00522 chanlist_t::index_t it;
00523 for(it=chanlist.prev(chanlist.end()); it!=chanlist.end(); it=chanlist.prev(it))
00524 if(chanlist[it]==id)
00525 break;
00526
00527 #ifdef __APPLE__
00528 ASSERTRET(playlist[id].snd_id!=invalid_Snd_ID,"playlist entry has invalid sound id");
00529 ASSERT(!sndlist[playlist[id].snd_id].macSpeech || it==chanlist.end(),"speech play id was found in channel list");
00530 #else
00531 ASSERT(it!=chanlist.end(),"SoundManager::stopPlay: play id does not seem to be playing");
00532 #endif
00533
00534 if(config->sound.verbose>=2) {
00535 char * cname = strrchr(sndlist[playlist[id].snd_id].name, '/');
00536 cname = (cname==NULL) ? sndlist[id].name : cname+1;
00537 cout << "End play " << cname << endl;
00538 }
00539 std::string name=sndlist[playlist[id].snd_id].name;
00540 playlist[id].cumulative+=playlist[id].offset;
00541 unsigned int ms=playlist[id].cumulative/(config->sound.sample_bits/8)/(config->sound.sample_rate/1000);
00542 release(playlist[id].snd_id);
00543 playlist[id].snd_id=invalid_Snd_ID;
00544 playlist.erase(id);
00545 if(it!=chanlist.end())
00546 chanlist.erase(it);
00547 if(name.size()>0)
00548 erouter->postEvent(EventBase::audioEGID,id,EventBase::deactivateETID,ms,name,0);
00549 else
00550 erouter->postEvent(EventBase::audioEGID,id,EventBase::deactivateETID,ms);
00551 }
00552
00553 void
00554 SoundManager::pausePlay(Play_ID id) {
00555 if(id==invalid_Play_ID)
00556 return;
00557 if(playlist[id].snd_id==invalid_Snd_ID) {
00558 std::cerr << "WARNING SoundManager: pausing play " << id << " already stopped" << std::endl;
00559 return;
00560 }
00561 AutoLock autolock(lock);
00562
00563 #ifdef __APPLE__
00564 ASSERTRET(playlist[id].snd_id!=invalid_Snd_ID,"playlist entry has invalid sound id");
00565 if(MacSpeechState* mss = sndlist[playlist[id].snd_id].macSpeech) {
00566 if(noErr != PauseSpeechAt(mss->chan, kEndOfWord))
00567 std::cerr << "ERROR SoundManager could not pause speech" << std::endl;
00568 return;
00569 }
00570 #endif
00571
00572 for(chanlist_t::index_t it=chanlist.begin(); it!=chanlist.end(); it=chanlist.next(it)) {
00573 if(chanlist[it]==id) {
00574 chanlist.erase(it);
00575 return;
00576 }
00577 }
00578 }
00579
00580 void
00581 SoundManager::resumePlay(Play_ID id) {
00582 if(id==invalid_Play_ID)
00583 return;
00584 if(playlist[id].snd_id==invalid_Snd_ID) {
00585 std::cerr << "WARNING SoundManager: resuming play " << id << " already stopped" << std::endl;
00586 return;
00587 }
00588 AutoLock autolock(lock);
00589
00590 #ifdef __APPLE__
00591 ASSERTRET(playlist[id].snd_id!=invalid_Snd_ID,"playlist entry has invalid sound id");
00592 if(MacSpeechState* mss = sndlist[playlist[id].snd_id].macSpeech) {
00593 if(noErr != ContinueSpeech(mss->chan))
00594 std::cerr << "ERROR SoundManager could not continue speech" << std::endl;
00595 return;
00596 }
00597 #endif
00598
00599 for(chanlist_t::index_t it=chanlist.begin(); it!=chanlist.end(); it=chanlist.next(it))
00600 if(chanlist[it]==id)
00601 return;
00602 chanlist.push_front(id);
00603 if(chanlist.size()==1) {
00604 if(ProcessID::getID()!=ProcessID::SoundProcess) {
00605 RCRegion * region=initRegion(MSG_SIZE);
00606 ASSERT(region!=NULL,"initRegion returned NULL");
00607 SoundManagerMsg * msg=new (reinterpret_cast<SoundManagerMsg*>(region->Base())) SoundManagerMsg;
00608 msg->setWakeup();
00609 #ifdef PLATFORM_APERIOS
00610
00611 subjs[ProcessID::getID()]->SetData(region);
00612 subjs[ProcessID::getID()]->NotifyObservers();
00613
00614 #else
00615 subjs[ProcessID::getID()]->sendMessage(region);
00616 region->RemoveReference();
00617 #endif
00618 }
00619 }
00620 }
00621
00622 void
00623 SoundManager::setMode(unsigned int max_channels, MixMode_t mixer_mode, QueueMode_t queuing_mode) {
00624 AutoLock autolock(lock);
00625 max_chan=max_channels;
00626 mix_mode=mixer_mode;
00627 queue_mode=queuing_mode;
00628 }
00629
00630 unsigned int
00631 SoundManager::getRemainTime(Play_ID id) const {
00632 if(playlist[id].snd_id==invalid_Snd_ID)
00633 return 0;
00634 AutoLock autolock(lock);
00635 unsigned int t=0;
00636 while(id!=invalid_Play_ID) {
00637 t+=sndlist[playlist[id].snd_id].len-playlist[id].offset;
00638 id=playlist[id].next_id;
00639 }
00640 const unsigned int bytesPerMS=config->sound.sample_bits/8*config->sound.sample_rate/1000;
00641 return t/bytesPerMS;
00642 }
00643
00644 void
00645 SoundManager::mixChannel(Play_ID channelId, void* buf, size_t destSize) {
00646 char *dest = (char*) buf;
00647
00648 PlayState& channel = playlist[channelId];
00649 while (destSize > 0) {
00650 const SoundData& buffer = sndlist[channel.snd_id];
00651 const char* samples = ((char*) (buffer.data)) + channel.offset;
00652 const unsigned int samplesSize = buffer.len - channel.offset;
00653 if (samplesSize > destSize) {
00654 memcpy(dest, samples, destSize);
00655 channel.offset += destSize;
00656 dest += destSize;
00657 destSize = 0;
00658 return;
00659 } else {
00660 memcpy(dest, samples, samplesSize);
00661 channel.offset += samplesSize;
00662 dest += samplesSize;
00663 destSize -= samplesSize;
00664 if (endPlay(channelId)) {
00665 break;
00666 }
00667 }
00668 }
00669 if (destSize > 0) {
00670 memset(dest, 0, destSize);
00671 }
00672 }
00673
00674 void
00675 SoundManager::mixChannelAdditively(Play_ID channelId, int bitsPerSample, MixMode_t mode,
00676 short scalingFactor, void* buf, size_t destSize)
00677 {
00678 PlayState& channel = playlist[channelId];
00679 while (destSize > 0) {
00680 const SoundData& buffer = sndlist[channel.snd_id];
00681 const unsigned int samplesSize = buffer.len - channel.offset;
00682 const unsigned int mixedSamplesSize =
00683 ((mode == Fast)
00684 ? ((samplesSize > destSize) ? destSize : samplesSize)
00685 : ((samplesSize > destSize / 2) ? destSize / 2 : samplesSize));
00686
00687 if (bitsPerSample == 8) {
00688
00689 const char* samples = (char*) (buffer.data + channel.offset);
00690 if (mode == Fast) {
00691
00692 char *dest = (char*) buf;
00693 for (size_t i = 0; i < mixedSamplesSize; i++) {
00694 *dest += samples[i] / scalingFactor;
00695 ++dest;
00696 }
00697 destSize -= (char*) dest - (char*) buf;
00698 buf = dest;
00699 } else {
00700
00701 short* dest = (short*) buf;
00702 for (size_t i = 0; i < mixedSamplesSize; i++) {
00703 *dest += samples[i];
00704 ++dest;
00705 }
00706 destSize -= (char*) dest - (char*) buf;
00707 buf = dest;
00708 }
00709 } else {
00710
00711 const short* samples = (short*) (buffer.data + channel.offset);
00712 if (mode == Fast) {
00713
00714 short* dest = (short*) buf;
00715 for (size_t i = 0; i < mixedSamplesSize / 2; i++) {
00716 *dest += samples[i] / scalingFactor;
00717 ++dest;
00718 }
00719 destSize -= (char*) dest - (char*) buf;
00720 buf = dest;
00721 } else {
00722
00723 int* dest = (int*) buf;
00724 for (size_t i = 0; i < mixedSamplesSize / 2; i++) {
00725 *dest += samples[i];
00726 ++dest;
00727 }
00728 destSize -= (char*) dest - (char*) buf;
00729 buf = dest;
00730 }
00731 }
00732 channel.offset += mixedSamplesSize;
00733 if (destSize == 0) {
00734 return;
00735 } else {
00736 if (endPlay(channelId)) {
00737 return;
00738 }
00739 }
00740 }
00741 }
00742
00743 #ifdef PLATFORM_APERIOS
00744 unsigned int
00745 SoundManager::CopyTo(OSoundVectorData* data) {
00746 AutoLock autolock(lock);
00747 return CopyTo(data->GetData(0), data->GetInfo(0)->dataSize);
00748 }
00749
00750 void
00751 SoundManager::ReceivedMsg(const ONotifyEvent& event) {
00752
00753 for(int x=0; x<event.NumOfData(); x++)
00754 ProcessMsg(event.RCData(x));
00755 }
00756 #endif
00757
00758 unsigned int
00759 SoundManager::CopyTo(void * dest, size_t destSize) {
00760 AutoLock autolock(lock);
00761
00762 void * origdest=dest;
00763 size_t origDestSize=destSize;
00764 if(chanlist.size() == 0) {
00765 memset(dest, 0, destSize);
00766 return 0;
00767 }
00768
00769 std::vector<Play_ID> channels;
00770 selectChannels(channels);
00771
00772 if (channels.size() == 0) {
00773
00774 memset(dest, 0, destSize);
00775 } else if (channels.size() == 1) {
00776
00777 mixChannel(channels.front(), dest, destSize);
00778 } else {
00779
00780 const MixMode_t mode = mix_mode;
00781 const int bitsPerSample = config->sound.sample_bits;
00782 if (mode == Quality) {
00783
00784 if ((mixerBuffer == 0) || (mixerBufferSize < destSize * 2)) {
00785 delete[] mixerBuffer;
00786 mixerBuffer = 0;
00787 mixerBufferSize = destSize * 2;
00788 mixerBuffer = new int[(mixerBufferSize / 4) + 1];
00789 }
00790 memset(mixerBuffer, 0, mixerBufferSize);
00791 dest = mixerBuffer;
00792 destSize *= 2;
00793 } else {
00794
00795 memset(dest, 0, destSize);
00796 }
00797
00798 const int channelCount = channels.size();
00799 const short scalingFactor = (short) ((mode == Fast) ? channelCount : 1);
00800 for(std::vector<Play_ID>::iterator i = channels.begin(); i != channels.end(); i++)
00801 mixChannelAdditively(*i, bitsPerSample, mode, scalingFactor, dest, destSize);
00802
00803 if (mode == Quality) {
00804
00805
00806 destSize /= 2;
00807 if (bitsPerSample == 8) {
00808
00809 char* destChar = (char*) origdest;
00810 short* mixerBufferShort = (short*) mixerBuffer;
00811 for (size_t i = 0; i < destSize; i++) {
00812 destChar[i] = (char) (mixerBufferShort[i] / channelCount);
00813 }
00814 } else {
00815
00816 short* destShort = (short*) origdest;
00817 const size_t destSampleCount = destSize / 2;
00818 for (size_t i = 0; i < destSampleCount; i++) {
00819 destShort[i] = (short) (mixerBuffer[i] / channelCount);
00820 }
00821 }
00822 }
00823 }
00824
00825 updateChannels(channels, origDestSize);
00826 #ifndef PLATFORM_APERIOS
00827
00828
00829 if(config->sound.volume==Config::sound_config::MUTE)
00830 memset(dest, 0, origDestSize);
00831 #endif
00832 return channels.size();
00833 }
00834
00835 void SoundManager::ProcessMsg(RCRegion * rcr) {
00836 SoundManagerMsg * msg = reinterpret_cast<SoundManagerMsg*>(rcr->Base());
00837
00838 switch(msg->type) {
00839 case SoundManagerMsg::add: {
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856 if(sndlist[msg->id].sn!=msg->sn) {
00857
00858
00859
00860
00861
00862 cerr << "Warning: serial numbers don't match... may be pathological sound usage (many load/releases very quickly)" << endl;
00863 break;
00864 }
00865 ASSERT(sndlist[msg->id].rcr==NULL,"The sndlist entry for an add message already has an attached region, I'm going to leak the old region")
00866 rcr->AddReference();
00867 sndlist[msg->id].rcr=rcr;
00868 sndlist[msg->id].data=reinterpret_cast<byte*>(rcr->Base()+MSG_SIZE);
00869
00870 for(playlist_t::index_t it=playlist.begin();it!=playlist.end();it=playlist.next(it))
00871 if(playlist[it].snd_id==msg->id) {
00872
00873 const char * name=sndlist[playlist[it].snd_id].name;
00874 if(name[0]!='\0')
00875 erouter->postEvent(EventBase::audioEGID,it,EventBase::activateETID,0,name,1);
00876 else
00877 erouter->postEvent(EventBase::audioEGID,it,EventBase::activateETID,0);
00878 }
00879 } break;
00880 case SoundManagerMsg::del: {
00881
00882 if(msg->region==NULL) {
00883 cerr << "SoundManager received a delete message for a NULL region" << endl;
00884 } else {
00885 msg->region->RemoveReference();
00886 }
00887 } break;
00888 case SoundManagerMsg::wakeup: {
00889
00890
00891 } break;
00892 default:
00893 printf("*** WARNING *** unknown SoundManager msg type received\n");
00894 }
00895 }
00896
00897
00898
00899
00900 RCRegion*
00901 SoundManager::initRegion(unsigned int size) {
00902 sn++;
00903 #ifdef PLATFORM_APERIOS
00904 unsigned int pagesize=4096;
00905 sError err=GetPageSize(&pagesize);
00906 if(err!=sSUCCESS)
00907 cerr << "Error "<<err<<" getting page size " << pagesize << endl;
00908 unsigned int pages=(size+pagesize-1)/pagesize;
00909 return new RCRegion(pages*pagesize);
00910 #else
00911 char name[RCRegion::MAX_NAME_LEN];
00912 snprintf(name,RCRegion::MAX_NAME_LEN,"SndMsg.%d.%d",ProcessID::getID(),sn);
00913 name[RCRegion::MAX_NAME_LEN-1]='\0';
00914
00915 return new RCRegion(name,size);
00916 #endif
00917 }
00918
00919 SoundManager::Snd_ID
00920 SoundManager::lookupPath(std::string const &path) const {
00921 std::string clippedPath;
00922 const char* cpath=NULL;
00923 if(path.size()>MAX_NAME_LEN) {
00924 clippedPath=path.substr(path.size()-MAX_NAME_LEN);
00925 cpath=clippedPath.c_str();
00926 } else
00927 cpath=path.c_str();
00928 for(sndlist_t::index_t it=sndlist.begin(); it!=sndlist.end(); it=sndlist.next(it)) {
00929 if(strncasecmp(cpath,sndlist[it].name,MAX_NAME_LEN)==0)
00930 return it;
00931 }
00932 return invalid_Snd_ID;
00933 }
00934
00935 void
00936 SoundManager::selectChannels(std::vector<Play_ID>& mix) {
00937 unsigned int selected=0;
00938 switch(queue_mode) {
00939 case Enqueue: {
00940 for(chanlist_t::index_t it=chanlist.prev(chanlist.end());it!=chanlist.end();it=chanlist.prev(it)) {
00941 if(sndlist[playlist[chanlist[it]].snd_id].data!=NULL) {
00942 mix.push_back(chanlist[it]);
00943 selected++;
00944 if(selected==max_chan)
00945 return;
00946 }
00947 }
00948 } break;
00949 case Override:
00950 case Pause: {
00951 for(chanlist_t::index_t it=chanlist.begin(); it!=chanlist.end(); it=chanlist.next(it)) {
00952 if(sndlist[playlist[chanlist[it]].snd_id].data!=NULL) {
00953 mix.push_back(chanlist[it]);
00954 selected++;
00955 if(selected==max_chan)
00956 return;
00957 }
00958 }
00959 } break;
00960 case Stop: {
00961 unsigned int numkeep=0;
00962 chanlist_t::index_t it=chanlist.begin();
00963 for(;it!=chanlist.end(); it=chanlist.next(it), numkeep++) {
00964 if(sndlist[playlist[chanlist[it]].snd_id].data!=NULL) {
00965 mix.push_back(chanlist[it]);
00966 selected++;
00967 if(selected==max_chan) {
00968 for(unsigned int i=chanlist.size()-numkeep-1; i>0; i--)
00969 endPlay(chanlist.back());
00970 return;
00971 }
00972 }
00973 }
00974 } break;
00975 default:
00976 cerr << "SoundManager::selectChannels(): Illegal queue mode" << endl;
00977 }
00978 }
00979
00980 void
00981 SoundManager::updateChannels(const std::vector<Play_ID>& mixs,size_t used) {
00982 switch(queue_mode) {
00983 case Enqueue:
00984 case Pause:
00985 case Stop:
00986 break;
00987 case Override: {
00988
00989 chanlist_t::index_t it=chanlist.begin();
00990 std::vector<Play_ID>::const_iterator mixit=mixs.begin();
00991 for(;it!=chanlist.end(); it=chanlist.next(it)) {
00992 for(;mixit!=mixs.end(); mixit++)
00993 if(*mixit==chanlist[it])
00994 break;
00995 if(mixit==mixs.end())
00996 break;
00997 }
00998 for(;it!=chanlist.end(); it=chanlist.next(it)) {
00999 const Play_ID channelId = chanlist[it];
01000 PlayState &channel = playlist[channelId];
01001 size_t skip = used;
01002 while (skip > 0) {
01003 SoundData &buffer = sndlist[channel.snd_id];
01004
01005 if (buffer.data != 0) {
01006 size_t remain = buffer.len - channel.offset;
01007 if (remain < skip) {
01008 channel.offset = buffer.len;
01009 skip -= buffer.len;
01010 if (endPlay(channelId)) {
01011 break;
01012 }
01013 } else {
01014 channel.offset += skip;
01015 skip = 0;
01016 }
01017 } else {
01018 break;
01019 }
01020 }
01021 }
01022 } break;
01023 default:
01024 cerr << "SoundManager::updateChannels(): Illegal queue mode" << endl;
01025 }
01026 }
01027
01028 bool
01029 SoundManager::endPlay(Play_ID id) {
01030 if(playlist[id].next_id==invalid_Play_ID) {
01031 stopPlay(id);
01032 return true;
01033 } else {
01034 #ifdef __APPLE__
01035 ASSERTRETVAL(playlist[id].snd_id!=invalid_Snd_ID,"playlist entry has invalid sound id",false);
01036 bool lastWasSpeech=(sndlist[playlist[id].snd_id].macSpeech);
01037 #endif
01038
01039 Play_ID next=playlist[id].next_id;
01040
01041 release(playlist[id].snd_id);
01042 playlist[id].snd_id=playlist[next].snd_id;
01043 playlist[id].cumulative+=playlist[id].offset;
01044 playlist[id].offset=0;
01045 playlist[id].next_id=playlist[next].next_id;
01046 playlist.erase(next);
01047 unsigned int ms=playlist[id].cumulative/(config->sound.sample_bits/8)/(config->sound.sample_rate/1000);
01048 const char * name=sndlist[playlist[id].snd_id].name;
01049 if(name[0]!='\0')
01050 erouter->postEvent(EventBase::audioEGID,id,EventBase::statusETID,ms,name,1);
01051 else
01052 erouter->postEvent(EventBase::audioEGID,id,EventBase::statusETID,ms);
01053 #ifdef __APPLE__
01054 if(lastWasSpeech)
01055 resumePlay(id);
01056 #endif
01057 return false;
01058 }
01059 }
01060
01061 SoundManager::SoundData::SoundData()
01062 : rcr(NULL), data(NULL), len(0), ref(0), sn(0)
01063 #ifdef __APPLE__
01064 , macSpeech(NULL)
01065 #endif
01066 {
01067 name[0]='\0';
01068 }
01069
01070 SoundManager::PlayState::PlayState()
01071 : snd_id(invalid_Snd_ID), offset(0), cumulative(0), next_id(invalid_Play_ID)
01072 {}
01073
01074 #ifdef __APPLE__
01075 void SoundManager::Lock::releaseResource(Data& d) {
01076 if(get_lock_level()!=1 || ( completedSpeech.size()==0 && initiatedSpeech.size()==0) ) {
01077 MutexLock<ProcessID::NumProcesses>::releaseResource(d);
01078 } else {
01079
01080 std::vector<MacSpeechState*> live(initiatedSpeech);
01081 std::vector<MacSpeechState*> dead(completedSpeech);
01082
01083 initiatedSpeech.clear();
01084 completedSpeech.clear();
01085
01086 MutexLock<ProcessID::NumProcesses>::releaseResource(d);
01087 for(size_t i=0; i<live.size(); ++i) {
01088 if(noErr != SpeakText(live[i]->chan,live[i]->text.c_str(),live[i]->text.size())) {
01089 std::cerr << "ERROR SoundManager: could not pass text to SpeakText" << std::endl;
01090 speechDoneCleanup(live[i]->id);
01091 }
01092 }
01093 for(size_t i=0; i<dead.size(); ++i)
01094 delete dead[i];
01095 }
01096 }
01097 void SoundManager::Lock::initiated(MacSpeechState* mss) {
01098 initiatedSpeech.push_back(mss);
01099 }
01100 void SoundManager::Lock::completed(MacSpeechState* mss) {
01101 completedSpeech.push_back(mss);
01102 }
01103 #endif
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174