| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683 |
- /*
- ** Command & Conquer Generals Zero Hour(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- //----------------------------------------------------------------------------
- //
- // Westwood Studios Pacific.
- //
- // Confidential Information
- // Copyright(C) 2001 - All Rights Reserved
- //
- //----------------------------------------------------------------------------
- //
- // Project: RTS3
- //
- // File name: GameSpeech.cpp
- //
- // Created: 10/30/01
- //
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Includes
- //----------------------------------------------------------------------------
- #include "wpaudio/attributes.h"
- #include "wsys/File.h"
- #include "wsys/List.h"
- #include "wpaudio/Streamer.h"
- #include "wpaudio/Time.h"
- #include "wpaudio/Device.h"
- #include "wpaudio/Streamer.h"
- #define DEFINE_DLG_EVENT_PRIORITY_NAMES
- #include "Common/GameAudio.h"
- #include "Common/GameSpeech.h"
- #include "Common/INI.h"
- #include "Common/STLTypedefs.h"
- //----------------------------------------------------------------------------
- // Externals
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Defines
- //----------------------------------------------------------------------------
- #define BASE_DLG_ID ((ID) 5000)
- #define BASE_DLG_DIR "Data\\Audio\\Sounds"
- #define BASE_DLG_EXT "wav"
- #define NUM_DLG_PRIORITIES 5
- //----------------------------------------------------------------------------
- // Private Types
- //----------------------------------------------------------------------------
- //===============================
- // Speech
- //===============================
- /**
- * The Speech struct holds all information about a line of dialog. While Speech itself is not
- * accessible from outside SpeechInterface, the embedded struct SpeechInfo is accessible to the game code.
- * Place data in SpeechInfo that is useful to the game code in determining what speech to play.
- */
- //===============================
- struct Speech
- {
- Speech();
- ~Speech();
-
- ID id; ///< Unquie GDI id
- Int index; ///< Speech index
- AsciiString name; ///< Logical name for line of speech
- Real volume; ///< Mixing level for this line
- SpeechInfo info; ///< Game info about this line of dialog (public)
- Bool valid; ///< Is this entry have valid data
- Int priority; ///< speech priority
- Int timeout; ///< speech time out in milliseconds
- Int interrupt; ///< speech interrupts current playing speech
- };
- static void speechFromInfo(SpeechInfo* pInSpeechInfo, Speech* pOutSpeech);
- static AsciiString getNextFilenameFromSpeech(Speech* pSpeechToGetFilenameFrom);
- //===============================
- // SpeechRequest
- //===============================
- /**
- * This is an internal structure used by the SpeechManager. It holds information
- * about the playback of a line of dialog.
- */
- //===============================
- struct SpeechItem
- {
- enum Flags
- {
- PAUSED = 0x00000001
- };
- LListNode nd;
- Flags flags;
- Speech *speech; ///< What to say
- Int priority; ///< Priority of this line
- TimeStamp timeout; ///< Time when this event is stale in milliseconds
- };
- //===============================
- // Speaker
- //===============================
- /**
- * Actual implementation of SpeakerInterface
- */
- //===============================
- class SpeechManager;
- class Speaker : public SpeakerInterface
- {
- AsciiString m_name; ///< name of this speaker
- AudioStreamer *m_stream; ///< Audio streamer for this speaker
- File *m_file; ///< file we are streaming
- Int m_priority; ///< Speaker's priority
- Int m_paused; ///< paused level
- TimeStamp m_delay; ///< current delay interval
- TimeStamp m_delayTime; ///< delay time between speeches
- SpeechManager *m_manager; ///< Manager that created use
- // info about current playing dialog
- SpeechItem *m_currentSpeech; ///< currently playing speech
- // list of pending speech items
- LList m_pending; ///< list of pending SpeechItems
- public:
- Speaker();
- ~Speaker();
- virtual void destroy( void ); ///< Delete and free speaker
- /// Submits speech to play
- virtual void say ( Speech *speech, // speech to say
- Int priority, // priority
- Int timeout, // time in which to say this line, 0 = infinite
- Int interrupt); // whether to interrupt current line
-
- virtual void say ( Char *speechName, // name ofspeech to say
- Int priority, // priority
- Int timeout, // time in which to say this line, 0 = infinite
- Int interrupt ); // whether to interrupt current line
- virtual void setPriority ( Int priority ); ///< Set speaker's priority level
- virtual void setDelay ( Int delay ); ///< Set speaker's delay between speeches( in milliseconds)
- virtual void setBuffering ( Int buffer_time ); ///< Set speaker's amount of buffer (in milliseconds)
- virtual Int getPriority ( void ); ///< Get speaker's priority level
- virtual Int getDelay ( void ); ///< Get speaker's delay between speeches( in milliseconds)
- virtual Int getBuffering ( void ); ///< Get speaker's amount of buffer (in milliseconds)
- virtual void pause ( void ); ///< pause speaker
- virtual void resume ( void ); ///< resume speaking
- virtual void stop ( void ); ///< stop speaking (flushes queue)
- virtual void cancel ( Speech *speech ); ///< cancel pending line of dialog
- virtual Bool hasSaid ( Speech *speech ); ///< is line of dialog no longer pending
- virtual Bool isGoingToSay ( Speech *speech ); ///< check in line of dialog is pending
- virtual Bool isTalking ( void ); ///< is speaker talking
- virtual Speech* saying ( void ); ///< returns currently spoken speech
- virtual void update( void ); ///< Service speaker
- void init ( char *name, Int priority, Int btime, Int delay ); ///< initialized speaker for use
- void deinit( void );
- void setManager( SpeechManager *manager ) { m_manager = manager;};
- SpeechItem* firstItem( TimeStamp now = 0 );
- SpeechItem* nextItem( SpeechItem *item, TimeStamp now = 0 );
- SpeechItem* findItem( Speech *speech );
- void flush( void );
- };
- typedef std::vector<Speech> VecSpeech;
- typedef std::hash_map<const char*, Speech, std::hash<const char*>, rts::equal_to<const char*> > HashSpeech;
- //===============================
- // SpeechManager:
- //===============================
- /**
- * Actual implementation od SpeechInterface
- */
- //===============================
- class SpeechManager: public SpeechInterface
- {
- protected:
- struct AudioAttribs *m_masterAttribs; ///< Attribs for all speech
- struct AudioAttribs *m_masterFadeAttribs; ///< Fade attribs for all speech
- Real m_volume; ///< Current speech volume
- Bool m_on; ///< Is speech turned on?
- Int m_count; ///< Number of speeches in the table
-
- struct AudioDeviceTag *m_device; ///< The audio device we were initilaized with
- LList m_speakers; ///< list of speakers created by this manager
- HashSpeech m_speech; ///< This is a hash table of all speeches we currently have loaded.
- VecAsciiString m_speechNames; ///< The purpose of this is to return to someone asking for the name of some element.
- VecSpeech m_temporarySpeeches; ///< This is a vector of speeches that are _like_ something in the hash, but differ by priority.
-
- AsciiString getFilenameForPlay( Speech *speech ); ///< Return the filename corresponding to this speech
- public:
- SpeechManager();
- virtual ~SpeechManager();
- virtual Bool init( void ); ///< Initlaizes the speech system
- virtual void deinit( void ); ///< De-initlaizes the speech system
- virtual void update( void ); ///< Services speech tasks. Called by AudioInterface
- virtual void reset( void ); ///< Resets the speech system
- virtual void loseFocus( void ); ///< Called when application loses focus
- virtual void regainFocus( void ); ///< Called when application regains focus
-
- // speech info access
- virtual Int numSpeeches( void ); ///< Returns the number of speechs defined
- virtual SpeechInfo* getSpeechInfo( Speech *speech ); ///< Returns speech info by speech
- virtual Int getSpeechIndex( Speech *speech ); ///< Returns speech index
- virtual ID getSpeechID( Speech *speech ); ///< Returns speech ID
- virtual Speech* getSpeech( Int index ); ///< Converts index to speech
- virtual Speech* getSpeech( ID id ); ///< Converts is to speech
- virtual Speech* getSpeech( const Char *speech_name );///< Converts speech name to speech
- virtual const Char* getSpeechName( Speech *speech ); ///< Converts speech to speech name
- // volume control
- virtual void fadeIn( void ); ///< Fade all speech in
- virtual void fadeOut( void ); ///< Fade all speech out
- virtual void fade( Real fade_value ); ///< Fade all speech by a specified amout (1.0 .. 0.0 )
- virtual Bool isFading( void ); ///< Returns whether or not any speech is in the process of a fade
- virtual void waitForFade( void ); ///< Returns when all fading has finished
- virtual void setVolume( Real new_volume ); ///< Set new volume level for all speech 1.0 (loudest) 0.0 (silent)
- virtual Real getVolume( void ); ///< Return current volume level for all speech
- /// Speaker factory
- virtual SpeakerInterface* createSpeaker ( Char *name,
- Int priority,
- Int buffer_time,
- Int delay);
- virtual Speech* addNewSpeech( SpeechInfo* pSpeechToAdd); ///< Create a speech specified by pSpeechToAdd
- virtual Speech* addTemporaryDialog( Speech& temporarySpeech ); ///< Speech to be taken over by
- // playback control
- virtual void stop( void ); ///< Stops all speech that's currently playing.
- virtual void pause( void ); ///< Pauses all speech
- virtual void resume( void ); ///< Resumes all paused speech
- virtual void turnOff( void ); ///< Turns off all speech. No more speech will play
- virtual void turnOn( void ); ///< Turns speech on.
- virtual Bool waitToStop( Int milliseconds ); ///< Returns when all speech has completely stopped playing
- virtual Bool say( Speech* pSpeechToSay); ///< Attempts to add a speech to the speach queue.
- virtual Bool say( AsciiString speechName); ///< Attempts to find and add a speech to the speech queue
-
- // info
- virtual Bool isOn( void ); ///< Returns whether or not speech is turned on at present
- virtual struct AudioAttribs* getMasterAttribs( void ); ///< Returns the master attribute control for all speech
- virtual struct AudioAttribs* getMasterFadeAttribs( void );///< Returns the master fade control for all speech
- virtual void addDialogEvent(const AudioEventRTS *eventRTS, Speech* speech, AudioEventRTS *returnEvent); ///< Add an event. speech can be NULL
- virtual void removeDialogEvent(const AudioEventRTS *eventRTS, AudioEventRTS *eventToUse); ///< remove an event, eventToUse shouldn't be NULL.
- void removeSpeaker ( Speaker *speaker );
- void addSpeaker ( Speaker *speaker );
- // empty string means that this sound wasn't found or some error occurred. CHECK FOR EMPTY STRING.
- virtual AsciiString getFilenameForPlayFromAudioEvent( const AudioEventRTS *eventToGetFrom );
- };
- //----------------------------------------------------------------------------
- // Private Data
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Public Data
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Private Prototypes
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Private Functions
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Public Functions
- //----------------------------------------------------------------------------
- //============================================================================
- // createSpeechInterface
- //============================================================================
- SpeechInterface* CreateSpeechInterface( void )
- {
- return NEW SpeechManager;
- }
- //============================================================================
- // Speech::Speech
- //============================================================================
- Speech::Speech()
- : id(INVALID_ID),
- valid(FALSE),
- volume(TheAudio->VOLUME_MIN)
- {
- }
- //============================================================================
- // Speech::~Speech
- //============================================================================
- Speech::~Speech()
- {
- }
- //============================================================================
- // SpeechManager::SpeechManager
- //============================================================================
- SpeechManager::SpeechManager()
- : m_on(FALSE),
- m_device(NULL),
- m_masterAttribs(NULL),
- m_masterFadeAttribs(NULL),
- m_speech(NULL),
- m_count(0)
- {
- if( (m_masterFadeAttribs = NEW AudioAttribs) != 0 ) // poolify
- {
- AudioAttribsInit( m_masterFadeAttribs );
- }
- if( (m_masterAttribs = NEW AudioAttribs) != 0 )
- {
- AudioAttribsInit( m_masterAttribs );
- }
- }
- //============================================================================
- // SpeechManager::~SpeechManager
- //============================================================================
- SpeechManager::~SpeechManager()
- {
- deinit();
- delete m_masterAttribs;
- delete m_masterFadeAttribs;
- }
- //============================================================================
- // SpeechManager::init
- //============================================================================
- Bool SpeechManager::init( void )
- {
- deinit();
- if ( m_device )
- {
- return TRUE;
- }
- m_device = TheAudio->device();
- if( m_device )
- {
- AudioDeviceAttribsAdd( m_device, m_masterAttribs );
- AudioDeviceAttribsAdd( m_device, m_masterFadeAttribs );
- }
- for (int i = 0; i < NUM_DLG_PRIORITIES; ++i) {
- createSpeaker(dlgPriorityNames[i], (i + 1), 3000, 300);
- }
-
- m_on = TRUE;
- return TRUE;
- }
- //============================================================================
- // SpeechManager::deinit
- //============================================================================
- void SpeechManager::deinit( void )
- {
- m_count = 0;
- m_speech.clear();
- m_speechNames.clear();
-
- for (int i = 0; i < NUM_DLG_PRIORITIES && m_speakers.firstNode(); ++i) {
- ((Speaker*) m_speakers.firstNode()->item())->destroy();
- }
- stop();
- if( m_device )
- {
- AudioDeviceAttribsRemove( m_device, m_masterAttribs );
- AudioDeviceAttribsRemove( m_device, m_masterFadeAttribs );
- m_device = NULL;
- }
- }
- //============================================================================
- // SpeechManager::update
- //============================================================================
- void SpeechManager::update( void )
- {
- LListNode *node = m_speakers.firstNode();
- while ( node )
- {
- Speaker *speaker = (Speaker *) node->item();
- if ( speaker )
- {
- speaker->update();
- }
- node = node->next();
- }
- }
- //============================================================================
- // SpeechManager::reset
- //============================================================================
- void SpeechManager::reset( void )
- {
- }
- //============================================================================
- // SpeechManager::loseFocus
- //============================================================================
- void SpeechManager::loseFocus( void )
- {
- }
- //============================================================================
- // SpeechManager::regainFocus
- //============================================================================
- void SpeechManager::regainFocus( void )
- {
- }
- //============================================================================
- // SpeechManager::numSpeeches
- //============================================================================
- Int SpeechManager::numSpeeches( void )
- {
- return m_count ;
- }
- //============================================================================
- // SpeechManager::getSpeechInfo
- //============================================================================
- SpeechInfo* SpeechManager::getSpeechInfo( Speech *speech )
- {
- if( speech )
- {
- return &speech->info ;
- }
- return NULL;
- }
- //============================================================================
- // SpeechManager::getSpeechIndex
- //============================================================================
- Int SpeechManager::getSpeechIndex( Speech *speech )
- {
- if( speech )
- {
- return speech->index ;
- }
- return SpeechInterface::INVALID_SPEECH;
- }
- //============================================================================
- // SpeechManager::getSpeechID
- //============================================================================
- ID SpeechManager::getSpeechID( Speech *speech )
- {
- if( speech )
- {
- return speech->id ;
- }
- return INVALID_ID;
- }
- //============================================================================
- // SpeechManager::getSpeech
- //============================================================================
- Speech* SpeechManager::getSpeech( const Char *name )
- {
- HashSpeech::iterator it = m_speech.find(name);
- if (it != m_speech.end()) {
- return &(*it).second;
- }
- return NULL;
- }
- //============================================================================
- // SpeechManager::getSpeech
- //============================================================================
- Speech* SpeechManager::getSpeech( ID id )
- {
- if ( m_count == 0 )
- {
- return NULL;
- }
- for (int i = 0; i < m_speechNames.size(); ++i) {
- Speech* pSpeech = getSpeech(m_speechNames[i].str());
- if (pSpeech && pSpeech->id == id) {
- return pSpeech;
- }
- }
- return NULL;
- }
- //============================================================================
- // SpeechManager::getSpeech
- //============================================================================
- Speech* SpeechManager::getSpeech( int index )
- {
- if (index < 0 || index > m_count) {
- return NULL;
- }
- return getSpeech(m_speechNames[index].str());
- }
- //============================================================================
- // SpeechManager::getSpeechName
- //============================================================================
- const Char* SpeechManager::getSpeechName( Speech *speech )
- {
- if( speech )
- {
- return speech->name.str();
- }
- return "(null)";
- }
- //============================================================================
- // SpeechManager::fadeIn
- //============================================================================
- void SpeechManager::fadeIn( void )
- {
- if(m_masterFadeAttribs )
- {
- AudioAttribsAdjustVolume( m_masterFadeAttribs, AUDIO_VOLUME_MAX );
- }
- }
- //============================================================================
- // SpeechManager::fadeOut
- //============================================================================
- void SpeechManager::fadeOut( void )
- {
- if(m_masterFadeAttribs )
- {
- AudioAttribsAdjustVolume( m_masterFadeAttribs, AUDIO_VOLUME_MIN );
- }
- }
- //============================================================================
- // SpeechManager::fade
- //============================================================================
- void SpeechManager::fade( Real new_volume )
- {
- if(m_masterFadeAttribs )
- {
- AudioAttribsAdjustVolume( m_masterFadeAttribs, TheAudio->convertRealVolume( new_volume) );
- }
- }
- //============================================================================
- // SpeechManager::isFading
- //============================================================================
- Bool SpeechManager::isFading( void )
- {
- if( m_masterFadeAttribs )
- {
- return !AudioAttribsVolumeAdjusted( m_masterFadeAttribs );
- }
- return FALSE;
- }
- //============================================================================
- // SpeechManager::waitForFade
- //============================================================================
- void SpeechManager::waitForFade( void )
- {
- }
- //============================================================================
- // SpeechManager::setVolume
- //============================================================================
- void SpeechManager::setVolume( Real new_volume )
- {
- m_volume = TheAudio->validateVolume(new_volume);
- if( m_masterAttribs )
- {
- AudioAttribsSetVolume( m_masterAttribs, TheAudio->convertRealVolume( new_volume ));
- }
- }
- //============================================================================
- // SpeechManager::getVolume
- //============================================================================
- Real SpeechManager::getVolume( void )
- {
- return m_volume;
- }
- void SpeechManager::stop( void )
- {
- LListNode *node = m_speakers.firstNode();
- while ( node )
- {
- Speaker *speaker = (Speaker *) node->item();
- if ( speaker )
- {
- speaker->stop();
- }
- node = node->next();
- }
- }
- //============================================================================
- // SpeechManager::pause
- //============================================================================
- void SpeechManager::pause( void )
- {
- LListNode *node = m_speakers.firstNode();
- while ( node )
- {
- Speaker *speaker = (Speaker *) node->item();
- if ( speaker )
- {
- speaker->pause();
- }
- node = node->next();
- }
- }
- //============================================================================
- // SpeechManager::resume
- //============================================================================
- void SpeechManager::resume( void )
- {
- LListNode *node = m_speakers.firstNode();
- while ( node )
- {
- Speaker *speaker = (Speaker *) node->item();
- if ( speaker )
- {
- speaker->resume();
- }
- node = node->next();
- }
- }
- //============================================================================
- // SpeechManager::turnOff
- //============================================================================
- void SpeechManager::turnOff( void )
- {
- stop();
- m_on = FALSE;
- }
- //============================================================================
- // SpeechManager::turnOn
- //============================================================================
- void SpeechManager::turnOn( void )
- {
- m_on = TRUE;
- }
- //============================================================================
- // SpeechManager::waitToStop
- //============================================================================
- Bool SpeechManager::waitToStop( Int milliseconds )
- {
- return TRUE;
- }
- //============================================================================
- // SpeechManager::say
- //============================================================================
- Bool SpeechManager::say( Speech* pSpeechToSay)
- {
- // TBD: Find the other conditions
- if (m_speakers.isEmpty() || !pSpeechToSay) {
- return false;
- }
-
- LListNode *node = m_speakers.firstNode();
- for (int i = 0; i < pSpeechToSay->priority && node; ++i) {
- node = node->next();
- }
-
- if (!node) {
- return false;
- }
-
- Speaker* currentSpeaker = (Speaker*) node->item();
- currentSpeaker->say(pSpeechToSay, pSpeechToSay->priority, pSpeechToSay->timeout, pSpeechToSay->interrupt);
- return true;
- }
- //============================================================================
- // SpeechManager::say
- //============================================================================
- Bool SpeechManager::say( AsciiString speechName)
- {
- Speech* pSpeech = getSpeech(speechName.str());
- if (pSpeech) {
- return false;
- }
- return say(pSpeech);
- }
- //============================================================================
- // SpeechManager::isOn
- //============================================================================
- Bool SpeechManager::isOn( void )
- {
- return m_on;
- }
- //============================================================================
- // SpeechManager::removeSpeaker
- //============================================================================
- void SpeechManager::removeSpeaker ( Speaker *speaker )
- {
- LListNode *node = m_speakers.findItem( speaker );
- if ( node )
- {
- node->remove();
- node->destroy();
- }
- }
- //============================================================================
- // SpeechManager::addSpeaker
- //============================================================================
- void SpeechManager::addSpeaker ( Speaker *speaker )
- {
- // remove it if it is already in the list
- removeSpeaker( speaker );
- m_speakers.addItem( speaker->getPriority(), speaker );
- }
- //============================================================================
- // SpeechManager::CreateSpeaker
- //============================================================================
- SpeakerInterface* SpeechManager::createSpeaker ( Char *name, Int priority, Int btime, Int delay )
- {
- Speaker *speaker = NEW Speaker; // poolify
- if ( speaker )
- {
- speaker->setManager( this );
- speaker->init( name, priority, btime, delay );
- m_speakers.addItem( priority, speaker );
- }
- return speaker;
- }
- //============================================================================
- // SpeechManager::addNewSpeech
- //============================================================================
- Speech* SpeechManager::addNewSpeech( SpeechInfo* pSpeechToAdd )
- {
- if (!pSpeechToAdd) {
- return NULL;
- }
- const char* entryKey = pSpeechToAdd->m_dialogEvent.str();
- if (m_speech.find(entryKey) == m_speech.end()) {
- ++m_count;
- m_speechNames.push_back(pSpeechToAdd->m_dialogEvent);
- }
- Speech newSpeech;
- speechFromInfo(pSpeechToAdd, &newSpeech);
- newSpeech.id = (ID) (m_count + BASE_DLG_ID);
- m_speech[entryKey] = newSpeech;
- return &m_speech[entryKey];
- }
- //============================================================================
- // SpeechManager::addTemporaryDialog
- //============================================================================
- Speech* SpeechManager::addTemporaryDialog( Speech& temporarySpeech )
- {
- m_temporarySpeeches.push_back(temporarySpeech);
- return &(m_temporarySpeeches.back());
- }
- //============================================================================
- // SpeechManager::getMasterAttribs
- //============================================================================
- struct AudioAttribs* SpeechManager::getMasterAttribs( void )
- {
- return m_masterAttribs;
- };
- //============================================================================
- // SpeechManager::getMasterFadeAttribs
- //============================================================================
- struct AudioAttribs* SpeechManager::getMasterFadeAttribs( void )
- {
- return m_masterFadeAttribs;
- };
- //============================================================================
- // SpeechManager::getMasterFadeAttribs
- //============================================================================
- void SpeechManager::addDialogEvent(const AudioEventRTS *eventRTS, Speech* speech, AudioEventRTS *returnEvent)
- {
- if (!eventRTS) {
- return;
- }
- Speech *useSpeech = speech;
- if (!useSpeech) {
- useSpeech = getSpeech(eventRTS->m_eventName.str());
- }
-
- if (!useSpeech) {
- return;
- }
-
- if (1 || (eventRTS->m_priorityBoost == 0 &&
- eventRTS->m_overrideLoopingBehavior == 0 &&
- eventRTS->m_timeOfDay == useSpeech->info.m_timeOfDay)) {
- // We can use the default sound, so no need to create and add a new one.
- say(useSpeech);
- if (returnEvent) {
- (*returnEvent) = (*eventRTS);
- (*returnEvent).m_speechToPlay = useSpeech;
- (*returnEvent).m_isCurrentlyPlaying = true;
- }
- return;
- }
- Speech tmpSpeech = (*useSpeech);
- tmpSpeech.info.m_priority += eventRTS->m_priorityBoost;
- // Can't go less than 0 priority or > NUM_DLG_PRIORITIES
- if (tmpSpeech.info.m_priority < 0) {
- tmpSpeech.info.m_priority = 0;
- } else if (tmpSpeech.info.m_priority > NUM_DLG_PRIORITIES) {
- tmpSpeech.info.m_priority = NUM_DLG_PRIORITIES;
- }
- tmpSpeech.info.m_timeOfDay = eventRTS->m_timeOfDay;
- #if 0
- // CRASHING BUG IN HERE. NEED TO FIX.
- Speech* playSpeech = addTemporaryDialog(tmpSpeech);
- if (returnEvent) {
- (*returnEvent) = (*eventRTS);
- returnEvent->m_speechToPlay = NULL;
- }
- say(playSpeech);
- #endif
- }
- //============================================================================
- // SpeechManager::removeDialogEvent
- //============================================================================
- void SpeechManager::removeDialogEvent(const AudioEventRTS *eventRTS, AudioEventRTS* eventToUse)
- {
- if (!eventRTS) {
- return;
- }
- Speech *useSpeech = eventRTS->m_speechToPlay;
- if (!useSpeech) {
- useSpeech = getSpeech(eventRTS->m_eventName.str());
- }
-
- if (!useSpeech) {
- return;
- }
- if (eventToUse) {
- (*eventToUse) = (*eventRTS);
- eventToUse->m_speechToPlay = useSpeech;
- }
- Bool isPlaying = true;
- LListNode *node = m_speakers.firstNode();
- while (node && isPlaying) {
- Speaker *pCurrSpeaker = (Speaker*) node->item();
- if (pCurrSpeaker->saying() == useSpeech || pCurrSpeaker->isGoingToSay(useSpeech)) {
- pCurrSpeaker->cancel(useSpeech);
- isPlaying = false;
- }
- }
-
- if (eventToUse) {
- (*eventToUse).m_isCurrentlyPlaying = isPlaying;
- }
- }
- //============================================================================
- // SpeechManager::getFilenameForPlayFromAudioEvent
- //============================================================================
- AsciiString SpeechManager::getFilenameForPlayFromAudioEvent( const AudioEventRTS *eventToGetFrom )
- {
- if (!eventToGetFrom) {
- return AsciiString::TheEmptyString;
- }
- if (eventToGetFrom->m_eventName.isEmpty()) {
- return AsciiString::TheEmptyString;
- }
- Speech* speech = getSpeech(eventToGetFrom->m_eventName.str());
- return getFilenameForPlay(speech);
- }
- //============================================================================
- // SpeechManager::getFilenameForPlay
- //============================================================================
- AsciiString SpeechManager::getFilenameForPlay( Speech *speech )
- {
- if (!speech) {
- return AsciiString::TheEmptyString;
- }
- SpeechInfo* speechInfo = getSpeechInfo(speech);
-
- if (!speechInfo) {
- return AsciiString::TheEmptyString;
- }
- Int regularSamples = speechInfo->m_dialogFiles.size();
- Int eveningSamples = speechInfo->m_dialogFilesEvening.size();
- Int morningSamples = speechInfo->m_dialogFilesMorning.size();
- Int nightSamples = speechInfo->m_dialogFilesNight.size();
- Int numSamples = regularSamples + eveningSamples + morningSamples + nightSamples;
-
- // using a random number generator, select a random sample from all the samples
- // that correspond to this sound name
- Int soundToPlay = GameClientRandomValue(0, numSamples - 1);
- char name[_MAX_PATH];
- if (soundToPlay < regularSamples) {
- strcpy(name, speechInfo->m_dialogFiles[soundToPlay].str());
- } else if (soundToPlay < (regularSamples + eveningSamples)) {
- strcpy(name, speechInfo->m_dialogFilesEvening[soundToPlay - regularSamples].str());
- } else if (soundToPlay < (regularSamples + eveningSamples + morningSamples)) {
- strcpy(name, speechInfo->m_dialogFilesMorning[soundToPlay - regularSamples - eveningSamples].str());
- } else if (soundToPlay < numSamples) {
- strcpy(name, speechInfo->m_dialogFilesNight[soundToPlay - regularSamples - eveningSamples - morningSamples].str());
- } else {
- return AsciiString::TheEmptyString;
- }
-
- // @todo this should all go into a function "generateLocalizedSoundName"
- Bool localized = FALSE;
- if ( name[0] == '$' )
- {
- localized = TRUE;
- char nameTemp[_MAX_PATH];
- strcpy(nameTemp, name + 1);
- strcpy(name, nameTemp);
- }
- if ( name[0] == 0 )
- {
- return NULL;
- }
- AsciiString path;
- char *localDir = "";
- if ( localized )
- {
- localDir = "english\\";
- }
- path.format( "data\\audio\\sounds\\%s%s.wav", localDir, name);
- return path;
- }
- //============================================================================
- //============================================================================
- //============================================================================
- // Speaker Code
- //============================================================================
- //============================================================================
- //============================================================================
- //============================================================================
- // Speaker::Speaker
- //============================================================================
- Speaker::Speaker()
- : m_delayTime(300),
- m_priority(0),
- m_currentSpeech(NULL),
- m_file(NULL),
- m_stream(NULL)
- {
- m_name.set("Unnamed");
- }
- //============================================================================
- // Speaker::~Speaker
- //============================================================================
- Speaker::~Speaker()
- {
- deinit();
- }
- //============================================================================
- // Speaker::init
- //============================================================================
- void Speaker::init( char *name, Int priority, Int btime, Int delay )
- {
- deinit();
- m_name.set( name );
- m_priority = priority;
- m_delayTime = delay;
- m_stream = AudioStreamerCreate( TheAudio->device(), btime );
- if ( m_stream )
- {
- AudioStreamerSetName ( m_stream, name );
- AudioStreamerSetAttribs ( m_stream, m_manager->getMasterAttribs());
- AudioStreamerSetFadeAttribs ( m_stream, m_manager->getMasterFadeAttribs() );
- AudioStreamerSetPriority ( m_stream, m_priority );
- }
- }
- //============================================================================
- // Speaker::deinit
- //============================================================================
- void Speaker::deinit( void )
- {
- stop();
- if ( m_stream != NULL )
- {
- AudioStreamerDestroy ( m_stream );
- m_stream = NULL;
- }
- }
- //============================================================================
- // Speaker::firstItem
- //============================================================================
- SpeechItem* Speaker::firstItem( TimeStamp now )
- {
- LListNode *node = m_pending.firstNode();
- SpeechItem *item = NULL;
- while ( node )
- {
- item = (SpeechItem*) node->item();
- if ( !now || !item->timeout || item->timeout >= now )
- {
- break;
- }
- // this dialog item has timed out so remove it
- node = item->nd.next();
- item->nd.remove();
- delete item;
- item = NULL;
- }
- return item;
- }
- //============================================================================
- // Speaker::nextItem
- //============================================================================
- SpeechItem* Speaker::nextItem ( SpeechItem *item, TimeStamp now )
- {
- LListNode *node = NULL;
- SpeechItem *next = NULL;
- if ( item )
- {
- node = item->nd.next();
- }
- while ( node )
- {
- next = (SpeechItem*) node->item();
- if ( !now || !next->timeout || next->timeout >= now )
- {
- break;
- }
- // this dialog item has timed out so remove it
- node = next->nd.next();
- next->nd.remove();
- delete next;
- next = NULL;
- }
- return next;
- }
- //============================================================================
- // Speaker::findItem
- //============================================================================
- SpeechItem* Speaker::findItem( Speech *speech )
- {
- TimeStamp now = AudioGetTime();
- SpeechItem *item = firstItem ( now );
- while ( item )
- {
- if ( item->speech == speech )
- {
- break;
- }
- item = nextItem( item, now );
- }
- return item;
- }
- //============================================================================
- // Speaker::flush
- //============================================================================
- void Speaker::flush( void )
- {
- SpeechItem *item;
- while ( ( item = firstItem()) != 0 )
- {
- item->nd.remove();
- delete item;
- }
- }
- //============================================================================
- // Speaker::destroy
- //============================================================================
- void Speaker::destroy( void )
- {
- if ( m_manager )
- {
- m_manager->removeSpeaker( this );
- }
- delete this;
- }
- //============================================================================
- // Speaker::say
- //============================================================================
- void Speaker::say ( char *speechName, Int priority, Int timeout, Int interrupt)
- {
- Speech *speech = TheAudio->Speeches->getSpeech( speechName );
- say( speech, priority, timeout, interrupt );
- }
- //============================================================================
- // Speaker::say
- //============================================================================
- void Speaker::say ( Speech *speech, Int priority, Int timeout, Int interrupt)
- {
-
- if ( speech == NULL || !m_stream || !speech->valid || !m_manager->isOn())
- {
- return;
- }
- if ( saying() == speech || isGoingToSay( speech ))
- {
- return ;
- }
- SpeechItem *item = NEW SpeechItem; // poolify
- if ( item == NULL )
- {
- return;
- }
- if ( timeout == 0 )
- {
- timeout = speech->timeout;
- }
- if ( priority == 0 )
- {
- priority = speech->priority;
- }
- if ( interrupt == 0 )
- {
- interrupt = speech->interrupt;
- }
- item->speech = speech;
- item->priority = priority;
- if ( m_paused )
- {
- item->flags = SpeechItem::Flags((Int)item->flags | (Int)SpeechItem::PAUSED);
- }
- if ( timeout )
- {
- item->timeout = m_paused ? MSECONDS(timeout) : AudioGetTime() + MSECONDS(timeout);
- }
- item->nd.setItem( item ) ;
- item->nd.setPriority( item->priority);
- m_pending.add( &item->nd );
- if ( interrupt && m_currentSpeech )
- {
- if ( m_currentSpeech->priority < item->priority )
- {
- AudioStreamerStop ( m_stream );
- m_delay = 0;
- }
- }
- }
- //============================================================================
- // Speaker::update
- //============================================================================
- void Speaker::update( void )
- {
- if ( m_stream == NULL )
- {
- stop();
- return;
- }
- if ( !AudioStreamerActive ( m_stream ))
- {
- if ( m_currentSpeech )
- {
- delete m_currentSpeech;
- m_currentSpeech = NULL;
- }
- }
- TimeStamp now = AudioGetTime();
- if ( !m_paused && m_currentSpeech == NULL && (AudioStreamerEndTimeStamp ( m_stream ) + m_delay) <= now )
- {
- SpeechItem *next = firstItem ( now );
- if ( next )
- {
- // ok we can start the next one
- next->nd.remove();
- m_currentSpeech = next;
- AudioStreamerSetMaxVolume ( m_stream, TheAudio->convertRealVolume(next->speech->volume) );
- AudioStreamerSetVolume ( m_stream, TheAudio->convertRealVolume(next->speech->volume) );
- AudioStreamerOpen( m_stream, getNextFilenameFromSpeech(next->speech).str());
- if (AudioStreamerStart( m_stream ) ) {
- m_delay = m_delayTime;
- }
- ///@todo write an INI compatible dialog player
- /*
- // REMOVE_GDF --> this must be converted to INI or something
- GDI_Asset *asset = TheGameData->openAsset( next->speech->handle );
-
- if( asset )
- {
- if ( (m_file = asset->open()))
- {
- if ( AudioStreamerOpen( m_stream, m_file ))
- {
- if ( AudioStreamerStart ( m_stream ) )
- {
- m_delay = m_delayTime;
- }
- }
- }
- asset->close();
- }
- */
- }
- }
- }
- //============================================================================
- // Speaker::setPriority
- //============================================================================
- void Speaker::setPriority ( Int priority )
- {
- m_priority = priority;
- if ( m_manager )
- {
- m_manager->removeSpeaker( this );
- m_manager->addSpeaker( this );
- }
- if ( m_stream )
- {
- AudioStreamerSetPriority( m_stream, priority );
- }
- }
- //============================================================================
- // Speaker::getPriority
- //============================================================================
- Int Speaker::getPriority ( void )
- {
- return m_priority;
- }
- //============================================================================
- // Speaker::setDelay
- //============================================================================
- void Speaker::setDelay ( Int delay )
- {
- m_delay = MSECONDS(delay);
- }
- //============================================================================
- // Speaker::getDelay
- //============================================================================
- Int Speaker::getDelay ( void )
- {
- return IN_MSECONDS(m_delay);
- }
- //============================================================================
- // Speaker::setBuffering
- //============================================================================
- void Speaker::setBuffering ( Int buffer_time )
- {
- DEBUG_ASSERTCRASH( FALSE, ("setBuffering not implemented"));
- }
- //===============================
- // Speaker::getBuffering
- //===============================
- Int Speaker::getBuffering ( void )
- {
- DEBUG_ASSERTCRASH( FALSE, ("setBuffering not implemented"));
- return 0;
- }
- //============================================================================
- // Speaker::pause
- //============================================================================
- void Speaker::pause ( void )
- {
- if ( !m_paused )
- {
- if ( m_stream )
- {
- AudioStreamerPause ( m_stream );
- }
- TimeStamp now = AudioGetTime();
- SpeechItem *item = firstItem( now );
- while ( item )
- {
- if ( !( item->flags & SpeechItem::PAUSED ))
- {
- item->flags = SpeechItem::Flags( (Int) item->flags | (Int) SpeechItem::PAUSED);
- if ( item->timeout )
- {
- item->timeout = item->timeout - now;
- }
- }
- item = nextItem ( item, now );
- }
- }
- m_paused++;
- }
- //============================================================================
- // Speaker::resume
- //============================================================================
- void Speaker::resume ( void )
- {
- if ( m_paused == 1 )
- {
- TimeStamp now = AudioGetTime();
- SpeechItem *item = firstItem ( now );
-
- while ( item )
- {
- if ( ( item->flags & SpeechItem::PAUSED ))
- {
- item->flags = SpeechItem::Flags( (Int) item->flags & ~((Int) SpeechItem::PAUSED));
- if ( item->timeout )
- {
- item->timeout = now + item->timeout;
- }
- }
- item = nextItem ( item, now );
- }
- if ( m_stream )
- {
- AudioStreamerResume ( m_stream );
- }
- }
- m_paused--;
- if ( m_paused < 0 )
- {
- m_paused = 0;
- }
- }
- //============================================================================
- // Speaker::stop
- //============================================================================
- void Speaker::stop ( void )
- {
- if ( m_stream )
- {
- AudioStreamerClose( m_stream );
- }
- if ( m_file )
- {
- m_file->close();
- m_file = NULL;
- }
- flush();
- if ( m_currentSpeech )
- {
- delete m_currentSpeech;
- m_currentSpeech = NULL;
- }
- }
- //============================================================================
- // Speaker::cancel
- //============================================================================
- void Speaker::cancel ( Speech *speech )
- {
- SpeechItem *item;
- while ( ( item = findItem ( speech )) != 0 )
- {
- item->nd.remove();
- delete item;
- }
- }
- //============================================================================
- // Speaker::hasSaid
- //============================================================================
- Bool Speaker::hasSaid ( Speech *speech )
- {
- return findItem ( speech ) == NULL && ( m_currentSpeech == NULL || m_currentSpeech->speech != speech);
- }
- //============================================================================
- // Speaker::isGoingToSay
- //============================================================================
- Bool Speaker::isGoingToSay ( Speech *speech )
- {
- return findItem ( speech ) != NULL;
- }
- //============================================================================
- // Speaker::isTalking
- //============================================================================
- Bool Speaker::isTalking ( void )
- {
- return m_currentSpeech != NULL;
- }
- //============================================================================
- // Speaker::saying
- //============================================================================
- Speech* Speaker::saying ( void )
- {
- if ( m_currentSpeech )
- {
- return m_currentSpeech->speech;
- }
- return NULL;
- }
- static void speechFromInfo(SpeechInfo *pInSpeechInfo, Speech *pOutSpeech)
- {
- if (!pInSpeechInfo || !pOutSpeech) {
- return;
- }
-
- // TBD: Do we need these fields:
- // index? info?
- pOutSpeech->name = pInSpeechInfo->m_dialogEvent;
- pOutSpeech->id = (ID) 1;
- pOutSpeech->volume = pInSpeechInfo->m_volume;
- pOutSpeech->timeout = 65000;
- pOutSpeech->interrupt = pInSpeechInfo->m_interruptable;
- pOutSpeech->valid = true;
- pOutSpeech->priority = pInSpeechInfo->m_priority;
-
- // Some housekeeping for pInSpeechInfo
- pInSpeechInfo->m_internalPlayCount = 0;
- pOutSpeech->info = *pInSpeechInfo;
-
- }
- static AsciiString getNextFilenameFromSpeech(Speech *pSpeechToPlay)
- {
- AsciiString returnString;
- if (!pSpeechToPlay) {
- return returnString;
- }
-
- ++pSpeechToPlay->info.m_internalPlayCount;
- Int indexToPlay = 0;
- if (pSpeechToPlay->info.m_sequentialStartIndex < 0) {
- indexToPlay = GameClientRandomValue(pSpeechToPlay->info.m_randomStartIndex,
- pSpeechToPlay->info.m_dialogFiles.size() - 1);
- }
- if (pSpeechToPlay->info.m_dialogFiles.size() > 0) {
- returnString = AsciiString(BASE_DLG_DIR);
- returnString.concat('\\');
- returnString.concat(pSpeechToPlay->info.m_dialogFiles[indexToPlay]);
- returnString.concat('.');
- returnString.concat(BASE_DLG_EXT);
- }
-
- return returnString;
- }
|