Browse Source

Merge branch 'ticket/38'

closes #38
tickets/38/38/2
rarified 2 years ago
parent
commit
1a930cb47f
  1. 2
      Build/VS2010/Plasma/PubUtilLib/plAudioCore/plAudioCore.vcxproj
  2. 6
      Build/VS2010/Plasma/PubUtilLib/plAudioCore/plAudioCore.vcxproj.filters
  3. 1
      Build/VS2010/Plasma/PubUtilLib/plMessage/plMessage.vcxproj
  4. 3
      Build/VS2010/Plasma/PubUtilLib/plMessage/plMessage.vcxproj.filters
  5. 1
      Sources/Plasma/Apps/plClient/plClient.cpp
  6. 5
      Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp
  7. 34
      Sources/Plasma/FeatureLib/pfPython/plPythonFileMod.cpp
  8. 1
      Sources/Plasma/FeatureLib/pfPython/plPythonFileMod.h
  9. 16
      Sources/Plasma/FeatureLib/pfPython/pyAudioControl.cpp
  10. 5
      Sources/Plasma/FeatureLib/pfPython/pyAudioControl.h
  11. 11
      Sources/Plasma/FeatureLib/pfPython/pyAudioControlGlue.cpp
  12. 80
      Sources/Plasma/NucleusLib/inc/plCreatableIndex.h
  13. 2
      Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.h
  14. 6
      Sources/Plasma/PubUtilLib/plAudio/plAudioSystem.cpp
  15. 3
      Sources/Plasma/PubUtilLib/plAudio/plAudioSystem.h
  16. 4
      Sources/Plasma/PubUtilLib/plAudio/plDSoundBuffer.cpp
  17. 30
      Sources/Plasma/PubUtilLib/plAudio/plWin32Sound.cpp
  18. 17
      Sources/Plasma/PubUtilLib/plAudio/plWin32StreamingSound.cpp
  19. 28
      Sources/Plasma/PubUtilLib/plAudioCore/plSoundBuffer.cpp
  20. 6
      Sources/Plasma/PubUtilLib/plAudioCore/plSoundBuffer.h
  21. 187
      Sources/Plasma/PubUtilLib/plAudioCore/plSrtFileReader.cpp
  22. 107
      Sources/Plasma/PubUtilLib/plAudioCore/plSrtFileReader.h
  23. 4
      Sources/Plasma/PubUtilLib/plMessage/plMessageCreatable.h
  24. 82
      Sources/Plasma/PubUtilLib/plMessage/plSubtitleMsg.h

2
Build/VS2010/Plasma/PubUtilLib/plAudioCore/plAudioCore.vcxproj

@ -244,6 +244,7 @@
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release_Internal|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSrtFileReader.cpp" />
<ClCompile Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plOGGCodec.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug_Internal|Win32'">Disabled</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
@ -315,6 +316,7 @@
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plAudioFileReader.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plBufferedFileReader.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plFastWavReader.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSrtFileReader.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plOGGCodec.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSoundBuffer.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSoundDeswizzler.h" />

6
Build/VS2010/Plasma/PubUtilLib/plAudioCore/plAudioCore.vcxproj.filters

@ -32,6 +32,9 @@
<ClCompile Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plWavFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSrtFileReader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plAudioCore.h">
@ -61,5 +64,8 @@
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plWavFile.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSrtFileReader.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

1
Build/VS2010/Plasma/PubUtilLib/plMessage/plMessage.vcxproj

@ -817,6 +817,7 @@
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSimStateMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSpawnModMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSpawnRequestMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSubtitleMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSwimMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSynchEnableMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plTimerCallbackMsg.h" />

3
Build/VS2010/Plasma/PubUtilLib/plMessage/plMessage.vcxproj.filters

@ -361,5 +361,8 @@
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plVaultNotifyMsg.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSubtitleMsg.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

1
Sources/Plasma/Apps/plClient/plClient.cpp

@ -2313,6 +2313,7 @@ void plClient::IDetectAudioVideoSettings()
WriteInt(stream, "Audio.SetChannelVolume Ambience", 1);
WriteInt(stream, "Audio.SetChannelVolume NPCVoice", 1);
WriteInt(stream, "Audio.EnableVoiceRecording", 1);
WriteInt(stream, "Audio.EnableSubtitles", false);
WriteString(stream, "Audio.SetDeviceName", deviceName );
stream->Close();
delete stream;

5
Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp

