SoundManager.ccGo to the documentation of this file.00001 #include "Shared/Config.h"
00002 #include "SoundManager.h"
00003 #include "IPC/LockScope.h"
00004 #include "WAV.h"
00005 #include "Events/EventRouter.h"
00006 #include <sys/types.h>
00007 #include <sys/stat.h>
00008 #include <unistd.h>
00009 #include <fstream>
00010 #ifdef PLATFORM_APERIOS
00011 # include <OPENR/OSubject.h>
00012 # include <OPENR/ObjcommEvent.h>
00013 #endif
00014
00015 using namespace std;
00016
00017 SoundManager * sndman=NULL;
00018
00019
00020 typedef LockScope<ProcessID::NumProcesses> AutoLock;
00021
00022 SoundManager::SoundManager()
00023 : mixerBuffer(0), mixerBufferSize(0), sndlist(),playlist(),chanlist(),mix_mode(Fast),queue_mode(Override),max_chan(4),lock(),sn(0)
00024 {}
00025
00026 #ifdef PLATFORM_APERIOS
00027 void
00028 SoundManager::InitAccess(OSubject* subj) {
00029 subjs[ProcessID::getID()]=subj;
00030 }
00031 #else //PLATFORM_LOCAL
00032 void
00033 SoundManager::InitAccess(MessageQueueBase& sndbufq) {
00034 subjs[ProcessID::getID()]=&sndbufq;
00035 }
00036 #endif //PLATFORM-specific initialization
00037
00038 SoundManager::~SoundManager() {
00039 StopPlay();
00040 if(!sndlist.empty())
00041 cerr << "Warning: SoundManager was deleted with active sound buffer references" << endl;
00042 while(!sndlist.empty()) {
00043 sndlist_t::index_t it=sndlist.begin();
00044 if(sndlist[it].rcr==NULL)
00045 cerr << sndlist[it].name << " was still inflight (IPC), with " << sndlist[it].ref << " sound references" << endl;
00046 else {
00047 cerr << sndlist[it].name << " was deleted, with " << sndlist[it].ref << " sound references and " << sndlist[it].rcr->NumberOfReference() << " region references (one will be removed)" << endl;
00048 sndlist[it].rcr->RemoveReference();
00049 }
00050 sndlist.erase(it);
00051 }
00052 delete[] mixerBuffer;
00053 }
00054
00055
00056 SoundManager::Snd_ID
00057 SoundManager::LoadFile(std::string const &name) {
00058 AutoLock autolock(lock,ProcessID::getID());
00059 if (name.size() == 0) {
00060 cout << "SoundManager::LoadFile() null filename" << endl;
00061 return invalid_Snd_ID;
00062 };
00063 std::string path(config->sound.makePath(name));
00064 Snd_ID id=lookupPath(path);
00065 if(id!=invalid_Snd_ID) {
00066
00067 sndlist[id].ref++;
00068 } else {
00069
00070 struct stat buf;
00071 if(stat(path.c_str(),&buf)==-1) {
00072 cout << "SoundManager::LoadFile(): Sound file not found: " << path << endl;
00073 return invalid_Snd_ID;
00074 }
00075 byte * sndbuf=new byte[buf.st_size];
00076 std::ifstream file(path.c_str());
00077 file.read(reinterpret_cast<char*>(sndbuf),buf.st_size);
00078 WAV wav;
00079 WAVError error = wav.Set(sndbuf);
00080 if (error != WAV_SUCCESS) {
00081 printf("%s : %s %d: '%s'","SoundManager::LoadFile()","wav.Set() FAILED",error, path.c_str());
00082 return invalid_Snd_ID;
00083 }
00084 if(wav.GetSamplingRate()!=config->sound.sample_rate || wav.GetBitsPerSample()!=config->sound.sample_bits) {
00085 printf("%s : %s %d","SoundManager::LoadFile()","bad sample rate/bits", error);
00086 return invalid_Snd_ID;
00087 }
00088
00089 id=LoadBuffer(reinterpret_cast<char*>(wav.GetDataStart()),wav.GetDataEnd()-wav.GetDataStart());
00090 delete [] sndbuf;
00091 if(path.size()>MAX_NAME_LEN)
00092 strncpy(sndlist[id].name,path.substr(path.size()-MAX_NAME_LEN).c_str(),MAX_NAME_LEN);
00093 else
00094 strncpy(sndlist[id].name,path.c_str(),MAX_NAME_LEN);
00095 }
00096 return id;
00097 }
00098
00099 SoundManager::Snd_ID
00100 SoundManager::LoadBuffer(const char buf[], unsigned int len) {
00101 cout << "SoundManager::LoadBuffer() of " << len << " bytes" << endl;
00102 if(buf==NULL || len==0)
00103 return invalid_Snd_ID;
00104 AutoLock autolock(lock,ProcessID::getID());
00105
00106 RCRegion * region=initRegion(len+MSG_SIZE);
00107
00108 SoundManagerMsg * msg=new (reinterpret_cast<SoundManagerMsg*>(region->Base())) SoundManagerMsg;
00109 Snd_ID msgid=sndlist.new_front();
00110 msg->setAdd(msgid,sn);
00111
00112 sndlist[msg->getID()].rcr=NULL;
00113 sndlist[msg->getID()].data=NULL;
00114 sndlist[msg->getID()].ref=1;
00115 sndlist[msg->getID()].len=len;
00116 sndlist[msg->getID()].sn=sn;
00117
00118 const byte* src=reinterpret_cast<const byte*>(buf);
00119 byte* dest=reinterpret_cast<byte*>(region->Base())+MSG_SIZE;
00120 byte* end=dest+len;
00121 if (config->sound.sample_bits==8)
00122 while (dest < end)
00123 *dest++ = *src++ ^ 0x80;
00124 else
00125 while (dest < end)
00126 *dest++ = *src++;
00127
00128
00129 if(ProcessID::getID()==ProcessID::SoundProcess) {
00130
00131 sndlist[msg->getID()].rcr=region;
00132 sndlist[msg->getID()].data=reinterpret_cast<byte*>(region->Base()+MSG_SIZE);
00133 } else {
00134 #ifdef PLATFORM_APERIOS
00135
00136 subjs[ProcessID::getID()]->SetData(region);
00137 subjs[ProcessID::getID()]->NotifyObservers();
00138
00139 #else
00140 subjs[ProcessID::getID()]->sendMessage(region);
00141 region->RemoveReference();
00142 #endif
00143 }
00144 return msgid;
00145 }
00146
00147 void
00148 SoundManager::ReleaseFile(std::string const &name) {
00149 AutoLock autolock(lock,ProcessID::getID());
00150 Release(lookupPath(config->sound.makePath(name)));
00151 }
00152
00153 void
00154 SoundManager::Release(Snd_ID id) {
00155 if(id==invalid_Snd_ID)
00156 return;
00157 if(sndlist[id].ref==0) {
00158 cerr << "SoundManager::Release() " << id << " extra release" << endl;
00159 return;
00160 }
00161 AutoLock autolock(lock,ProcessID::getID());
00162 sndlist[id].ref--;
00163 if(sndlist[id].ref==0) {
00164 if(sndlist[id].rcr!=NULL) {
00165
00166
00167
00168
00169 if(ProcessID::getID()==ProcessID::SoundProcess) {
00170
00171 sndlist[id].rcr->RemoveReference();
00172 sndlist[id].rcr=NULL;
00173 } else {
00174
00175
00176 RCRegion * region=initRegion(MSG_SIZE);
00177
00178 SoundManagerMsg * msg=new (reinterpret_cast<SoundManagerMsg*>(region->Base())) SoundManagerMsg;
00179 msg->setDelete(sndlist[id].rcr);
00180
00181
00182 #ifdef PLATFORM_APERIOS
00183
00184 subjs[ProcessID::getID()]->SetData(region);
00185 subjs[ProcessID::getID()]->NotifyObservers();
00186
00187 #else
00188 subjs[ProcessID::getID()]->sendMessage(region);
00189 region->RemoveReference();
00190 #endif
00191 }
00192 }
00193
00194 sndlist[id].sn=0;
00195 sndlist.erase(id);
00196 }
00197 }
00198
00199 SoundManager::Play_ID
00200 SoundManager::PlayFile(std::string const &name) {
00201 if(playlist.size()>=playlist_t::MAX_ENTRIES)
00202 return invalid_Play_ID;
00203 AutoLock autolock(lock,ProcessID::getID());
00204 Snd_ID sndid=LoadFile(name);
00205 if(sndid==invalid_Snd_ID)
00206 return invalid_Play_ID;
00207 sndlist[sndid].ref--;
00208 return Play(sndid);
00209 }
00210
00211 SoundManager::Play_ID
00212 SoundManager::PlayBuffer(const char buf[], unsigned int len) {
00213 if(playlist.size()>=playlist_t::MAX_ENTRIES || buf==NULL || len==0)
00214 return invalid_Play_ID;
00215 AutoLock autolock(lock,ProcessID::getID());
00216 Snd_ID sndid=LoadBuffer(buf,len);
00217 if(sndid==invalid_Snd_ID)
00218 return invalid_Play_ID;
00219 sndlist[sndid].ref--;
00220 return Play(sndid);
00221 }
00222
00223 SoundManager::Play_ID
00224 SoundManager::Play(Snd_ID id) {
00225
00226 if(id==invalid_Snd_ID)
00227 return invalid_Play_ID;
00228 AutoLock autolock(lock,ProcessID::getID());
00229 Play_ID playid=playlist.new_front();
00230 if(playid!=invalid_Play_ID) {
00231 sndlist[id].ref++;
00232 playlist[playid].snd_id=id;
00233 playlist[playid].offset=0;
00234
00235
00236 chanlist.push_front(playid);
00237
00238
00239
00240
00241 if(ProcessID::getID()!=ProcessID::SoundProcess) {
00242 RCRegion * region=initRegion(MSG_SIZE);
00243 ASSERT(region!=NULL,"initRegion returned NULL");
00244 SoundManagerMsg * msg=new (reinterpret_cast<SoundManagerMsg*>(region->Base())) SoundManagerMsg;
00245 msg->setWakeup();
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 if(sndlist[id].rcr!=NULL) {
00259 const char * name=sndlist[playlist[playid].snd_id].name;
00260 if(name[0]!='\0')
00261 erouter->postEvent(EventBase::audioEGID,playid,EventBase::activateETID,0,name,1);
00262 else
00263 erouter->postEvent(EventBase::audioEGID,playid,EventBase::activateETID,0);
00264 }
00265 }
00266 return playid;
00267 }
00268
00269 SoundManager::Play_ID
00270 SoundManager::ChainFile(Play_ID base, std::string const &next) {
00271 if(base==invalid_Play_ID)
00272 return base;
00273 Play_ID orig=base;
00274 while(playlist[base].next_id!=invalid_Play_ID)
00275 base=playlist[base].next_id;
00276 Play_ID nplay=playlist.new_front();
00277 if(nplay==invalid_Play_ID)
00278 return nplay;
00279 Snd_ID nsnd=LoadFile(next);
00280 if(nsnd==invalid_Snd_ID) {
00281 playlist.pop_front();
00282 return invalid_Play_ID;
00283 }
00284 playlist[nplay].snd_id=nsnd;
00285 playlist[base].next_id=nplay;
00286 return orig;
00287 }
00288
00289 SoundManager::Play_ID
00290 SoundManager::ChainBuffer(Play_ID base, const char buf[], unsigned int len) {
00291 if(base==invalid_Play_ID || buf==NULL || len==0)
00292 return base;
00293 Play_ID orig=base;
00294 while(playlist[base].next_id!=invalid_Play_ID)
00295 base=playlist[base].next_id;
00296 Play_ID nplay=playlist.new_front();
00297 if(nplay==invalid_Play_ID)
00298 return nplay;
00299 Snd_ID nsnd=LoadBuffer(buf,len);
00300 if(nsnd==invalid_Snd_ID) {
00301 playlist.pop_front();
00302 return invalid_Play_ID;
00303 }
00304 playlist[nplay].snd_id=nsnd;
00305 playlist[base].next_id=nplay;
00306 return orig;
00307 }
00308
00309 SoundManager::Play_ID
00310 SoundManager::Chain(Play_ID base, Snd_ID next) {
00311 if(base==invalid_Play_ID || next==invalid_Snd_ID)
00312 return base;
00313 Play_ID orig=base;
00314 while(playlist[base].next_id!=invalid_Play_ID)
00315 base=playlist[base].next_id;
00316 Play_ID nplay=playlist.new_front();
00317 if(nplay==invalid_Play_ID)
00318 return nplay;
00319 playlist[nplay].snd_id=next;
00320 playlist[base].next_id=nplay;
00321 return orig;
00322 }
00323
00324 void
00325 SoundManager::StopPlay() {
00326 while(!playlist.empty())
00327 StopPlay(playlist.begin());
00328 }
00329
00330 void
00331 SoundManager::StopPlay(Play_ID id) {
00332 if(id==invalid_Play_ID)
00333 return;
00334 AutoLock autolock(lock,ProcessID::getID());
00335
00336
00337 for(chanlist_t::index_t it=chanlist.prev(chanlist.end()); it!=chanlist.end(); it=chanlist.prev(it))
00338 if(chanlist[it]==id) {
00339 std::string name=sndlist[playlist[id].snd_id].name;
00340 Release(playlist[id].snd_id);
00341 playlist.erase(id);
00342 chanlist.erase(it);
00343 playlist[id].cumulative+=playlist[id].offset;
00344 unsigned int ms=playlist[id].cumulative/(config->sound.sample_bits/8)/(config->sound.sample_rate/1000);
00345 if(name.size()>0)
00346 erouter->postEvent(EventBase::audioEGID,id,EventBase::deactivateETID,ms,name,0);
00347 else
00348 erouter->postEvent(EventBase::audioEGID,id,EventBase::deactivateETID,ms);
00349 return;
00350 }
00351 cerr << "SoundManager::StopPlay(): " << id << " does not seem to be playing" << endl;
00352 }
00353
00354 void
00355 SoundManager::PausePlay(Play_ID id) {
00356 if(id==invalid_Play_ID)
00357 return;
00358 AutoLock autolock(lock,ProcessID::getID());
00359 for(chanlist_t::index_t it=chanlist.begin(); it!=chanlist.end(); it=chanlist.next(it))
00360 if(chanlist[it]==id) {
00361 chanlist.erase(it);
00362 return;
00363 }
00364 }
00365
00366 void
00367 SoundManager::ResumePlay(Play_ID id) {
00368 if(id==invalid_Play_ID)
00369 return;
00370 AutoLock autolock(lock,ProcessID::getID());
00371 for(chanlist_t::index_t it=chanlist.begin(); it!=chanlist.end(); it=chanlist.next(it))
00372 if(chanlist[it]==id)
00373 return;
00374 chanlist.push_front(id);
00375 }
00376
00377 void
00378 SoundManager::SetMode(unsigned int max_channels, MixMode_t mixer_mode, QueueMode_t queuing_mode) {
00379 AutoLock autolock(lock,ProcessID::getID());
00380 max_chan=max_channels;
00381 mix_mode=mixer_mode;
00382 queue_mode=queuing_mode;
00383 }
00384
00385 unsigned int
00386 SoundManager::GetRemainTime(Play_ID id) const {
00387 AutoLock autolock(lock,ProcessID::getID());
00388 unsigned int t=0;
00389 while(id!=invalid_Play_ID) {
00390 t+=sndlist[playlist[id].snd_id].len-playlist[id].offset;
00391 id=playlist[id].next_id;
00392 }
00393 const unsigned int bytesPerMS=config->sound.sample_bits/8*config->sound.sample_rate/1000;
00394 return t/bytesPerMS;
00395 }
00396
00397 void
00398 SoundManager::MixChannel(Play_ID channelId, void* buf, size_t destSize) {
00399 char *dest = (char*) buf;
00400
00401 PlayState& channel = playlist[channelId];
00402 while (destSize > 0) {
00403 const SoundData& buffer = sndlist[channel.snd_id];
00404 const char* samples = ((char*) (buffer.data)) + channel.offset;
00405 const unsigned int samplesSize = buffer.len - channel.offset;
00406 if (samplesSize > destSize) {
00407 memcpy(dest, samples, destSize);
00408 channel.offset += destSize;
00409 dest += destSize;
00410 destSize = 0;
00411 return;
00412 } else {
00413 memcpy(dest, samples, samplesSize);
00414 channel.offset += samplesSize;
00415 dest += samplesSize;
00416 destSize -= samplesSize;
00417 if (endPlay(channelId)) {
00418 break;
00419 }
00420 }
00421 }
00422 if (destSize > 0) {
00423 memset(dest, 0, destSize);
00424 }
00425 }
00426
00427 void
00428 SoundManager::MixChannelAdditively(Play_ID channelId, int bitsPerSample, MixMode_t mode,
00429 short scalingFactor, void* buf, size_t destSize)
00430 {
00431 PlayState& channel = playlist[channelId];
00432 while (destSize > 0) {
00433 const SoundData& buffer = sndlist[channel.snd_id];
00434 const unsigned int samplesSize = buffer.len - channel.offset;
00435 const unsigned int mixedSamplesSize =
00436 ((mode == Fast)
00437 ? ((samplesSize > destSize) ? destSize : samplesSize)
00438 : ((samplesSize > destSize / 2) ? destSize / 2 : samplesSize));
00439
00440 if (bitsPerSample == 8) {
00441
00442 const char* samples = (char*) (buffer.data + channel.offset);
00443 if (mode == Fast) {
00444
00445 char *dest = (char*) buf;
00446 for (size_t i = 0; i < mixedSamplesSize; i++) {
00447 *dest += samples[i] / scalingFactor;
00448 dest++;
00449 }
00450 destSize -= (char*) dest - (char*) buf;
00451 buf = dest;
00452 } else {
00453
00454 short* dest = (short*) buf;
00455 for (size_t i = 0; i < mixedSamplesSize; i++) {
00456 *dest += samples[i];
00457 *dest++;
00458 }
00459 destSize -= (char*) dest - (char*) buf;
00460 buf = dest;
00461 }
00462 } else {
00463
00464 const short* samples = (short*) (buffer.data + channel.offset);
00465 if (mode == Fast) {
00466
00467 short* dest = (short*) buf;
00468 for (size_t i = 0; i < mixedSamplesSize / 2; i++) {
00469 *dest += samples[i] / scalingFactor;
00470 *dest++;
00471 }
00472 destSize -= (char*) dest - (char*) buf;
00473 buf = dest;
00474 } else {
00475
00476 int* dest = (int*) buf;
00477 for (size_t i = 0; i < mixedSamplesSize / 2; i++) {
00478 *dest += samples[i];
00479 *dest++;
00480 }
00481 destSize -= (char*) dest - (char*) buf;
00482 buf = dest;
00483 }
00484 }
00485 channel.offset += mixedSamplesSize;
00486 if (destSize == 0) {
00487 return;
00488 } else {
00489 if (endPlay(channelId)) {
00490 return;
00491 }
00492 }
00493 }
00494 }
00495
00496 #ifdef PLATFORM_APERIOS
00497 unsigned int
00498 SoundManager::CopyTo(OSoundVectorData* data) {
00499 AutoLock autolock(lock,ProcessID::getID());
00500 return CopyTo(data->GetData(0), data->GetInfo(0)->dataSize);
00501 }
00502
00503 void
00504 SoundManager::ReceivedMsg(const ONotifyEvent& event) {
00505
00506 for(int x=0; x<event.NumOfData(); x++)
00507 ProcessMsg(event.RCData(x));
00508 }
00509 #endif
00510
00511 unsigned int SoundManager::CopyTo(void * dest, size_t destSize) {
00512 AutoLock autolock(lock,ProcessID::getID());
00513
00514 void * origdest=dest;
00515 size_t origDestSize=destSize;
00516 if(chanlist.size() == 0) {
00517 memset(dest, 0, destSize);
00518 return 0;
00519 }
00520
00521 std::vector<Play_ID> channels;
00522 selectChannels(channels);
00523
00524 if (channels.size() == 0) {
00525
00526 memset(dest, 0, destSize);
00527 } else if (channels.size() == 1) {
00528
00529 MixChannel(channels.front(), dest, destSize);
00530 } else {
00531
00532 const MixMode_t mode = mix_mode;
00533 const int bitsPerSample = config->sound.sample_bits;
00534 if (mode == Quality) {
00535
00536 if ((mixerBuffer == 0) || (mixerBufferSize < destSize * 2)) {
00537 delete[] mixerBuffer;
00538 mixerBuffer = 0;
00539 mixerBufferSize = destSize * 2;
00540 mixerBuffer = new int[(mixerBufferSize / 4) + 1];
00541 }
00542 memset(mixerBuffer, 0, mixerBufferSize);
00543 dest = mixerBuffer;
00544 destSize *= 2;
00545 } else {
00546
00547 memset(dest, 0, destSize);
00548 }
00549
00550 const int channelCount = channels.size();
00551 const short scalingFactor = (short) ((mode == Fast) ? channelCount : 1);
00552 for(std::vector<Play_ID>::iterator i = channels.begin(); i != channels.end(); i++)
00553 MixChannelAdditively(*i, bitsPerSample, mode, scalingFactor, dest, destSize);
00554
00555 if (mode == Quality) {
00556
00557
00558 destSize /= 2;
00559 if (bitsPerSample == 8) {
00560
00561 char* destChar = (char*) origdest;
00562 short* mixerBufferShort = (short*) mixerBuffer;
00563 for (size_t i = 0; i < destSize; i++) {
00564 destChar[i] = (char) (mixerBufferShort[i] / channelCount);
00565 }
00566 } else {
00567
00568 short* destShort = (short*) origdest;
00569 const size_t destSampleCount = destSize / 2;
00570 for (size_t i = 0; i < destSampleCount; i++) {
00571 destShort[i] = (short) (mixerBuffer[i] / channelCount);
00572 }
00573 }
00574 }
00575 }
00576
00577 updateChannels(channels, origDestSize);
00578 return channels.size();
00579 }
00580
00581 void SoundManager::ProcessMsg(RCRegion * rcr) {
00582 SoundManagerMsg * msg = reinterpret_cast<SoundManagerMsg*>(rcr->Base());
00583
00584 switch(msg->type) {
00585 case SoundManagerMsg::add: {
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602 if(sndlist[msg->id].sn!=msg->sn) {
00603
00604
00605
00606
00607
00608 cerr << "Warning: serial numbers don't match... may be pathological sound usage (many load/releases very quickly)" << endl;
00609 break;
00610 }
00611 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")
00612 rcr->AddReference();
00613 sndlist[msg->id].rcr=rcr;
00614 sndlist[msg->id].data=reinterpret_cast<byte*>(rcr->Base()+MSG_SIZE);
00615
00616 for(playlist_t::index_t it=playlist.begin();it!=playlist.end();it=playlist.next(it))
00617 if(playlist[it].snd_id==msg->id) {
00618
00619 const char * name=sndlist[playlist[it].snd_id].name;
00620 if(name[0]!='\0')
00621 erouter->postEvent(EventBase::audioEGID,it,EventBase::activateETID,0,name,1);
00622 else
00623 erouter->postEvent(EventBase::audioEGID,it,EventBase::activateETID,0);
00624 }
00625 } break;
00626 case SoundManagerMsg::del: {
00627
00628 if(msg->region==NULL) {
00629 cerr << "SoundManager received a delete message for a NULL region" << endl;
00630 } else {
00631 msg->region->RemoveReference();
00632 }
00633 } break;
00634 case SoundManagerMsg::wakeup: {
00635
00636
00637 } break;
00638 default:
00639 printf("*** WARNING *** unknown SoundManager msg type received\n");
00640 }
00641 }
00642
00643
00644
00645
00646 RCRegion*
00647 SoundManager::initRegion(unsigned int size) {
00648 sn++;
00649 #ifdef PLATFORM_APERIOS
00650 unsigned int pagesize=4096;
00651 sError err=GetPageSize(&pagesize);
00652 ASSERT(err==sSUCCESS,"Error "<<err<<" getting page size");
00653 unsigned int pages=(size+pagesize-1)/pagesize;
00654 return new RCRegion(pages*pagesize);
00655 #else
00656 char name[RCRegion::MAX_NAME_LEN];
00657 snprintf(name,RCRegion::MAX_NAME_LEN,"SndMsg.%d.%d",ProcessID::getID(),sn);
00658 name[RCRegion::MAX_NAME_LEN-1]='\0';
00659
00660 return new RCRegion(name,size);
00661 #endif
00662 }
00663
00664 SoundManager::Snd_ID
00665 SoundManager::lookupPath(std::string const &path) const {
00666 std::string clippedPath;
00667 const char* cpath=NULL;
00668 if(path.size()>MAX_NAME_LEN) {
00669 clippedPath=path.substr(path.size()-MAX_NAME_LEN);
00670 cpath=clippedPath.c_str();
00671 } else
00672 cpath=path.c_str();
00673 for(sndlist_t::index_t it=sndlist.begin(); it!=sndlist.end(); it=sndlist.next(it)) {
00674 if(strncasecmp(cpath,sndlist[it].name,MAX_NAME_LEN)==0)
00675 return it;
00676 }
00677 return invalid_Snd_ID;
00678 }
00679
00680 void
00681 SoundManager::selectChannels(std::vector<Play_ID>& mix) {
00682 unsigned int selected=0;
00683 switch(queue_mode) {
00684 case Enqueue: {
00685 for(chanlist_t::index_t it=chanlist.prev(chanlist.end());it!=chanlist.end();it=chanlist.prev(it)) {
00686 if(sndlist[playlist[chanlist[it]].snd_id].data!=NULL) {
00687 mix.push_back(chanlist[it]);
00688 selected++;
00689 if(selected==max_chan)
00690 return;
00691 }
00692 }
00693 } break;
00694 case Override:
00695 case Pause: {
00696 for(chanlist_t::index_t it=chanlist.begin(); it!=chanlist.end(); it=chanlist.next(it)) {
00697 if(sndlist[playlist[chanlist[it]].snd_id].data!=NULL) {
00698 mix.push_back(chanlist[it]);
00699 selected++;
00700 if(selected==max_chan)
00701 return;
00702 }
00703 }
00704 } break;
00705 case Stop: {
00706 unsigned int numkeep=0;
00707 chanlist_t::index_t it=chanlist.begin();
00708 for(;it!=chanlist.end(); it=chanlist.next(it), numkeep++) {
00709 if(sndlist[playlist[chanlist[it]].snd_id].data!=NULL) {
00710 mix.push_back(chanlist[it]);
00711 selected++;
00712 if(selected==max_chan) {
00713 for(unsigned int i=chanlist.size()-numkeep-1; i>0; i--)
00714 endPlay(chanlist.back());
00715 return;
00716 }
00717 }
00718 }
00719 } break;
00720 default:
00721 cout << "SoundManager::selectChannels(): Illegal queue mode" << endl;
00722 }
00723 }
00724
00725 void
00726 SoundManager::updateChannels(const std::vector<Play_ID>& mixs,size_t used) {
00727 switch(queue_mode) {
00728 case Enqueue:
00729 case Pause:
00730 case Stop:
00731 break;
00732 case Override: {
00733
00734 chanlist_t::index_t it=chanlist.begin();
00735 std::vector<Play_ID>::const_iterator mixit=mixs.begin();
00736 for(;it!=chanlist.end(); it=chanlist.next(it)) {
00737 for(;mixit!=mixs.end(); mixit++)
00738 if(*mixit==chanlist[it])
00739 break;
00740 if(mixit==mixs.end())
00741 break;
00742 }
00743 for(;it!=chanlist.end(); it=chanlist.next(it)) {
00744 const Play_ID channelId = chanlist[it];
00745 PlayState &channel = playlist[channelId];
00746 size_t skip = used;
00747 while (skip > 0) {
00748 SoundData &buffer = sndlist[channel.snd_id];
00749
00750 if (buffer.data != 0) {
00751 size_t remain = buffer.len - channel.offset;
00752 if (remain < skip) {
00753 channel.offset = buffer.len;
00754 skip -= buffer.len;
00755 if (endPlay(channelId)) {
00756 break;
00757 }
00758 } else {
00759 channel.offset += skip;
00760 skip = 0;
00761 }
00762 } else {
00763 break;
00764 }
00765 }
00766 }
00767 } break;
00768 default:
00769 cout << "SoundManager::updateChannels(): Illegal queue mode" << endl;
00770 }
00771 }
00772
00773 bool
00774 SoundManager::endPlay(Play_ID id) {
00775 if(playlist[id].next_id==invalid_Play_ID) {
00776 StopPlay(id);
00777 return true;
00778 } else {
00779
00780 Play_ID next=playlist[id].next_id;
00781
00782 Release(playlist[id].snd_id);
00783 playlist[id].snd_id=playlist[next].snd_id;
00784 playlist[id].cumulative+=playlist[id].offset;
00785 playlist[id].offset=0;
00786 playlist[id].next_id=playlist[next].next_id;
00787 playlist.erase(next);
00788 unsigned int ms=playlist[id].cumulative/(config->sound.sample_bits/8)/(config->sound.sample_rate/1000);
00789 const char * name=sndlist[playlist[id].snd_id].name;
00790 if(name[0]!='\0')
00791 erouter->postEvent(EventBase::audioEGID,id,EventBase::statusETID,ms,name,1);
00792 else
00793 erouter->postEvent(EventBase::audioEGID,id,EventBase::statusETID,ms);
00794 return false;
00795 }
00796 }
00797
00798 SoundManager::SoundData::SoundData()
00799 : rcr(NULL), data(NULL), len(0), ref(0), sn(0)
00800 {
00801 name[0]='\0';
00802 }
00803
00804 SoundManager::PlayState::PlayState()
00805 : snd_id(invalid_Snd_ID), offset(0), cumulative(0), next_id(invalid_Play_ID)
00806 {}
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
|