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