@ -3391,6 +3391,11 @@ PF_CONSOLE_CMD( Audio, MuteAll, "bool on", "Mute or unmute all sounds")
plgAudioSys::SetMuted( (bool)params[ 0 ] );
}
PF_CONSOLE_CMD(Audio, EnableSubtitles, "bool on", "Enable or disable displaying subtitles for audio files containing speech")
{
plgAudioSys::SetEnableSubtitles((bool)params[0]);
}
PF_CONSOLE_CMD( Audio, SetDistanceModel, "int type", "Sets the distance model for all 3d sounds")
{
if(plgAudioSys::Sys())

34
Sources/Plasma/FeatureLib/pfPython/plPythonFileMod.cpp

@ -94,6 +94,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "../pfGameMgr/pfGameMgr.h"
#include "../plMessage/plAIMsg.h"
#include "../plAvatar/plAvBrainCritter.h"
#include "../plMessage/plSubtitleMsg.h"
#include "plProfile.h"
@ -189,6 +190,7 @@ char* plPythonFileMod::fFunctionNames[] =
{ "OnGameMgrMsg" }, // kfunc_OnGameMgrMsg
{ "OnGameCliMsg" }, // kfunc_OnGameCliMsg
{ "OnAIMsg" }, // kfunc_OnAIMsg
{ "OnSubtitleMsg" }, // kfunc_OnSubtitleMsg
{ nil }
};
@ -828,6 +830,8 @@ void plPythonFileMod::AddTarget(plSceneObject* sobj)
// the message that is spammed to anyone who will listen
plgDispatch::Dispatch()->RegisterForExactType(plAIBrainCreatedMsg::Index(), GetKey());
}
if (fPyFunctionInstances[kfunc_OnSubtitleMsg])
plgDispatch::Dispatch()->RegisterForExactType(plSubtitleMsg::Index(), GetKey());
// As the last thing... call the OnInit function if they have one
if ( fPyFunctionInstances[kfunc_Init] != nil )
@ -2780,6 +2784,36 @@ hsBool plPythonFileMod::MsgReceive(plMessage* msg)
}
}
if (fPyFunctionInstances[kfunc_OnSubtitleMsg])
{
plSubtitleMsg* pSubMsg = plSubtitleMsg::ConvertNoRef(msg);
if (pSubMsg)
{
plProfile_BeginTiming(PythonUpdate);
PyObject* retVal = PyObject_CallMethod(
fPyFunctionInstances[kfunc_OnSubtitleMsg], fFunctionNames[kfunc_OnSubtitleMsg],
"ss", pSubMsg->GetText().c_str(), pSubMsg->GetSpeaker().c_str());
if (retVal == nil)
{
#ifndef PLASMA_EXTERNAL_RELEASE
// for some reason this function didn't, remember that and not call it again
fPyFunctionInstances[kfunc_OnSubtitleMsg] = nil;
#endif //PLASMA_EXTERNAL_RELEASE
// if there was an error make sure that the stderr gets flushed so it can be seen
ReportError();
}
Py_XDECREF(retVal);
plProfile_EndTiming(PythonUpdate);
// display any output (NOTE: this would be disabled in production)
DisplayPythonOutput();
// we handled this message (I think)
return true;
}
}
return plModifier::MsgReceive(msg);
}

1
Sources/Plasma/FeatureLib/pfPython/plPythonFileMod.h

@ -202,6 +202,7 @@ public:
kfunc_OnGameMgrMsg,
kfunc_OnGameCliMsg,
kfunc_OnAIMsg,
kfunc_OnSubtitleMsg,
kfunc_lastone
};
// array of matching Python instance where the functions are, if defined

16
Sources/Plasma/FeatureLib/pfPython/pyAudioControl.cpp

