AudioSource.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  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(false), _gain(1.0f), _pitch(1.0f), _node(NULL)
  12. {
  13. GP_ASSERT(buffer);
  14. if (isStreamed())
  15. AL_CHECK(alSourceQueueBuffers(_alSource, 1, &buffer->_alBufferQueue[0]));
  16. else
  17. AL_CHECK(alSourcei(_alSource, AL_BUFFER, buffer->_alBufferQueue[0]));
  18. AL_CHECK(alSourcei(_alSource, AL_LOOPING, _looped && !isStreamed()));
  19. AL_CHECK( alSourcef(_alSource, AL_PITCH, _pitch) );
  20. AL_CHECK( alSourcef(_alSource, AL_GAIN, _gain) );
  21. AL_CHECK( alSourcefv(_alSource, AL_VELOCITY, (const ALfloat*)&_velocity) );
  22. }
  23. AudioSource::~AudioSource()
  24. {
  25. if (_alSource)
  26. {
  27. // Remove the source from the controller's set of currently playing sources
  28. // regardless of the source's state. E.g. when the AudioController::pause is called
  29. // all sources are paused but still remain in controller's set of currently
  30. // playing sources. When the source is deleted afterwards, it should be removed
  31. // from controller's set regardless of its playing state.
  32. AudioController* audioController = Game::getInstance()->getAudioController();
  33. GP_ASSERT(audioController);
  34. audioController->removePlayingSource(this);
  35. AL_CHECK(alDeleteSources(1, &_alSource));
  36. _alSource = 0;
  37. }
  38. SAFE_RELEASE(_buffer);
  39. }
  40. AudioSource* AudioSource::create(const char* url, bool streamed)
  41. {
  42. // Load from a .audio file.
  43. std::string pathStr = url;
  44. if (pathStr.find(".audio") != std::string::npos)
  45. {
  46. Properties* properties = Properties::create(url);
  47. if (properties == NULL)
  48. {
  49. GP_ERROR("Failed to create audio source from .audio file.");
  50. return NULL;
  51. }
  52. AudioSource* audioSource = create((strlen(properties->getNamespace()) > 0) ? properties : properties->getNextNamespace());
  53. SAFE_DELETE(properties);
  54. return audioSource;
  55. }
  56. // Create an audio buffer from this URL.
  57. AudioBuffer* buffer = AudioBuffer::create(url, streamed);
  58. if (buffer == NULL)
  59. return NULL;
  60. // Load the audio source.
  61. ALuint alSource = 0;
  62. AL_CHECK( alGenSources(1, &alSource) );
  63. if (AL_LAST_ERROR())
  64. {
  65. SAFE_RELEASE(buffer);
  66. GP_ERROR("Error generating audio source.");
  67. return NULL;
  68. }
  69. return new AudioSource(buffer, alSource);
  70. }
  71. AudioSource* AudioSource::create(Properties* properties)
  72. {
  73. // Check if the properties is valid and has a valid namespace.
  74. GP_ASSERT(properties);
  75. if (!properties || !(strcmp(properties->getNamespace(), "audio") == 0))
  76. {
  77. GP_ERROR("Failed to load audio source from properties object: must be non-null object and have namespace equal to 'audio'.");
  78. return NULL;
  79. }
  80. std::string path;
  81. if (!properties->getPath("path", &path))
  82. {
  83. GP_ERROR("Audio file failed to load; the file path was not specified.");
  84. return NULL;
  85. }
  86. bool streamed = false;
  87. if (properties->exists("streamed"))
  88. {
  89. streamed = properties->getBool("streamed");
  90. }
  91. // Create the audio source.
  92. AudioSource* audio = AudioSource::create(path.c_str(), streamed);
  93. if (audio == NULL)
  94. {
  95. GP_ERROR("Audio file '%s' failed to load properly.", path.c_str());
  96. return NULL;
  97. }
  98. // Set any properties that the user specified in the .audio file.
  99. if (properties->exists("looped"))
  100. {
  101. audio->setLooped(properties->getBool("looped"));
  102. }
  103. if (properties->exists("gain"))
  104. {
  105. audio->setGain(properties->getFloat("gain"));
  106. }
  107. if (properties->exists("pitch"))
  108. {
  109. audio->setPitch(properties->getFloat("pitch"));
  110. }
  111. Vector3 v;
  112. if (properties->getVector3("velocity", &v))
  113. {
  114. audio->setVelocity(v);
  115. }
  116. return audio;
  117. }
  118. AudioSource::State AudioSource::getState() const
  119. {
  120. ALint state;
  121. AL_CHECK( alGetSourcei(_alSource, AL_SOURCE_STATE, &state) );
  122. switch (state)
  123. {
  124. case AL_PLAYING:
  125. return PLAYING;
  126. case AL_PAUSED:
  127. return PAUSED;
  128. case AL_STOPPED:
  129. return STOPPED;
  130. default:
  131. return INITIAL;
  132. }
  133. return INITIAL;
  134. }
  135. bool AudioSource::isStreamed() const
  136. {
  137. GP_ASSERT(_buffer);
  138. return _buffer->_streamed;
  139. }
  140. void AudioSource::play()
  141. {
  142. AL_CHECK( alSourcePlay(_alSource) );
  143. // Add the source to the controller's list of currently playing sources.
  144. AudioController* audioController = Game::getInstance()->getAudioController();
  145. GP_ASSERT(audioController);
  146. audioController->addPlayingSource(this);
  147. }
  148. void AudioSource::pause()
  149. {
  150. AL_CHECK( alSourcePause(_alSource) );
  151. // Remove the source from the controller's set of currently playing sources
  152. // if the source is being paused by the user and not the controller itself.
  153. AudioController* audioController = Game::getInstance()->getAudioController();
  154. GP_ASSERT(audioController);
  155. audioController->removePlayingSource(this);
  156. }
  157. void AudioSource::resume()
  158. {
  159. if (getState() == PAUSED)
  160. {
  161. play();
  162. }
  163. }
  164. void AudioSource::stop()
  165. {
  166. AL_CHECK( alSourceStop(_alSource) );
  167. // Remove the source from the controller's set of currently playing sources.
  168. AudioController* audioController = Game::getInstance()->getAudioController();
  169. GP_ASSERT(audioController);
  170. audioController->removePlayingSource(this);
  171. }
  172. void AudioSource::rewind()
  173. {
  174. AL_CHECK( alSourceRewind(_alSource) );
  175. }
  176. bool AudioSource::isLooped() const
  177. {
  178. return _looped;
  179. }
  180. void AudioSource::setLooped(bool looped)
  181. {
  182. AL_CHECK(alSourcei(_alSource, AL_LOOPING, (looped && !isStreamed()) ? AL_TRUE : AL_FALSE));
  183. if (AL_LAST_ERROR())
  184. {
  185. GP_ERROR("Failed to set audio source's looped attribute with error: %d", AL_LAST_ERROR());
  186. }
  187. _looped = looped;
  188. }
  189. float AudioSource::getGain() const
  190. {
  191. return _gain;
  192. }
  193. void AudioSource::setGain(float gain)
  194. {
  195. AL_CHECK( alSourcef(_alSource, AL_GAIN, gain) );
  196. _gain = gain;
  197. }
  198. float AudioSource::getPitch() const
  199. {
  200. return _pitch;
  201. }
  202. void AudioSource::setPitch(float pitch)
  203. {
  204. AL_CHECK( alSourcef(_alSource, AL_PITCH, pitch) );
  205. _pitch = pitch;
  206. }
  207. const Vector3& AudioSource::getVelocity() const
  208. {
  209. return _velocity;
  210. }
  211. void AudioSource::setVelocity(const Vector3& velocity)
  212. {
  213. AL_CHECK( alSourcefv(_alSource, AL_VELOCITY, (ALfloat*)&velocity) );
  214. _velocity = velocity;
  215. }
  216. void AudioSource::setVelocity(float x, float y, float z)
  217. {
  218. setVelocity(Vector3(x, y, z));
  219. }
  220. Node* AudioSource::getNode() const
  221. {
  222. return _node;
  223. }
  224. void AudioSource::setNode(Node* node)
  225. {
  226. if (_node != node)
  227. {
  228. // Disconnect our current transform.
  229. if (_node)
  230. {
  231. _node->removeListener(this);
  232. }
  233. // Connect the new node.
  234. _node = node;
  235. if (_node)
  236. {
  237. _node->addListener(this);
  238. // Update the audio source position.
  239. transformChanged(_node, 0);
  240. }
  241. }
  242. }
  243. void AudioSource::transformChanged(Transform* transform, long cookie)
  244. {
  245. if (_node)
  246. {
  247. Vector3 translation = _node->getTranslationWorld();
  248. AL_CHECK( alSourcefv(_alSource, AL_POSITION, (const ALfloat*)&translation.x) );
  249. }
  250. }
  251. AudioSource* AudioSource::clone(NodeCloneContext &context) const
  252. {
  253. GP_ASSERT(_buffer);
  254. ALuint alSource = 0;
  255. AL_CHECK( alGenSources(1, &alSource) );
  256. if (AL_LAST_ERROR())
  257. {
  258. GP_ERROR("Error generating audio source.");
  259. return NULL;
  260. }
  261. AudioSource* audioClone = new AudioSource(_buffer, alSource);
  262. _buffer->addRef();
  263. audioClone->setLooped(isLooped());
  264. audioClone->setGain(getGain());
  265. audioClone->setPitch(getPitch());
  266. audioClone->setVelocity(getVelocity());
  267. if (Node* node = getNode())
  268. {
  269. Node* clonedNode = context.findClonedNode(node);
  270. if (clonedNode)
  271. {
  272. audioClone->setNode(clonedNode);
  273. }
  274. }
  275. return audioClone;
  276. }
  277. bool AudioSource::streamDataIfNeeded()
  278. {
  279. GP_ASSERT( isStreamed() );
  280. if( getState() != PLAYING )
  281. return false;
  282. int queuedBuffers;
  283. alGetSourcei(_alSource, AL_BUFFERS_QUEUED, &queuedBuffers);
  284. int buffersNeeded = std::min<int>(_buffer->_buffersNeededCount, AudioBuffer::STREAMING_BUFFER_QUEUE_SIZE);
  285. if (queuedBuffers < buffersNeeded)
  286. {
  287. while (queuedBuffers < buffersNeeded)
  288. {
  289. if (!_buffer->streamData(_buffer->_alBufferQueue[queuedBuffers], _looped))
  290. return false;
  291. AL_CHECK( alSourceQueueBuffers(_alSource, 1, &_buffer->_alBufferQueue[queuedBuffers]) );
  292. queuedBuffers++;
  293. }
  294. }
  295. else
  296. {
  297. int processedBuffers;
  298. alGetSourcei(_alSource, AL_BUFFERS_PROCESSED, &processedBuffers);
  299. while (processedBuffers-- > 0)
  300. {
  301. ALuint bufferID;
  302. AL_CHECK( alSourceUnqueueBuffers(_alSource, 1, &bufferID) );
  303. if (!_buffer->streamData(bufferID, _looped))
  304. return false;
  305. AL_CHECK( alSourceQueueBuffers(_alSource, 1, &bufferID) );
  306. }
  307. }
  308. return true;
  309. }
  310. }