SDL: docs: Corrections to audio section of README-migration.md

From 97b2f747d0a41ae7e4f48512fe1ddb9fb72cc2fa Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Thu, 22 Jun 2023 01:17:16 -0400
Subject: [PATCH] docs: Corrections to audio section of README-migration.md

---
 docs/README-migration.md | 27 ++++++++++++++++-----------
 1 file changed, 16 insertions(+), 11 deletions(-)

diff --git a/docs/README-migration.md b/docs/README-migration.md
index c5d6131d74f0..10366ced2092 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -84,8 +84,9 @@ in SDL3:
 
 ```c
     /* ...somewhere near startup... */
-    SDL_AudioDeviceID my_audio_device = SDL_OpenAudioDevice(0, SDL_AUDIO_S16, 2, 44100);
-    SDL_AudioSteam *stream = SDL_CreateAndBindAudioStream(my_audio_device, SDL_AUDIO_S16, 2, 44100);
+    SDL_AudioSpec spec = { SDL_AUDIO_S16, 2, 44100 };
+    SDL_AudioDeviceID my_audio_device = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, &spec);
+    SDL_AudioSteam *stream = SDL_CreateAndBindAudioStream(my_audio_device, &spec);
 
     /* ...in your main loop... */
     /* calculate a little more audio into `buf`, add it to `stream` */
@@ -102,8 +103,9 @@ If you absolutely require the callback method, SDL_AudioStreams can use a callba
     }
 
     /* ...somewhere near startup... */
-    SDL_AudioDeviceID my_audio_device = SDL_OpenAudioDevice(0, SDL_AUDIO_S16, 2, 44100);
-    SDL_AudioSteam *stream = SDL_CreateAndBindAudioStream(my_audio_device, SDL_AUDIO_S16, 2, 44100);
+    SDL_AudioSpec spec = { SDL_AUDIO_S16, 2, 44100 };
+    SDL_AudioDeviceID my_audio_device = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, &spec);
+    SDL_AudioSteam *stream = SDL_CreateAndBindAudioStream(my_audio_device, &spec);
     SDL_SetAudioStreamGetCallback(stream, MyAudioCallback);
 
     /* MyAudioCallback will be called whenever the device requests more audio data. */
@@ -113,11 +115,11 @@ SDL_AudioInit() and SDL_AudioQuit() have been removed. Instead you can call SDL_
 
 The `SDL_AUDIO_ALLOW_*` symbols have been removed; now one may request the format they desire from the audio device, but ultimately SDL_AudioStream will manage the difference. One can use SDL_GetAudioDeviceFormat() to see what the final format is, if any "allowed" changes should be accomodated by the app.
 
-SDL_AudioDeviceID no longer represents an open audio device's handle, it's now the device's instance ID that the device owns as long as it exists on the system. The separation between device instances and device indexes is gone.
+SDL_AudioDeviceID now represents both an open audio device's handle (a "logical" device) and the instance ID that the hardware owns as long as it exists on the system (a "physical" device). The separation between device instances and device indexes is gone.
 
-Devices are opened by device instance ID, and a new handle is not generated by the open operation; instead, opens of the same device instance are reference counted. This allows any device to be opened multiple times, possibly by unrelated pieces of code.
+Devices are opened by physical device instance ID, and a new logical instance ID is generated by the open operation; This allows any device to be opened multiple times, possibly by unrelated pieces of code. SDL will manage the logical devices to provide a single stream of audio to the physical device behind the scenes.
 
-Devices are not opened by an arbitrary string name anymore, but by device instance ID (or 0 to request a reasonable default, like a NULL string in SDL2). In SDL2, the string was used to open both a standard list of system devices, but also allowed for arbitrary devices, such as hostnames of network sound servers. In SDL3, many of the backends that supported arbitrary device names are obsolete and have been removed; of those that remain, arbitrary devices will be opened with a device ID of 0 and an SDL_hint, so specific end-users can set an environment variable to fit their needs and apps don't have to concern themselves with it.
+Devices are not opened by an arbitrary string name anymore, but by device instance ID (or magic numbers to request a reasonable default, like a NULL string in SDL2). In SDL2, the string was used to open both a standard list of system devices, but also allowed for arbitrary devices, such as hostnames of network sound servers. In SDL3, many of the backends that supported arbitrary device names are obsolete and have been removed; of those that remain, arbitrary devices will be opened with a default device ID and an SDL_hint, so specific end-users can set an environment variable to fit their needs and apps don't have to concern themselves with it.
 
 Many functions that would accept a device index and an `iscapture` parameter now just take an SDL_AudioDeviceID, as they are unique across all devices, instead of separate indices into output and capture device lists.
 
@@ -142,7 +144,7 @@ Rather than iterating over audio devices using a device index, there is a new fu
 }

-SDL_LockAudioDevice() and SDL_UnlockAudioDevice() have been removed, since there is no callback in another thread to protect. Internally, SDL’s audio subsystem and SDL_AudioStream maintain their own locks internally, so audio streams are safe to use from any thread.
+SDL_LockAudioDevice() and SDL_UnlockAudioDevice() have been removed, since there is no callback in another thread to protect. SDL’s audio subsystem and SDL_AudioStream maintain their own locks internally, so audio streams are safe to use from any thread. If the app assigns a callback to a specific stream, it can use the stream’s lock through SDL_LockAudioStream() if necessary.

SDL_PauseAudioDevice() no longer takes a second argument; it always pauses the device. To unpause, use SDL_UnpauseAudioDevice().

@@ -164,6 +166,8 @@ SDL_AudioInit() and SDL_AudioQuit() have been removed. Instead you can call SDL_

SDL_FreeWAV has been removed and calls can be replaced with SDL_free.

+SDL_LoadWAV() is a proper function now and no longer a macro (but offers the same functionality otherwise).
+
SDL_AudioCVT interface has been removed, the SDL_AudioStream interface (for audio supplied in pieces) or the new SDL_ConvertAudioSamples() function (for converting a complete audio buffer in one call) can be used instead.

Code that used to look like this:
@@ -180,8 +184,9 @@ should be changed to:

    Uint8 *dst_data = NULL;
    int dst_len = 0;
-    if (SDL_ConvertAudioSamples(src_format, src_channels, src_rate, src_data, src_len
-                                dst_format, dst_channels, dst_rate, &dst_data, &dst_len) < 0) {
+    const SDL_AudioSpec src_spec = { src_format, src_channels, src_rate };
+    const SDL_AudioSpec dst_spec = { dst_format, dst_channels, dst_rate };
+    if (SDL_ConvertAudioSamples(&src_spec, src_data, src_len, &dst_spec, &dst_data, &dst_len) < 0) {
        /* error */
    }
    do_something(dst_data, dst_len);
@@ -210,7 +215,7 @@ If you need to convert U16 audio data to a still-supported format at runtime, th

All remaining `AUDIO_*` symbols have been renamed to `SDL_AUDIO_*` for API consistency, but othewise are identical in value and usage.

-In SDL2, SDL_AudioStream would convert/resample audio data during input (via SDL_AudioStreamPut). In SDL3, it does this work when requesting audio (via SDL_GetAudioStreamData, which would have been SDL_AudioStreamPut in SDL2. The way you use an AudioStream is roughly the same, just be aware that the workload moved to a different phase.
+In SDL2, SDL_AudioStream would convert/resample audio data during input (via SDL_AudioStreamPut). In SDL3, it does this work when requesting audio (via SDL_GetAudioStreamData, which would have been SDL_AudioStreamGet in SDL2). The way you use an AudioStream is roughly the same, just be aware that the workload moved to a different phase.
In SDL2, SDL_AudioStreamAvailable() returns 0 if passed a NULL stream. In SDL3, the equivalent SDL_GetAudioStreamAvailable() call returns -1 and sets an error string, which matches other audiostream APIs' behavior.