/src/lipsofsuna/extension/sound/sound-module.c

https://gitlab.com/xenodora/lipsofsuna · C · 290 lines · 198 code · 37 blank · 55 comment · 57 complexity · b042251db2ada680be9ab2f25f0539a1 MD5 · raw file

  1. /* Lips of Suna
  2. * Copyright© 2007-2013 Lips of Suna development team.
  3. *
  4. * Lips of Suna is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Lesser General Public License as
  6. * published by the Free Software Foundation, either version 3 of the
  7. * License, or (at your option) any later version.
  8. *
  9. * Lips of Suna is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public License
  15. * along with Lips of Suna. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. /**
  18. * \addtogroup LIExt Extension
  19. * @{
  20. * \addtogroup LIExtSound Sound
  21. * @{
  22. */
  23. #include "sound-module.h"
  24. #ifndef LI_DISABLE_SOUND
  25. static int private_tick (
  26. LIExtModule* self,
  27. float secs);
  28. #endif
  29. /*****************************************************************************/
  30. LIMaiExtensionInfo liext_sound_info =
  31. {
  32. LIMAI_EXTENSION_VERSION, "Sound",
  33. liext_sound_new,
  34. liext_sound_free,
  35. liext_sound_get_memstat
  36. };
  37. LIExtModule* liext_sound_new (
  38. LIMaiProgram* program)
  39. {
  40. LIExtModule* self;
  41. /* Allocate self. */
  42. self = lisys_calloc (1, sizeof (LIExtModule));
  43. if (self == NULL)
  44. return NULL;
  45. self->program = program;
  46. self->music_looping = 0;
  47. self->music_volume = 1.0f;
  48. self->music_fading = 1.0f;
  49. self->listener_rotation = limat_quaternion_identity ();
  50. #ifndef LI_DISABLE_SOUND
  51. /* Initialize sound. */
  52. self->system = lisnd_system_new ();
  53. if (self->system != NULL)
  54. self->sound = lisnd_manager_new (self->system);
  55. else
  56. printf ("WARNING: cannot initialize sound: %s\n", lisys_error_get_string ());
  57. /* Register callbacks. */
  58. if (!lical_callbacks_insert (program->callbacks, "tick", 1, private_tick, self, self->calls + 0))
  59. {
  60. liext_sound_free (self);
  61. return NULL;
  62. }
  63. #endif
  64. /* Register classes. */
  65. liscr_script_set_userdata (program->script, LIEXT_SCRIPT_SOUND, self);
  66. liscr_script_set_userdata (program->script, LIEXT_SCRIPT_SOUND_SOURCE, self);
  67. liext_script_sound (program->script);
  68. liext_script_sound_source (program->script);
  69. return self;
  70. }
  71. void liext_sound_free (
  72. LIExtModule* self)
  73. {
  74. #ifndef LI_DISABLE_SOUND
  75. /* Remove callbacks. */
  76. lical_handle_releasev (self->calls, sizeof (self->calls) / sizeof (LICalHandle));
  77. /* Free music. */
  78. if (self->music != NULL)
  79. lisnd_source_free (self->music);
  80. if (self->music_fade != NULL)
  81. lisnd_source_free (self->music_fade);
  82. /* Disable sound. */
  83. if (self->sound != NULL)
  84. lisnd_manager_free (self->sound);
  85. if (self->sound != NULL)
  86. lisnd_system_free (self->system);
  87. #endif
  88. lisys_free (self);
  89. }
  90. /**
  91. * \brief Gets the memory statistics of the module.
  92. * \param self Module.
  93. * \param stat Return location for the stats.
  94. */
  95. void liext_sound_get_memstat (
  96. LIExtModule* self,
  97. LIMaiMemstat* stat)
  98. {
  99. /* TODO: memstat */
  100. }
  101. #ifndef LI_DISABLE_SOUND
  102. /**
  103. * \brief Finds a sound sample by name.
  104. *
  105. * \param self Module.
  106. * \param name Name of the sample.
  107. * \return Sample owned by the module or NULL.
  108. */
  109. LISndSample* liext_sound_find_sample (
  110. LIExtModule* self,
  111. const char* name)
  112. {
  113. int ret;
  114. char* file;
  115. const char* path;
  116. LISndSample* sample;
  117. /* Check for existing. */
  118. sample = lisnd_manager_get_sample (self->sound, name);
  119. if (sample != NULL)
  120. return sample;
  121. /* Try to load FLAC. */
  122. file = lisys_string_concat (name, ".flac");
  123. if (file == NULL)
  124. return NULL;
  125. path = lipth_paths_find_file (self->program->paths, file);
  126. lisys_free (file);
  127. if (path != NULL)
  128. {
  129. ret = lisnd_manager_set_sample (self->sound, name, path);
  130. if (ret)
  131. return lisnd_manager_get_sample (self->sound, name);
  132. }
  133. /* Try to load OGG. */
  134. file = lisys_string_concat (name, ".ogg");
  135. if (file == NULL)
  136. return NULL;
  137. path = lipth_paths_find_file (self->program->paths, file);
  138. lisys_free (file);
  139. if (path != NULL)
  140. {
  141. ret = lisnd_manager_set_sample (self->sound, name, path);
  142. if (ret)
  143. return lisnd_manager_get_sample (self->sound, name);
  144. }
  145. return 0;
  146. }
  147. int liext_sound_set_music (
  148. LIExtModule* self,
  149. const char* value)
  150. {
  151. LISndSource* music;
  152. LISndSample* sample;
  153. /* Find sample. */
  154. if (self->sound == NULL)
  155. return 1;
  156. sample = liext_sound_find_sample (self, value);
  157. if (sample == NULL)
  158. return 0;
  159. /* Fade in a new music track. */
  160. music = lisnd_source_new (self->sound, 1);
  161. if (music == NULL)
  162. return 0;
  163. lisnd_source_queue_sample (music, sample);
  164. lisnd_source_set_fading (music, 0.0f, 1.0f / self->music_fading);
  165. lisnd_source_set_volume (music, self->music_volume);
  166. lisnd_source_set_looping (music, self->music_looping);
  167. lisnd_source_set_playing (music, 1);
  168. /* Fade out the old music track. */
  169. if (self->music_fade != NULL)
  170. lisnd_source_free (self->music_fade);
  171. if (self->music != NULL)
  172. lisnd_source_set_fading (self->music, 1.0f, -1.0f / self->music_fading);
  173. self->music_fade = self->music;
  174. self->music = music;
  175. return 1;
  176. }
  177. void liext_sound_set_music_fading (
  178. LIExtModule* self,
  179. float value)
  180. {
  181. self->music_fading = value;
  182. }
  183. void liext_sound_set_music_looping (
  184. LIExtModule* self,
  185. int value)
  186. {
  187. if (self->music_looping != value)
  188. {
  189. self->music_looping = value;
  190. if (self->music != NULL)
  191. lisnd_source_set_looping (self->music, self->music_looping);
  192. }
  193. }
  194. void liext_sound_set_music_volume (
  195. LIExtModule* self,
  196. float value)
  197. {
  198. if (self->sound == NULL)
  199. return;
  200. if (value < 0.0f)
  201. value = 0.0f;
  202. if (value > 1.0f)
  203. value = 1.0f;
  204. self->music_volume = value;
  205. if (self->music != NULL)
  206. lisnd_source_set_volume (self->music, value);
  207. if (self->music_fade != NULL)
  208. lisnd_source_set_volume (self->music_fade, value);
  209. }
  210. #endif
  211. /*****************************************************************************/
  212. #ifndef LI_DISABLE_SOUND
  213. static int private_tick (
  214. LIExtModule* self,
  215. float secs)
  216. {
  217. LIMatVector direction;
  218. LIMatVector velocity;
  219. LIMatVector up;
  220. /* Update listener position. */
  221. velocity = self->listener_velocity;
  222. direction = limat_quaternion_get_basis (self->listener_rotation, 2);
  223. up = limat_quaternion_get_basis (self->listener_rotation, 1);
  224. if (self->system != NULL)
  225. lisnd_system_set_listener (self->system, &self->listener_position, &velocity, &direction, &up);
  226. /* Update music. */
  227. if (self->music_fade != NULL)
  228. {
  229. if (!lisnd_source_update (self->music_fade, secs))
  230. {
  231. limai_program_event (self->program, "music-fade-ended", NULL);
  232. lisnd_source_free (self->music_fade);
  233. self->music_fade = NULL;
  234. }
  235. }
  236. if (self->music != NULL)
  237. {
  238. lisnd_source_set_position (self->music, &self->listener_position);
  239. if (!lisnd_source_update (self->music, secs))
  240. {
  241. limai_program_event (self->program, "music-ended", NULL);
  242. lisnd_source_free (self->music);
  243. self->music = NULL;
  244. }
  245. }
  246. /* Update sound sources. */
  247. if (self->sound != NULL)
  248. lisnd_manager_update (self->sound, secs);
  249. return 1;
  250. }
  251. #endif
  252. /** @} */
  253. /** @} */