AudioSource.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #include "Base.h"
  2. #include "Node.h"
  3. #include "AudioBuffer.h"
  4. #include "AudioController.h"
  5. #include "AudioSource.h"
  6. #include "Game.h"
  7. #include "Node.h"
  8. namespace gameplay
  9. {
  10. AudioSource::AudioSource(AudioBuffer* buffer, ALuint source)
  11. : _alSource(source), _buffer(buffer), _looped(true), _gain(1.0f), _pitch(1.0f), _node(NULL)
  12. {
  13. GP_ASSERT(buffer);
  14. AL_CHECK( alSourcei(_alSource, AL_BUFFER, buffer->_alBuffer) );
  15. AL_CHECK( alSourcei(_alSource, AL_LOOPING, _looped) );
  16. AL_CHECK( alSourcef(_alSource, AL_PITCH, _pitch) );
  17. AL_CHECK( alSourcef(_alSource, AL_GAIN, _gain) );
  18. AL_CHECK( alSourcefv(_alSource, AL_VELOCITY, (const ALfloat*)&_velocity) );
  19. }
  20. AudioSource::~AudioSource()
  21. {
  22. if (_alSource)
  23. {
  24. AL_CHECK( alDeleteSources(1, &_alSource) );
  25. _alSource = 0;
  26. }
  27. SAFE_RELEASE(_buffer);
  28. }
  29. AudioSource* AudioSource::create(const char* url)
  30. {
  31. GP_ASSERT(url);
  32. // Load from a .audio file.
  33. std::string pathStr = url;
  34. if (pathStr.find(".audio") != pathStr.npos)
  35. {
  36. Properties* properties = Properties::create(url);
  37. GP_ASSERT(properties);
  38. if (properties == NULL)
  39. {
  40. return NULL;
  41. }
  42. AudioSource* audioSource = create((strlen(properties->getNamespace()) > 0) ? properties : properties->getNextNamespace());
  43. SAFE_DELETE(properties);
  44. return audioSource;
  45. }
  46. // Create an audio buffer from this URL.
  47. AudioBuffer* buffer = AudioBuffer::create(url);
  48. if (buffer == NULL)
  49. return NULL;
  50. // Load the audio source.
  51. ALuint alSource = 0;
  52. AL_CHECK( alGenSources(1, &alSource) );
  53. if (AL_LAST_ERROR())
  54. {
  55. SAFE_RELEASE(buffer);
  56. GP_ERROR("Error generating audio source.");
  57. return NULL;
  58. }
  59. return new AudioSource(buffer, alSource);
  60. }
  61. AudioSource* AudioSource::create(Properties* properties)
  62. {
  63. // Check if the properties is valid and has a valid namespace.
  64. GP_ASSERT(properties);
  65. if (!properties || !(strcmp(properties->getNamespace(), "audio") == 0))
  66. {
  67. GP_ERROR("Failed to load audio source from properties object: must be non-null object and have namespace equal to 'audio'.");
  68. return NULL;
  69. }
  70. const char* path = properties->getString("path");
  71. if (path == NULL)
  72. {
  73. GP_ERROR("Audio file failed to load; the file path was not specified.");
  74. return NULL;
  75. }
  76. // Create the audio source.
  77. AudioSource* audio = AudioSource::create(path);
  78. if (audio == NULL)
  79. {
  80. GP_ERROR("Audio file '%s' failed to load properly.", path);
  81. return NULL;
  82. }
  83. // Set any properties that the user specified in the .audio file.
  84. if (properties->exists("looped"))
  85. {
  86. audio->setLooped(properties->getBool("looped"));
  87. }
  88. if (properties->exists("gain"))
  89. {
  90. audio->setGain(properties->getFloat("gain"));
  91. }
  92. if (properties->exists("pitch"))
  93. {
  94. audio->setPitch(properties->getFloat("pitch"));
  95. }
  96. Vector3 v;
  97. if (properties->getVector3("velocity", &v))
  98. {
  99. audio->setVelocity(v);
  100. }
  101. return audio;
  102. }
  103. AudioSource::State AudioSource::getState() const
  104. {
  105. ALint state;
  106. AL_CHECK( alGetSourcei(_alSource, AL_SOURCE_STATE, &state) );
  107. switch (state)
  108. {
  109. case AL_PLAYING:
  110. return PLAYING;
  111. case AL_PAUSED:
  112. return PAUSED;
  113. case AL_STOPPED:
  114. return STOPPED;
  115. default:
  116. return INITIAL;
  117. }
  118. return INITIAL;
  119. }
  120. void AudioSource::play()
  121. {
  122. AL_CHECK( alSourcePlay(_alSource) );
  123. // Add the source to the controller's list of currently playing sources.
  124. AudioController* audioController = Game::getInstance()->getAudioController();
  125. GP_ASSERT(audioController);
  126. if (audioController->_playingSources.find(this) == audioController->_playingSources.end())
  127. audioController->_playingSources.insert(this);
  128. }
  129. void AudioSource::pause()
  130. {
  131. AL_CHECK( alSourcePause(_alSource) );
  132. // Remove the source from the controller's set of currently playing sources
  133. // if the source is being paused by the user and not the controller itself.
  134. AudioController* audioController = Game::getInstance()->getAudioController();
  135. GP_ASSERT(audioController);
  136. if (audioController->_pausingSource != this)
  137. {
  138. std::set<AudioSource*>::iterator iter = audioController->_playingSources.find(this);
  139. if (iter != audioController->_playingSources.end())
  140. audioController->_playingSources.erase(iter);
  141. }
  142. }
  143. void AudioSource::resume()
  144. {
  145. if (getState() == PAUSED)
  146. {
  147. play();
  148. }
  149. }
  150. void AudioSource::stop()
  151. {
  152. AL_CHECK( alSourceStop(_alSource) );
  153. // Remove the source from the controller's set of currently playing sources.
  154. AudioController* audioController = Game::getInstance()->getAudioController();
  155. GP_ASSERT(audioController);
  156. std::set<AudioSource*>::iterator iter = audioController->_playingSources.find(this);
  157. if (iter != audioController->_playingSources.end())
  158. audioController->_playingSources.erase(iter);
  159. }
  160. void AudioSource::rewind()
  161. {
  162. AL_CHECK( alSourceRewind(_alSource) );
  163. }
  164. bool AudioSource::isLooped() const
  165. {
  166. return _looped;
  167. }
  168. void AudioSource::setLooped(bool looped)
  169. {
  170. AL_CHECK( alSourcei(_alSource, AL_LOOPING, (looped) ? AL_TRUE : AL_FALSE) );
  171. if (AL_LAST_ERROR())
  172. {
  173. GP_ERROR("Failed to set audio source's looped attribute with error: %d", AL_LAST_ERROR());
  174. }
  175. _looped = looped;
  176. }
  177. float AudioSource::getGain() const
  178. {
  179. return _gain;
  180. }
  181. void AudioSource::setGain(float gain)
  182. {
  183. AL_CHECK( alSourcef(_alSource, AL_GAIN, gain) );
  184. _gain = gain;
  185. }
  186. float AudioSource::getPitch() const
  187. {
  188. return _pitch;
  189. }
  190. void AudioSource::setPitch(float pitch)
  191. {
  192. AL_CHECK( alSourcef(_alSource, AL_PITCH, pitch) );
  193. _pitch = pitch;
  194. }
  195. const Vector3& AudioSource::getVelocity() const
  196. {
  197. return _velocity;
  198. }
  199. void AudioSource::setVelocity(const Vector3& velocity)
  200. {
  201. AL_CHECK( alSourcefv(_alSource, AL_VELOCITY, (ALfloat*)&velocity) );
  202. _velocity = velocity;
  203. }
  204. Node* AudioSource::getNode() const
  205. {
  206. return _node;
  207. }
  208. void AudioSource::setNode(Node* node)
  209. {
  210. if (_node != node)
  211. {
  212. // Disconnect our current transform.
  213. if (_node)
  214. {
  215. _node->removeListener(this);
  216. }
  217. // Connect the new node.
  218. _node = node;
  219. if (_node)
  220. {
  221. _node->addListener(this);
  222. // Update the audio source position.
  223. transformChanged(_node, 0);
  224. }
  225. }
  226. }
  227. void AudioSource::transformChanged(Transform* transform, long cookie)
  228. {
  229. if (_node)
  230. {
  231. Vector3 translation = _node->getTranslationWorld();
  232. AL_CHECK( alSourcefv(_alSource, AL_POSITION, (const ALfloat*)&translation.x) );
  233. }
  234. }
  235. AudioSource* AudioSource::clone(NodeCloneContext &context) const
  236. {
  237. GP_ASSERT(_buffer);
  238. ALuint alSource = 0;
  239. AL_CHECK( alGenSources(1, &alSource) );
  240. if (AL_LAST_ERROR())
  241. {
  242. GP_ERROR("Error generating audio source.");
  243. return NULL;
  244. }
  245. AudioSource* audioClone = new AudioSource(_buffer, alSource);
  246. _buffer->addRef();
  247. audioClone->setLooped(isLooped());
  248. audioClone->setGain(getGain());
  249. audioClone->setPitch(getPitch());
  250. audioClone->setVelocity(getVelocity());
  251. if (Node* node = getNode())
  252. {
  253. Node* clonedNode = context.findClonedNode(node);
  254. if (clonedNode)
  255. {
  256. audioClone->setNode(clonedNode);
  257. }
  258. }
  259. return audioClone;
  260. }
  261. }