- 档位模式用 BackgroundAudioManager+预合成循环 mp3, 锁屏可继续播放 - 自定义模式保留 InnerAudio, 支持任意 BPM(40~240)/拍号(2/3/4), 仅前台 - UI 折叠区区分两种模式, preset 默认进, 点"⚙ 自定义节奏"切换 - 音频资产全部迁移到腾讯云 COS, 删除本地 6 个 mp3/jpg (-210KB) - server 上传白名单补 mp3/wav/m4a/aac/amr/wma 格式
216 lines
8.4 KiB
Markdown
216 lines
8.4 KiB
Markdown
# 训练模块静态资源
|
||
|
||
本目录用于存放"练一练"功能的所有音频素材。
|
||
|
||
## 目录结构
|
||
|
||
```
|
||
training/static/
|
||
├── audio/ # 当前为空 —— 节拍器音频已全部迁移到 COS CDN
|
||
├── voice/ # (规划中) TTS 语音教练
|
||
│ ├── numbers/ 数字报数 1~30
|
||
│ └── prompts/ 开始/休息/再来 等口令
|
||
├── bgm/ # (规划中) 训练/休息背景乐
|
||
└── footprint.svg # 脚印图标(早期方案残留,可保留作为备用素材)
|
||
```
|
||
|
||
> 节拍器音频已完全走 CDN(`gz-1349751149.cos.ap-guangzhou.myqcloud.com`),减少小程序包体积约 210 KB。`useMetronomeBg.ts` / `useMetronome.ts` 中的 URL 即源信息,更换音色只需改 hook 里的常量。
|
||
|
||
## 准备步骤
|
||
|
||
### 1. 语音素材(小米 MiMo TTS 自动生成)
|
||
|
||
需要 Node 18+(用内置 `fetch`)。先准备小米 MiMo API Key:
|
||
|
||
- 文档: https://platform.xiaomimimo.com/
|
||
- API Key 形如 `sk-xxxxxxxx`
|
||
|
||
```bash
|
||
export MIMO_API_KEY=sk-your-key-here
|
||
|
||
cd uniapp
|
||
node scripts/generate-voice.mjs
|
||
```
|
||
|
||
会自动调用 `mimo-v2.5-tts` 模型生成 39 个 mp3(30 个数字 + 9 个口令)到 `voice/` 目录。
|
||
|
||
**可选参数**:
|
||
|
||
```bash
|
||
# 换音色(默认 冰糖;可选:冰糖/茉莉/苏打/白桦/Mia/Chloe/Milo/Dean)
|
||
node scripts/generate-voice.mjs --voice 茉莉
|
||
|
||
# 换格式(默认 mp3,需要跟 hooks/useVoiceCoach.ts 里的 .mp3 后缀对应)
|
||
node scripts/generate-voice.mjs --format wav
|
||
|
||
# 强制重新生成(默认存在则跳过)
|
||
node scripts/generate-voice.mjs --force
|
||
```
|
||
|
||
**音色推荐**(中文女声更适合健身教练):
|
||
- `冰糖`:温柔甜美,亲和力强(默认)
|
||
- `茉莉`:清爽利落,有"运动博主"感
|
||
- `苏打`:年轻男声,有力量感
|
||
- `白桦`:成熟男声,沉稳
|
||
|
||
### 2. 节拍器 click / 循环音轨
|
||
|
||
**全部托管在腾讯云 COS(2026-05-26 上传)**,本地不再保留:
|
||
|
||
| 用途 | 文件 | 大小 | 引擎 |
|
||
|---|---|---|---|
|
||
| 单拍 click(基础) | `click.mp3` | 3.4 KB | InnerAudio |
|
||
| 单拍 click(木鱼,推荐) | `click-wood.mp3` | 4.6 KB | InnerAudio (custom 模式) |
|
||
| 循环音轨 慢走 80 BPM | `loop_80bpm_2.mp3` | 71 KB | BgAudio (preset) |
|
||
| 循环音轨 健走 110 BPM | `loop_110bpm_2.mp3` | 65 KB | BgAudio (preset) |
|
||
| 循环音轨 快走 130 BPM | `loop_130bpm_2.mp3` | 66 KB | BgAudio (preset) |
|
||
|
||
> 微信 `BackgroundAudioManager.src` 只接受 https URL,不支持包内资源,所以必须走 CDN。
|
||
> COS 域名已加入小程序后台 `downloadFile 合法域名`,跑步视频也走同一域名。
|
||
|
||
更换音色:去 [pixabay.com/sound-effects](https://pixabay.com/sound-effects/) 找新素材 → 上传到 COS → 在 `useMetronomeBg.ts` / `useMetronome.ts` 里替换 URL 即可。
|
||
|
||
### 3. 背景音乐
|
||
|
||
每首 30 秒~2 分钟即可(loop 后听不出接缝)。
|
||
|
||
推荐来源(免费可商用):
|
||
- [pixabay.com/music](https://pixabay.com/music) 搜 "calm" / "meditation" / "lofi"
|
||
- [freemusicarchive.org](https://freemusicarchive.org)
|
||
- [bensound.com](https://bensound.com)(含署名)
|
||
|
||
文件大小建议 < 1MB(mp3 128kbps 单声道即可)。
|
||
|
||
## 在代码里被引用的位置
|
||
|
||
- `training/hooks/useMetronome.ts` → `DEFAULT_CLICK_SRC` (CDN: click.mp3)
|
||
- `training/hooks/useMetronomeBg.ts` → `LOOP_PRESETS[*].src` (CDN: loop_*.mp3)
|
||
- `training/pages/metronome.vue` → `CLICK_WOOD_URL` (CDN: click-wood.mp3, custom 模式)
|
||
- `training/hooks/useVoiceCoach.ts` → `voice/numbers/*.mp3`、`voice/prompts/*.mp3` (规划中)
|
||
- `training/hooks/useTrainingBgm.ts` → `bgm/*.mp3` (规划中)
|
||
|
||
如需修改路径,修改对应 hook 文件里的常量即可。
|
||
|
||
## 注意事项
|
||
|
||
- 微信小程序对单个文件大小有 10MB 上限,本目录所有文件加起来建议控制在 5MB 以内。
|
||
- 小程序整包大小限制(主包 2MB / 总包 20MB),如果资源较大建议放 CDN 而非本地 static。
|
||
- 把 `useVoiceCoach.ts` 里的 `VOICE_BASE` 改成 CDN URL 即可。
|
||
|
||
---
|
||
|
||
## 后台/锁屏播放设计备忘(未来健身模块用)
|
||
|
||
> 节拍器目前用 `InnerAudioContext` + `requiredBackgroundModes:["audio"]` 已能覆盖 5~10 分钟健走场景。
|
||
> 真要做长时间训练 BGM、锁屏控制条等高级能力,参考下面的 `BackgroundAudioManager` 方案。
|
||
|
||
### 引擎选择对照表
|
||
|
||
健身模块的音频天然分两类,配两套引擎不冲突:
|
||
|
||
| 音频类型 | 时长 | 推荐引擎 | 理由 |
|
||
|---|---|---|---|
|
||
| 训练/休息 BGM | 30s~2min 循环 | **BackgroundAudioManager** | 长流、需要后台/锁屏不停 |
|
||
| 语音教练("开始/休息/再来") | 1~3s 单句 | InnerAudioContext | 短促,前台用即可 |
|
||
| 报数(1, 2, 3...) | 0.5~1s | InnerAudioContext + 池子 | 高频短促 |
|
||
| 节拍器 click | 50~150ms | InnerAudioContext + 池子 | 极短,BgAudio 不接受 |
|
||
|
||
**关键约束:BgAudio 是全局单例,一次只能播 1 个音频**。所以让它专门播 BGM 这类"长流",其他短音用 InnerAudio 配合,互不打架。
|
||
|
||
### BackgroundAudioManager 限制清单(踩坑预警)
|
||
|
||
1. **全局单例**:整个小程序同一时刻只能播一个,多场景要协调切换
|
||
2. **音频时长 ≥ 1 秒**:太短的 click 会被微信判定异常忽略
|
||
3. **必填 metadata**:`title` / `coverImgUrl` / `singer` / `epname` / `webUrl` 缺一会报错
|
||
4. **切 src 有延迟**:200~500ms 初始化抖动,频繁切换会卡顿
|
||
5. **必须声明 `requiredBackgroundModes:["audio"]`** 才能后台播放
|
||
6. **iOS 锁屏豁免**:声明后能锁屏继续播,无 5 分钟时长限制(vs InnerAudio 的 5min)
|
||
7. **会显示系统控制条**:锁屏/通知栏出现带封面+暂停按钮的控制条
|
||
|
||
### 推荐架构(健身模块上线时)
|
||
|
||
```
|
||
training/hooks/
|
||
├── useTrainingBgm.ts → BackgroundAudioManager (后台/锁屏继续放音乐)
|
||
├── useVoiceCoach.ts → InnerAudioContext (语音指导,前台用)
|
||
└── useMetronome.ts → InnerAudioContext (节拍器,池子方案,保持现状)
|
||
```
|
||
|
||
页面 `pages.json` 声明:
|
||
|
||
```json
|
||
{
|
||
"path": "pages/index",
|
||
"style": {
|
||
"navigationBarTitleText": "练一练",
|
||
"requiredBackgroundModes": ["audio"]
|
||
}
|
||
}
|
||
```
|
||
|
||
锁屏会显示 BGM 控制条,老人能直接在锁屏点暂停。训练页面通过 `bgm.onPause()` 监听同步暂停训练,体验连贯。
|
||
|
||
### 必备资产清单
|
||
|
||
到时候要准备的文件:
|
||
|
||
- **BGM 2 首**:`bgm/train-light.mp3`(训练)、`bgm/rest-meditation.mp3`(休息)
|
||
- 每个 30s~1min,128kbps 单声道,30~80KB
|
||
- 推荐来源:[pixabay.com/music](https://pixabay.com/music) 搜 "calm" / "meditation" / "lofi"
|
||
- **锁屏封面**:`audio/cover.jpg` 200×200
|
||
- 简洁绿色背景 + 训练 emoji 即可
|
||
|
||
### BackgroundAudioManager API 速查
|
||
|
||
```ts
|
||
const bgm = uni.getBackgroundAudioManager()
|
||
|
||
/* 必填 metadata,缺一会报错 */
|
||
bgm.title = '健走训练中'
|
||
bgm.coverImgUrl = '/training/static/audio/cover.jpg'
|
||
bgm.epname = '甄养堂'
|
||
bgm.singer = '健走节拍'
|
||
bgm.webUrl = '' // 必填,空字符串可
|
||
|
||
/* src 一旦赋值会自动播放 */
|
||
bgm.src = '/training/static/audio/bgm/train-light.mp3'
|
||
|
||
/* 控制 */
|
||
bgm.pause() // 暂停 (锁屏控制条仍在)
|
||
bgm.play() // 继续
|
||
bgm.stop() // 真停 + 隐藏控制条
|
||
bgm.seek(30) // 跳到 30s
|
||
|
||
/* 事件监听 — 用户从锁屏点暂停时会触发 */
|
||
bgm.onPause(() => { /* 同步训练 UI 状态 */ })
|
||
bgm.onPlay(() => {})
|
||
bgm.onStop(() => {})
|
||
bgm.onEnded(() => { /* 不 loop 时触发,可手动接下一首 */ })
|
||
bgm.onError((err) => { console.error(err) })
|
||
```
|
||
|
||
### 切换不同场景音乐的模式
|
||
|
||
```ts
|
||
function switchBgm(scene: 'training' | 'resting' | 'none') {
|
||
if (scene === 'none') {
|
||
bgm.stop()
|
||
return
|
||
}
|
||
bgm.title = scene === 'training' ? '健走训练中' : '休息恢复中'
|
||
bgm.src = scene === 'training'
|
||
? '/training/static/audio/bgm/train-light.mp3'
|
||
: '/training/static/audio/bgm/rest-meditation.mp3'
|
||
/* 注:setSrc 会自动播放,有 200~500ms 切换延迟 */
|
||
}
|
||
```
|
||
|
||
### 节拍器要不要也升级到 BgAudio?
|
||
|
||
**目前不需要**。节拍器升级 BgAudio 的代价:
|
||
- 需要预合成 3 个档位的循环 mp3(80/110/130 BPM × 2 拍)
|
||
- 必须砍掉右下角微调按钮(预合成 mp3 改不了 BPM)
|
||
- 切档位有 200~500ms 卡顿
|
||
|
||
如果未来发现"健走 30 分钟以上锁屏会停"才考虑改。当前 5~10 分钟场景 InnerAudio + `requiredBackgroundModes` 够用。
|