@ -256,6 +256,22 @@ hsBool pyAudioControl::IsMuted()
return plgAudioSys::IsMuted();
}
// Enable or disable displaying speech subtitles
void pyAudioControl::EnableSubtitles()
{
plgAudioSys::SetEnableSubtitles(true);
}
void pyAudioControl::DisableSubtitles()
{
plgAudioSys::SetEnableSubtitles(false);
}
bool pyAudioControl::AreSubtitlesEnabled() const
{
return plgAudioSys::AreSubtitlesEnabled();
}
hsBool pyAudioControl::SupportEAX(const char *deviceName)
{
return plgAudioSys::SupportsEAX(deviceName);

5
Sources/Plasma/FeatureLib/pfPython/pyAudioControl.h

@ -109,6 +109,11 @@ public:
virtual void UnmuteAll();
virtual hsBool IsMuted();
// Enable or disable displaying speech subtitles
void EnableSubtitles();
void DisableSubtitles();
bool AreSubtitlesEnabled() const;
virtual void SetAudioSystemMode(int mode); // sets the current mode
virtual int GetAudioSystemMode(); // returns the current mode
virtual int GetHighestAudioMode(); // returns the highest mode the card is capable of handling

11
Sources/Plasma/FeatureLib/pfPython/pyAudioControlGlue.cpp

@ -242,6 +242,14 @@ PYTHON_METHOD_DEFINITION_NOARGS(ptAudioControl, isMuted)
PYTHON_RETURN_BOOL(self->fThis->IsMuted());
}
PYTHON_BASIC_METHOD_DEFINITION(ptAudioControl, enableSubtitles, EnableSubtitles)
PYTHON_BASIC_METHOD_DEFINITION(ptAudioControl, disableSubtitles, DisableSubtitles)
PYTHON_METHOD_DEFINITION_NOARGS(ptAudioControl, areSubtitlesEnabled)
{
PYTHON_RETURN_BOOL(self->fThis->AreSubtitlesEnabled());
}
PYTHON_METHOD_DEFINITION_NOARGS(ptAudioControl, canSetMicLevel)
{
PYTHON_RETURN_BOOL(self->fThis->CanSetMicLevel());
@ -484,6 +492,9 @@ PYTHON_START_METHODS_TABLE(ptAudioControl)
PYTHON_BASIC_METHOD(ptAudioControl, muteAll, "Mutes all sounds."),
PYTHON_BASIC_METHOD(ptAudioControl, unmuteAll, "Unmutes all sounds."),
PYTHON_METHOD_NOARGS(ptAudioControl, isMuted, "Are all sounds muted? Returns 1 if true otherwise returns 0."),
PYTHON_BASIC_METHOD(ptAudioControl, enableSubtitles, "Enables audio subtitles."),
PYTHON_BASIC_METHOD(ptAudioControl, disableSubtitles, "Disables audio subtitles."),
PYTHON_METHOD_NOARGS(ptAudioControl, areSubtitlesEnabled, "Are audio subtitles enabled? Returns 1 if true otherwise returns 0."),
PYTHON_METHOD_NOARGS(ptAudioControl, canSetMicLevel, "Can the microphone level be set? Returns 1 if true otherwise returns 0."),
PYTHON_METHOD(ptAudioControl, setMicLevel, "Params: level\nSets the microphone recording level (0.0 to 1.0)."),
PYTHON_METHOD_NOARGS(ptAudioControl, getMicLevel, "Returns the microphone recording level (0.0 to 1.0)."),

80
Sources/Plasma/NucleusLib/inc/plCreatableIndex.h

@ -34,9 +34,9 @@ work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
@ -46,19 +46,19 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plClassIndexMacros.h" // for CLASS_INDEX macro defn
CLASS_INDEX_LIST_START
//---------------------------------------------------------------------
//---------------------------------------------------------------------
// hsKeyedObjects should appear in the first section of the enum list
// And everything else in the next section
// Otherwise you will get an Assert
//---------------------------------------------------------------------
//---------------------------------------------------------------------
CLASS_INDEX(plSceneNode),
CLASS_INDEX(plSceneObject),
CLASS_INDEX(plSceneObject),
CLASS_INDEX(hsKeyedObject),
CLASS_INDEX(plBitmap),
CLASS_INDEX(plMipmap),
CLASS_INDEX(plCubicEnvironmap),
CLASS_INDEX(plLayer),
CLASS_INDEX(hsGMaterial),
CLASS_INDEX(plLayer),
CLASS_INDEX(hsGMaterial),
CLASS_INDEX(plParticleSystem),
CLASS_INDEX(plParticleEffect),
CLASS_INDEX(plParticleCollisionEffectBeat),
@ -74,7 +74,7 @@ CLASS_INDEX_LIST_START
CLASS_INDEX(plWinAudible),
CLASS_INDEX(plCoordinateInterface),
CLASS_INDEX(plDrawInterface),
CLASS_INDEX(plDrawable),
CLASS_INDEX(plDrawable),
CLASS_INDEX(plDrawableMesh),
CLASS_INDEX(plDrawableIce),
CLASS_INDEX(plPhysical),
@ -131,7 +131,7 @@ CLASS_INDEX_LIST_START
CLASS_INDEX(UNUSED_plDrawablePatchSet),
CLASS_INDEX(plInputManager),
CLASS_INDEX(plLogicModBase),
CLASS_INDEX(plFogEnvironment),
CLASS_INDEX(plFogEnvironment),
CLASS_INDEX(plNetApp),
CLASS_INDEX(plNetClientMgr),
CLASS_INDEX(pl2WayWinAudible),
@ -243,7 +243,7 @@ CLASS_INDEX_LIST_START
CLASS_INDEX(pfGUIDynDisplayCtrl),
CLASS_INDEX(UNUSED_plLayerProject),
CLASS_INDEX(plInputInterfaceMgr),
CLASS_INDEX(plRailCameraMod),
CLASS_INDEX(plRailCameraMod),
CLASS_INDEX(plMultistageBehMod),
CLASS_INDEX(plCameraBrain1_Circle),
CLASS_INDEX(plParticleWindEffect),
@ -368,14 +368,15 @@ CLASS_INDEX_LIST_START
CLASS_INDEX(plRidingAnimatedPhysicalDetector),
CLASS_INDEX(plVolumeSensorConditionalObjectNoArbitration),
CLASS_INDEX(plPXSubWorld),
//---------------------------------------------------------
// Keyed objects above this line, unkeyed (such as messages) below..
//---------------------------------------------------------
CLASS_INDEX(pfConfirmationMgr),
//---------------------------------------------------------
// Keyed objects above this line, unkeyed (such as messages) below..
//---------------------------------------------------------
CLASS_INDEX_NONKEYED_OBJ_START
CLASS_INDEX(plObjRefMsg),
CLASS_INDEX(plObjRefMsg),
CLASS_INDEX(plNodeRefMsg),
CLASS_INDEX(plMessage),
CLASS_INDEX(plMessage),
CLASS_INDEX(plRefMsg),
CLASS_INDEX(plGenRefMsg),
CLASS_INDEX(plTimeMsg),
@ -411,12 +412,12 @@ CLASS_INDEX_LIST_START
CLASS_INDEX(hsSfxObjDistFade),
CLASS_INDEX(hsSfxObjDistShade),
CLASS_INDEX(hsDynamicValue),
CLASS_INDEX(hsDynamicScalar),
CLASS_INDEX(hsDynamicScalar),
CLASS_INDEX(hsDynamicColorRGBA),
CLASS_INDEX(hsDynamicMatrix33),
CLASS_INDEX(hsDynamicMatrix44),
CLASS_INDEX(plOmniSqApplicator),
CLASS_INDEX(plPreResourceMsg),
CLASS_INDEX(plPreResourceMsg),
CLASS_INDEX(UNUSED_hsDynamicColorRGBA),
CLASS_INDEX(UNUSED_hsDynamicMatrix33),
CLASS_INDEX(UNUSED_hsDynamicMatrix44),
@ -427,7 +428,7 @@ CLASS_INDEX_LIST_START
CLASS_INDEX(UNUSED_plPosController),
CLASS_INDEX(UNUSED_plScalarController),
CLASS_INDEX(UNUSED_plPoint3Controller),
CLASS_INDEX(UNUSED_plScaleValueController),
CLASS_INDEX(UNUSED_plScaleValueController),
CLASS_INDEX(UNUSED_plQuatController),
CLASS_INDEX(UNUSED_plMatrix33Controller),
CLASS_INDEX(UNUSED_plMatrix44Controller),
@ -437,7 +438,7 @@ CLASS_INDEX_LIST_START
CLASS_INDEX(plCompoundRotController),
CLASS_INDEX(UNUSED_plSimplePosController),
CLASS_INDEX(plCompoundPosController),
CLASS_INDEX(plTMController),
CLASS_INDEX(plTMController),
CLASS_INDEX(hsFogControl),
CLASS_INDEX(plIntRefMsg),
CLASS_INDEX(plCollisionReactor),
@ -577,8 +578,8 @@ CLASS_INDEX_LIST_START
CLASS_INDEX(plNetServerMsgPing),
CLASS_INDEX(plNetMsgAlive),
CLASS_INDEX(plNetMsgTerminated),
CLASS_INDEX(plSDLModifierMsg),
CLASS_INDEX(plNetMsgSDLState),
CLASS_INDEX(plSDLModifierMsg),
CLASS_INDEX(plNetMsgSDLState),
CLASS_INDEX(plNetServerMsgSessionReset),
CLASS_INDEX(plCCRBanLinkingMsg),
CLASS_INDEX(plCCRSilencePlayerMsg),
@ -780,17 +781,17 @@ CLASS_INDEX_LIST_START
CLASS_INDEX(plShadowCastMsg),
CLASS_INDEX(plBoundsIsect),
CLASS_INDEX(plResMgrHelperMsg),
CLASS_INDEX(plNetCommAuthMsg),
CLASS_INDEX(plNetCommFileListMsg),
CLASS_INDEX(plNetCommFileDownloadMsg),
CLASS_INDEX(plNetCommLinkToAgeMsg),
CLASS_INDEX(plNetCommPlayerListMsg),
CLASS_INDEX(plNetCommActivePlayerMsg),
CLASS_INDEX(plNetCommCreatePlayerMsg),
CLASS_INDEX(plNetCommDeletePlayerMsg),
CLASS_INDEX(plNetCommPublicAgeListMsg),
CLASS_INDEX(plNetCommPublicAgeMsg),
CLASS_INDEX(plNetCommRegisterAgeMsg),
CLASS_INDEX(plNetCommAuthMsg),
CLASS_INDEX(plNetCommFileListMsg),
CLASS_INDEX(plNetCommFileDownloadMsg),
CLASS_INDEX(plNetCommLinkToAgeMsg),
CLASS_INDEX(plNetCommPlayerListMsg),
CLASS_INDEX(plNetCommActivePlayerMsg),
CLASS_INDEX(plNetCommCreatePlayerMsg),
CLASS_INDEX(plNetCommDeletePlayerMsg),
CLASS_INDEX(plNetCommPublicAgeListMsg),
CLASS_INDEX(plNetCommPublicAgeMsg),
CLASS_INDEX(plNetCommRegisterAgeMsg),
CLASS_INDEX(plVaultAdminInitializationTask),
CLASS_INDEX(plMultistageModMsg),
CLASS_INDEX(plSoundVolumeApplicator),
@ -948,6 +949,17 @@ CLASS_INDEX_LIST_START
CLASS_INDEX(plAngularVelocityMsg),
CLASS_INDEX(plRideAnimatedPhysMsg),
CLASS_INDEX(plAvBrainRideAnimatedPhysical),
CLASS_INDEX(pfGameScoreMsg), // This index and below are unused currently and placed for indexing plSubtitleMsg consistently with H'uru
CLASS_INDEX(pfGameScoreListMsg),
CLASS_INDEX(pfGameScoreTransferMsg),
CLASS_INDEX(pfGameScoreUpdateMsg),
CLASS_INDEX(plLoadClothingMsg),
CLASS_INDEX(plNullPipeline),
CLASS_INDEX(plGLPipeline),
CLASS_INDEX(plSDLModifierStateMsg),
CLASS_INDEX(plConfirmationMsg),
CLASS_INDEX(plLocalizedConfirmationMsg), // This index and above are unused currently and placed for indexing plSubtitleMsg consistently with H'uru
CLASS_INDEX(plSubtitleMsg),
CLASS_INDEX_LIST_END
#endif // plCreatableIndex_inc
#endif // plCreatableIndex_inc

2
Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.h

@ -43,7 +43,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#ifndef plLogicModBase_inc
#define plLogicModBase_inc
#include <stdint.h>
#include <cstdint>
#include "plSingleModifier.h"
#include "../pnNetCommon/plSynchedValue.h"
#include "hsTemplates.h"

6
Sources/Plasma/PubUtilLib/plAudio/plAudioSystem.cpp

@ -994,6 +994,7 @@ hsBool plgAudioSys::fInit = false;
hsBool plgAudioSys::fActive = false;
hsBool plgAudioSys::fUseHardware = false;
hsBool plgAudioSys::fMuted = true;
bool plgAudioSys::fEnableSubtitles = false;
hsBool plgAudioSys::fDelayedActivate = false;
hsBool plgAudioSys::fEnableEAX = false;
hsWindowHndl plgAudioSys::fWnd = nil;
@ -1047,6 +1048,11 @@ void plgAudioSys::SetMuted( hsBool b )
SetGlobalFadeVolume(1.0);
}
void plgAudioSys::SetEnableSubtitles(bool b)
{
fEnableSubtitles = b;
}
void plgAudioSys::SetUseHardware(hsBool b)
{
fUseHardware = b;

3
Sources/Plasma/PubUtilLib/plAudio/plAudioSystem.h

@ -193,11 +193,13 @@ public:
static void SetUseHardware(hsBool b);
static void SetActive(hsBool b);
static void SetMuted( hsBool b );
static void SetEnableSubtitles(bool b);
static void EnableEAX( hsBool b );
static hsBool Active() { return fInit; }
static void Shutdown();
static void Activate(hsBool b);
static hsBool IsMuted( void ) { return fMuted; }
static bool AreSubtitlesEnabled() { return fEnableSubtitles; }
static hsWindowHndl hWnd() { return fWnd; }
static plAudioSystem* Sys() { return fSys; }
static void Restart( void );
@ -258,6 +260,7 @@ private:
static hsBool fInit;
static hsBool fActive;
static hsBool fMuted;
static bool fEnableSubtitles;
static hsWindowHndl fWnd;
static hsBool fUseHardware;
static hsBool fDelayedActivate;

4
Sources/Plasma/PubUtilLib/plAudio/plDSoundBuffer.cpp

@ -710,9 +710,9 @@ hsBool plDSoundBuffer::IsEAXAccelerated( void ) const
//// BytePosToMSecs //////////////////////////////////////////////////////////
UInt32 plDSoundBuffer::BytePosToMSecs( UInt32 bytePos ) const
UInt32 plDSoundBuffer::BytePosToMSecs(UInt32 bytePos) const
{
return (UInt32)(bytePos * 1000 / (hsScalar)fBufferDesc->fAvgBytesPerSec);
return (UInt32)(bytePos / ((float)fBufferDesc->fAvgBytesPerSec / 1000.0f));
}
//// GetBufferBytePos ////////////////////////////////////////////////////////

30
Sources/Plasma/PubUtilLib/plAudio/plWin32Sound.cpp

@ -53,10 +53,12 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plWavFile.h"
#include "../plAudible/plWinAudible.h"
#include "../plAudioCore/plSrtFileReader.h"
#include "../pnMessage/plEventCallbackMsg.h"
#include "../pnMessage/plSoundMsg.h"
#include "../plMessage/plSubtitleMsg.h"
#include "../plNetMessage/plNetMessage.h"
#include "../pnNetCommon/plNetApp.h"
#include "../pnMessage/plSoundMsg.h"
#include "../pnMessage/plEventCallbackMsg.h"
#include "../plPipeline/plPlates.h"
#include "../plStatusLog/plStatusLog.h"
@ -108,6 +110,19 @@ void plWin32Sound::IFreeBuffers( void )
void plWin32Sound::Update()
{
plSoundBuffer* buf = GetDataBuffer();
if (plgAudioSys::AreSubtitlesEnabled() && buf != nullptr) {
plSrtFileReader* srtReader = buf->GetSrtReader();
if (srtReader != nullptr) {
uint32_t currentTimeMs = (uint32_t)(GetActualTimeSec() * 1000.0f);
while (plSrtEntry* nextEntry = srtReader->GetNextEntryStartingBeforeTime(currentTimeMs)) {
// add a plSubtitleMsg to go... to whoever is listening (probably the KI)
plSubtitleMsg* msg = new plSubtitleMsg(nextEntry->GetSubtitleText(), nextEntry->GetSpeakerName());
msg->Send();
}
}
}
plSound::Update();
}
@ -120,6 +135,17 @@ void plWin32Sound::IActuallyPlay( void )
{
if (fDSoundBuffer && plgAudioSys::Active() )
{
if (!fReallyPlaying && fSynchedStartTimeSec > 0) {
// advance past any subtitles that would end before the synched start time
// not sure when this actually happens...
plSoundBuffer* buf = GetDataBuffer();
if (buf != nullptr) {
plSrtFileReader* srtReader = buf->GetSrtReader();
if (srtReader != nullptr) {
srtReader->AdvanceToTime(fSynchedStartTimeSec * 1000.0);
}
}
}
// Sometimes base/derived classes can be annoying
IDerivedActuallyPlay();

17
Sources/Plasma/PubUtilLib/plAudio/plWin32StreamingSound.cpp

@ -455,21 +455,24 @@ void plWin32StreamingSound::IActuallyStop()
unsigned plWin32StreamingSound::GetByteOffset()
{
if(fDataStream && fDSoundBuffer)
{
if (fDataStream && fDSoundBuffer)
{
UInt32 totalSize = fDataStream->GetDataSize();
UInt32 bytesRemaining = fDataStream->NumBytesLeft();
unsigned bytesQueued = fDSoundBuffer->BuffersQueued() * STREAM_BUFFER_SIZE;
unsigned offset = fDSoundBuffer->GetByteOffset();
long byteoffset = ((fDataStream->GetDataSize() - fDataStream->NumBytesLeft()) - bytesQueued) + offset;
return byteoffset < 0 ? fDataStream->GetDataSize() - abs(byteoffset) : byteoffset;
long byteoffset = ((totalSize - bytesRemaining) - bytesQueued) + offset;
return byteoffset < 0 ? totalSize - std::abs(byteoffset) : byteoffset;
}
return 0;
}
float plWin32StreamingSound::GetActualTimeSec()
{
if(fDataStream && fDSoundBuffer)
return fDSoundBuffer->BytePosToMSecs(fDataStream->NumBytesLeft()) / 1000.0f;
if (fDataStream && fDSoundBuffer)
return fDSoundBuffer->BytePosToMSecs(this->GetByteOffset()) / 1000.0f;
return 0.0f;
}

28
Sources/Plasma/PubUtilLib/plAudioCore/plSoundBuffer.cpp

@ -45,9 +45,11 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "hsStream.h"
#include "hsUtils.h"
#include <cstring>
#include "plgDispatch.h"
#include "hsResMgr.h"
#include "plSrtFileReader.h"
#include "../pnMessage/plRefMsg.h"
#include "../plFile/plFileUtils.h"
#include "../plFile/hsFiles.h"
@ -117,20 +119,35 @@ static void LoadCallback(void *)
else
{
plAudioFileReader *reader = nil;
plSrtFileReader* srtReader = nullptr;
while(plSoundBuffer *buffer = templist.Head())
{
if(buffer->GetData())
{
reader = CreateReader(true, buffer->GetFileName(), buffer->GetAudioReaderType(), buffer->GetReaderSelect());
const char* srcFilename = buffer->GetFileName();
reader = CreateReader(true, srcFilename, buffer->GetAudioReaderType(), buffer->GetReaderSelect());
if( reader )
{
unsigned readLen = buffer->GetAsyncLoadLength() ? buffer->GetAsyncLoadLength() : buffer->GetDataLength();
reader->Read( readLen, buffer->GetData() );
buffer->SetAudioReader(reader); // give sound buffer reader, since we may need it later
plSrtFileReader* srtReader = buffer->GetSrtReader();
if (srtReader != nullptr && (strcmp(srtReader->GetCurrentAudioFileName(), srcFilename) == 0)) {
// same file we were playing before, so start the SRT feed over instead of deleting and reloading
srtReader->StartOver();
} else {
std::unique_ptr<plSrtFileReader> newSrtFileReader(new plSrtFileReader(srcFilename));
if (newSrtFileReader->ReadFile())
buffer->SetSrtReader(newSrtFileReader.release());
}
}
else
{
buffer->SetError();
}
}
templist.Unlink(buffer);
@ -194,6 +211,8 @@ plSoundBuffer::~plSoundBuffer()
ASSERT(!link.IsLinked());
delete [] fFileName;
UnLoad();
delete fSrtReader;
}
void plSoundBuffer::IInitBuffer()
@ -206,6 +225,7 @@ void plSoundBuffer::IInitBuffer()
fFlags = 0;
fDataRead = 0;
fReader = nil;
fSrtReader = nullptr;
fLoaded = 0;
fLoading = false;
fHeader.fFormatTag = 0;
@ -458,6 +478,12 @@ void plSoundBuffer::SetLoaded(bool loaded)
fLoaded = loaded;
}
void plSoundBuffer::SetSrtReader(plSrtFileReader* reader)
{
delete fSrtReader;
fSrtReader = reader;
}
/*****************************************************************************
*

6
Sources/Plasma/PubUtilLib/plAudioCore/plSoundBuffer.h

@ -61,6 +61,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
class plUnifiedTime;
class plAudioFileReader;
class plSrtFileReader;
class plSoundBuffer : public hsKeyedObject
{
public:
@ -118,6 +119,8 @@ public:
plAudioFileReader * GetAudioReader(); // transfers ownership to caller
void SetAudioReader(plAudioFileReader *reader);
void SetLoaded(bool loaded);
plSrtFileReader* GetSrtReader() const { return fSrtReader; } // does not transfer ownership
void SetSrtReader(plSrtFileReader* reader);
plAudioFileReader::StreamType GetAudioReaderType() { return fStreamType; }
unsigned GetAsyncLoadLength() { return fAsyncLoadLength ? fAsyncLoadLength : fDataLength; }
@ -148,7 +151,8 @@ protected:
bool fLoading;
bool fError;
plAudioFileReader * fReader;
plAudioFileReader * fReader;
plSrtFileReader* fSrtReader;
UInt8 * fData;
plWAVHeader fHeader;
UInt32 fDataLength;

187
Sources/Plasma/PubUtilLib/plAudioCore/plSrtFileReader.cpp

@ -0,0 +1,187 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, 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/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plSrtFileReader.h"
#include "hsStream.h"
#include "../plStatusLog/plStatusLog.h"
#include "../pnUtils/pnUtils.h"
#include <regex>
static const std::regex speakerTextRegex("^((([\\w.]+(\\s\\w+)?):) )?(.*)");
static const std::regex timingsRegex("^(\\d{2}):(\\d{2}):(\\d{2}),(\\d{3}) --> (\\d{2}):(\\d{2}):(\\d{2}),(\\d{3})$");
bool plSrtFileReader::ReadFile()
{
wchar path[MAX_PATH];
StrPrintf(path, arrsize(path), L"sfx\\%S", fAudioFileName);
PathSetExtension(path, path, L".sub", arrsize(path));
if (PathDoesFileExist(path)) {
// read sets of SRT data until end of file
hsUNIXStream srtFileStream;
// if file exists and was opened successfully
if (srtFileStream.Open(path, L"r")) {
plStatusLog::AddLineS("audio.log", "Successfully opened subtitle file %S", path);
uint32_t subtitleNumber = 0;
uint32_t subtitleStartTimeMs = 0;
uint32_t subtitleEndTimeMs = 0;
char line[4096];
std::string speakerName;
std::string subtitleText;
std::cmatch matches;
for (unsigned int lnCounter = 0; !srtFileStream.AtEnd(); lnCounter++) {
if (lnCounter % 4 == 0 && srtFileStream.ReadLn(line)) {
subtitleNumber = std::stoul(line);
} else if (lnCounter % 4 == 1 && srtFileStream.ReadLn(line)) {
if (std::regex_match(line, matches, timingsRegex)) {
if (matches.size() < 9) {
// add error message and ensure this subtitle line won't be added to the entries
plStatusLog::AddLineS("audio.log", plStatusLog::kRed, " Subtitle timings '%s' are formatted incorrectly.", line);
subtitleNumber = 0;
}
else {
// matches[0] is the entire match, we don't do anything with it
// matches[1] is the first group -- the start hour number
subtitleStartTimeMs += std::stoul(matches[1].str()) * 3600000;
// matches[2] is the second group -- the start minute number
subtitleStartTimeMs += std::stoul(matches[2].str()) * 60000;
// matches[3] is the third group -- the start seconds number
subtitleStartTimeMs += std::stoul(matches[3].str()) * 1000;
// matches[4] is the fourth group -- the start milliseconds number
subtitleStartTimeMs += std::stoul(matches[4].str());
// matches[5] is the fifth group -- the end hour number
subtitleEndTimeMs += std::stoul(matches[5].str()) * 3600000;
// matches[6] is the sixth group -- the end minute number
subtitleEndTimeMs += std::stoul(matches[6].str()) * 60000;
// matches[7] is the seventh group -- the end seconds number
subtitleEndTimeMs += std::stoul(matches[7].str()) * 1000;
// matches[8] is the eighth group -- the end milliseconds number
subtitleEndTimeMs += std::stoul(matches[8].str());
}
}
} else if (lnCounter % 4 == 2 && srtFileStream.ReadLn(line)) {
if (std::regex_match(line, matches, speakerTextRegex)) {
if (matches.size() < 5) {
// add error message and ensure this subtitle line won't be added to the entries
plStatusLog::AddLineS("audio.log", plStatusLog::kRed, " Subtitle text and/or speaker name '%s' are formatted incorrectly.", line);
subtitleNumber = 0;
} else {
// matches[0] is the entire match, we don't do anything with it
// matches[2] is the second group (the optional subtitle speaker with colon but no space at the end)
speakerName = matches[2];
// matches[5] is the fourth group (the subtitle text)
subtitleText = matches[5];
}
}
} else if (lnCounter % 4 == 3 && subtitleNumber > 0 && subtitleStartTimeMs >= 0 && subtitleEndTimeMs >= 0 && !subtitleText.empty()) {
// entry is complete, add to the queue and reset our temp variables
if (!speakerName.empty())
fEntries.emplace_back(plSrtEntry(subtitleNumber, subtitleStartTimeMs, subtitleEndTimeMs, std::move(subtitleText), std::move(speakerName)));
else
fEntries.emplace_back(plSrtEntry(subtitleNumber, subtitleStartTimeMs, subtitleEndTimeMs, std::move(subtitleText)));
subtitleNumber = 0;
subtitleStartTimeMs = 0;
subtitleEndTimeMs = 0;
subtitleText.clear();
speakerName.clear();
}
}
if (subtitleNumber > 0 && subtitleStartTimeMs >= 0 && subtitleEndTimeMs >= 0 && !subtitleText.empty()) {
// enqueue the last subtitle from the file if we didn't have an extra blank line at the end
if (!speakerName.empty())
fEntries.emplace_back(plSrtEntry(subtitleNumber, subtitleStartTimeMs, subtitleEndTimeMs, std::move(subtitleText), std::move(speakerName)));
else
fEntries.emplace_back(plSrtEntry(subtitleNumber, subtitleStartTimeMs, subtitleEndTimeMs, std::move(subtitleText)));
}
return true;
}
}
return false;
}
void plSrtFileReader::AdvanceToTime(uint32_t timeMs)
{
while (fCurrentEntryIndex < fEntries.size() && fEntries.at(fCurrentEntryIndex).GetEndTimeMs() <= timeMs) {
fCurrentEntryIndex++;
}
}
plSrtEntry* plSrtFileReader::GetNextEntryStartingBeforeTime(uint32_t timeMs)
{
if (fCurrentEntryIndex < fEntries.size()) {
plSrtEntry& nextEntry = fEntries.at(fCurrentEntryIndex);
if (nextEntry.GetStartTimeMs() <= timeMs) {
fCurrentEntryIndex++;
return &nextEntry;
}
}
return nullptr;
}
plSrtEntry* plSrtFileReader::GetNextEntryEndingBeforeTime(uint32_t timeMs)
{
if (fCurrentEntryIndex < fEntries.size()) {
plSrtEntry& nextEntry = fEntries.at(fCurrentEntryIndex);
if (nextEntry.GetEndTimeMs() <= timeMs) {
fCurrentEntryIndex++;
return &nextEntry;
}
}
return nullptr;
}

107
Sources/Plasma/PubUtilLib/plAudioCore/plSrtFileReader.h

@ -0,0 +1,107 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, 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/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plSrtFileReader - Class for reading an SRT format file and //
// storing the read entries for access later //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plSrtFileReader_h
#define _plSrtFileReader_h
#include "hsTypes.h"
#include "../pnUtils/pnUtils.h"
#include <cstdint>
#include <vector>
class plSrtEntry
{
public:
plSrtEntry(uint32_t entryNum, uint32_t startTimeMs, uint32_t endTimeMs, std::string subtitleText, std::string speakerName)
: fEntryNum(entryNum), fStartTimeMs(startTimeMs), fEndTimeMs(endTimeMs), fSubtitleText(std::move(subtitleText)),
fSpeakerName(std::move(speakerName)) { }
plSrtEntry(uint32_t entryNum, uint32_t startTimeMs, uint32_t endTimeMs, std::string subtitleText)
: fEntryNum(entryNum), fStartTimeMs(startTimeMs), fEndTimeMs(endTimeMs), fSubtitleText(std::move(subtitleText)) { }
std::string GetSubtitleText() const { return fSubtitleText; }
std::string GetSpeakerName() const { return fSpeakerName; }
uint32_t GetStartTimeMs() const { return fStartTimeMs; }
uint32_t GetEndTimeMs() const { return fEndTimeMs; }
protected:
uint32_t fEntryNum;
uint32_t fStartTimeMs;
uint32_t fEndTimeMs;
std::string fSubtitleText;
std::string fSpeakerName;
};
class plSrtFileReader
{
public:
plSrtFileReader(const char* audioFileName)
: fAudioFileName(StrDup(audioFileName)), fCurrentEntryIndex(0) { }
virtual ~plSrtFileReader() { delete[] fAudioFileName; }
bool ReadFile();
void StartOver() { fCurrentEntryIndex = 0; }
const char* GetCurrentAudioFileName() const { return fAudioFileName; }
void AdvanceToTime(uint32_t timeMs);
plSrtEntry* GetNextEntryStartingBeforeTime(uint32_t timeMs);
plSrtEntry* GetNextEntryEndingBeforeTime(uint32_t timeMs);
protected:
const char* fAudioFileName;
std::vector<plSrtEntry> fEntries;
uint32_t fCurrentEntryIndex;
};
#endif //_plSrtFileReader_h

4
Sources/Plasma/PubUtilLib/plMessage/plMessageCreatable.h

@ -133,6 +133,10 @@ REGISTER_CREATABLE( plSpawnModMsg );
REGISTER_CREATABLE( plSpawnRequestMsg );
#include "plSubtitleMsg.h"
REGISTER_CREATABLE(plSubtitleMsg);
#include "plNodeCleanupMsg.h"
REGISTER_CREATABLE( plNodeCleanupMsg );

82
Sources/Plasma/PubUtilLib/plMessage/plSubtitleMsg.h

@ -0,0 +1,82 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, 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/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plSubtitleMsg_inc
#define plSubtitleMsg_inc
#include "../pnMessage/plMessage.h"
/** Show subtitle text for in-game audio */
class plSubtitleMsg : public plMessage
{
protected:
std::string fText;
std::string fSpeaker;
public:
plSubtitleMsg() : plMessage()
{
SetBCastFlag(plMessage::kBCastByExactType);
}
plSubtitleMsg(std::string msgText) : plMessage(), fText(std::move(msgText))
{
SetBCastFlag(plMessage::kBCastByExactType);
}
plSubtitleMsg(std::string msgText, std::string msgSpeaker) : plMessage(), fText(std::move(msgText)),
fSpeaker(std::move(msgSpeaker))
{
SetBCastFlag(plMessage::kBCastByExactType);
}
CLASSNAME_REGISTER(plSubtitleMsg);
GETINTERFACE_ANY(plSubtitleMsg, plMessage);
void Read(hsStream*, hsResMgr*) override { FATAL("no"); }
void Write(hsStream*, hsResMgr*) override { FATAL("no"); }
std::string GetText() const { return fText; }
std::string GetSpeaker() const { return fSpeaker; }
};
#endif // plSubtitleMsg_inc
Loading…
Cancel
Save