SDL3_API分类参考_音频(CategoryAudio)

2026-3-6 / 0 评论 / 2 阅读

音频子系统(CategoryAudio)

SDL 库的音频功能模块,SDL3 中所有音频相关操作均围绕 SDL_AudioStream(音频流)展开。无论是播放/录制音频、格式转换、流式传输、数据缓冲还是混音,都需要通过音频流来处理。

音频流核心特性

音频流具备高度灵活性:

  • 可随时接收任意数量的音频数据,支持所有SDL兼容格式;
  • 可按需输出任意目标格式的音频数据,即使在处理过程中输入/输出格式发生变化;
  • 应用程序可打开音频设备并绑定多个音频流,按需向流中填充数据;
  • 当设备需要音频数据时,会从所有绑定的流中拉取数据并混音后播放;
  • 支持通过应用提供的回调函数按需获取数据,与SDL2的音频模型高度兼容。

SDL 还提供了简易的 WAV 文件加载接口:SDL_LoadWAV(从文件加载)和 SDL_LoadWAV_IO(从自定义IO加载),作为程序加载音频数据的基础方式。

逻辑音频设备

在SDL3中,打开物理音频设备(如声卡)会得到一个逻辑设备ID,可绑定音频流使用。核心特性:

  1. 隔离性:每次打开设备都会生成新的逻辑设备,程序不同模块(如语音库、混音器)的音频操作互不干扰;
  2. 自动混音:SDL会在底层将所有逻辑设备的音频混合为单个缓冲区,输出到物理设备;
  3. 资源优化:SDL仅在系统层面打开物理设备一次,内部管理所有逻辑设备;
  4. 动态迁移:使用默认设备时,SDL可自动将逻辑设备迁移到新的物理硬件(如插入耳机、系统默认设备变更),无需程序干预。

简化音频模型

针对仅需单音频源的场景,SDL提供 SDL_OpenAudioDeviceStream 简化接口:

  • 单个函数完成:打开音频设备 → 创建音频流 → 绑定流到设备 → (可选)设置数据回调;
  • 核心操作接口为 SDL_AudioStream,设备句柄被隐藏;
  • 销毁该函数创建的流会自动关闭设备,且无法修改流绑定关系;
  • 设备默认处于暂停状态,需显式恢复播放(非简化模型中,设备默认未暂停,绑定流后即播放)。

声道布局

SDL处理的音频数据为非压缩的交错式PCM数据(可通过第三方解码器处理MP3等格式,SDL不内置解码)。各声道数据在内存中有固定排列顺序:

缩写说明

  • FRONT = 单声道扬声器
  • FL = 前置左声道
  • FR = 前置右声道
  • FC = 前置中声道
  • BL = 后置左声道
  • BR = 后置右声道
  • SR = 环绕右声道
  • SL = 环绕左声道
  • BC = 后置中声道
  • LFE = 低频声道(重低音)

标准声道布局(内存排列顺序)

  • 1声道(单声道):FRONT
  • 2声道(立体声):FL, FR
  • 3声道(2.1):FL, FR, LFE
  • 4声道(四声道):FL, FR, BL, BR
  • 5声道(4.1):FL, FR, LFE, BL, BR
  • 6声道(5.1):FL, FR, FC, LFE, BL, BR(后两个也可为SL, SR)
  • 7声道(6.1):FL, FR, FC, LFE, BC, SL, SR
  • 8声道(7.1):FL, FR, FC, LFE, BL, BR, SL, SR

该顺序与DirectSound一致,SDL会自动适配不同平台的声道顺序要求。SDL_AudioStream 也支持自定义声道映射,满足特殊音频处理需求。


