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

Tekkotsu v2.2.2
Generated Tue Jan 4 15:43:15 2005 by Doxygen 1.4.0