@@ -290,20 +290,23 @@ <h1>sound</h1>
290290
291291 < div class ="markdown-body ">
292292 < p > 音效与本地音频播放:短音效、长音频 Player、音量与静音开关控制。</ p >
293- < blockquote class ="callout note "> < strong > 边界</ strong > :短反馈用 < code > play_effect</ code > ;本地长音频用 < code > Player</ code > 。远程视频/流媒体请看 < a href ="../../pages/avplayer-module/ "> avplayer</ a > ;文字朗读用 < a href ="../../pages/speech-module/ "> speech</ a > 。< code > MIDIPlayer</ code > 为兼容占位,不提供完整 MIDI 播放。</ blockquote >
293+ < blockquote class ="callout note "> < strong > 边界</ strong > :短反馈用 < code > play_effect</ code > ;本地长音频用 < code > Player</ code > 。远程视频/流媒体请看 < a href ="../../pages/avplayer-module/ "> avplayer</ a > ;文字朗读用 < a href ="../../pages/speech-module/ "> speech</ a > 。< code > MIDIPlayer</ code > 由原生 < code > AVMIDIPlayer</ code > 播放本地 MIDI,可选本地 sound bank,不是占位返回值。</ blockquote >
294+ < p > R2 增量:本地音频可传项目相对路径、< code > appui.FileResource</ code > 或 < code > appui.MediaSource.file/asset</ code > 。App 不附带内置音效库;请先把音频导入项目。inline data 与需自定义 header 的远程媒体不属于此字符串 bridge。</ p >
295+ < p > R7 增量:播放器和 MIDI 资源按 MiniApp owner 注册并在 session 结束时释放;< code > controller_status()</ code > 可查看当前 owner 资源数,< code > play_effect_async(..., budget=...)</ code > 提供统一任务/错误/预算入口。</ p >
296+ < p > 严格异步失败抛出 < code > SoundError</ code > 。</ p >
294297< h2 id ="模块概览 "> < a class ="heading-anchor " href ="#模块概览 "> #</ a > 模块概览</ h2 >
295298< div class ="table-scroll "> < table > < thead > < tr > < th > 项</ th > < th > 说明</ th > </ tr > </ thead > < tbody > < tr > < td > 导入</ td > < td > < code > import sound</ code > </ td > </ tr > < tr > < td > 适合做什么</ td > < td > 点击音效、成功/错误提示音、本地音乐/播客播放</ td > </ tr > < tr > < td > 调用时机</ td > < td > 放在按钮回调;页面关闭时停止循环音效</ td > </ tr > < tr > < td > 推荐顺序</ td > < td > 短音 < code > play_effect</ code > → 保存 handle → 需要时 < code > stop_effect</ code > </ td > </ tr > < tr > < td > 循环音效</ td > < td > < code > looping=True</ code > 时必须保存 handle,否则无法停止</ td > </ tr > </ tbody > </ table > </ div >
296299< hr >
297300< h2 id ="快速开始 "> < a class ="heading-anchor " href ="#快速开始 "> #</ a > 快速开始</ h2 >
298301< p > 下面脚本播放短音效并调节全局音量:</ p >
299- < figure class ="code-block " data-code-id ="31f965925d48 ">
302+ < figure class ="code-block " data-code-id ="506569566026 ">
300303 < figcaption >
301304 < span > python</ span >
302- < div class ="code-copy-actions "> < button class ="copy-code " type ="button " data-copy-code ="31f965925d48 " aria-label ="复制 "> < svg width ="16 " height ="16 " viewBox ="0 0 24 24 " fill ="none " aria-hidden ="true "> < rect x ="9 " y ="9 " width ="11 " height ="11 " rx ="2.25 " stroke ="currentColor " stroke-width ="1.75 "/> < rect x ="4 " y ="4 " width ="11 " height ="11 " rx ="2.25 " stroke ="currentColor " stroke-width ="1.75 "/> </ svg > </ button > < span class ="copy-code-toast " role ="status " aria-live ="polite " hidden > 已复制</ span > </ div >
305+ < div class ="code-copy-actions "> < button class ="copy-code " type ="button " data-copy-code ="506569566026 " aria-label ="复制 "> < svg width ="16 " height ="16 " viewBox ="0 0 24 24 " fill ="none " aria-hidden ="true "> < rect x ="9 " y ="9 " width ="11 " height ="11 " rx ="2.25 " stroke ="currentColor " stroke-width ="1.75 "/> < rect x ="4 " y ="4 " width ="11 " height ="11 " rx ="2.25 " stroke ="currentColor " stroke-width ="1.75 "/> </ svg > </ button > < span class ="copy-code-toast " role ="status " aria-live ="polite " hidden > 已复制</ span > </ div >
303306 </ figcaption >
304- < pre > < code id ="code-31f965925d48 " class ="language-python "> import sound
307+ < pre > < code id ="code-506569566026 " class ="language-python "> import sound
305308
306- handle = sound.play_effect("arcade:Coin_1 ", volume=0.8)
309+ handle = sound.play_effect("assets/click.wav ", volume=0.8)
307310print("handle:", handle)
308311
309312sound.set_volume(0.8)
@@ -315,12 +318,12 @@ <h2 id="快速开始"><a class="heading-anchor" href="#快速开始">#</a>快速
315318< hr >
316319< h2 id ="appui-示例 "> < a class ="heading-anchor " href ="#appui-示例 "> #</ a > AppUI 示例</ h2 >
317320< p > 音效和音量控制放在按钮回调里,状态同步写回界面。</ p >
318- < figure class ="code-block " data-code-id ="b78a0e8b4d95 ">
321+ < figure class ="code-block " data-code-id ="f46ada4fe3d6 ">
319322 < figcaption >
320323 < span > python</ span >
321- < div class ="code-copy-actions "> < button class ="copy-code " type ="button " data-copy-code ="b78a0e8b4d95 " aria-label ="复制 "> < svg width ="16 " height ="16 " viewBox ="0 0 24 24 " fill ="none " aria-hidden ="true "> < rect x ="9 " y ="9 " width ="11 " height ="11 " rx ="2.25 " stroke ="currentColor " stroke-width ="1.75 "/> < rect x ="4 " y ="4 " width ="11 " height ="11 " rx ="2.25 " stroke ="currentColor " stroke-width ="1.75 "/> </ svg > </ button > < span class ="copy-code-toast " role ="status " aria-live ="polite " hidden > 已复制</ span > </ div >
324+ < div class ="code-copy-actions "> < button class ="copy-code " type ="button " data-copy-code ="f46ada4fe3d6 " aria-label ="复制 "> < svg width ="16 " height ="16 " viewBox ="0 0 24 24 " fill ="none " aria-hidden ="true "> < rect x ="9 " y ="9 " width ="11 " height ="11 " rx ="2.25 " stroke ="currentColor " stroke-width ="1.75 "/> < rect x ="4 " y ="4 " width ="11 " height ="11 " rx ="2.25 " stroke ="currentColor " stroke-width ="1.75 "/> </ svg > </ button > < span class ="copy-code-toast " role ="status " aria-live ="polite " hidden > 已复制</ span > </ div >
322325 </ figcaption >
323- < pre > < code id ="code-b78a0e8b4d95 " class ="language-python "> import appui
326+ < pre > < code id ="code-f46ada4fe3d6 " class ="language-python "> import appui
324327import sound
325328
326329state = appui.State(
@@ -331,15 +334,15 @@ <h2 id="appui-示例"><a class="heading-anchor" href="#appui-示例">#</a>AppUI
331334
332335
333336def play_click():
334- handle = sound.play_effect("arcade:Coin_1 ", volume=state.volume)
337+ handle = sound.play_effect("assets/click.wav ", volume=state.volume)
335338 state.handle = handle
336339 state.status = "音效已触发" if handle else "音效不可用(检查名称或文件)"
337340
338341
339342def play_loop():
340343 if state.handle:
341344 sound.stop_effect(state.handle)
342- handle = sound.play_effect("arcade:Coin_1 ", volume=state.volume, looping=True)
345+ handle = sound.play_effect("assets/click.wav ", volume=state.volume, looping=True)
343346 state.handle = handle
344347 state.status = "循环播放中" if handle else "循环音效不可用"
345348
@@ -392,20 +395,20 @@ <h2 id="appui-示例"><a class="heading-anchor" href="#appui-示例">#</a>AppUI
392395< hr >
393396< h2 id ="api-参考 "> < a class ="heading-anchor " href ="#api-参考 "> #</ a > API 参考</ h2 >
394397< h3 id ="速查 "> < a class ="heading-anchor " href ="#速查 "> #</ a > 速查</ h3 >
395- < div class ="table-scroll "> < table > < thead > < tr > < th > API</ th > < th > 作用</ th > </ tr > </ thead > < tbody > < tr > < td > < code > play_effect(name, ...)</ code > </ td > < td > 播放短音效 → handle</ td > </ tr > < tr > < td > < code > stop_effect(handle)</ code > </ td > < td > 停止指定音效</ td > </ tr > < tr > < td > < code > stop_all_effects()</ code > </ td > < td > 停止全部音效</ td > </ tr > < tr > < td > < code > set_volume(v)</ code > / < code > get_volume()</ code > </ td > < td > 全局主音量 0.0–1.0</ td > </ tr > < tr > < td > < code > set_honors_silent_switch(flag)</ code > </ td > < td > 是否遵守 iOS 静音开关</ td > </ tr > < tr > < td > < code > Player(path)</ code > </ td > < td > 本地长音频播放器</ td > </ tr > </ tbody > </ table > </ div >
398+ < div class ="table-scroll "> < table > < thead > < tr > < th > API</ th > < th > 作用</ th > </ tr > </ thead > < tbody > < tr > < td > < code > play_effect(name, ...)</ code > </ td > < td > 播放短音效 → handle</ td > </ tr > < tr > < td > < code > stop_effect(handle)</ code > </ td > < td > 停止指定音效</ td > </ tr > < tr > < td > < code > stop_all_effects()</ code > </ td > < td > 停止全部音效</ td > </ tr > < tr > < td > < code > set_volume(v)</ code > / < code > get_volume()</ code > </ td > < td > 全局主音量 0.0–1.0</ td > </ tr > < tr > < td > < code > set_honors_silent_switch(flag)</ code > </ td > < td > 是否遵守 iOS 静音开关</ td > </ tr > < tr > < td > < code > Player(path)</ code > </ td > < td > 本地长音频播放器</ td > </ tr > < tr > < td > < code > MIDIPlayer(path, sound_bank_path="") </ code > </ td > < td > 原生 MIDI 播放器 </ td > </ tr > < tr > < td > < code > controller_status() </ code > </ td > < td > 当前 owner 的播放器/音效资源状态 </ td > </ tr > < tr > < td > < code > play_effect_async(..., budget=...) </ code > </ td > < td > 可取消、可超时的短音效任务 </ td > </ tr > < /tbody > </ table > </ div >
396399< h3 id ="短音效 "> < a class ="heading-anchor " href ="#短音效 "> #</ a > 短音效</ h3 >
397400< p > < strong > < code > play_effect(name, volume=1.0, pitch=1.0, pan=0.0, looping=False)</ code > </ strong > </ p >
398- < figure class ="code-block " data-code-id ="3de7728599a1 ">
401+ < figure class ="code-block " data-code-id ="17460c90c1e6 ">
399402 < figcaption >
400403 < span > python</ span >
401- < div class ="code-copy-actions "> < button class ="copy-code " type ="button " data-copy-code ="3de7728599a1 " aria-label ="复制 "> < svg width ="16 " height ="16 " viewBox ="0 0 24 24 " fill ="none " aria-hidden ="true "> < rect x ="9 " y ="9 " width ="11 " height ="11 " rx ="2.25 " stroke ="currentColor " stroke-width ="1.75 "/> < rect x ="4 " y ="4 " width ="11 " height ="11 " rx ="2.25 " stroke ="currentColor " stroke-width ="1.75 "/> </ svg > </ button > < span class ="copy-code-toast " role ="status " aria-live ="polite " hidden > 已复制</ span > </ div >
404+ < div class ="code-copy-actions "> < button class ="copy-code " type ="button " data-copy-code ="17460c90c1e6 " aria-label ="复制 "> < svg width ="16 " height ="16 " viewBox ="0 0 24 24 " fill ="none " aria-hidden ="true "> < rect x ="9 " y ="9 " width ="11 " height ="11 " rx ="2.25 " stroke ="currentColor " stroke-width ="1.75 "/> < rect x ="4 " y ="4 " width ="11 " height ="11 " rx ="2.25 " stroke ="currentColor " stroke-width ="1.75 "/> </ svg > </ button > < span class ="copy-code-toast " role ="status " aria-live ="polite " hidden > 已复制</ span > </ div >
402405 </ figcaption >
403- < pre > < code id ="code-3de7728599a1 " class ="language-python "> handle = sound.play_effect("arcade:Coin_1 ", volume=0.8)
404- handle = sound.play_effect("ui:click1 ", looping=True)
406+ < pre > < code id ="code-17460c90c1e6 " class ="language-python "> handle = sound.play_effect("assets/click.wav ", volume=0.8)
407+ handle = sound.play_effect("assets/loop.wav ", looping=True)
405408sound.stop_effect(handle)
406409sound.stop_all_effects()</ code > </ pre >
407410</ figure >
408- < div class ="table-scroll "> < table > < thead > < tr > < th > 参数</ th > < th > 说明</ th > </ tr > </ thead > < tbody > < tr > < td > < code > name</ code > </ td > < td > Pythonista 风格名(如 < code > arcade:Coin_1 </ code > )或文件路径 </ td > </ tr > < tr > < td > < code > volume</ code > </ td > < td > 0.0–1.0</ td > </ tr > < tr > < td > < code > pitch</ code > </ td > < td > 播放速率 0.5–2.0</ td > </ tr > < tr > < td > < code > pan</ code > </ td > < td > 立体声 -1.0(左)到 1.0(右)</ td > </ tr > < tr > < td > < code > looping</ code > </ td > < td > 循环播放,需保存 handle 才能停止</ td > </ tr > </ tbody > </ table > </ div >
411+ < div class ="table-scroll "> < table > < thead > < tr > < th > 参数</ th > < th > 说明</ th > </ tr > </ thead > < tbody > < tr > < td > < code > name</ code > </ td > < td > 项目内音频路径、 < code > FileResource </ code > 或受支持的 < code > MediaSource </ code > </ td > </ tr > < tr > < td > < code > volume</ code > </ td > < td > 0.0–1.0</ td > </ tr > < tr > < td > < code > pitch</ code > </ td > < td > 播放速率 0.5–2.0</ td > </ tr > < tr > < td > < code > pan</ code > </ td > < td > 立体声 -1.0(左)到 1.0(右)</ td > </ tr > < tr > < td > < code > looping</ code > </ td > < td > 循环播放,需保存 handle 才能停止</ td > </ tr > </ tbody > </ table > </ div >
409412< p > 失败时返回 < code > None</ code > 。</ p >
410413< h3 id ="长音频-player "> < a class ="heading-anchor " href ="#长音频-player "> #</ a > 长音频 Player</ h3 >
411414< p > < strong > < code > Player(file_path)</ code > </ strong > — 本地音频文件播放器:</ p >
0 commit comments