函数

  • SDL_AudioDevicePaused:检查音频设备是否处于暂停状态(返回布尔值)
  • SDL_AudioStreamDevicePaused:检查音频流绑定的设备是否暂停
  • SDL_BindAudioStream:将单个音频流绑定到指定音频设备(混音播放)
  • SDL_BindAudioStreams:批量绑定多个音频流到指定音频设备
  • SDL_ClearAudioStream:清空音频流中的所有缓冲数据
  • SDL_CloseAudioDevice:关闭音频设备(释放设备资源,停止播放)
  • SDL_ConvertAudioSamples:直接转换音频样本格式(单次转换,无需创建流)
  • SDL_CreateAudioStream:创建音频流(指定输入/输出格式、采样率、声道数)
  • SDL_DestroyAudioStream:销毁音频流(释放内存,若为简化模型创建则关闭设备)
  • SDL_FlushAudioStream:刷新音频流(强制输出所有缓冲数据)
  • SDL_GetAudioDeviceChannelMap:获取音频设备的声道映射表
  • SDL_GetAudioDeviceFormat:获取音频设备的当前格式(采样率、声道数、格式)
  • SDL_GetAudioDeviceGain:获取音频设备的增益(音量,0~1.0)
  • SDL_GetAudioDeviceName:通过设备ID获取音频设备名称
  • SDL_GetAudioDriver:获取指定索引的音频驱动名称
  • SDL_GetAudioFormatName:获取音频格式的可读名称(如 "SDL_AUDIO_F32")
  • SDL_GetAudioPlaybackDevices:枚举系统中所有音频播放设备(返回设备ID列表)
  • SDL_GetAudioRecordingDevices:枚举系统中所有音频录制设备(返回设备ID列表)
  • SDL_GetAudioStreamAvailable:获取音频流中可读取的输出数据字节数
  • SDL_GetAudioStreamData:从音频流读取转换后的音频数据
  • SDL_GetAudioStreamDevice:获取音频流绑定的音频设备ID
  • SDL_GetAudioStreamFormat:获取音频流的输入/输出格式信息
  • SDL_GetAudioStreamFrequencyRatio:获取音频流的采样率转换比率
  • SDL_GetAudioStreamGain:获取音频流的增益(独立于设备增益)
  • SDL_GetAudioStreamInputChannelMap:获取音频流的输入声道映射
  • SDL_GetAudioStreamOutputChannelMap:获取音频流的输出声道映射
  • SDL_GetAudioStreamProperties:获取音频流的属性集合(延迟、缓冲等)
  • SDL_GetAudioStreamQueued:获取音频流中待处理的输入数据字节数
  • SDL_GetCurrentAudioDriver:获取当前使用的音频驱动名称
  • SDL_GetNumAudioDrivers:获取系统中可用的音频驱动数量
  • SDL_GetSilenceValueForFormat:获取指定音频格式的静音值(用于填充静音数据)
  • SDL_IsAudioDevicePhysical:检查音频设备是否为物理设备(非逻辑设备)
  • SDL_IsAudioDevicePlayback:检查音频设备是否为播放设备(非录制设备)
  • SDL_LoadWAV:从文件加载WAV音频数据(返回音频格式和数据缓冲区)
  • SDL_LoadWAV_IO:从自定义IO流加载WAV音频数据
  • SDL_LockAudioStream:锁定音频流(线程安全操作)
  • SDL_MixAudio:混音多个音频缓冲区(按指定格式混合)
  • SDL_OpenAudioDevice:打开音频设备(返回逻辑设备ID)
  • SDL_OpenAudioDeviceStream:简化接口,一键创建设备+流并绑定
  • SDL_PauseAudioDevice:暂停音频设备(停止播放,保留缓冲数据)
  • SDL_PauseAudioStreamDevice:暂停音频流绑定的设备
  • SDL_PutAudioStreamData:向音频流写入输入数据(进行格式转换)
  • SDL_PutAudioStreamDataNoCopy:写入数据但不拷贝(直接使用原缓冲区)
  • SDL_PutAudioStreamPlanarData:向音频流写入平面格式音频数据(非交错)
  • SDL_ResumeAudioDevice:恢复暂停的音频设备(继续播放)
  • SDL_ResumeAudioStreamDevice:恢复音频流绑定设备的播放
  • SDL_SetAudioDeviceGain:设置音频设备的增益(调整整体音量)
  • SDL_SetAudioPostmixCallback:设置音频后混音回调(最终输出前处理)
  • SDL_SetAudioStreamFormat:动态修改音频流的输入/输出格式
  • SDL_SetAudioStreamFrequencyRatio:设置音频流的采样率转换比率
  • SDL_SetAudioStreamGain:设置音频流的增益(仅影响该流的音量)
  • SDL_SetAudioStreamGetCallback:设置音频流的数据源回调(按需获取数据)
  • SDL_SetAudioStreamInputChannelMap:设置音频流的输入声道映射
  • SDL_SetAudioStreamOutputChannelMap:设置音频流的输出声道映射
  • SDL_SetAudioStreamPutCallback:设置音频流的数据输出回调(数据就绪时触发)
  • SDL_UnbindAudioStream:解除音频流与设备的绑定
  • SDL_UnbindAudioStreams:批量解除多个音频流的绑定
  • SDL_UnlockAudioStream:解锁音频流(与SDL_LockAudioStream配对使用)

