Browse Source

Corrections to audio sync tutorial

Juan Linietsky 6 years ago
parent
commit
6e17fc8c1b
1 changed files with 25 additions and 14 deletions
  1. 25 14
      tutorials/audio/sync_with_audio.rst

+ 25 - 14
tutorials/audio/sync_with_audio.rst

@@ -6,28 +6,34 @@ Sync the gameplay with audio and music
 Introduction
 ------------
 
-Normally, music plays on the background, without precise interaction with the gameplay.
-
-For sound effects, there may be a slight delay and latency in the output, but it's so small players won't really care in most cases.
+In any application or game, sound and music playback will have a slight delay. For games, this delay is often so small that is negligible. Sound effects will come out a few milliseconds after any play() function is called. For music this does not matter as in most games it does not interact with the gameplay.
 
 Still, for some games (mainly, rythm games), it may be required to synchronize player actions with something happening in a song (usually in sync with the BPM). For this, having more precise timing information for an exact playback position is very welcome.
 
-Achieving very low playback timing precision is very difficult. This because many factors are at play during audio playback, not just the song:
+Achieving very low playback timing precision is very difficult. This because many factors are at play during audio playback:
+
 
-* Audio is mixed in chunks (not continuously), depending on the size of buffers used.
+* Audio is mixed in chunks (not continuously), depending on the size of audio buffers used (check latency in project settings).
 * Audio has latency after mixed, it doesn't immediately play after mixed.
 * Graphics APIs display two or three frames late.
 * When playing on TVs, some delay may be added due to image processing.
 
-That said, beginning Godot 3.2, some helpers were added to obtain more precise playback timing.
+The most common way to reducing latency is to shrink the audio buffers (again, by editing the latency setting in the project settings). The problem is that when latency is too small, it will require considerably higher amount of CPU for sound mixing. this increases the risk of skpping (a crack in sound because a mix callback was lost). 
+
+This is common a tradeoff, so Godot ships with sensible defaults that should not need to be commonly altered. 
+
+The problem, in the end, is dealing with synchronization for games tha require it, and not so much this slight delay. Beginning Godot 3.2, some helpers were added to obtain more precise playback timing.
 
 Using the system clock to sync
 -------------------------------
 
-If you call :ref:`AudioStreamPlayer.play()<class_AudioStreamPlayer_method_play>`, sound will not begin immediately, but when the 
-audio thread processes the next block. 
+As mentioned before, If you call :ref:`AudioStreamPlayer.play()<class_AudioStreamPlayer_method_play>`, sound will not begin immediately, but when the audio thread processes the next block. 
+
+This delay can't be avoided but it can be estimated by calling :ref:`AudioServer.get_time_to_next_mix()<class_AudioServer_method_get_time_to_next_mix>`.
 
-The timing when the next mix callback will happen can be estimated by calling :ref:`AudioServer.get_time_to_next_mix()<class_AudioServer_method_get_time_to_next_mix>` and the output latency can also be guessed by calling :ref:`AudioServer.get_output_latency()<class_AudioServer_get_output_latency>`. Add these two and it's possible to know almost exactly when a song will begin playing.
+The output latency (what happens after the mix) can also be estimated by calling :ref:`AudioServer.get_output_latency()<class_AudioServer_get_output_latency>`. 
+
+Add these two and it's possible to guess almost exactly when sound or music will begin playing in the speakers:
 
 .. tabs::
  .. code-tab:: gdscript GDScript
@@ -35,7 +41,7 @@ The timing when the next mix callback will happen can be estimated by calling :r
     var actual_play_time = AudioServer.get_time_to_next_mix() + AudioServer.get_output_latency()
     $Song.play()
 
-This way, obtaining the actual playback position is possible:
+This way, obtaining the actual playback position during *_process()* is possible:
 
 .. tabs::
  .. code-tab:: gdscript GDScript
@@ -58,21 +64,26 @@ This way, obtaining the actual playback position is possible:
         print("Time is: ",time)
 
 
-In the long run, though, the sound hardware clock is never exactly in sync with the system clock, so they will slowly drift. For a rythm game where a song begins and ends after a few minutes, this approach is fine. For a game where playback can last a much longer time, the game will eventually go out of sync and a different approach is needed.
+In the long run, though, as the sound hardware clock is never exactly in sync with the system clock, they timing information will slowly drift away. 
+
+For a rythm game where a song begins and ends after a few minutes, this approach is fine (and it's the recommended approach). For a game where playback can last a much longer time, the game will eventually go out of sync and a different approach is needed.
 
 Using the sound hardware clock to sync
 -------------------------------
 
-Using :ref:`AudioStreamPlayer.get_playback_position()<class_AudioStreamPlayer_method_get_playback_position>` to obtain the current position for the song sounds ideal, but it's not that useful as-is. This value will increment in chunks, so many calls can return the same value. Added to this, the value will be out of sync with the speakers.
+Using :ref:`AudioStreamPlayer.get_playback_position()<class_AudioStreamPlayer_method_get_playback_position>` to obtain the current position for the song sounds ideal, but it's not that useful as-is. This value will increment in chunks (every time the audio callback mixed a block of sound), so many calls can return the same value. Added to this, the value will be out of sync with the speakers too because of the previously mentioned reasons.
+
+To compensate for the "chunked" output, there is a function that can help: :ref:`AudioServer.get_time_since_last_mix()<class_AudioServer_get_time_since_last_mix>`.
+
 
-To compensate for the chunked output, there is a function that can help: :ref:`AudioServer.get_time_since_last_mix()<class_AudioServer_get_time_since_last_mix>`. Adding the return value from this function increases precision:
+Adding the return value from this function to *get_playback_position()* increases precision:
 
 .. tabs::
  .. code-tab:: gdscript GDScript
 
     var time = $Player.get_playback_position() + AudioServer.get_time_since_last_mix()
 
-Finally, substract the latency:
+To increase precision, substract the latency information (how much it takes for the audio to be heard after it was mixed):
 
 .. tabs::
  .. code-tab:: gdscript GDScript