AudioProcess.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2005-2007 The Pentagram team
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 */
00018 
00019 #include "pent_include.h"
00020 #include "AudioProcess.h"
00021 #include "intrinsics.h"
00022 #include "Object.h"
00023 
00024 #include "GameData.h"
00025 #include "SoundFlex.h"
00026 #include "SpeechFlex.h"
00027 #include "AudioSample.h"
00028 #include "AudioMixer.h"
00029 
00030 #include "getObject.h"
00031 #include "Item.h"
00032 #include "CameraProcess.h"
00033 
00034 #include "IDataSource.h"
00035 #include "ODataSource.h"
00036 
00037 using Pentagram::AudioSample;
00038 using Pentagram::AudioMixer;
00039 
00040 // p_dynamic_class stuff 
00041 DEFINE_RUNTIME_CLASSTYPE_CODE(AudioProcess,Process);
00042 
00043 AudioProcess * AudioProcess::the_audio_process = 0;
00044 
00045 AudioProcess::AudioProcess(void) : paused(0)
00046 {
00047         the_audio_process = this;
00048         type = 1; // persistent
00049 }
00050 
00051 AudioProcess::~AudioProcess(void)
00052 {
00053         the_audio_process = 0;
00054 }
00055 
00056 bool AudioProcess::calculateSoundVolume(ObjId objid, int &lvol, int &rvol) const
00057 {
00058         Item *item = getItem(objid);
00059         if (!item) return false;
00060 
00061         // Need to get items relative coords from avatar
00062 
00063         sint32 ax, ay, az, ix, iy, iz;
00064         CameraProcess::GetCameraLocation(ax,ay,az);
00065         item->getLocationAbsolute(ix, iy, iz);
00066         ix -= ax; iy -= ay; iz -= az; 
00067 
00068         //
00069         // Convert to screenspace
00070         //
00071         // Note that this should also correct for Crusader too. 
00072         //
00073 
00074         int x = (ix - iy)/4;
00075         int y = (ix + iy)/8 - iz;
00076 
00077         // Fall off over 350 pixels
00078         int limit = 350*350;
00079         int dist = limit-(x*x + y*y);
00080         if (dist < 0) dist = 0;
00081         dist = (dist*256)/limit;
00082 
00083         int lbal = 160;
00084         int rbal = 160;
00085 
00086         if (x < 0) {
00087                 if (x < -160) rbal = 0;
00088                 else rbal = x + 160;
00089         }
00090         else if (x > 0) {
00091                 if (x > 160) lbal = 0;
00092                 else lbal = 160 -x;
00093         }
00094 
00095         lvol = (dist*lbal)/160;
00096         rvol = (dist*rbal)/160;
00097 
00098         return true;
00099 }
00100 
00101 bool AudioProcess::run(const uint32)
00102 {
00103         AudioMixer *mixer = AudioMixer::get_instance();
00104 
00105         // Update the channels
00106         std::list<SampleInfo>::iterator it;
00107         for (it = sample_info.begin(); it != sample_info.end(); ) {
00108                 bool finished = false;
00109                 if (!mixer->isPlaying(it->channel)) {
00110                         if (it->sfxnum == -1)
00111                                 finished = !continueSpeech(*it);
00112                         else
00113                                 finished = true;
00114                 }
00115 
00116                 if (finished)
00117                         it = sample_info.erase(it);
00118                 else {
00119 
00120                         int lvol = 256, rvol = 256;
00121                         if (it->sfxnum != -1 && it->objid) calculateSoundVolume(it->objid, lvol,rvol);
00122                         mixer->setVolume(it->channel, (lvol*it->volume)/256,(rvol*it->volume)/256);
00123 
00124                         ++it;
00125                 }
00126         }
00127 
00128         return false;
00129 }
00130 
00131 bool AudioProcess::continueSpeech(SampleInfo& si)
00132 {
00133         assert(si.sfxnum == -1);
00134 
00135         SpeechFlex *speechflex;
00136         speechflex = GameData::get_instance()->getSpeechFlex(si.priority);
00137         if (!speechflex) return false;
00138 
00139         if (si.curspeech_end >= si.barked.size()) return false;
00140 
00141         si.curspeech_start = si.curspeech_end;
00142         int index = speechflex->getIndexForPhrase(si.barked,
00143                                                                                           si.curspeech_start,
00144                                                                                           si.curspeech_end);
00145         if (!index) return false;
00146 
00147         AudioSample *sample = speechflex->getSample(index);
00148         if (!sample) return false;
00149 
00150         // hack to prevent playSample from deleting 'si'
00151         si.channel = -1;
00152         int channel = playSample(sample,200,0);
00153         if (channel == -1)
00154                 return false;
00155 
00156         si.channel = channel;
00157         return true;
00158 }
00159 
00160 
00161 void AudioProcess::saveData(ODataSource* ods)
00162 {
00163         Process::saveData(ods);
00164 
00165         ods->write1(static_cast<uint8>(sample_info.size()));
00166 
00167         std::list<SampleInfo>::iterator it;
00168         for (it = sample_info.begin(); it != sample_info.end(); ++it) {
00169                 ods->write2(it->sfxnum);
00170                 ods->write2(it->priority);
00171                 ods->write2(it->objid);
00172                 ods->write2(it->loops);
00173                 ods->write4(it->pitch_shift);
00174                 ods->write2(it->volume);
00175 
00176                 if (it->sfxnum == -1)   // Speech
00177                 {
00178                         ods->write4(static_cast<uint32>(it->barked.size()));
00179                         ods->write(it->barked.c_str(),static_cast<uint32>(it->barked.size()));
00180                 }
00181         }
00182 }
00183 
00184 bool AudioProcess::loadData(IDataSource* ids, uint32 version)
00185 {
00186         if (!Process::loadData(ids, version)) return false;
00187 
00188         uint32 count = ids->read1();
00189 
00190         while (count--) {
00191                 sint16 sfxnum = ids->read2();
00192                 sint16 priority = ids->read2();
00193                 sint16 objid = ids->read2();
00194                 sint16 loops = ids->read2();
00195                 uint32 pitch_shift = ids->read4();
00196                 uint16 volume = ids->read2();
00197 
00198                 if (sfxnum != -1)       // SFX
00199                         playSFX(sfxnum,priority,objid,loops,false,pitch_shift,volume);
00200 
00201                 else {                                  // Speech
00202                         uint32 slen = ids->read4();
00203 
00204                         char* buf = new char[slen+1];
00205                         ids->read(buf, slen);
00206                         buf[slen] = 0;
00207                         std::string text = buf;
00208                         delete[] buf;
00209 
00210                         playSpeech(text,priority,objid,pitch_shift,volume);
00211                 }
00212         }
00213 
00214         return true;
00215 }
00216 
00217 int AudioProcess::playSample(AudioSample* sample, int priority, int loops, uint32 pitch_shift, int lvol, int rvol)
00218 {
00219         AudioMixer *mixer = AudioMixer::get_instance();
00220         int channel = mixer->playSample(sample,loops,priority,false,pitch_shift,lvol,rvol);
00221 
00222         if (channel == -1) return channel;
00223 
00224         // Erase old sample using channel (if any)
00225         std::list<SampleInfo>::iterator it;
00226         for (it = sample_info.begin(); it != sample_info.end(); ) {
00227                 if (it->channel == channel) {
00228                         it = sample_info.erase(it);
00229                 }
00230                 else {
00231                         ++it;
00232                 }
00233         }
00234 
00235         return channel;
00236 }
00237 
00238 void AudioProcess::playSFX(int sfxnum, int priority, ObjId objid, int loops,
00239                                                    bool no_duplicates, uint32 pitch_shift, uint16 volume)
00240 {
00241         //con.Printf("playSFX(%i, %i, 0x%X, %i)\n", sfxnum, priority, objid, loops);
00242 
00243         SoundFlex *soundflx= GameData::get_instance()->getSoundFlex();
00244         
00245         AudioMixer *mixer = AudioMixer::get_instance();
00246 
00247         if (no_duplicates) {
00248                 std::list<SampleInfo>::iterator it;
00249                 for (it = sample_info.begin(); it != sample_info.end(); ) {
00250                         if (it->sfxnum == sfxnum && it->objid == objid &&
00251                                 it->loops == loops)
00252                         {
00253 
00254                                 // Exactly the same (and playing) so just return
00255                                 //if (it->priority == priority) 
00256                                 if (mixer->isPlaying(it->channel))
00257                                 {
00258                                         pout << "Sound already playing" << std::endl;
00259                                         return;
00260                                 }
00261                                 else {
00262                                         it = sample_info.erase(it);
00263                                         continue;
00264                                 }
00265                         }
00266 
00267                         ++it;
00268                 }
00269         }
00270 
00271         AudioSample *sample = soundflx->getSample(sfxnum);
00272         if (!sample) return;
00273 
00274         int lvol=256, rvol=256;
00275         if (objid) calculateSoundVolume(objid, lvol, rvol);
00276 
00277         int channel = playSample(sample,priority,loops,pitch_shift,(lvol*volume)/256,(rvol*volume)/256);
00278         if (channel == -1) return;
00279 
00280         // Update list
00281         sample_info.push_back(SampleInfo(sfxnum,priority,objid,loops,channel,pitch_shift,volume));
00282 }
00283 
00284 void AudioProcess::stopSFX(int sfxnum, ObjId objid)
00285 {
00286         //con.Printf("stopSFX(%i, 0x%X)\n", sfxnum, objid);
00287 
00288         AudioMixer *mixer = AudioMixer::get_instance();
00289 
00290         std::list<SampleInfo>::iterator it;
00291         for (it = sample_info.begin(); it != sample_info.end(); ) {
00292                 if (it->sfxnum == sfxnum && it->objid == objid) {
00293                         if (mixer->isPlaying(it->channel)) mixer->stopSample(it->channel);
00294                         it = sample_info.erase(it);
00295                 }
00296                 else {
00297                         ++it;
00298                 }
00299         }
00300 }
00301 
00302 bool AudioProcess::isSFXPlaying(int sfxnum)
00303 {
00304         //con.Printf("isSFXPlaying(%i)\n", sfxnum);
00305 
00306         std::list<SampleInfo>::iterator it;
00307         for (it = sample_info.begin(); it != sample_info.end(); ++it) {
00308                 if (it->sfxnum == sfxnum)
00309                         return true;
00310         }
00311 
00312         return false;
00313 }
00314 
00315 void AudioProcess::setVolumeSFX(int sfxnum, uint8 volume)
00316 {
00317         //con.Printf("setVolumeSFX(%i, %i)\n", sfxnum, volume);
00318         AudioMixer *mixer = AudioMixer::get_instance();
00319 
00320         std::list<SampleInfo>::iterator it;
00321         for (it = sample_info.begin(); it != sample_info.end(); ++it) {
00322                 if (it->sfxnum == sfxnum && it->sfxnum != -1) {
00323                         it->volume = volume; 
00324 
00325                         int lvol = 256, rvol = 256;
00326                         if (it->objid) calculateSoundVolume(it->objid, lvol,rvol);
00327                         mixer->setVolume(it->channel, (lvol*it->volume)/256,(rvol*it->volume)/256);
00328                 }
00329         }
00330 }
00331 
00332 //
00333 // Speech
00334 //
00335 
00336 bool AudioProcess::playSpeech(std::string &barked, int shapenum, ObjId objid, uint32 pitch_shift, uint16 volume)
00337 {
00338         SpeechFlex *speechflex = GameData::get_instance()->getSpeechFlex(shapenum);
00339 
00340         if (!speechflex) return false;
00341 
00342         AudioMixer *mixer = AudioMixer::get_instance();
00343 
00344         std::list<SampleInfo>::iterator it;
00345         for (it = sample_info.begin(); it != sample_info.end();) {
00346 
00347                 if (it->sfxnum == -1 && it->barked == barked && 
00348                         it->priority == shapenum && it->objid == objid) {
00349 
00350                         if (mixer->isPlaying(it->channel)) {
00351                                 pout << "Speech already playing" << std::endl;
00352                                 return true;
00353                         } 
00354                         else {
00355                                 it = sample_info.erase(it);
00356                                 continue;
00357                         }
00358                 }
00359 
00360                 ++it;
00361         }
00362 
00363         uint32 speech_start = 0;
00364         uint32 speech_end;
00365         int index = speechflex->getIndexForPhrase(barked,speech_start,speech_end);
00366         if (!index) return false;
00367 
00368         AudioSample *sample = speechflex->getSample(index);
00369         if (!sample) return false;
00370 
00371         int channel = playSample(sample,200,0,pitch_shift,volume,volume);
00372 
00373         if (channel == -1) return false;
00374 
00375         // Update list
00376         sample_info.push_back(SampleInfo(barked,shapenum,objid,channel,
00377                                                                          speech_start,speech_end,pitch_shift,volume));
00378 
00379         return true;
00380 }
00381 
00382 uint32 AudioProcess::getSpeechLength(std::string &barked, int shapenum) const
00383 {
00384         SpeechFlex *speechflex = GameData::get_instance()->getSpeechFlex(shapenum);
00385         if (!speechflex) return 0;
00386 
00387         return speechflex->getSpeechLength(barked);
00388 }
00389 
00390 
00391 void AudioProcess::stopSpeech(std::string &barked, int shapenum, ObjId objid)
00392 {
00393         AudioMixer *mixer = AudioMixer::get_instance();
00394 
00395         std::list<SampleInfo>::iterator it;
00396         for (it = sample_info.begin(); it != sample_info.end(); ) {
00397                 if (it->sfxnum == -1 && it->priority == shapenum &&
00398                         it->objid == objid && it->barked == barked)
00399                 {
00400                         if (mixer->isPlaying(it->channel)) mixer->stopSample(it->channel);
00401                         it = sample_info.erase(it);
00402                 }
00403                 else {
00404                         ++it;
00405                 }
00406         }
00407 }
00408 
00409 bool AudioProcess::isSpeechPlaying(std::string &barked, int shapenum)
00410 {
00411         std::list<SampleInfo>::iterator it;
00412         for (it = sample_info.begin(); it != sample_info.end(); ++it) {
00413                 if (it->sfxnum == -1 && it->priority == shapenum &&
00414                         it->barked == barked)
00415                 {
00416                         return true;
00417                 }
00418         }
00419 
00420         return false;
00421 }
00422 
00423 void AudioProcess::pauseAllSamples()
00424 {
00425         paused++;
00426         if (paused != 1) return;
00427 
00428         AudioMixer *mixer = AudioMixer::get_instance();
00429 
00430         std::list<SampleInfo>::iterator it;
00431         for (it = sample_info.begin(); it != sample_info.end(); ) {
00432                 if (mixer->isPlaying(it->channel)) {
00433                         mixer->setPaused(it->channel,true);
00434                         ++it;
00435                 }
00436                 else {
00437                         it = sample_info.erase(it);
00438                 }
00439 
00440         }
00441 
00442 }
00443 
00444 void AudioProcess::unpauseAllSamples()
00445 {
00446         paused--;
00447         if (paused != 0) return;
00448 
00449         AudioMixer *mixer = AudioMixer::get_instance();
00450 
00451         std::list<SampleInfo>::iterator it;
00452         for (it = sample_info.begin(); it != sample_info.end(); ) {
00453                 if (mixer->isPlaying(it->channel)) {
00454                         mixer->setPaused(it->channel,false);
00455                         ++it;
00456                 }
00457                 else {
00458                         it = sample_info.erase(it);
00459                 }
00460 
00461         }
00462 
00463 }
00464 
00465 void AudioProcess::stopAllExceptSpeech()
00466 {
00467         AudioMixer *mixer = AudioMixer::get_instance();
00468 
00469         std::list<SampleInfo>::iterator it;
00470         for (it = sample_info.begin(); it != sample_info.end(); ) {
00471                 if (it->barked.empty()) {
00472                         if (mixer->isPlaying(it->channel)) mixer->stopSample(it->channel);
00473                         it = sample_info.erase(it);
00474                 } else {
00475                         ++it;
00476                 }
00477         }
00478 }
00479 
00480 //
00481 // Intrinsics
00482 //
00483 
00484 uint32 AudioProcess::I_playSFX(const uint8* args, unsigned int argsize)
00485 {
00486         ARG_SINT16(sfxnum);
00487 
00488         sint16 priority = 0x60;
00489         if (argsize >= 4) {
00490                 ARG_SINT16(priority_);
00491                 priority = priority_;
00492         }
00493 
00494         ObjId objid = 0;
00495         if (argsize == 6) {
00496                 ARG_OBJID(objid_);
00497                 objid = objid_;
00498         }
00499 
00500         AudioProcess *ap = AudioProcess::get_instance();
00501         if(ap) ap->playSFX(sfxnum,priority,objid,0);
00502         else perr << "Error: No AudioProcess" << std::endl;
00503 
00504         return 0;
00505 }
00506 
00507 uint32 AudioProcess::I_playAmbientSFX(const uint8* args, unsigned int argsize)
00508 {
00509         ARG_SINT16(sfxnum);
00510 
00511         sint16 priority = 0x60;
00512         if (argsize >= 4) {
00513                 ARG_SINT16(priority_);
00514                 priority = priority_;
00515         }
00516 
00517         ObjId objid = 0;
00518         if (argsize == 6) {
00519                 ARG_OBJID(objid_);
00520                 objid = objid_;
00521         }
00522 
00523 //      con.Printf("playAmbientSFX(%i, %i, 0x%X)\n", sfxnum, priority, objID);
00524         AudioProcess *ap = AudioProcess::get_instance();
00525         if(ap) ap->playSFX(sfxnum,priority,objid,-1,true);
00526         else perr << "Error: No AudioProcess" << std::endl;
00527 
00528         return 0;
00529 }
00530 
00531 uint32 AudioProcess::I_isSFXPlaying(const uint8* args, unsigned int argsize)
00532 {
00533         ARG_SINT16(sfxnum);
00534 
00535         AudioProcess *ap = AudioProcess::get_instance();
00536         if(ap) return ap->isSFXPlaying(sfxnum);
00537         else perr << "Error: No AudioProcess" << std::endl;
00538         return 0;
00539 }
00540 
00541 uint32 AudioProcess::I_setVolumeSFX(const uint8* args, unsigned int /*argsize*/)
00542 {
00543         // Sets volume for last played instances of sfxnum (???)
00544         ARG_SINT16(sfxnum);
00545         ARG_UINT8(volume);
00546 
00547         AudioProcess *ap = AudioProcess::get_instance();
00548         if(ap) ap->setVolumeSFX(sfxnum, volume);
00549         else perr << "Error: No AudioProcess" << std::endl;
00550 
00551         return 0;
00552 }
00553 
00554 uint32 AudioProcess::I_stopSFX(const uint8* args, unsigned int argsize)
00555 {
00556         ARG_SINT16(sfxnum);
00557 
00558         ObjId objid = 0;
00559         if (argsize == 4) {
00560                 ARG_OBJID(objid_);
00561                 objid = objid_;
00562         }
00563 
00564         AudioProcess *ap = AudioProcess::get_instance();
00565         if(ap) ap->stopSFX(sfxnum,objid);
00566         else perr << "Error: No AudioProcess" << std::endl;
00567 
00568         return 0;
00569 }
00570 
00571 // static
00572 void AudioProcess::ConCmd_listSFX(const Console::ArgvType &argv)
00573 {
00574         AudioProcess *ap = AudioProcess::get_instance();
00575         if (!ap) {
00576                 perr << "Error: No AudioProcess" << std::endl;
00577                 return;
00578         }
00579 
00580         std::list<SampleInfo>::iterator it;
00581         for (it = ap->sample_info.begin(); it != ap->sample_info.end(); ++it) {
00582                 pout.printf("Sample: num %d, obj %d, loop %d, prio %d",
00583                                         it->sfxnum, it->objid, it->loops, it->priority);
00584                 if (!it->barked.empty()) {
00585                         pout << ", speech: \"" << it->barked.substr(it->curspeech_start, it->curspeech_end - it->curspeech_start) << "\"";
00586                 }
00587                 pout << std::endl;
00588         }
00589 }
00590 
00591 // static
00592 void AudioProcess::ConCmd_stopSFX(const Console::ArgvType &argv)
00593 {
00594         AudioProcess *ap = AudioProcess::get_instance();
00595         if (!ap) {
00596                 perr << "Error: No AudioProcess" << std::endl;
00597                 return;
00598         }
00599 
00600         switch (argv.size() - 1) {
00601         case 1:
00602                 ap->stopSFX(strtol(argv[1].c_str(), 0, 0), 0);
00603                 break;
00604         case 2:
00605                 ap->stopSFX(strtol(argv[1].c_str(), 0, 0),
00606                                         strtol(argv[2].c_str(), 0, 0));
00607                 break;
00608         default:
00609                 pout << "usage: stopSFX <sfxnum> [<objid>]" << std::endl;
00610                 break;
00611         }
00612 }
00613 
00614 // static
00615 void AudioProcess::ConCmd_playSFX(const Console::ArgvType &argv)
00616 {
00617         AudioProcess *ap = AudioProcess::get_instance();
00618         if (!ap) {
00619                 perr << "Error: No AudioProcess" << std::endl;
00620                 return;
00621         }
00622 
00623         switch (argv.size() - 1) {
00624         case 1:
00625                 ap->playSFX(strtol(argv[1].c_str(), 0, 0), 0x60, 0, 0);
00626                 break;
00627         default:
00628                 pout << "usage: playSFX <sfxnum>" << std::endl;
00629                 break;
00630         }
00631 }

Generated on Fri Jul 27 22:27:09 2007 for pentagram by  doxygen 1.4.7