StereoChannel.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "Audio.h"
  25. #include "Entity.h"
  26. #include "ReplicationUtils.h"
  27. #include "ResourceCache.h"
  28. #include "Sound.h"
  29. #include "StereoChannel.h"
  30. #include "StringUtils.h"
  31. #include "XMLElement.h"
  32. #include "DebugNew.h"
  33. static const std::string typeNames[] =
  34. {
  35. "master",
  36. "effect",
  37. "music",
  38. "voice"
  39. };
  40. StereoChannel::StereoChannel(Audio* audio, const std::string& name) :
  41. Channel(audio),
  42. Component(name),
  43. mAutoRemoveTimer(0.0f),
  44. mAutoRemove(false)
  45. {
  46. }
  47. void StereoChannel::save(Serializer& dest)
  48. {
  49. // Read Component properties
  50. Component::save(dest);
  51. // Write channel properties
  52. dest.writeUByte((unsigned char)mChannelType);
  53. dest.writeFloat(mFrequency);
  54. dest.writeFloat(mGain);
  55. dest.writeFloat(mAttenuation);
  56. dest.writeFloat(mPanning);
  57. dest.writeBool(mAutoRemove);
  58. // Write currently playing sound and its offset (if any)
  59. Sound* sound = getSound();
  60. dest.writeStringHash(getResourceHash(sound));
  61. if (sound)
  62. dest.writeUInt((unsigned)(getPlayPosition() - sound->getStart()));
  63. }
  64. void StereoChannel::load(Deserializer& source, ResourceCache* cache)
  65. {
  66. // Read Component properties
  67. Component::load(source, cache);
  68. // Read channel properties
  69. mChannelType = (ChannelType)source.readUByte();
  70. mFrequency = source.readFloat();
  71. mGain = source.readFloat();
  72. mAttenuation = source.readFloat();
  73. mPanning = source.readFloat();
  74. mAutoRemove = source.readBool();
  75. // Read currently playing sound (if any)
  76. StringHash soundHash = source.readStringHash();
  77. if (soundHash)
  78. {
  79. Sound* sound = cache->getResource<Sound>(soundHash);
  80. unsigned offset = source.readUInt();
  81. play(sound);
  82. setPlayPosition(sound->getStart() + offset);
  83. }
  84. }
  85. void StereoChannel::saveXML(XMLElement& dest)
  86. {
  87. // Write Component properties
  88. Component::saveXML(dest);
  89. // Write channel properties
  90. XMLElement channelElem = dest.createChildElement("channel");
  91. channelElem.setString("type", typeNames[mChannelType]);
  92. channelElem.setFloat("frequency", mFrequency);
  93. channelElem.setFloat("gain", mGain);
  94. channelElem.setFloat("attenuation", mAttenuation);
  95. channelElem.setFloat("panning", mPanning);
  96. channelElem.setBool("autoremove", mAutoRemove);
  97. // Write currently playing sound and its offset (if any)
  98. Sound* sound = getSound();
  99. if (sound)
  100. {
  101. XMLElement soundElem = dest.createChildElement("sound");
  102. soundElem.setString("name", getResourceName(sound));
  103. soundElem.setInt("offset", (unsigned)(getPlayPosition() - sound->getStart()));
  104. }
  105. }
  106. void StereoChannel::loadXML(const XMLElement& source, ResourceCache* cache)
  107. {
  108. // Read Component properties
  109. Component::loadXML(source, cache);
  110. // Read channel properties
  111. XMLElement channelElem = source.getChildElement("channel");
  112. mChannelType = (ChannelType)getIndexFromStringList(channelElem.getStringLower("type"), typeNames, 4, 1);
  113. mFrequency = channelElem.getFloat("frequency");
  114. mGain = channelElem.getFloat("gain");
  115. mAttenuation = channelElem.getFloat("attenuation");
  116. mPanning = channelElem.getFloat("panning");
  117. mAutoRemove = channelElem.getBool("autoremove");
  118. // Read currently playing sound (if any)
  119. XMLElement soundElem = source.getChildElement("sound");
  120. if (soundElem)
  121. {
  122. Sound* sound = cache->getResource<Sound>(soundElem.getString("name"));
  123. unsigned offset = soundElem.getInt("offset");
  124. play(sound);
  125. setPlayPosition(sound->getStart() + offset);
  126. }
  127. }
  128. bool StereoChannel::writeNetUpdate(Serializer& dest, Serializer& destRevision, Deserializer& baseRevision, const NetUpdateInfo& info)
  129. {
  130. Sound* sound = getSound();
  131. // Build bitmask of changed properties
  132. unsigned char bits = 0;
  133. checkUByte((unsigned char)mChannelType, (unsigned char)CHANNEL_EFFECT, baseRevision, bits, 1);
  134. checkFloat(mFrequency, baseRevision, bits, 2);
  135. checkFloat(mGain, 1.0f, baseRevision, bits, 4);
  136. checkFloat(mAttenuation, 1.0f, baseRevision, bits, 8);
  137. checkFloat(mPanning, 0.0f, baseRevision, bits, 16);
  138. checkStringHash(getResourceHash(sound), StringHash(), baseRevision, bits, 32);
  139. // Update replication state fully, and network stream by delta
  140. dest.writeUByte(bits);
  141. writeUByteDelta((unsigned char)mChannelType, dest, destRevision, bits & 1);
  142. writeFloatDelta(mFrequency, dest, destRevision, bits & 2);
  143. writeFloatDelta(mGain, dest, destRevision, bits & 4);
  144. writeFloatDelta(mAttenuation, dest, destRevision, bits & 8);
  145. writeFloatDelta(mPanning, dest, destRevision, bits & 16);
  146. writeStringHashDelta(getResourceHash(sound), dest, destRevision, bits & 32);
  147. return bits != 0;
  148. }
  149. void StereoChannel::readNetUpdate(Deserializer& source, ResourceCache* cache, const NetUpdateInfo& info)
  150. {
  151. StringHash soundHash;
  152. unsigned char bits = source.readUByte();
  153. if (bits & 1)
  154. mChannelType = (ChannelType)source.readUByte();
  155. if (bits & 2)
  156. mFrequency = source.readFloat();
  157. if (bits & 4)
  158. mGain = source.readFloat();
  159. if (bits & 8)
  160. mAttenuation = source.readFloat();
  161. if (bits & 16)
  162. mPanning = source.readFloat();
  163. if (bits & 32)
  164. soundHash = source.readStringHash();
  165. // Trigger sound only if not yet playing (we might get multiple copies of the same update)
  166. if ((soundHash) && (!isPlaying()))
  167. {
  168. Sound* sound = cache->getResource<Sound>(soundHash);
  169. play(sound);
  170. }
  171. }
  172. void StereoChannel::getResourceRefs(std::vector<Resource*>& dest)
  173. {
  174. Sound* sound = getSound();
  175. if (sound)
  176. dest.push_back(sound);
  177. }
  178. void StereoChannel::update(float timeStep)
  179. {
  180. if (!mAudio)
  181. return;
  182. Channel::update(timeStep);
  183. // Check automatic remove. Never do autoremove for client proxy components, because this could lead in exceptions
  184. // as the server could still be sending updates to a removed component
  185. if ((mAutoRemove) && (!isProxy()) && (mEntity))
  186. {
  187. if (!isPlaying())
  188. {
  189. mAutoRemoveTimer += timeStep;
  190. if (mAutoRemoveTimer > CHANNEL_AUTOREMOVE_DELAY)
  191. {
  192. mEntity->removeComponent(this);
  193. return;
  194. }
  195. }
  196. else
  197. mAutoRemoveTimer = 0.0f;
  198. }
  199. }
  200. void StereoChannel::setAutoRemove(bool enable)
  201. {
  202. mAutoRemove = enable;
  203. }