sfxFMODEvent.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "sfx/fmod/sfxFMODEvent.h"
  24. #include "sfx/fmod/sfxFMODEventGroup.h"
  25. #include "sfx/fmod/sfxFMODProject.h"
  26. #include "sfx/fmod/sfxFMODDevice.h"
  27. #include "sfx/sfxParameter.h"
  28. #include "sfx/sfxDescription.h"
  29. #include "core/stream/bitStream.h"
  30. IMPLEMENT_CO_DATABLOCK_V1( SFXFMODEvent );
  31. ConsoleDocClass( SFXFMODEvent,
  32. "@brief A playable sound event in an FMOD Designer audio project.\n\n"
  33. "@ingroup SFXFMOD\n"
  34. "@ingroup Datablocks"
  35. );
  36. //-----------------------------------------------------------------------------
  37. SFXFMODEvent::SFXFMODEvent()
  38. : mGroup( NULL ),
  39. mHandle( NULL ),
  40. mGroupId( 0 ),
  41. mSibling( NULL )
  42. {
  43. dMemset( mParameterRanges, 0, sizeof( mParameterRanges ) );
  44. dMemset( mParameterValues, 0, sizeof( mParameterValues ) );
  45. }
  46. //-----------------------------------------------------------------------------
  47. SFXFMODEvent::SFXFMODEvent( SFXFMODEventGroup* group, FMOD_EVENT* handle )
  48. : mGroup( group ),
  49. mHandle( handle ),
  50. mGroupId( 0 ),
  51. mSibling( NULL )
  52. {
  53. dMemset( mParameterRanges, 0, sizeof( mParameterRanges ) );
  54. dMemset( mParameterValues, 0, sizeof( mParameterValues ) );
  55. // Fetch name.
  56. int index;
  57. char* name = NULL;
  58. SFXFMODDevice::smFunc->FMOD_Event_GetInfo( mHandle, &index, &name, ( FMOD_EVENT_INFO* ) 0 );
  59. mName = name;
  60. // Read out the parameter info so we can immediately create
  61. // the events on the client-side without having to open and
  62. // read all the project info there.
  63. int numParameters;
  64. SFXFMODDevice::smFunc->FMOD_Event_GetNumParameters( mHandle, &numParameters );
  65. if( numParameters > MaxNumParameters )
  66. {
  67. Con::errorf( "SFXFMODEvent::SFXFMODEvent - event '%s' has more parameters (%i) than supported per SFXTrack (%i)",
  68. getQualifiedName().c_str(),
  69. numParameters,
  70. MaxNumParameters );
  71. numParameters = MaxNumParameters;
  72. }
  73. for( U32 i = 0; i < numParameters; ++ i )
  74. {
  75. FMOD_EVENTPARAMETER* parameter;
  76. SFXFMODDevice::smFunc->FMOD_Event_GetParameterByIndex( mHandle, i, &parameter );
  77. SFXFMODDevice::smFunc->FMOD_EventParameter_GetInfo( parameter, &index, &name );
  78. setParameter( i, name );
  79. // Get value and range of parameter.
  80. SFXFMODDevice::smFunc->FMOD_EventParameter_GetValue( parameter, &mParameterValues[ i ] );
  81. SFXFMODDevice::smFunc->FMOD_EventParameter_GetRange( parameter, &mParameterRanges[ i ].x, &mParameterRanges[ i ].y );
  82. }
  83. // Read out the properties and create a custom SFXDescription for the event.
  84. mDescription = new SFXDescription;
  85. if( !group->isClientOnly() )
  86. mDescription->assignId();
  87. mDescription->registerObject(
  88. String::ToString( "%s_%s_Description",
  89. group->getName(),
  90. FMODEventPathToTorqueName( mName ).c_str()
  91. )
  92. );
  93. if( group->isClientOnly() )
  94. Sim::getRootGroup()->addObject( mDescription );
  95. FMOD_MODE modeValue;
  96. float floatValue;
  97. if( SFXFMODDevice::smFunc->FMOD_Event_GetPropertyByIndex( mHandle, FMOD_EVENTPROPERTY_MODE, &modeValue, true ) == FMOD_OK )
  98. mDescription->mIs3D = ( modeValue == FMOD_3D );
  99. if( SFXFMODDevice::smFunc->FMOD_Event_GetPropertyByIndex( mHandle, FMOD_EVENTPROPERTY_VOLUME, &floatValue, true ) == FMOD_OK )
  100. mDescription->mVolume = floatValue;
  101. if( SFXFMODDevice::smFunc->FMOD_Event_GetPropertyByIndex( mHandle, FMOD_EVENTPROPERTY_PITCH, &floatValue, true ) == FMOD_OK )
  102. mDescription->mPitch = floatValue;
  103. if( SFXFMODDevice::smFunc->FMOD_Event_GetPropertyByIndex( mHandle, FMOD_EVENTPROPERTY_3D_MINDISTANCE, &floatValue, true ) == FMOD_OK )
  104. mDescription->mMinDistance = floatValue;
  105. if( SFXFMODDevice::smFunc->FMOD_Event_GetPropertyByIndex( mHandle, FMOD_EVENTPROPERTY_3D_MAXDISTANCE, &floatValue, true ) == FMOD_OK )
  106. mDescription->mMaxDistance = floatValue;
  107. if( SFXFMODDevice::smFunc->FMOD_Event_GetPropertyByIndex( mHandle, FMOD_EVENTPROPERTY_3D_CONEINSIDEANGLE, &floatValue, true ) == FMOD_OK )
  108. mDescription->mConeInsideAngle = floatValue;
  109. if( SFXFMODDevice::smFunc->FMOD_Event_GetPropertyByIndex( mHandle, FMOD_EVENTPROPERTY_3D_CONEOUTSIDEANGLE, &floatValue, true ) == FMOD_OK )
  110. mDescription->mConeOutsideAngle = floatValue;
  111. if( SFXFMODDevice::smFunc->FMOD_Event_GetPropertyByIndex( mHandle, FMOD_EVENTPROPERTY_3D_CONEOUTSIDEVOLUME, &floatValue, true ) == FMOD_OK )
  112. mDescription->mConeOutsideVolume = floatValue;
  113. // Don't read out fade values as we want to leave fade-effects to
  114. // FMOD rather than having the fading system built into SFX pick
  115. // these values up.
  116. }
  117. //-----------------------------------------------------------------------------
  118. SFXFMODEvent::~SFXFMODEvent()
  119. {
  120. }
  121. //-----------------------------------------------------------------------------
  122. void SFXFMODEvent::initPersistFields()
  123. {
  124. addGroup( "DO NOT MODIFY!!" );
  125. addField( "fmodGroup", TYPEID< SFXFMODEventGroup >(), Offset( mGroup, SFXFMODEvent ), "DO NOT MODIFY!!" );
  126. addField( "fmodName", TypeRealString, Offset( mName, SFXFMODEvent ), "DO NOT MODIFY!!" );
  127. addField( "fmodParameterRanges", TypePoint2F, Offset( mParameterRanges, SFXFMODEvent ), MaxNumParameters, "DO NOT MODIFY!!" );
  128. addField( "fmodParameterValues", TypeF32, Offset( mParameterValues, SFXFMODEvent ), MaxNumParameters, "DO NOT MODIFY!!" );
  129. endGroup( "DO NOT MODIFY!!" );
  130. Parent::initPersistFields();
  131. }
  132. //-----------------------------------------------------------------------------
  133. bool SFXFMODEvent::onAdd()
  134. {
  135. if( !Parent::onAdd() )
  136. return false;
  137. if( !mGroup )
  138. {
  139. Con::errorf( "SFXFMODEvent::onAdd - no group set; this event was not properly constructed" );
  140. return false;
  141. }
  142. mGroup->_addEvent( this );
  143. mGroup->mProject->_addEvent( this );
  144. // For non-networked event datablocks, create the parameter
  145. // instances now.
  146. if( isClientOnly() )
  147. _createParameters();
  148. return true;
  149. }
  150. //-----------------------------------------------------------------------------
  151. void SFXFMODEvent::onRemove()
  152. {
  153. Parent::onRemove();
  154. if( !mGroup )
  155. return;
  156. release();
  157. mGroup->_removeEvent( this );
  158. }
  159. //-----------------------------------------------------------------------------
  160. bool SFXFMODEvent::preload( bool server, String& errorStr )
  161. {
  162. if( !Parent::preload( server, errorStr ) )
  163. return false;
  164. if( !server )
  165. {
  166. if( !Sim::findObject( mGroupId, mGroup ) )
  167. {
  168. errorStr = String::ToString( "SFXFMODEvent - group '%i' does not exist", mGroupId );
  169. return false;
  170. }
  171. // Create parameters.
  172. _createParameters();
  173. }
  174. return true;
  175. }
  176. //-----------------------------------------------------------------------------
  177. void SFXFMODEvent::packData( BitStream* stream )
  178. {
  179. Parent::packData( stream );
  180. stream->write( mName );
  181. stream->writeRangedS32( mGroup->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast );
  182. for( U32 i = 0; i < MaxNumParameters; ++ i )
  183. if( stream->writeFlag( mParameters[ i ] ) )
  184. {
  185. stream->write( mParameterValues[ i ] );
  186. stream->write( mParameterRanges[ i ].x );
  187. stream->write( mParameterRanges[ i ].y );
  188. }
  189. }
  190. //-----------------------------------------------------------------------------
  191. void SFXFMODEvent::unpackData( BitStream* stream )
  192. {
  193. Parent::unpackData( stream );
  194. stream->read( &mName );
  195. mGroupId = stream->readRangedS32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
  196. for( U32 i = 0; i < MaxNumParameters; ++ i )
  197. if( stream->readFlag() )
  198. {
  199. stream->read( &mParameterValues[ i ] );
  200. stream->read( &mParameterRanges[ i ].x );
  201. stream->read( &mParameterRanges[ i ].y );
  202. }
  203. else
  204. {
  205. mParameterValues[ i ] = 0.f;
  206. mParameterRanges[ i ].x = 0.f;
  207. mParameterRanges[ i ].y = 0.f;
  208. }
  209. }
  210. //-----------------------------------------------------------------------------
  211. void SFXFMODEvent::acquire()
  212. {
  213. if( mHandle )
  214. return;
  215. mGroup->acquire();
  216. if( SFXFMODDevice::smFunc->FMOD_EventGroup_GetEvent(
  217. mGroup->mHandle, mName.c_str(), FMOD_EVENT_INFOONLY, &mHandle ) != FMOD_OK )
  218. {
  219. Con::errorf( "SFXFMODEvent::acquire() - failed to acquire event '%s'", getQualifiedName().c_str() );
  220. return;
  221. }
  222. }
  223. //-----------------------------------------------------------------------------
  224. void SFXFMODEvent::release()
  225. {
  226. if( !mHandle )
  227. return;
  228. SFXFMODDevice::smFunc->FMOD_Event_Release( mHandle, true, false );
  229. mHandle = NULL;
  230. }
  231. //-----------------------------------------------------------------------------
  232. String SFXFMODEvent::getQualifiedName() const
  233. {
  234. return String::ToString( "%s/%s", getEventGroup()->getQualifiedName().c_str(), mName.c_str() );
  235. }
  236. //-----------------------------------------------------------------------------
  237. void SFXFMODEvent::_createParameters()
  238. {
  239. const String& projectFileName = getEventGroup()->getProject()->getFileName();
  240. const String qualifiedGroupName = getEventGroup()->getQualifiedName();
  241. const String description = String::ToString( "FMOD Event Parameter (%s)", projectFileName.c_str() );
  242. for( U32 i = 0; i < MaxNumParameters; ++ i )
  243. {
  244. StringTableEntry name = getParameter( i );
  245. if( !name )
  246. continue;
  247. SFXParameter* parameter = SFXParameter::find( name );
  248. if( !parameter )
  249. {
  250. parameter = new SFXParameter();
  251. parameter->setInternalName( name );
  252. parameter->registerObject();
  253. // Set up parameter.
  254. parameter->setChannel( SFXChannelUser0 );
  255. parameter->setRange( mParameterRanges[ i ] );
  256. parameter->setDefaultValue( mParameterValues[ i ] );
  257. parameter->setValue( mParameterValues[ i ] );
  258. parameter->setDescription( description );
  259. // Set categories for easy filtering.
  260. static StringTableEntry sCategories = StringTable->insert( "categories" );
  261. parameter->setDataField( sCategories, "0", "FMOD" );
  262. parameter->setDataField( sCategories, "1", avar( "FMOD Project: %s", projectFileName.c_str() ) );
  263. parameter->setDataField( sCategories, "2", avar( "FMOD Group: %s", qualifiedGroupName.c_str() ) );
  264. }
  265. }
  266. }