00001 #include "Shared/Config.h"
00002 #include "SoundManager.h"
00003 #include "Shared/MarkScope.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 MarkScope 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);
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 cout << "Loading " << name << endl;
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
00102 if(buf==NULL || len==0)
00103 return invalid_Snd_ID;
00104 AutoLock autolock(lock);
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);
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);
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);
00204 Snd_ID sndid=loadFile(name);
00205 if(sndid==invalid_Snd_ID)
00206 return invalid_Play_ID;
00207 sndlist[sndid].ref--;
00208 cout << "Playing " << name << endl;
00209 return play(sndid);
00210 }
00211
00212 SoundManager::Play_ID
00213 SoundManager::playBuffer(const char buf[], unsigned int len) {
00214 if(playlist.size()>=playlist_t::MAX_ENTRIES || buf==NULL || len==0)
00215 return invalid_Play_ID;
00216 AutoLock autolock(lock);
00217 Snd_ID sndid=loadBuffer(buf,len);
00218 if(sndid==invalid_Snd_ID)
00219 return invalid_Play_ID;
00220 sndlist[sndid].ref--;
00221 return play(sndid);
00222 }
00223
00224 SoundManager::Play_ID
00225 SoundManager::play(Snd_ID id) {
00226
00227 if(id==invalid_Snd_ID)
00228 return invalid_Play_ID;
00229 AutoLock autolock(lock);
00230 Play_ID playid=playlist.new_front();
00231 if(playid!=invalid_Play_ID) {
00232 sndlist[id].ref++;
00233 playlist[playid].snd_id=id;
00234 playlist[playid].offset=0;
00235
00236
00237 chanlist.push_front(playid);
00238
00239
00240
00241
00242 if(ProcessID::getID()!=ProcessID::SoundProcess) {
00243 RCRegion * region=initRegion(MSG_SIZE);
00244 ASSERT(region!=NULL,"initRegion returned NULL");
00245 SoundManagerMsg * msg=new (reinterpret_cast<SoundManagerMsg*>(region->Base())) SoundManagerMsg;
00246 msg->setWakeup();
00247 #ifdef PLATFORM_APERIOS
00248
00249 subjs[ProcessID::getID()]->SetData(region);
00250 subjs[ProcessID::getID()]->NotifyObservers();
00251
00252 #else
00253 subjs[ProcessID::getID()]->sendMessage(region);
00254 region->RemoveReference();
00255 #endif
00256 }
00257
00258
00259 if(sndlist[id].rcr!=NULL) {
00260 const char * name=sndlist[playlist[playid].snd_id].name;
00261 if(name[0]!='\0')
00262 erouter->postEvent(EventBase::audioEGID,playid,EventBase::activateETID,0,name,1);
00263 else
00264 erouter->postEvent(EventBase::audioEGID,playid,EventBase::activateETID,0);
00265 }
00266 }
00267 return playid;
00268 }
00269
00270 SoundManager::Play_ID
00271 SoundManager::chainFile(Play_ID base, std::string const &next) {
00272 if(base==invalid_Play_ID)
00273 return playFile(next);
00274 Play_ID orig=base;
00275 while(playlist[base].next_id!=invalid_Play_ID)
00276 base=playlist[base].next_id;
00277 Play_ID nplay=playlist.new_front();
00278 if(nplay==invalid_Play_ID)
00279 return nplay;
00280 Snd_ID nsnd=loadFile(next);
00281 if(nsnd==invalid_Snd_ID) {
00282 playlist.pop_front();
00283 return invalid_Play_ID;
00284 }
00285 playlist[nplay].snd_id=nsnd;
00286 playlist[base].next_id=nplay;
00287 return orig;
00288 }
00289
00290 SoundManager::Play_ID
00291 SoundManager::chainBuffer(Play_ID base, const char buf[], unsigned int len) {
00292 if(base==invalid_Play_ID || buf==NULL || len==0)
00293 return playBuffer(buf,len);
00294 Play_ID orig=base;
00295 while(playlist[base].next_id!=invalid_Play_ID)
00296 base=playlist[base].next_id;
00297 Play_ID nplay=playlist.new_front();
00298 if(nplay==invalid_Play_ID)
00299 return nplay;
00300 Snd_ID nsnd=loadBuffer(buf,len);
00301 if(nsnd==invalid_Snd_ID) {
00302 playlist.pop_front();
00303 return invalid_Play_ID;
00304 }
00305 playlist[nplay].snd_id=nsnd;
00306 playlist[base].next_id=nplay;
00307 return orig;
00308 }
00309
00310 SoundManager::Play_ID
00311 SoundManager::chain(Play_ID base, Snd_ID next) {
00312 if(base==invalid_Play_ID || next==invalid_Snd_ID)
00313 return play(next);
00314 Play_ID orig=base;
00315 while(playlist[base].next_id!=invalid_Play_ID)
00316 base=playlist[base].next_id;
00317 Play_ID nplay=playlist.new_front();
00318 if(nplay==invalid_Play_ID)
00319 return nplay;
00320 playlist[nplay].snd_id=next;
00321 playlist[base].next_id=nplay;
00322 return orig;
00323 }
00324
00325 void
00326 SoundManager::stopPlay() {
00327 while(!playlist.empty())
00328 stopPlay(playlist.begin());
00329 }
00330
00331 void
00332 SoundManager::stopPlay(Play_ID id) {
00333 if(id==invalid_Play_ID)
00334 return;
00335 AutoLock autolock(lock);
00336
00337
00338 for(chanlist_t::index_t it=chanlist.prev(chanlist.end()); it!=chanlist.end(); it=chanlist.prev(it))
00339 if(chanlist[it]==id) {
00340 std::string name=sndlist[playlist[id].snd_id].name;
00341 release(playlist[id].snd_id);
00342 playlist.erase(id);
00343 chanlist.erase(it);
00344 playlist[id].cumulative+=playlist[id].offset;
00345 unsigned int ms=playlist[id].cumulative/(config->sound.sample_bits/8)/(config->sound.sample_rate/1000);
00346 if(name.size()>0)
00347 erouter->postEvent(EventBase::audioEGID,id,EventBase::deactivateETID,ms,name,0);
00348 else
00349 erouter->postEvent(EventBase::audioEGID,id,EventBase::deactivateETID,ms);
00350 return;
00351 }
00352 cerr << "SoundManager::stopPlay(): " << id << " does not seem to be playing" << endl;
00353 }
00354
00355 void
00356 SoundManager::pausePlay(Play_ID id) {
00357 if(id==invalid_Play_ID)
00358 return;
00359 AutoLock autolock(lock);
00360 for(chanlist_t::index_t it=chanlist.begin(); it!=chanlist.end(); it=chanlist.next(it))
00361 if(chanlist[it]==id) {
00362 chanlist.erase(it);
00363 return;
00364 }
00365 }
00366
00367 void
00368 SoundManager::resumePlay(Play_ID id) {
00369 if(id==invalid_Play_ID)
00370 return;
00371 AutoLock autolock(lock);
00372 for(chanlist_t::index_t it=chanlist.begin(); it!=chanlist.end(); it=chanlist.next(it))
00373 if(chanlist[it]==id)
00374 return;
00375 chanlist.push_front(id);
00376 }
00377
00378 void
00379 SoundManager::setMode(unsigned int max_channels, MixMode_t mixer_mode, QueueMode_t queuing_mode) {
00380 AutoLock autolock(lock);
00381 max_chan=max_channels;
00382 mix_mode=mixer_mode;
00383 queue_mode=queuing_mode;
00384 }
00385
00386 unsigned int
00387 SoundManager::getRemainTime(Play_ID id) const {
00388 AutoLock autolock(lock);
00389 unsigned int t=0;
00390 while(id!=invalid_Play_ID) {
00391 t+=sndlist[playlist[id].snd_id].len-playlist[id].offset;
00392 id=playlist[id].next_id;
00393 }
00394 const unsigned int bytesPerMS=config->sound.sample_bits/8*config->sound.sample_rate/1000;
00395 return t/bytesPerMS;
00396 }
00397
00398 void
00399 SoundManager::mixChannel(Play_ID channelId, void* buf, size_t destSize) {
00400 char *dest = (char*) buf;
00401
00402 PlayState& channel = playlist[channelId];
00403 while (destSize > 0) {
00404 const SoundData& buffer = sndlist[channel.snd_id];
00405 const char* samples = ((char*) (buffer.data)) + channel.offset;
00406 const unsigned int samplesSize = buffer.len - channel.offset;
00407 if (samplesSize > destSize) {
00408 memcpy(dest, samples, destSize);
00409 channel.offset += destSize;
00410 dest += destSize;
00411 destSize = 0;
00412 return;
00413 } else {
00414 memcpy(dest, samples, samplesSize);
00415 channel.offset += samplesSize;
00416 dest += samplesSize;
00417 destSize -= samplesSize;
00418 if (endPlay(channelId)) {
00419 break;
00420 }
00421 }
00422 }
00423 if (destSize > 0) {
00424 memset(dest, 0, destSize);
00425 }
00426 }
00427
00428 void
00429 SoundManager::mixChannelAdditively(Play_ID channelId, int bitsPerSample, MixMode_t mode,
00430 short scalingFactor, void* buf, size_t destSize)
00431 {
00432 PlayState& channel = playlist[channelId];
00433 while (destSize > 0) {
00434 const SoundData& buffer = sndlist[channel.snd_id];
00435 const unsigned int samplesSize = buffer.len - channel.offset;
00436 const unsigned int mixedSamplesSize =
00437 ((mode == Fast)
00438 ? ((samplesSize > destSize) ? destSize : samplesSize)
00439 : ((samplesSize > destSize / 2) ? destSize / 2 : samplesSize));
00440
00441 if (bitsPerSample == 8) {
00442
00443 const char* samples = (char*) (buffer.data + channel.offset);
00444 if (mode == Fast) {
00445
00446 char *dest = (char*) buf;
00447 for (size_t i = 0; i < mixedSamplesSize; i++) {
00448 *dest += samples[i] / scalingFactor;
00449 dest++;
00450 }
00451 destSize -= (char*) dest - (char*) buf;
00452 buf = dest;
00453 } else {
00454
00455 short* dest = (short*) buf;
00456 for (size_t i = 0; i < mixedSamplesSize; i++) {
00457 *dest += samples[i];
00458 *dest++;
00459 }
00460 destSize -= (char*) dest - (char*) buf;
00461 buf = dest;
00462 }
00463 } else {
00464
00465 const short* samples = (short*) (buffer.data + channel.offset);
00466 if (mode == Fast) {
00467
00468 short* dest = (short*) buf;
00469 for (size_t i = 0; i < mixedSamplesSize / 2; i++) {
00470 *dest += samples[i] / scalingFactor;
00471 *dest++;
00472 }
00473 destSize -= (char*) dest - (char*) buf;
00474 buf = dest;
00475 } else {
00476
00477 int* dest = (int*) buf;
00478 for (size_t i = 0; i < mixedSamplesSize / 2; i++) {
00479 *dest += samples[i];
00480 *dest++;
00481 }
00482 destSize -= (char*) dest - (char*) buf;
00483 buf = dest;
00484 }
00485 }
00486 channel.offset += mixedSamplesSize;
00487 if (destSize == 0) {
00488 return;
00489 } else {
00490 if (endPlay(channelId)) {
00491 return;
00492 }
00493 }
00494 }
00495 }
00496
00497 #ifdef PLATFORM_APERIOS
00498 unsigned int
00499 SoundManager::CopyTo(OSoundVectorData* data) {
00500 AutoLock autolock(lock);
00501 return CopyTo(data->GetData(0), data->GetInfo(0)->dataSize);
00502 }
00503
00504 void
00505 SoundManager::ReceivedMsg(const ONotifyEvent& event) {
00506
00507 for(int x=0; x<event.NumOfData(); x++)
00508 ProcessMsg(event.RCData(x));
00509 }
00510 #endif
00511
00512 unsigned int SoundManager::CopyTo(void * dest, size_t destSize) {
00513 AutoLock autolock(lock);
00514
00515 void * origdest=dest;
00516 size_t origDestSize=destSize;
00517 if(chanlist.size() == 0) {
00518 memset(dest, 0, destSize);
00519 return 0;
00520 }
00521
00522 std::vector<Play_ID> channels;
00523 selectChannels(channels);
00524
00525 if (channels.size() == 0) {
00526
00527 memset(dest, 0, destSize);
00528 } else if (channels.size() == 1) {
00529
00530 mixChannel(channels.front(), dest, destSize);
00531 } else {
00532
00533 const MixMode_t mode = mix_mode;
00534 const int bitsPerSample = config->sound.sample_bits;
00535 if (mode == Quality) {
00536
00537 if ((mixerBuffer == 0) || (mixerBufferSize < destSize * 2)) {
00538 delete[] mixerBuffer;
00539 mixerBuffer = 0;
00540 mixerBufferSize = destSize * 2;
00541 mixerBuffer = new int[(mixerBufferSize / 4) + 1];
00542 }
00543 memset(mixerBuffer, 0, mixerBufferSize);
00544 dest = mixerBuffer;
00545 destSize *= 2;
00546 } else {
00547
00548 memset(dest, 0, destSize);
00549 }
00550
00551 const int channelCount = channels.size();
00552 const short scalingFactor = (short) ((mode == Fast) ? channelCount : 1);
00553 for(std::vector<Play_ID>::iterator i = channels.begin(); i != channels.end(); i++)
00554 mixChannelAdditively(*i, bitsPerSample, mode, scalingFactor, dest, destSize);
00555
00556 if (mode == Quality) {
00557
00558
00559 destSize /= 2;
00560 if (bitsPerSample == 8) {
00561
00562 char* destChar = (char*) origdest;
00563 short* mixerBufferShort = (short*) mixerBuffer;
00564 for (size_t i = 0; i < destSize; i++) {
00565 destChar[i] = (char) (mixerBufferShort[i] / channelCount);
00566 }
00567 } else {
00568
00569 short* destShort = (short*) origdest;
00570 const size_t destSampleCount = destSize / 2;
00571 for (size_t i = 0; i < destSampleCount; i++) {
00572 destShort[i] = (short) (mixerBuffer[i] / channelCount);
00573 }
00574 }
00575 }
00576 }
00577
00578 updateChannels(channels, origDestSize);
00579 return channels.size();
00580 }
00581
00582 void SoundManager::ProcessMsg(RCRegion * rcr) {
00583 SoundManagerMsg * msg = reinterpret_cast<SoundManagerMsg*>(rcr->Base());
00584
00585 switch(msg->type) {
00586 case SoundManagerMsg::add: {
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603 if(sndlist[msg->id].sn!=msg->sn) {
00604
00605
00606
00607
00608
00609 cerr << "Warning: serial numbers don't match... may be pathological sound usage (many load/releases very quickly)" << endl;
00610 break;