Chapter 112 · 音频系统

流式音频 Stream

Stream 是通用流式播放器,兼具 Music 的低内存和 Sound 的 3D 定位能力,适合长语音、环境音。

112

概念

Stream 是 Sound 与 Music 的混合体:
• 像 Music 一样流式解码(低内存)
• 像 Sound 一样支持 3D 空间定位(SetPosition)
典型场景:长语音对话、环境音(瀑布、风声)、NPC 对话音频。 生命周期用 Open/Close(而非 Load/Free)。

API 速查

函数说明
int xgeStreamOpen(xge_stream pStream, const char* sPath)打开音频流
int xgeStreamOpenGroup(xge_stream pStream, const char* sPath, xge_audio_group pGroup)打开到分组
int xgeStreamPlay(xge_stream pStream)播放
int xgeStreamStop(xge_stream pStream)停止
int xgeStreamPause(xge_stream pStream)暂停
int xgeStreamResume(xge_stream pStream)恢复
void xgeStreamClose(xge_stream pStream)关闭流
void xgeStreamSetLoop(xge_stream pStream, int bLoop)设置循环
void xgeStreamSetVolume(xge_stream pStream, float fVolume)设置音量
void xgeStreamSetPosition(xge_stream pStream, float fX, float fY, float fZ)3D 位置
void xgeStreamFade(xge_stream pStream, float fFrom, float fTo, int iMilliseconds)音量渐变
int xgeStreamIsPlaying(xge_stream pStream)是否正在播放

编译本章示例

gcc -O2 -I. -o ch112.exe ch112_main.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch112.exe

示例:环境音 + 3D 定位

// 打开瀑布环境音(3D 定位)
xge_stream_t stmWaterfall;
xgeStreamOpen(&stmWaterfall, "ambience/waterfall.ogg");
xgeStreamSetLoop(&stmWaterfall, 1);
xgeStreamSetPosition(&stmWaterfall,
    500.0f, 300.0f, 0);
xgeStreamSetVolume(&stmWaterfall, 0.6f);
xgeStreamPlay(&stmWaterfall);

// NPC 对话语音(一次性播放)
xge_stream_t stmVoice;
xgeStreamOpen(&stmVoice, "voice/npc_greeting.ogg");
xgeStreamSetPosition(&stmVoice,
    npc.x, npc.y, 0);
xgeStreamPlay(&stmVoice);

// 每帧更新:玩家靠近时音量增大
void onFrame(void) {
    float dist = distance(player, waterfall);
    float vol = 1.0f - dist / 800.0f;
    if (vol < 0) vol = 0;
    xgeStreamSetVolume(&stmWaterfall, vol);
}

// 关闭
xgeStreamClose(&stmWaterfall);
xgeStreamClose(&stmVoice);

完整代码

将以下代码保存为 ch112_main.c,编译后运行即可看到流式音频 3D 环境音效果:

#include "xge.h"
#include <math.h>

static xge_stream_t g_stmWater;
static xge_stream_t g_stmWind;
static xge_font g_font = NULL;
static float g_time = 0.0f;

static int onFrame(void* pUser) {
    (void)pUser;
    g_time += 0.016f;
    xgeClear(0x081114FF);

    // 玩家位置(绕圈移动)
    float px = 400.0f + 250.0f * cosf(g_time * 0.5f);
    float py = 300.0f + 180.0f * sinf(g_time * 0.5f);

    // 更新听者位置
    xge_audio_listener_t lis = { 0 };
    lis.fX = px; lis.fY = py;
    xgeAudioListenerSet(&lis);

    // 根据距离调整瀑布音量
    float dx = px - 600.0f, dy = py - 200.0f;
    float dist = sqrtf(dx*dx + dy*dy);
    float vol = 1.0f - dist / 600.0f;
    if (vol < 0) vol = 0;
    xgeStreamSetVolume(&g_stmWater, vol);

    // 绘制场景
    xgeShapeCircleFill(600, 200, 20, 0x4488FFFF);
    xgeShapeCircleFill(200, 400, 16, 0x88FF88FF);
    xgeShapeCircleFill(px, py, 10, 0xFFB454FF);

    // HUD
    char buf[128];
    sprintf(buf, "Waterfall vol: %.2f | dist: %.0f", vol, dist);
    xgeTextDraw(g_font, buf, 50, 50, 0xFFFFFFFF);
    xgeTextDraw(g_font, "Blue=Waterfall Green=Wind Yellow=Player",
        50, 90, 0xFFFFFFFF);

    return XGE_OK;
}

int main(void) {
    xge_desc_t d = {0};
    d.iWidth  = 800;
    d.iHeight = 600;
    d.sTitle  = "ch112 - Stream";
    d.iFlags  = XGE_INIT_VSYNC;
    xgeInit(&d);
    xgeAudioInit();

    // 打开环境音流
    xgeStreamOpen(&g_stmWater, "ambience/waterfall.ogg");
    xgeStreamSetLoop(&g_stmWater, 1);
    xgeStreamSetPosition(&g_stmWater, 600, 200, 0);
    xgeStreamPlay(&g_stmWater);

    xgeStreamOpen(&g_stmWind, "ambience/wind.ogg");
    xgeStreamSetLoop(&g_stmWind, 1);
    xgeStreamSetPosition(&g_stmWind, 200, 400, 0);
    xgeStreamSetVolume(&g_stmWind, 0.4f);
    xgeStreamPlay(&g_stmWind);

    g_font = xgeFontLoad("res/font/default.ttf", 24);
    xgeRun(onFrame, NULL);

    xgeStreamClose(&g_stmWater);
    xgeStreamClose(&g_stmWind);
    xgeFontFree(g_font);
    xgeAudioUnit();
    xgeUnit();
    return 0;
}

代码讲解

  • xgeStreamOpen:打开音频流(流式解码,低内存)。
  • xgeStreamSetPosition:3D 定位,这是 Stream 相对 Music 的优势。
  • xgeStreamSetLoop:环境音通常循环播放。
  • 距离衰减:每帧根据玩家与声源距离动态调整音量。
  • xgeStreamClose:关闭流(对应 Sound 的 Free)。

要点与陷阱

  • Open/Close:Stream 用 Open 打开、Close 关闭(非 Load/Free)。
  • 3D + 流式:Stream 是唯一同时支持 3D 定位和流式解码的类型。
  • 适用场景:长音频 + 需要空间感(环境音、语音)。
  • 对比选择:短音效→Sound,纯音乐→Music,长音频+3D→Stream。

进阶练习

  1. 实现多环境音混合:瀑布 + 鸟鸣 + 风声,各自 3D 定位。
  2. 语音对话系统:队列播放多段 Stream 语音。

已验证实现

权威源码为 examples/tutorial_capture/ch112_main1.c。它打开一个 stream,设置循环、音量和三维位置,再验证播放、暂停、恢复和停止。短 WAV 只用于可重复验证;真实场景应以持续解码的媒体文件评估内存与 I/O。

XGE stream open and playback lifecycle validation
图:第 112 章真实运行的 Stream API 状态链。截图证明对象已打开、播放并停止;听感仍需在目标音频设备上冒烟测试。