Homepage Demos Overview Downloads Tutorials Reference
Credits

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

Tekkotsu v2.2
Generated Tue Oct 19 14:19:16 2004 by Doxygen 1.3.9.1