custom_audiostreams.rst 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. .. _doc_custom_audiostreams:
  2. Custom AudioStreams
  3. ===================
  4. Introduction
  5. ------------
  6. AudioStream is the base class of all audio emitting objects.
  7. AudioStreamPlayer binds onto an AudioStream to emit PCM data
  8. into an AudioServer which manages audio drivers.
  9. All audio resources require two audio based classes: AudioStream
  10. and AudioStreamPlayback. As a data container, AudioStream contains
  11. the resource and exposes itself to GDScript. AudioStream references
  12. its own internal custom AudioStreamPlayback which translates
  13. AudioStream into PCM data.
  14. This guide assumes the reader knows how to create C++ modules. If not, refer to this guide
  15. :ref:`doc_custom_modules_in_cpp`.
  16. References:
  17. ~~~~~~~~~~~
  18. - `servers/audio/audio_stream.h <https://github.com/godotengine/godot/blob/master/servers/audio/audio_stream.h>`__
  19. - `scene/audio/audio_stream_player.cpp <https://github.com/godotengine/godot/blob/master/scene/audio/audio_stream_player.cpp>`__
  20. What for?
  21. ---------
  22. - Binding external libraries (like Wwise, FMOD, etc).
  23. - Adding custom audio queues
  24. - Adding support for more audio formats
  25. Create an AudioStream
  26. ---------------------
  27. An AudioStream consists of three components: data container, stream name,
  28. and an AudioStreamPlayback friend class generator. Audio data can be
  29. loaded in a number of ways such as with an internal counter for a tone generator,
  30. internal/external buffer, or a file reference.
  31. Some AudioStreams need to be stateless such as objects loaded from
  32. ResourceLoader. ResourceLoader loads once and references the same
  33. object regardless how many times ``load`` is called on a specific resource.
  34. Therefore, playback state must be self-contained in AudioStreamPlayback.
  35. .. code-block:: cpp
  36. :caption: audiostream_mytone.h
  37. #include "core/reference.h"
  38. #include "core/resource.h"
  39. #include "servers/audio/audio_stream.h"
  40. class AudioStreamMyTone : public AudioStream {
  41. GDCLASS(AudioStreamMyTone, AudioStream)
  42. private:
  43. friend class AudioStreamPlaybackMyTone;
  44. uint64_t pos;
  45. int mix_rate;
  46. bool stereo;
  47. int hz;
  48. public:
  49. void reset();
  50. void set_position(uint64_t pos);
  51. virtual Ref<AudioStreamPlayback> instance_playback();
  52. virtual String get_stream_name() const;
  53. void gen_tone(int16_t *pcm_buf, int size);
  54. virtual float get_length() const { return 0; } // if supported, otherwise return 0
  55. AudioStreamMyTone();
  56. protected:
  57. static void _bind_methods();
  58. };
  59. .. code-block:: cpp
  60. :caption: audiostream_mytone.cpp
  61. #include "audiostream_mytone.h"
  62. AudioStreamMyTone::AudioStreamMyTone()
  63. : mix_rate(44100), stereo(false), hz(639) {
  64. }
  65. Ref<AudioStreamPlayback> AudioStreamMyTone::instance_playback() {
  66. Ref<AudioStreamPlaybackMyTone> talking_tree;
  67. talking_tree.instantiate();
  68. talking_tree->base = Ref<AudioStreamMyTone>(this);
  69. return talking_tree;
  70. }
  71. String AudioStreamMyTone::get_stream_name() const {
  72. return "MyTone";
  73. }
  74. void AudioStreamMyTone::reset() {
  75. set_position(0);
  76. }
  77. void AudioStreamMyTone::set_position(uint64_t p) {
  78. pos = p;
  79. }
  80. void AudioStreamMyTone::gen_tone(int16_t *pcm_buf, int size) {
  81. for (int i = 0; i < size; i++) {
  82. pcm_buf[i] = 32767.0 * sin(2.0 * Math_PI * double(pos + i) / (double(mix_rate) / double(hz)));
  83. }
  84. pos += size;
  85. }
  86. void AudioStreamMyTone::_bind_methods() {
  87. ClassDB::bind_method(D_METHOD("reset"), &AudioStreamMyTone::reset);
  88. ClassDB::bind_method(D_METHOD("get_stream_name"), &AudioStreamMyTone::get_stream_name);
  89. }
  90. References:
  91. ~~~~~~~~~~~
  92. - `servers/audio/audio_stream.h <https://github.com/godotengine/godot/blob/master/servers/audio/audio_stream.h>`__
  93. Create an AudioStreamPlayback
  94. -----------------------------
  95. AudioStreamPlayer uses ``mix`` callback to obtain PCM data. The callback must match sample rate and fill the buffer.
  96. Since AudioStreamPlayback is controlled by the audio thread, i/o and dynamic memory allocation are forbidden.
  97. .. code-block:: cpp
  98. :caption: audiostreamplayer_mytone.h
  99. #include "core/reference.h"
  100. #include "core/resource.h"
  101. #include "servers/audio/audio_stream.h"
  102. class AudioStreamPlaybackMyTone : public AudioStreamPlayback {
  103. GDCLASS(AudioStreamPlaybackMyTone, AudioStreamPlayback)
  104. friend class AudioStreamMyTone;
  105. private:
  106. enum {
  107. PCM_BUFFER_SIZE = 4096
  108. };
  109. enum {
  110. MIX_FRAC_BITS = 13,
  111. MIX_FRAC_LEN = (1 << MIX_FRAC_BITS),
  112. MIX_FRAC_MASK = MIX_FRAC_LEN - 1,
  113. };
  114. void *pcm_buffer;
  115. Ref<AudioStreamMyTone> base;
  116. bool active;
  117. public:
  118. virtual void start(float p_from_pos = 0.0);
  119. virtual void stop();
  120. virtual bool is_playing() const;
  121. virtual int get_loop_count() const; // times it looped
  122. virtual float get_playback_position() const;
  123. virtual void seek(float p_time);
  124. virtual void mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames);
  125. virtual float get_length() const; // if supported, otherwise return 0
  126. AudioStreamPlaybackMyTone();
  127. ~AudioStreamPlaybackMyTone();
  128. };
  129. .. code-block:: cpp
  130. :caption: audiostreamplayer_mytone.cpp
  131. #include "audiostreamplayer_mytone.h"
  132. #include "core/math/math_funcs.h"
  133. #include "core/print_string.h"
  134. AudioStreamPlaybackMyTone::AudioStreamPlaybackMyTone()
  135. : active(false) {
  136. AudioServer::get_singleton()->lock();
  137. pcm_buffer = AudioServer::get_singleton()->audio_data_alloc(PCM_BUFFER_SIZE);
  138. zeromem(pcm_buffer, PCM_BUFFER_SIZE);
  139. AudioServer::get_singleton()->unlock();
  140. }
  141. AudioStreamPlaybackMyTone::~AudioStreamPlaybackMyTone() {
  142. if(pcm_buffer) {
  143. AudioServer::get_singleton()->audio_data_free(pcm_buffer);
  144. pcm_buffer = NULL;
  145. }
  146. }
  147. void AudioStreamPlaybackMyTone::stop() {
  148. active = false;
  149. base->reset();
  150. }
  151. void AudioStreamPlaybackMyTone::start(float p_from_pos) {
  152. seek(p_from_pos);
  153. active = true;
  154. }
  155. void AudioStreamPlaybackMyTone::seek(float p_time) {
  156. float max = get_length();
  157. if (p_time < 0) {
  158. p_time = 0;
  159. }
  160. base->set_position(uint64_t(p_time * base->mix_rate) << MIX_FRAC_BITS);
  161. }
  162. void AudioStreamPlaybackMyTone::mix(AudioFrame *p_buffer, float p_rate, int p_frames) {
  163. ERR_FAIL_COND(!active);
  164. if (!active) {
  165. return;
  166. }
  167. zeromem(pcm_buffer, PCM_BUFFER_SIZE);
  168. int16_t *buf = (int16_t *)pcm_buffer;
  169. base->gen_tone(buf, p_frames);
  170. for(int i = 0; i < p_frames; i++) {
  171. float sample = float(buf[i]) / 32767.0;
  172. p_buffer[i] = AudioFrame(sample, sample);
  173. }
  174. }
  175. int AudioStreamPlaybackMyTone::get_loop_count() const {
  176. return 0;
  177. }
  178. float AudioStreamPlaybackMyTone::get_playback_position() const {
  179. return 0.0;
  180. }
  181. float AudioStreamPlaybackMyTone::get_length() const {
  182. return 0.0;
  183. }
  184. bool AudioStreamPlaybackMyTone::is_playing() const {
  185. return active;
  186. }
  187. Resampling
  188. ~~~~~~~~~~
  189. Godot's AudioServer currently uses 44100 Hz sample rate. When other sample rates are
  190. needed such as 48000, either provide one or use AudioStreamPlaybackResampled.
  191. Godot provides cubic interpolation for audio resampling.
  192. Instead of overloading ``mix``, AudioStreamPlaybackResampled uses ``_mix_internal`` to
  193. query AudioFrames and ``get_stream_sampling_rate`` to query current mix rate.
  194. .. code-block:: cpp
  195. :caption: mytone_audiostream_resampled.h
  196. #include "core/reference.h"
  197. #include "core/resource.h"
  198. #include "servers/audio/audio_stream.h"
  199. class AudioStreamMyToneResampled;
  200. class AudioStreamPlaybackResampledMyTone : public AudioStreamPlaybackResampled {
  201. GDCLASS(AudioStreamPlaybackResampledMyTone, AudioStreamPlaybackResampled)
  202. friend class AudioStreamMyToneResampled;
  203. private:
  204. enum {
  205. PCM_BUFFER_SIZE = 4096
  206. };
  207. enum {
  208. MIX_FRAC_BITS = 13,
  209. MIX_FRAC_LEN = (1 << MIX_FRAC_BITS),
  210. MIX_FRAC_MASK = MIX_FRAC_LEN - 1,
  211. };
  212. void *pcm_buffer;
  213. Ref<AudioStreamMyToneResampled> base;
  214. bool active;
  215. protected:
  216. virtual void _mix_internal(AudioFrame *p_buffer, int p_frames);
  217. public:
  218. virtual void start(float p_from_pos = 0.0);
  219. virtual void stop();
  220. virtual bool is_playing() const;
  221. virtual int get_loop_count() const; // times it looped
  222. virtual float get_playback_position() const;
  223. virtual void seek(float p_time);
  224. virtual float get_length() const; // if supported, otherwise return 0
  225. virtual float get_stream_sampling_rate();
  226. AudioStreamPlaybackResampledMyTone();
  227. ~AudioStreamPlaybackResampledMyTone();
  228. };
  229. .. code-block:: cpp
  230. :caption: mytone_audiostream_resampled.cpp
  231. #include "mytone_audiostream_resampled.h"
  232. #include "core/math/math_funcs.h"
  233. #include "core/print_string.h"
  234. AudioStreamPlaybackResampledMyTone::AudioStreamPlaybackResampledMyTone()
  235. : active(false) {
  236. AudioServer::get_singleton()->lock();
  237. pcm_buffer = AudioServer::get_singleton()->audio_data_alloc(PCM_BUFFER_SIZE);
  238. zeromem(pcm_buffer, PCM_BUFFER_SIZE);
  239. AudioServer::get_singleton()->unlock();
  240. }
  241. AudioStreamPlaybackResampledMyTone::~AudioStreamPlaybackResampledMyTone() {
  242. if (pcm_buffer) {
  243. AudioServer::get_singleton()->audio_data_free(pcm_buffer);
  244. pcm_buffer = NULL;
  245. }
  246. }
  247. void AudioStreamPlaybackResampledMyTone::stop() {
  248. active = false;
  249. base->reset();
  250. }
  251. void AudioStreamPlaybackResampledMyTone::start(float p_from_pos) {
  252. seek(p_from_pos);
  253. active = true;
  254. }
  255. void AudioStreamPlaybackResampledMyTone::seek(float p_time) {
  256. float max = get_length();
  257. if (p_time < 0) {
  258. p_time = 0;
  259. }
  260. base->set_position(uint64_t(p_time * base->mix_rate) << MIX_FRAC_BITS);
  261. }
  262. void AudioStreamPlaybackResampledMyTone::_mix_internal(AudioFrame *p_buffer, int p_frames) {
  263. ERR_FAIL_COND(!active);
  264. if (!active) {
  265. return;
  266. }
  267. zeromem(pcm_buffer, PCM_BUFFER_SIZE);
  268. int16_t *buf = (int16_t *)pcm_buffer;
  269. base->gen_tone(buf, p_frames);
  270. for(int i = 0; i < p_frames; i++) {
  271. float sample = float(buf[i]) / 32767.0;
  272. p_buffer[i] = AudioFrame(sample, sample);
  273. }
  274. }
  275. float AudioStreamPlaybackResampledMyTone::get_stream_sampling_rate() {
  276. return float(base->mix_rate);
  277. }
  278. int AudioStreamPlaybackResampledMyTone::get_loop_count() const {
  279. return 0;
  280. }
  281. float AudioStreamPlaybackResampledMyTone::get_playback_position() const {
  282. return 0.0;
  283. }
  284. float AudioStreamPlaybackResampledMyTone::get_length() const {
  285. return 0.0;
  286. }
  287. bool AudioStreamPlaybackResampledMyTone::is_playing() const {
  288. return active;
  289. }
  290. References:
  291. ~~~~~~~~~~~
  292. - `core/math/audio_frame.h <https://github.com/godotengine/godot/blob/master/core/math/audio_frame.h>`__
  293. - `servers/audio/audio_stream.h <https://github.com/godotengine/godot/blob/master/servers/audio/audio_stream.h>`__
  294. - `scene/audio/audio_stream_player.cpp <https://github.com/godotengine/godot/blob/master/scene/audio/audio_stream_player.cpp>`__