数据类型

  • SDL_AudioDeviceID:音频设备标识类型(区分不同的逻辑/物理设备)
  • SDL_AudioPostmixCallback:音频后混音回调函数类型(处理最终输出数据)
  • SDL_AudioStream:音频流句柄类型(标识已创建的音频流)
  • SDL_AudioStreamCallback:音频流数据回调函数类型(按需提供/处理数据)
  • SDL_AudioStreamDataCompleteCallback:音频流数据完成回调类型(数据处理完毕触发)

结构体

  • SDL_AudioSpec:音频格式描述结构体(包含采样率、声道数、格式、样本数等)

枚举

  • SDL_AudioFormat:音频格式枚举(如SDL_AUDIO_U8、SDL_AUDIO_S16、SDL_AUDIO_F32等)

  • SDL_AUDIO_BITSIZE:提取音频格式的位深度(如16位、32位)
  • SDL_AUDIO_BYTESIZE:计算音频格式的字节大小(位深度/8)
  • SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK:默认音频播放设备标识
  • SDL_AUDIO_DEVICE_DEFAULT_RECORDING:默认音频录制设备标识
  • SDL_AUDIO_FRAMESIZE:计算单帧音频数据的字节大小(声道数×字节大小)
  • SDL_AUDIO_ISBIGENDIAN:检查音频格式是否为大端序
  • SDL_AUDIO_ISFLOAT:检查音频格式是否为浮点型
  • SDL_AUDIO_ISINT:检查音频格式是否为整型
  • SDL_AUDIO_ISLITTLEENDIAN:检查音频格式是否为小端序
  • SDL_AUDIO_ISSIGNED:检查音频格式是否为有符号类型
  • SDL_AUDIO_ISUNSIGNED:检查音频格式是否为无符号类型
  • SDL_AUDIO_MASK_BIG_ENDIAN:大端序格式掩码
  • SDL_AUDIO_MASK_BITSIZE:位深度格式掩码
  • SDL_AUDIO_MASK_FLOAT:浮点型格式掩码
  • SDL_AUDIO_MASK_SIGNED:有符号类型格式掩码
  • SDL_DEFINE_AUDIO_FORMAT:自定义音频格式宏(组合位深度、字节序、类型等)

FreeBASIC 示例代码

' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL3 库)
#Include "SDL.bi"

' 播放WAV文件示例
Sub PlayWAVFile(ByVal filename As String)
    SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "尝试播放WAV文件:%s", filename)

    ' 1. 加载WAV文件
    Dim As SDL_AudioSpec wavSpec
    Dim As UByte Ptr wavBuffer = NULL
    Dim As Uint64 wavLength = 0

    If (SDL_LoadWAV(filename, @wavSpec, @wavBuffer, @wavLength) = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "加载WAV文件失败:%s", SDL_GetError())
        Return
    End If

    SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "WAV文件加载成功:")
    SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "  采样率:%d Hz", wavSpec.freq)
    SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "  声道数:%d", wavSpec.channels)
    SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "  格式:%s", SDL_GetAudioFormatName(wavSpec.format))
    SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "  数据长度:%llu 字节", wavLength)

    ' 2. 获取默认播放设备
    Dim As SDL_AudioDeviceID defaultDevice = SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK

    ' 3. 打开音频设备(使用WAV文件的格式)
    Dim As SDL_AudioDeviceID devID = SDL_OpenAudioDevice(defaultDevice, @wavSpec, 0)
    If (devID = 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "打开音频设备失败:%s", SDL_GetError())
        SDL_FreeWAV(wavBuffer)
        Return
    End If

    ' 4. 创建音频流(转换为设备兼容格式)
    Dim As SDL_AudioStream Ptr stream = SDL_CreateAudioStream( _
        wavSpec.format, wavSpec.channels, wavSpec.freq, _
        wavSpec.format, wavSpec.channels, wavSpec.freq _
    )

    If (stream = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "创建音频流失败:%s", SDL_GetError())
        SDL_CloseAudioDevice(devID)
        SDL_FreeWAV(wavBuffer)
        Return
    End If

    ' 5. 向音频流写入WAV数据
    SDL_PutAudioStreamData(stream, wavBuffer, wavLength)
    SDL_FlushAudioStream(stream) ' 刷新流,确保所有数据可输出

    ' 6. 绑定音频流到设备
    If (SDL_BindAudioStream(devID, stream) < 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "绑定音频流失败:%s", SDL_GetError())
        SDL_DestroyAudioStream(stream)
        SDL_CloseAudioDevice(devID)
        SDL_FreeWAV(wavBuffer)
        Return
    End If

    ' 7. 恢复设备播放(默认暂停)
    SDL_ResumeAudioDevice(devID)

    SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "开始播放音频...")

    ' 8. 等待播放完成(检查流中是否还有数据)
    While (SDL_GetAudioStreamAvailable(stream) > 0)
        SDL_Delay(100)
    Wend

    SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "音频播放完成")

    ' 9. 清理资源
    SDL_UnbindAudioStream(devID, stream)
    SDL_DestroyAudioStream(stream)
    SDL_CloseAudioDevice(devID)
    SDL_FreeWAV(wavBuffer)
