373 lines
15 KiB
C++
373 lines
15 KiB
C++
/*
|
|
** Command & Conquer Generals(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/>.
|
|
*/
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// (c) 2001-2003 Electronic Arts Inc. //
|
|
// //
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Westwood Studios Pacific.
|
|
//
|
|
// Confidential Information
|
|
// Copyright (C) 2001 - All Rights Reserved
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Project: RTS 3
|
|
//
|
|
// File name: Common/GameAudio.h
|
|
//
|
|
// Created: 5/01/01
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#pragma once
|
|
|
|
#ifndef __COMMON_GAMEAUDIO_H_
|
|
#define __COMMON_GAMEAUDIO_H_
|
|
|
|
// Includes
|
|
#include "Lib/BaseType.h"
|
|
#include "Common/STLTypedefs.h"
|
|
#include "Common/SubsystemInterface.h"
|
|
|
|
|
|
// Forward Declarations
|
|
|
|
class AsciiString;
|
|
class AudioEventRTS;
|
|
class DebugDisplayInterface;
|
|
class Drawable;
|
|
class MusicManager;
|
|
class Object;
|
|
class SoundManager;
|
|
|
|
|
|
enum AudioAffect;
|
|
enum AudioType;
|
|
|
|
struct AudioEventInfo;
|
|
struct AudioRequest;
|
|
struct AudioSettings;
|
|
struct MiscAudio;
|
|
|
|
typedef std::hash_map<AsciiString, AudioEventInfo*, rts::hash<AsciiString>, rts::equal_to<AsciiString> > AudioEventInfoHash;
|
|
typedef AudioEventInfoHash::iterator AudioEventInfoHashIt;
|
|
typedef UnsignedInt AudioHandle;
|
|
|
|
|
|
// Defines
|
|
enum
|
|
{
|
|
PROVIDER_ERROR = 0xFFFFFFFF
|
|
};
|
|
|
|
// Class AudioManager
|
|
/**
|
|
The life of audio.
|
|
|
|
When audio is requested to play, it is done so in the following manner:
|
|
1) An AudioEventRTS is created on the stack.
|
|
2) Its guts are copied from elsewhere (for instance, a ThingTemplate, or MiscAudio).
|
|
3) It is added to TheAudio via TheAudio->addAudioEvent(...)
|
|
|
|
The return value from addAudioEvent can be saved in case the sound needs to loop and/or be
|
|
terminated at some point.
|
|
|
|
To reomve a playing sound, the call TheAudio->removeAudioEvent(...) is used. This will search
|
|
the list of currently playing audio for the specified handle, and kill the attached sound. It
|
|
will play a decay sound, if one is specified.
|
|
|
|
The important functions of TheAudio, are therefore
|
|
GameAudio::addAudioEvent()
|
|
GameAudio::removeAudioEvent()
|
|
All other functions exist to support these two basic requirements.
|
|
|
|
In addition to the fundamental requirements, the audio has a fairly complicated sound management
|
|
scheme. If all units were always allowed to sound off, the sound engine would be overwhelmed and
|
|
would sound awful. Therefore, when an audio event is requested, it goes through a series of
|
|
checks to determine if it is near enough to the camera, if it should be heard based on shroud,
|
|
local player affiliation, etc. (The entire list of checks is contained in shouldPlayLocally()).
|
|
|
|
In addition, the world and unit audio are never allowed to exceed their footprint, as specified
|
|
in the audio settings INI file. In order to accomodate this, the audio uses an audio cache. The
|
|
audio cache will attempt to load a sample, assuming there is enough room. If there is not enough
|
|
room, then it goes through and finds any samples that are lower priority, and kills them until
|
|
enough room is present for the sample. If it cannot free enough room, nothing happens to the
|
|
cache.
|
|
|
|
Although the audio is multithreaded, most of the operations are performed such that the worst
|
|
case scenario for thread miscommunication is that the main thread misses an event for one frame.
|
|
One specific case of this is the status of playing audio. Because audio is playing
|
|
asynchronously, it can complete at any time. When most audio completes, it sets a flag on the
|
|
event noting that it has completed. During the next update (from the main thread), anything with
|
|
that flag set is moved to the stopped list, and then is cleaned up. (Basically, the audio uses
|
|
a push model for its multithreadedness, which doesn't require thread safety such as mutexes or
|
|
semaphores).
|
|
|
|
All in all, the best way to learn how the audio works is to track the lifetime of an event
|
|
through the system. This will give a better understanding than all the documentation I could
|
|
write.
|
|
|
|
-jkmcd
|
|
-December 2002
|
|
*/
|
|
|
|
class AudioManager : public SubsystemInterface
|
|
{
|
|
public:
|
|
AudioManager();
|
|
virtual ~AudioManager();
|
|
#if defined(_DEBUG) || defined(_INTERNAL)
|
|
virtual void audioDebugDisplay(DebugDisplayInterface *dd, void *userData, FILE *fp = NULL ) = 0;
|
|
#endif
|
|
|
|
// From SubsystemInterface
|
|
virtual void init();
|
|
virtual void postProcessLoad();
|
|
virtual void reset();
|
|
virtual void update();
|
|
|
|
// device dependent stop, pause and resume
|
|
virtual void stopAudio( AudioAffect which ) = 0;
|
|
virtual void pauseAudio( AudioAffect which ) = 0;
|
|
virtual void resumeAudio( AudioAffect which ) = 0;
|
|
virtual void pauseAmbient( Bool shouldPause ) = 0;
|
|
|
|
// device dependent stops.
|
|
virtual void stopAllAmbientsBy( Object* obj ) = 0;
|
|
virtual void stopAllAmbientsBy( Drawable* draw ) = 0;
|
|
|
|
// for focus issues
|
|
virtual void loseFocus( void );
|
|
virtual void regainFocus( void );
|
|
|
|
// control for AudioEventsRTS
|
|
virtual AudioHandle addAudioEvent( const AudioEventRTS *eventToAdd ); ///< Add an audio event (event must be declared in an INI file)
|
|
virtual void removeAudioEvent( AudioHandle audioEvent ); ///< Remove an audio event, stop for instance.
|
|
virtual void killAudioEventImmediately( AudioHandle audioEvent ) = 0;
|
|
|
|
virtual Bool isValidAudioEvent( const AudioEventRTS *eventToCheck ) const; ///< validate that this piece of audio exists
|
|
virtual Bool isValidAudioEvent( AudioEventRTS *eventToCheck ) const; ///< validate that this piece of audio exists
|
|
|
|
// add tracks during INIification
|
|
void addTrackName( const AsciiString& trackName );
|
|
AsciiString nextTrackName(const AsciiString& currentTrack );
|
|
AsciiString prevTrackName(const AsciiString& currentTrack );
|
|
|
|
// changing music tracks
|
|
virtual void nextMusicTrack( void ) = 0;
|
|
virtual void prevMusicTrack( void ) = 0;
|
|
virtual Bool isMusicPlaying( void ) const = 0;
|
|
virtual Bool hasMusicTrackCompleted( const AsciiString& trackName, Int numberOfTimes ) const = 0;
|
|
virtual AsciiString getMusicTrackName( void ) const = 0;
|
|
|
|
virtual void setAudioEventEnabled( AsciiString eventToAffect, Bool enable );
|
|
virtual void setAudioEventVolumeOverride( AsciiString eventToAffect, Real newVolume );
|
|
virtual void removeAudioEvent( AsciiString eventToRemove );
|
|
virtual void removeDisabledEvents();
|
|
|
|
// Really meant for internal purposes only, but cannot be protected.
|
|
virtual void getInfoForAudioEvent( const AudioEventRTS *eventToFindAndFill ) const; // Note: m_eventInfo is Mutable, and so this function will overwrite it if found
|
|
|
|
///< Return whether the current audio is playing or not.
|
|
///< NOTE NOTE NOTE !!DO NOT USE THIS IN FOR GAMELOGIC PURPOSES!! NOTE NOTE NOTE
|
|
virtual Bool isCurrentlyPlaying( AudioHandle handle );
|
|
|
|
// Device Dependent open and close functions
|
|
virtual void openDevice( void ) = 0;
|
|
virtual void closeDevice( void ) = 0;
|
|
virtual void *getDevice( void ) = 0;
|
|
|
|
// Debice Dependent notification functions
|
|
virtual void notifyOfAudioCompletion( UnsignedInt audioCompleted, UnsignedInt flags ) = 0;
|
|
|
|
// Device Dependent enumerate providers functions. It is okay for there to be only 1 provider (Miles provides a maximum of 64.
|
|
virtual UnsignedInt getProviderCount( void ) const = 0;
|
|
virtual AsciiString getProviderName( UnsignedInt providerNum ) const = 0;
|
|
virtual UnsignedInt getProviderIndex( AsciiString providerName ) const = 0;
|
|
virtual void selectProvider( UnsignedInt providerNdx ) = 0;
|
|
virtual void unselectProvider( void ) = 0;
|
|
virtual UnsignedInt getSelectedProvider( void ) const = 0;
|
|
virtual void setSpeakerType( UnsignedInt speakerType ) = 0;
|
|
virtual UnsignedInt getSpeakerType( void ) = 0;
|
|
|
|
virtual UnsignedInt translateSpeakerTypeToUnsignedInt( const AsciiString& speakerType );
|
|
virtual AsciiString translateUnsignedIntToSpeakerType( UnsignedInt speakerType );
|
|
|
|
// Device Dependent calls to get the number of channels for each type of audio (2-D, 3-D, Streams)
|
|
virtual UnsignedInt getNum2DSamples( void ) const = 0;
|
|
virtual UnsignedInt getNum3DSamples( void ) const = 0;
|
|
virtual UnsignedInt getNumStreams( void ) const = 0;
|
|
|
|
// Device Dependent calls to determine sound prioritization info
|
|
virtual Bool doesViolateLimit( AudioEventRTS *event ) const = 0;
|
|
virtual Bool isPlayingLowerPriority( AudioEventRTS *event ) const = 0;
|
|
virtual Bool isPlayingAlready( AudioEventRTS *event ) const = 0;
|
|
virtual Bool isObjectPlayingVoice( UnsignedInt objID ) const = 0;
|
|
|
|
virtual void adjustVolumeOfPlayingAudio(AsciiString eventName, Real newVolume) = 0;
|
|
virtual void removePlayingAudio( AsciiString eventName ) = 0;
|
|
virtual void removeAllDisabledAudio() = 0;
|
|
|
|
// Is the audio device on? We can skip a lot of audio processing if not.
|
|
virtual Bool isOn( AudioAffect whichToGet ) const;
|
|
virtual void setOn( Bool turnOn, AudioAffect whichToAffect );
|
|
|
|
// Set and get the device Volume
|
|
virtual void setVolume( Real volume, AudioAffect whichToAffect );
|
|
virtual Real getVolume( AudioAffect whichToGet );
|
|
|
|
// To get a more 3-D feeling from the universe, we adjust the volume of the 3-D samples based
|
|
// on zoom.
|
|
virtual void set3DVolumeAdjustment( Real volumeAdjustment );
|
|
|
|
virtual void *getHandleForBink( void ) = 0;
|
|
virtual void releaseHandleForBink( void ) = 0;
|
|
|
|
// this function will play an audio event rts by loading it into memory. It should not be used
|
|
// by anything except for the load screens.
|
|
virtual void friend_forcePlayAudioEventRTS(const AudioEventRTS* eventToPlay) = 0;
|
|
|
|
// Update Listener position information
|
|
virtual void setListenerPosition( const Coord3D *newListenerPos, const Coord3D *newListenerOrientation );
|
|
virtual const Coord3D *getListenerPosition( void ) const;
|
|
|
|
virtual AudioRequest *allocateAudioRequest( Bool useAudioEvent );
|
|
virtual void releaseAudioRequest( AudioRequest *requestToRelease );
|
|
virtual void appendAudioRequest( AudioRequest *m_request );
|
|
virtual void processRequestList( void );
|
|
|
|
virtual AudioEventInfo *newAudioEventInfo( AsciiString newEventName );
|
|
virtual AudioEventInfo *findAudioEventInfo( AsciiString eventName ) const;
|
|
|
|
const AudioSettings *getAudioSettings( void ) const;
|
|
const MiscAudio *getMiscAudio( void ) const;
|
|
|
|
// This function should only be called by AudioManager, MusicManager and SoundManager
|
|
virtual void releaseAudioEventRTS( AudioEventRTS *eventToRelease );
|
|
|
|
// For INI
|
|
AudioSettings *friend_getAudioSettings( void );
|
|
MiscAudio *friend_getMiscAudio( void );
|
|
const FieldParse *getFieldParseTable( void ) const;
|
|
|
|
const AudioEventRTS *getValidSilentAudioEvent() const { return m_silentAudioEvent; }
|
|
|
|
virtual void setHardwareAccelerated(Bool accel) { m_hardwareAccel = accel; }
|
|
virtual Bool getHardwareAccelerated() { return m_hardwareAccel; }
|
|
|
|
virtual void setSpeakerSurround(Bool surround) { m_surroundSpeakers = surround; }
|
|
virtual Bool getSpeakerSurround() { return m_surroundSpeakers; }
|
|
|
|
virtual void refreshCachedVariables();
|
|
|
|
virtual void setPreferredProvider(AsciiString providerNdx) = 0;
|
|
virtual void setPreferredSpeaker(AsciiString speakerType) = 0;
|
|
|
|
// For Scripting
|
|
virtual Real getAudioLengthMS( const AudioEventRTS *event );
|
|
virtual Real getFileLengthMS( AsciiString strToLoad ) const = 0;
|
|
|
|
// For the file cache to know when to remove files.
|
|
virtual void closeAnySamplesUsingFile( const void *fileToClose ) = 0;
|
|
|
|
virtual Bool isMusicAlreadyLoaded(void) const;
|
|
virtual Bool isMusicPlayingFromCD(void) const { return m_musicPlayingFromCD; }
|
|
|
|
Bool getDisallowSpeech( void ) const { return m_disallowSpeech; }
|
|
void setDisallowSpeech( Bool disallowSpeech ) { m_disallowSpeech = disallowSpeech; }
|
|
|
|
// For Worldbuilder, to build lists from which to select
|
|
virtual void findAllAudioEventsOfType( AudioType audioType, std::vector<AudioEventInfo*>& allEvents );
|
|
|
|
Real getZoomVolume() const { return m_zoomVolume; }
|
|
protected:
|
|
|
|
// Is the currently selected provider actually HW accelerated?
|
|
virtual Bool isCurrentProviderHardwareAccelerated();
|
|
|
|
// Is the currently selected speaker type Surround sound?
|
|
virtual Bool isCurrentSpeakerTypeSurroundSound();
|
|
|
|
// Should this piece of audio play on the local machine?
|
|
virtual Bool shouldPlayLocally(const AudioEventRTS *audioEvent);
|
|
|
|
// Set the Listening position for the device
|
|
virtual void setDeviceListenerPosition( void ) = 0;
|
|
|
|
// For tracking purposes
|
|
virtual AudioHandle allocateNewHandle( void );
|
|
|
|
protected:
|
|
AudioSettings *m_audioSettings;
|
|
MiscAudio *m_miscAudio;
|
|
MusicManager *m_music;
|
|
SoundManager *m_sound;
|
|
Coord3D m_listenerPosition;
|
|
Coord3D m_listenerOrientation;
|
|
std::list<AudioRequest*> m_audioRequests;
|
|
std::vector<AsciiString> m_musicTracks;
|
|
|
|
AudioEventInfoHash m_allAudioEventInfo;
|
|
AudioHandle theAudioHandlePool;
|
|
std::list<std::pair<AsciiString, Real> > m_adjustedVolumes;
|
|
|
|
Real m_musicVolume;
|
|
Real m_soundVolume;
|
|
Real m_sound3DVolume;
|
|
Real m_speechVolume;
|
|
|
|
Real m_scriptMusicVolume;
|
|
Real m_scriptSoundVolume;
|
|
Real m_scriptSound3DVolume;
|
|
Real m_scriptSpeechVolume;
|
|
|
|
Real m_systemMusicVolume;
|
|
Real m_systemSoundVolume;
|
|
Real m_systemSound3DVolume;
|
|
Real m_systemSpeechVolume;
|
|
Real m_zoomVolume;
|
|
|
|
|
|
AudioEventRTS *m_silentAudioEvent;
|
|
|
|
enum { NUM_VOLUME_TYPES = 4 };
|
|
Real *m_savedValues;
|
|
|
|
// Group of 8
|
|
Bool m_speechOn : 1;
|
|
Bool m_soundOn : 1;
|
|
Bool m_sound3DOn : 1;
|
|
Bool m_musicOn : 1;
|
|
Bool m_volumeHasChanged : 1;
|
|
Bool m_hardwareAccel : 1;
|
|
Bool m_surroundSpeakers : 1;
|
|
Bool m_musicPlayingFromCD : 1;
|
|
|
|
// Next 8
|
|
Bool m_disallowSpeech : 1;
|
|
};
|
|
|
|
extern AudioManager *TheAudio;
|
|
|
|
#endif // __COMMON_GAMEAUDIO_H_
|