Homepage Demos Overview Downloads Tutorials Reference
Credits
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members | Related Pages | Search

SoundManager.cc

Go to the documentation of this file.
00001 #include "Shared/Config.h"
00002 #include "SoundManager.h"
00003 #include "Shared/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 #include <OPENR/OSubject.h>
00011 #include <OPENR/ObjcommEvent.h>
00012 
00013 
00014 SoundManager * sndman=NULL;
00015 
00016 //!for convenience when locking each of the functions
00017 typedef LockScope<ProcessID::NumProcesses> AutoLock;
00018 
00019 SoundManager::SoundManager()
00020   : sndlist(),playlist(),chanlist(),mix_mode(Fast),queue_mode(Override),max_chan(4),lock()
00021 {}
00022 
00023 void
00024 SoundManager::InitAccess(OSubject* subj) {
00025   subjs[ProcessID::getID()]=subj;
00026 }
00027 
00028 //!@todo this does one more copy than it really needs to
00029 SoundManager::Snd_ID
00030 SoundManager::LoadFile(const char* name) {
00031   if(name==NULL || name[0]=='\0')
00032     return invalid_Snd_ID;
00033   AutoLock autolock(lock,ProcessID::getID());
00034   char tmp[MAX_NAME_LEN];
00035   const char* path=makePath(name,tmp);
00036   Snd_ID id=lookupPath(path);
00037   if(id!=invalid_Snd_ID) {
00038     //    cout << "add reference to pre-existing" << endl;
00039     sndlist[id].ref++;
00040   } else {
00041     //    cout << "load new file" << endl;
00042     struct stat buf;
00043     if(stat(path,&buf)==-1) {
00044       cout << "SoundManager::LoadFile(): Sound file not found " << path << endl;
00045       return invalid_Snd_ID;
00046     }
00047     byte * sndbuf=new byte[buf.st_size];
00048     std::ifstream file(path);
00049     file.read(reinterpret_cast<char*>(sndbuf),buf.st_size);
00050     WAV wav;
00051     WAVError error = wav.Set(sndbuf);
00052     if (error != WAV_SUCCESS) {
00053       OSYSLOG1((osyslogERROR, "%s : %s %d","SoundManager::LoadFile()","wav.Set() FAILED", error));
00054       return invalid_Snd_ID;
00055     }
00056     if(wav.GetSamplingRate()!=config->sound.sample_rate || wav.GetBitsPerSample()!=config->sound.sample_bits) {
00057       OSYSLOG1((osyslogERROR, "%s : %s %s","SoundManager::LoadFile()","bad sample rate/bits", error));
00058       return invalid_Snd_ID;
00059     }
00060     id=LoadBuffer(reinterpret_cast<char*>(wav.GetDataStart()),wav.GetDataEnd()-wav.GetDataStart());
00061     delete [] sndbuf;
00062     strncpy(sndlist[id].name,path,MAX_NAME_LEN);
00063   }
00064   return id;
00065 }
00066 
00067 SoundManager::Snd_ID
00068 SoundManager::LoadBuffer(const char buf[], unsigned int len) {
00069   cout << "SoundManager::LoadBuffer() of " << len << " bytes" << endl;
00070   if(buf==NULL || len==0)
00071     return invalid_Snd_ID;
00072   AutoLock autolock(lock,ProcessID::getID());
00073   //setup region
00074   RCRegion * region=initRegion(len+SoundManagerMsg::MSG_SIZE);
00075   //setup message
00076   SoundManagerMsg * msg=new (reinterpret_cast<SoundManagerMsg*>(region->Base())) SoundManagerMsg;
00077   msg->setAdd(sndlist.new_front());
00078   //init sound structure
00079   sndlist[msg->getID()].rcr=NULL;  // set by SoundPlay upon reception
00080   sndlist[msg->getID()].data=NULL; // set by SoundPlay upon reception
00081   sndlist[msg->getID()].ref=1;
00082   sndlist[msg->getID()].len=len;
00083   //copy buffer, do any filtering needed here
00084   const byte* src=reinterpret_cast<const byte*>(buf);
00085   byte* dest=reinterpret_cast<byte*>(region->Base())+SoundManagerMsg::MSG_SIZE;
00086   byte* end=dest+len;
00087   if (config->sound.sample_bits==8)
00088     while (dest < end)
00089       *dest++ = *src++ ^ 0x80; // offset binary -> signed char 
00090   else
00091     while (dest < end)
00092       *dest++ = *src++;
00093   //send message
00094   if(ProcessID::getID()==ProcessID::SoundProcess) {
00095     //if SoundPlay is preloading files, don't need to do inter-object comm
00096     sndlist[msg->getID()].rcr=region;
00097     sndlist[msg->getID()].data=reinterpret_cast<byte*>(region->Base()+SoundManagerMsg::MSG_SIZE);   
00098   } else {
00099     subjs[ProcessID::getID()]->SetData(region);
00100     subjs[ProcessID::getID()]->NotifyObservers();
00101   }
00102   return msg->getID();
00103 }
00104   
00105 void
00106 SoundManager::ReleaseFile(const char* name) {
00107   if(name==NULL || name[0]=='\0')
00108     return;
00109   AutoLock autolock(lock,ProcessID::getID());
00110   Release(lookup(name));
00111 }
00112 
00113 void
00114 SoundManager::Release(Snd_ID id) {
00115   if(id==invalid_Snd_ID)
00116     return;
00117   if(sndlist[id].ref==0) {
00118     cout << "SoundManager::Release() " << id << " extra release" << endl;
00119     return;
00120   }
00121   AutoLock autolock(lock,ProcessID::getID());
00122   sndlist[id].ref--;
00123   if(sndlist[id].ref==0) {
00124     //cout << "releasing snd_id " << id << endl;
00125     //setup region
00126     RCRegion * region=initRegion(SoundManagerMsg::MSG_SIZE);
00127     //setup message
00128     SoundManagerMsg * msg=new (reinterpret_cast<SoundManagerMsg*>(region->Base())) SoundManagerMsg;
00129     msg->setDelete(sndlist[id].rcr);
00130     //clean up sound data structure
00131     sndlist.erase(id);
00132     //send message
00133     if(ProcessID::getID()==ProcessID::SoundProcess) {
00134       msg->region->RemoveReference();
00135     } else {
00136       subjs[ProcessID::getID()]->SetData(region);
00137       subjs[ProcessID::getID()]->NotifyObservers();
00138     }
00139   }
00140 }
00141 
00142 SoundManager::Play_ID
00143 SoundManager::PlayFile(const char* name) {
00144   if(playlist.size()>=playlist_t::MAX_ENTRIES || name==NULL || name[0]=='\0')
00145     return invalid_Play_ID; 
00146   AutoLock autolock(lock,ProcessID::getID());
00147   Snd_ID sndid=LoadFile(name);
00148   if(sndid==invalid_Snd_ID)
00149     return invalid_Play_ID;
00150   sndlist[sndid].ref--;
00151   return Play(sndid);
00152 }
00153 
00154 SoundManager::Play_ID
00155 SoundManager::PlayBuffer(const char buf[], unsigned int len) {
00156   if(playlist.size()>=playlist_t::MAX_ENTRIES || buf==NULL || len==0)
00157     return invalid_Play_ID; 
00158   AutoLock autolock(lock,ProcessID::getID());
00159   Snd_ID sndid=LoadBuffer(buf,len);
00160   if(sndid==invalid_Snd_ID)
00161     return invalid_Play_ID;
00162   sndlist[sndid].ref--;
00163   return Play(sndid);
00164 }
00165   
00166 SoundManager::Play_ID
00167 SoundManager::Play(Snd_ID id) {
00168   //  cout << "Play " << id << endl;
00169   if(id==invalid_Snd_ID)
00170     return invalid_Play_ID;
00171   AutoLock autolock(lock,ProcessID::getID());
00172   Play_ID playid=playlist.new_front();
00173   if(playid!=invalid_Play_ID) {
00174     sndlist[id].ref++;
00175     playlist[playid].snd_id=id;
00176     playlist[playid].offset=0;
00177     //playlist.size() should be greater than or equal to chanlist.size
00178     //so if we got a playid, we can get a channel slot.
00179     chanlist.push_front(playid);
00180 
00181     //setup message to "wake-up" 
00182     //(only really need if chanlist was empty)
00183     //    if(chanlist.size()==1) { //commented out because sometimes doesn't wake up, thinks it's playing but isn't
00184     if(ProcessID::getID()!=ProcessID::SoundProcess) {
00185       RCRegion * region=initRegion(SoundManagerMsg::MSG_SIZE);
00186       ASSERT(region!=NULL,"initRegion returned NULL");
00187       SoundManagerMsg * msg=new (reinterpret_cast<SoundManagerMsg*>(region->Base())) SoundManagerMsg;
00188       msg->setWakeup();
00189       subjs[ProcessID::getID()]->SetData(region);
00190       subjs[ProcessID::getID()]->NotifyObservers();
00191     }
00192     //    }
00193     
00194     if(sndlist[id].rcr!=NULL)
00195       erouter->postEvent(EventBase::audioEGID,playid,EventBase::activateETID,0);
00196     return playid;
00197   }
00198 }
00199   
00200 SoundManager::Play_ID
00201 SoundManager::ChainFile(Play_ID base, const char * next) {
00202   if(base==invalid_Play_ID || next==NULL || next[0]=='\0')
00203     return base;
00204   Play_ID orig=base;
00205   while(playlist[base].next_id!=invalid_Play_ID)
00206     base=playlist[base].next_id;
00207   Play_ID nplay=playlist.new_front();
00208   if(nplay==invalid_Play_ID)
00209     return nplay;
00210   Snd_ID nsnd=LoadFile(next);
00211   if(nsnd==invalid_Snd_ID) {
00212     playlist.pop_front();
00213     return invalid_Play_ID;
00214   }
00215   playlist[nplay].snd_id=nsnd;
00216   playlist[base].next_id=nplay;
00217   return orig;
00218 }
00219 
00220 SoundManager::Play_ID
00221 SoundManager::ChainBuffer(Play_ID base, const char buf[], unsigned int len) {
00222   if(base==invalid_Play_ID || buf==NULL || len==0)
00223     return base;
00224   Play_ID orig=base;
00225   while(playlist[base].next_id!=invalid_Play_ID)
00226     base=playlist[base].next_id;
00227   Play_ID nplay=playlist.new_front();
00228   if(nplay==invalid_Play_ID)
00229     return nplay;
00230   Snd_ID nsnd=LoadBuffer(buf,len);
00231   if(nsnd==invalid_Snd_ID) {
00232     playlist.pop_front();
00233     return invalid_Play_ID;
00234   }
00235   playlist[nplay].snd_id=nsnd;
00236   playlist[base].next_id=nplay;
00237   return orig;
00238 }
00239 
00240 SoundManager::Play_ID
00241 SoundManager::Chain(Play_ID base, Snd_ID next) {
00242   if(base==invalid_Play_ID || next==invalid_Snd_ID)
00243     return base;
00244   Play_ID orig=base;
00245   while(playlist[base].next_id!=invalid_Play_ID)
00246     base=playlist[base].next_id;
00247   Play_ID nplay=playlist.new_front();
00248   if(nplay==invalid_Play_ID)
00249     return nplay;
00250   playlist[nplay].snd_id=next;
00251   playlist[base].next_id=nplay;
00252   return orig;
00253 }
00254 
00255 void
00256 SoundManager::StopPlay() {
00257   while(!playlist.empty())
00258     StopPlay(playlist.begin());
00259 }
00260 
00261 void
00262 SoundManager::StopPlay(Play_ID id) {
00263   //  cout << "Stopping sound " << id << endl;
00264   if(id==invalid_Play_ID)
00265     return;
00266   AutoLock autolock(lock,ProcessID::getID());
00267   //we start at the back (oldest) since these are the most likely to be removed...
00268   for(chanlist_t::index_t it=chanlist.prev(chanlist.end()); it!=chanlist.end(); it=chanlist.prev(it))
00269     if(chanlist[it]==id) {
00270       Release(playlist[id].snd_id);
00271       playlist.erase(id);
00272       chanlist.erase(it);
00273       playlist[id].cumulative+=playlist[id].offset;
00274       unsigned int ms=playlist[id].cumulative/(config->sound.sample_bits/8)/(config->sound.sample_rate/1000);
00275       erouter->postEvent(EventBase::audioEGID,id,EventBase::deactivateETID,ms);
00276       return;
00277     }
00278   cout << "SoundManager::StopPlay(): " << id << " does not seem to be playing" << endl;
00279 }
00280 
00281 void
00282 SoundManager::PausePlay(Play_ID id) {
00283   if(id==invalid_Play_ID)
00284     return;
00285   AutoLock autolock(lock,ProcessID::getID());
00286   for(chanlist_t::index_t it=chanlist.begin(); it!=chanlist.end(); it=chanlist.next(it))
00287     if(chanlist[it]==id) {
00288       chanlist.erase(it);
00289       return;
00290     }
00291 }
00292   
00293 void
00294 SoundManager::ResumePlay(Play_ID id) {
00295   if(id==invalid_Play_ID)
00296     return;
00297   AutoLock autolock(lock,ProcessID::getID());
00298   for(chanlist_t::index_t it=chanlist.begin(); it!=chanlist.end(); it=chanlist.next(it))
00299     if(chanlist[it]==id)
00300       return;
00301   chanlist.push_front(id);
00302 }
00303   
00304 void
00305 SoundManager::SetMode(unsigned int max_channels, MixMode_t mixer_mode, QueueMode_t queuing_mode) {
00306   AutoLock autolock(lock,ProcessID::getID());
00307   max_chan=max_channels;
00308   mix_mode=mixer_mode;
00309   queue_mode=queuing_mode;
00310 }
00311 
00312 unsigned int
00313 SoundManager::GetRemainTime(Play_ID id) const {
00314   AutoLock autolock(lock,ProcessID::getID());
00315   unsigned int t=0;
00316   while(id!=invalid_Play_ID) {
00317     t+=sndlist[playlist[id].snd_id].len-playlist[id].offset;
00318     id=playlist[id].next_id;
00319   }
00320   const unsigned int bytesPerMS=config->sound.sample_bits/8*config->sound.sample_rate/1000;
00321   return t/bytesPerMS;
00322 }
00323 
00324 unsigned int
00325 SoundManager::CopyTo(OSoundVectorData* data) {
00326   AutoLock autolock(lock,ProcessID::getID());
00327 
00328   size_t avail  = data->GetInfo(0)->dataSize; 
00329   byte*  dest   = data->GetData(0);
00330   byte*  end    = dest+avail;
00331   
00332   if(chanlist.size()==0) {
00333     memset(dest,0,avail);
00334     return 0;
00335   }
00336 
00337   std::vector<Play_ID> mixs;
00338   selectChannels(mixs);
00339 
00340   std::vector<byte*> srcs;
00341   std::vector<byte*> ends;
00342   for(std::vector<Play_ID>::iterator it=mixs.begin(); it!=mixs.end(); it++) {
00343     Snd_ID cursnd=playlist[*it].snd_id;
00344     srcs.push_back(sndlist[cursnd].data+playlist[*it].offset);
00345     ends.push_back(sndlist[cursnd].data+sndlist[cursnd].len);
00346   }
00347 
00348   if(mixs.size()==0) { // nothing right now, but one's coming
00349     memset(dest,0,avail);
00350     return 1;
00351   } else if(mixs.size()==1) { // only 1, just copy it directly (most common case)
00352     size_t remain=ends.front()-srcs.front();
00353     if(remain>=avail) { //just copy a buffer's worth
00354       memcpy(dest,srcs.front(),avail);
00355       playlist[mixs.front()].offset+=avail;
00356       updateChannels(mixs,avail);
00357       return 1;
00358     } else { //copy what remains, 0 the rest
00359       memcpy(dest,srcs.front(),remain);
00360       memset(dest+remain,0,avail-remain);
00361       playlist[mixs.front()].offset=sndlist[playlist[mixs.front()].snd_id].len;
00362       endPlay(mixs.front());
00363       return 0;
00364     }
00365   } else { // do a mix
00366     if(mix_mode==Fast) { //essentially the same as quality mode below, but rounds off low order bits early
00367       byte* begin=dest;
00368       unsigned int stopped=0;
00369       if(config->sound.sample_bits==8) { // have to mix, 8 bit
00370         char size=srcs.size();
00371         //just the first one, set dest
00372         for(unsigned int c=0; c<1; c++) {
00373           if(ends[c]-srcs[c]>avail) {
00374             for(dest=begin;dest<end;dest++) {
00375               *dest=(*(char*)srcs[c])/size;
00376               srcs[c]++;
00377             }
00378           } else {
00379             for(dest=begin;srcs[c]<ends[c];srcs[c]++) {
00380               *dest=(*(char*)srcs[c])/size;
00381               dest++;
00382             }
00383             playlist[mixs[c]].offset=sndlist[playlist[mixs[c]].snd_id].len;
00384             endPlay(mixs[c]);
00385             stopped++;
00386             memset(dest,0,end-dest); //zero out the rest
00387           }             
00388         }
00389         //the rest, add to dest
00390         for(unsigned int c=1; c<srcs.size(); c++) {
00391           if(ends[c]-srcs[c]>avail) {
00392             for(dest=begin;dest<end;dest++) {
00393               *dest+=(*(char*)srcs[c])/size;
00394               srcs[c]++;
00395             }
00396           } else {
00397             for(dest=begin;srcs[c]<ends[c];srcs[c]++) {
00398               *dest+=(*(char*)srcs[c])/size;
00399               dest++;
00400             }
00401             playlist[mixs[c]].offset=sndlist[playlist[mixs[c]].snd_id].len;
00402             endPlay(mixs[c]);
00403             stopped++;
00404           }             
00405         }
00406       } else { // have to mix,  16 bit
00407         short size=srcs.size();
00408         //just the first one, set dest
00409         for(unsigned int c=0; c<1; c++) {
00410           if(ends[c]-srcs[c]>avail) {
00411             for(dest=begin;dest<end;dest+=2) {
00412               *(short*)dest=(*(short*)srcs[c])/size;
00413               srcs[c]+=2;
00414             }
00415           } else {
00416             for(dest=begin;srcs[c]<ends[c];srcs[c]+=2) {
00417               *(short*)dest=(*(short*)srcs[c])/size;
00418               dest+=2;
00419             }
00420             playlist[mixs[c]].offset=sndlist[playlist[mixs[c]].snd_id].len;
00421             endPlay(mixs[c]);
00422             stopped++;
00423             memset(dest,0,end-dest); //zero out the rest
00424           }
00425         }
00426         //the rest, add to dest
00427         for(unsigned int c=1; c<srcs.size(); c++) {
00428           if(ends[c]-srcs[c]>avail) {
00429             for(dest=begin;dest<end;dest+=2) {
00430               *(short*)dest+=(*(short*)srcs[c])/size;
00431               srcs[c]+=2;
00432             }
00433           } else {
00434             for(dest=begin;srcs[c]<ends[c];srcs[c]+=2) {
00435               *(short*)dest+=(*(short*)srcs[c])/size;
00436               dest+=2;
00437             }
00438             playlist[mixs[c]].offset=sndlist[playlist[mixs[c]].snd_id].len;
00439             endPlay(mixs[c]);
00440             stopped++;
00441           }
00442         }
00443       }
00444       for(unsigned int c=0; c<mixs.size(); c++)
00445         playlist[mixs[c]].offset+=avail;
00446       updateChannels(mixs,avail);
00447       return mixs.size()-stopped;
00448     } else { //mix_mode==quality
00449       if(config->sound.sample_bits==8) { // have to mix, 8 bit
00450         for(;dest!=end;dest++) {
00451           short total=0;
00452           for(unsigned int c=0; c<srcs.size(); c++) {
00453             if(srcs[c]==ends[c]) {
00454               playlist[mixs[c]].offset=sndlist[playlist[mixs[c]].snd_id].len;
00455               if(endPlay(mixs[c])) {
00456                 std::swap(mixs[c],mixs.back());
00457                 std::swap(srcs[c],srcs.back());
00458                 std::swap(ends[c],ends.back());
00459                 mixs.pop_back();
00460                 srcs.pop_back();
00461                 ends.pop_back();
00462                 if(srcs.size()==0) {
00463                   memset(dest,0,end-dest);
00464                   return 0;
00465                 }
00466                 continue;
00467               }
00468             }
00469             total+=*(char*)srcs[c];
00470             srcs[c]++;
00471           }
00472           *dest=total/(int)srcs.size();
00473         }
00474       } else { // have to mix,  16 bit
00475         for(;dest!=end;dest+=2) {
00476           int total=0;
00477           for(unsigned int c=0; c<srcs.size(); c++) {
00478             if(srcs[c]==ends[c]) {
00479               playlist[mixs[c]].offset=sndlist[playlist[mixs[c]].snd_id].len;
00480               if(endPlay(mixs[c])) {
00481                 std::swap(mixs[c],mixs.back());
00482                 std::swap(srcs[c],srcs.back());
00483                 std::swap(ends[c],ends.back());
00484                 mixs.pop_back();
00485                 srcs.pop_back();
00486                 ends.pop_back();
00487                 if(srcs.size()==0) {
00488                   memset(dest,0,end-dest);
00489                   return 0;
00490                 }
00491                 continue;
00492               }
00493             }
00494             total+=*(short*)srcs[c];
00495             srcs[c]+=2;
00496           }
00497           *(short*)dest=total/(int)srcs.size();
00498         }
00499       }
00500       for(unsigned int c=0; c<mixs.size(); c++)
00501         playlist[mixs[c]].offset+=avail;
00502       updateChannels(mixs,avail);
00503       return mixs.size();
00504     } // endif mix_mode==quality
00505   } // endif do a mix
00506 }
00507 
00508 void
00509 SoundManager::ReceivedMsg(const ONotifyEvent& event) {
00510   for(int x=0; x<event.NumOfData(); x++) {
00511     RCRegion * rcr = event.RCData(x);
00512     SoundManagerMsg * msg = reinterpret_cast<SoundManagerMsg*>(rcr->Base());
00513     switch(msg->type) {
00514     case SoundManagerMsg::add: {
00515       rcr->AddReference();
00516       sndlist[msg->id].rcr=rcr;
00517       sndlist[msg->id].data=reinterpret_cast<byte*>(rcr->Base()+SoundManagerMsg::MSG_SIZE);
00518       //look to see if there's any play's for the sound we just finished loading
00519       for(playlist_t::index_t it=playlist.begin();it!=playlist.end();it=playlist.next(it))
00520         if(playlist[it].snd_id==msg->id)
00521           //send an event if there are
00522           erouter->postEvent(EventBase::audioEGID,it,EventBase::activateETID,0);
00523     } break;
00524     case SoundManagerMsg::del: {
00525       msg->region->RemoveReference();
00526     } break;
00527     case SoundManagerMsg::wakeup: {
00528       //doesn't need to do anything, just causes SoundPlay to check activity
00529     } break;
00530     default:
00531       printf("*** WARNING *** unknown SoundManager msg type received\n");
00532     }
00533   }
00534 }
00535 
00536 //protected:
00537 
00538 RCRegion*
00539 SoundManager::initRegion(unsigned int size) {
00540   unsigned int pagesize=4096;
00541   sError err=GetPageSize(&pagesize);
00542   ASSERT(err==sSUCCESS,"Error "<<err<<" getting page size");
00543   unsigned int pages=(size+pagesize-1)/pagesize;
00544   return new RCRegion(pages*pagesize);
00545 }
00546 
00547 SoundManager::Snd_ID 
00548 SoundManager::lookup(const char* name) const {
00549   char tmp[MAX_NAME_LEN];
00550   return lookupPath(makePath(name,tmp));
00551 }
00552 SoundManager::Snd_ID 
00553 SoundManager::lookupPath(const char* path) const {
00554   for(sndlist_t::index_t it=sndlist.begin(); it!=sndlist.end(); it=sndlist.next(it))
00555     if(strncasecmp(path,sndlist[it].name,MAX_NAME_LEN)==0)
00556       return it;
00557   return invalid_Snd_ID;
00558 }
00559 
00560 const char*
00561 SoundManager::makePath(const char* name, char tmp[MAX_NAME_LEN]) {
00562   const char* path=name;
00563   if(name[0]!='/') {
00564     path=tmp;
00565     strncpy(tmp,config->sound.root.c_str(),MAX_NAME_LEN);
00566     strncat(tmp,"/",MAX_NAME_LEN);
00567     strncat(tmp,name,MAX_NAME_LEN);
00568   }
00569   //  cout << name << " is " << path << endl;
00570   return path;
00571 }
00572 
00573 void
00574 SoundManager::selectChannels(std::vector<Play_ID>& mix) {
00575   unsigned int selected=0;
00576   switch(queue_mode) {
00577   case Enqueue: { //select the oldest channels
00578     for(chanlist_t::index_t it=chanlist.prev(chanlist.end());it!=chanlist.end();it=chanlist.prev(it)) {
00579       if(sndlist[playlist[chanlist[it]].snd_id].data!=NULL) {
00580         mix.push_back(chanlist[it]);
00581         selected++;
00582         if(selected==max_chan)
00583           return;
00584       }
00585     }
00586   } break;
00587   case Override:
00588   case Pause: { //select the youngest channels (difference between these two is in the final update)
00589     for(chanlist_t::index_t it=chanlist.begin(); it!=chanlist.end(); it=chanlist.next(it)) {
00590       if(sndlist[playlist[chanlist[it]].snd_id].data!=NULL) {
00591         mix.push_back(chanlist[it]);
00592         selected++;
00593         if(selected==max_chan)
00594           return;
00595       }
00596     }
00597   } break;
00598   case Stop: { //select the youngest, stop anything that remains
00599     unsigned int numkeep=0;
00600     chanlist_t::index_t it=chanlist.begin();
00601     for(;it!=chanlist.end(); it=chanlist.next(it), numkeep++) {
00602       if(sndlist[playlist[chanlist[it]].snd_id].data!=NULL) {
00603         mix.push_back(chanlist[it]);
00604         selected++;
00605         if(selected==max_chan) {
00606           for(unsigned int i=chanlist.size()-numkeep-1; i>0; i--)
00607             endPlay(chanlist.back());
00608           return;
00609         }
00610       }
00611     }
00612   } break;
00613   default:
00614     cout << "SoundManager::selectChannels(): Illegal queue mode" << endl;
00615   }
00616 }
00617 
00618 void
00619 SoundManager::updateChannels(const std::vector<Play_ID>& mixs,size_t used) {
00620   switch(queue_mode) {
00621   case Enqueue:
00622   case Pause:
00623   case Stop: 
00624     break;
00625   case Override: { //increase offset of everything that wasn't selected
00626     //assumes mode hasn't changed since the mix list was created... (so order is same as chanlist)
00627     chanlist_t::index_t it=chanlist.begin(); 
00628     std::vector<Play_ID>::const_iterator mixit=mixs.begin();
00629     for(;it!=chanlist.end(); it=chanlist.next(it)) {
00630       for(;mixit!=mixs.end(); mixit++) //some mixs may have been stopped during play
00631         if(*mixit==chanlist[it])
00632           break;
00633       if(mixit==mixs.end())
00634         break;
00635     }
00636     for(;it!=chanlist.end(); it=chanlist.next(it)) {
00637       Snd_ID cursnd=playlist[chanlist[it]].snd_id;
00638       if(sndlist[cursnd].data!=NULL) {
00639         size_t remain = sndlist[cursnd].len-playlist[chanlist[it]].offset;
00640         if(remain<used) {
00641           playlist[chanlist[it]].offset=sndlist[playlist[chanlist[it]].snd_id].len;
00642           endPlay(chanlist[it]);
00643         } else {
00644           playlist[chanlist[it]].offset+=used;
00645         }
00646       }
00647     }
00648   } break;
00649   default:
00650     cout << "SoundManager::updateChannels(): Illegal queue mode" << endl;
00651   }
00652 }
00653 
00654 bool
00655 SoundManager::endPlay(Play_ID id) {
00656   if(playlist[id].next_id==invalid_Play_ID) {
00657     StopPlay(id);
00658     return true;
00659   } else {
00660     //copies the next one into current so that the Play_ID consistently refers to the same "sound"
00661     Play_ID next=playlist[id].next_id;
00662     //    cout << "play " << id << " moving from " << playlist[id].snd_id << " to " << playlist[next].snd_id << endl;
00663     Release(playlist[id].snd_id);
00664     playlist[id].snd_id=playlist[next].snd_id;
00665     playlist[id].cumulative+=playlist[id].offset;
00666     playlist[id].offset=0;
00667     playlist[id].next_id=playlist[next].next_id;
00668     playlist.erase(next);
00669     unsigned int ms=playlist[id].cumulative/(config->sound.sample_bits/8)/(config->sound.sample_rate/1000);
00670     erouter->postEvent(EventBase::audioEGID,id,EventBase::statusETID,ms);
00671     return false;
00672   }
00673 }
00674 
00675 SoundManager::SoundData::SoundData()
00676   : rcr(NULL), data(NULL), len(0), ref(0)
00677 {
00678   name[0]='\0';
00679 }
00680 
00681 SoundManager::PlayState::PlayState()
00682   : snd_id(invalid_Snd_ID), offset(0), cumulative(0), next_id(invalid_Play_ID)
00683 {}
00684 
00685 
00686 /*! @file
00687  * @brief Implements SoundManager, which provides sound effects and caching services, as well as mixing buffers for the SoundPlay process
00688  * @author ejt (Creator)
00689  *
00690  * $Author: ejt $
00691  * $Name: tekkotsu-1_4_1 $
00692  * $Revision: 1.13 $
00693  * $State: Exp $
00694  * $Date: 2003/06/10 00:53:48 $
00695  */
00696 
00697 
00698 
00699 
00700 //This is a faster mix algo using bit shifting, but it doesn't work with
00701 // non power of two number of channels, despite my efforts... eh, maybe
00702 // i'll fix it later...
00703     // NOT WORKING
00704     /*
00705     if(mixs.size()==2 || mix_mode==Fast) {
00706       unsigned int shift=0;
00707       unsigned int offset=0;
00708       unsigned int tmp=mixs.size();
00709       while(tmp>1) {
00710         tmp>>=1;
00711         shift++;
00712       }
00713       unsigned int mask;
00714       if(config->sound.sample_bits==8) {
00715         unsigned int c=(unsigned char)~0;
00716         c>>=shift;
00717         mask=(c<<24)|(c<<16)|(c<<8)|c;
00718         offset=(1<<7)|(1<<15)|(1<<23)|(1<<31);
00719       } else {
00720         unsigned int c=(unsigned short)~0;
00721         c>>=shift;
00722         mask=(c<<16)|c;
00723         offset=(1<<31)|(1<<15);
00724       }
00725       memset(dest,0,avail);
00726       for(unsigned int c=0; c<mixs.size(); c++) {
00727         if(ends[c]-srcs[c]>avail) {
00728           for(unsigned int * beg=(unsigned int*)dest;beg<(unsigned int*)end;beg++) {
00729             const unsigned int src=*(unsigned int*)srcs[c];
00730             if(beg==(unsigned int*)dest) {
00731               cout << src <<' '<< (void*)src << endl;
00732               unsigned int x=((src^offset)>>shift)&mask;
00733               cout << x <<' '<< (void*)x << endl;
00734               cout << "****" << endl;
00735             }
00736             *beg+=((src^offset)>>shift)&mask;
00737             if(beg==(unsigned int*)dest)
00738               cout << *beg <<' '<< (void*)*beg << endl << "########" << endl;
00739             srcs[c]+=sizeof(int);
00740           }
00741           playlist[mixs[c]].offset+=avail;
00742         } else {
00743           unsigned int * beg=(unsigned int*)dest;
00744           for(;srcs[c]<ends[c];srcs[c]+=sizeof(int)) {
00745             const unsigned int src=*(unsigned int*)srcs[c];
00746             *beg+=((src^offset)>>shift)&mask;
00747             beg++;
00748           }
00749           for(;beg<(unsigned int*)end; beg++)
00750             *beg+=offset>>shift;
00751           playlist[mixs[c]].offset=sndlist[playlist[mixs[c]].snd_id].len;
00752           StopPlay(mixs[c]);
00753         }
00754       }
00755       unsigned int leftover=(offset>>shift)*((1<<shift)-mixs.size());
00756       for(unsigned int * beg=(unsigned int*)dest;beg<(unsigned int*)end;beg++)
00757         *beg=*(beg+leftover)^offset;
00758       updateChannels(avail);
00759       return mixs.size();
00760       } else*/

Tekkotsu v1.4
Generated Sat Jul 19 00:06:31 2003 by Doxygen 1.3.2