End Sub

' 简化音频播放示例(使用SDL_OpenAudioDeviceStream)
Sub PlayAudioSimplified()
    SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, vbCrLf & "==== 简化音频播放示例 ====")

    ' 定义音频格式(44.1kHz,立体声,32位浮点)
    Dim As SDL_AudioSpec spec
    spec.freq = 44100
    spec.format = SDL_AUDIO_F32
    spec.channels = 2
    spec.samples = 4096 ' 缓冲区大小

    ' 1. 打开简化音频流
    Dim As SDL_AudioStream Ptr stream = SDL_OpenAudioDeviceStream( _
        SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, _
        @spec, _
        NULL, NULL _
    )

    If (stream = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "打开简化音频流失败:%s", SDL_GetError())
        Return
    End If

    ' 2. 生成测试音频(正弦波,440Hz A调)
    Const sampleCount As Integer = 44100 * 2 ' 2秒音频
    Dim As Single Ptr audioData = Allocate(sampleCount * 2 * SizeOf(Single))

    If (audioData = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "分配音频数据内存失败")
        SDL_DestroyAudioStream(stream)
        Return
    End If

    ' 生成立体声正弦波
    For i As Integer = 0 To sampleCount - 1
        Dim As Single t = i / 44100.0
        Dim As Single val = Sin(2 * 3.14159265 * 440 * t) * 0.5 ' 0.5音量

        ' 左右声道相同
        audioData[i * 2] = val
        audioData[i * 2 + 1] = val
    Next

    ' 3. 写入音频数据到流
    SDL_PutAudioStreamData(stream, audioData, sampleCount * 2 * SizeOf(Single))
    SDL_FlushAudioStream(stream)

    ' 4. 恢复播放
    SDL_ResumeAudioStreamDevice(stream)

    SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "播放2秒440Hz正弦波...")

    ' 5. 等待播放完成
    While (SDL_GetAudioStreamAvailable(stream) > 0)
        SDL_Delay(100)
    Wend

    ' 6. 清理资源
    Deallocate(audioData)
    SDL_DestroyAudioStream(stream) ' 销毁流自动关闭设备

    SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "简化音频播放完成")
End Sub

' 枚举音频设备示例
Sub EnumerateAudioDevices()
    SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, vbCrLf & "==== 枚举音频设备 ====")

    ' 枚举播放设备
    Dim As Integer playbackCount = SDL_GetAudioPlaybackDevices(NULL, 0)
    If (playbackCount > 0) Then
        Dim As SDL_AudioDeviceID Ptr playbackDevs = Callocate(playbackCount * SizeOf(SDL_AudioDeviceID))
        playbackCount = SDL_GetAudioPlaybackDevices(playbackDevs, playbackCount)

        SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "播放设备(%d个):", playbackCount)
        For i As Integer = 0 To playbackCount - 1
            Dim As ZString Ptr devName = SDL_GetAudioDeviceName(playbackDevs[i])
            SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "  %d: %s (物理设备:%s)", _
                i, devName, IIf(SDL_IsAudioDevicePhysical(playbackDevs[i]), "是", "否"))
            If (devName <> NULL) Then SDL_free(devName)
        Next

        Deallocate(playbackDevs)
    Else
        SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "未检测到音频播放设备")
    End If

    ' 枚举录制设备
    Dim As Integer recordCount = SDL_GetAudioRecordingDevices(NULL, 0)
    If (recordCount > 0) Then
        Dim As SDL_AudioDeviceID Ptr recordDevs = Callocate(recordCount * SizeOf(SDL_AudioDeviceID))
        recordCount = SDL_GetAudioRecordingDevices(recordDevs, recordCount)

        SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "录制设备(%d个):", recordCount)
        For i As Integer = 0 To recordCount - 1
            Dim As ZString Ptr devName = SDL_GetAudioDeviceName(recordDevs[i])
            SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "  %d: %s", i, devName)
            If (devName <> NULL) Then SDL_free(devName)
        Next

        Deallocate(recordDevs)
    Else
        SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "未检测到音频录制设备")
    End If
End Sub

' 主程序
Sub Main()
    ' 初始化SDL音频子系统
    If (SDL_Init(SDL_INIT_AUDIO) < 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL初始化失败:%s", SDL_GetError())
        Exit Sub
    End If

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "=== SDL3 音频示例程序 ===")

    ' 1. 枚举音频设备
    EnumerateAudioDevices()

    ' 2. 播放WAV文件(替换为实际的WAV文件路径)
    Dim As String wavFile = "test.wav"
    If (SDL_FileExists(wavFile)) Then
        PlayWAVFile(wavFile)
    Else
        SDL_LogWarn(SDL_LOG_CATEGORY_AUDIO, "WAV文件不存在:%s,跳过播放", wavFile)
    End If

    ' 3. 简化音频播放(生成正弦波)
    PlayAudioSimplified()

    ' 退出SDL
    SDL_Quit()

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "程序结束")
End Sub

' 辅助函数:检查文件是否存在
Function SDL_FileExists(ByVal filename As String) As Boolean
    Dim As FILE Ptr f = fopen(filename, "rb")
    If (f <> NULL) Then
        fclose(f)
        Return True
    End If
    Return False
End Function

' 运行主程序
Main()

核心知识点补充

  1. 音频格式说明 格式常量 描述 位深度 类型 字节序
    SDL_AUDIO_U8 无符号8位整型 8 整型 -
    SDL_AUDIO_S16 有符号16位整型 16 整型 小端序
    SDL_AUDIO_S32 有符号32位整型 32 整型 小端序
    SDL_AUDIO_F32 32位浮点型 32 浮点型 小端序
    SDL_AUDIO_S16MSB 有符号16位整型 16 整型 大端序
  2. 开发注意事项

    • 数据对齐:交错式PCM数据中,每个采样点的各声道数据连续排列(如立体声:左、右、左、右...);
    • 缓冲区大小spec.samples 建议设置为2的幂(如1024、2048、4096),避免音频卡顿;
    • 线程安全:音频流操作需加锁(SDL_LockAudioStream/SDL_UnlockAudioStream);
    • 资源释放:加载WAV后必须调用 SDL_FreeWAV,避免内存泄漏;
    • 跨平台兼容:不同平台的默认音频格式可能不同,建议使用浮点格式(SDL_AUDIO_F32)提高兼容性。
  3. 性能优化技巧

    • 批量写入/读取音频数据,减少频繁的 SDL_PutAudioStreamData/SDL_GetAudioStreamData 调用;
    • 使用 SDL_PutAudioStreamDataNoCopy 避免数据拷贝,提升性能;
    • 合理设置缓冲区大小,平衡延迟和卡顿风险;
    • 多个音频源使用不同的音频流,通过SDL自动混音,避免手动混音的性能损耗。

总结

  1. 核心优势
    • SDL3 以 SDL_AudioStream 为核心,统一了音频处理流程,简化格式转换、混音等操作;
    • 逻辑设备机制实现了音频隔离和自动混音,简化多音频源管理;
    • 提供简化接口和完整接口两套API,兼顾易用性和灵活性;
    • 跨平台统一的声道布局,自动适配不同系统的音频硬件。
  2. 使用建议
    • 简单音频播放优先使用 SDL_OpenAudioDeviceStream 简化接口;
    • 多音频源场景使用逻辑设备+音频流绑定,利用SDL自动混音;
    • 音频格式转换必须通过音频流,避免直接操作原始数据;
    • 播放WAV文件后务必释放缓冲区,设备使用完毕及时关闭。
  3. 关键接口
    • 设备管理:SDL_OpenAudioDevice/SDL_CloseAudioDevice/SDL_GetAudioPlaybackDevices
    • 音频流:SDL_CreateAudioStream/SDL_PutAudioStreamData/SDL_GetAudioStreamData
    • 简化播放:SDL_OpenAudioDeviceStream
    • WAV加载:SDL_LoadWAV/SDL_FreeWAV

评论一下?

OωO
取消