docs: add Phase 5-1 through 6-3 specs, plans, and Cargo.lock
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
128
docs/superpowers/specs/2026-03-25-phase6-3-mixer.md
Normal file
128
docs/superpowers/specs/2026-03-25-phase6-3-mixer.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# Phase 6-3: Mixer — Design Spec
|
||||
|
||||
## Overview
|
||||
|
||||
`voltex_audio`에 그룹 기반 믹서를 추가한다. BGM/SFX/Voice 그룹별 독립 볼륨 제어와 페이드 인/아웃을 지원한다.
|
||||
|
||||
## Scope
|
||||
|
||||
- MixGroup enum (Master, Bgm, Sfx, Voice)
|
||||
- GroupState (볼륨 + 페이드)
|
||||
- MixerState (전체 그룹 관리, effective_volume = group * master)
|
||||
- PlayingSound에 group 필드 추가
|
||||
- mix_sounds에 mixer 파라미터 추가
|
||||
- AudioSystem API: set_group_volume, fade_group
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- 동적 그룹 생성 (고정 4개만)
|
||||
- 그룹 간 라우팅/버스
|
||||
- 이펙트 체인 (reverb, EQ 등)
|
||||
- 페이드 커브 (선형만)
|
||||
|
||||
## Module Structure
|
||||
|
||||
- `crates/voltex_audio/src/mix_group.rs` — MixGroup, GroupState, MixerState (Create)
|
||||
- `crates/voltex_audio/src/mixing.rs` — PlayingSound에 group, mix_sounds에 mixer (Modify)
|
||||
- `crates/voltex_audio/src/audio_system.rs` — SetGroupVolume, FadeGroup 명령 (Modify)
|
||||
- `crates/voltex_audio/src/lib.rs` — mix_group 모듈 등록 (Modify)
|
||||
|
||||
## Types
|
||||
|
||||
### MixGroup
|
||||
|
||||
```rust
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum MixGroup {
|
||||
Master,
|
||||
Bgm,
|
||||
Sfx,
|
||||
Voice,
|
||||
}
|
||||
```
|
||||
|
||||
### GroupState
|
||||
|
||||
```rust
|
||||
pub struct GroupState {
|
||||
pub volume: f32,
|
||||
pub fade_target: f32,
|
||||
pub fade_speed: f32,
|
||||
}
|
||||
```
|
||||
|
||||
- `new()` → volume=1.0, fade_target=1.0, fade_speed=0.0
|
||||
- `tick(dt: f32)` — volume을 fade_target으로 fade_speed * dt만큼 이동. 도달하면 fade_speed=0.
|
||||
|
||||
### MixerState
|
||||
|
||||
```rust
|
||||
pub struct MixerState {
|
||||
groups: [GroupState; 4], // Master, Bgm, Sfx, Voice 순서
|
||||
}
|
||||
```
|
||||
|
||||
배열 인덱스로 접근 (HashMap 대신 간결하게).
|
||||
|
||||
- `new()` — 전부 volume=1.0
|
||||
- `set_volume(group, volume)` — 즉시 설정, fade 중지
|
||||
- `fade(group, target, duration)` — fade_speed = |target - current| / duration
|
||||
- `tick(dt)` — 모든 그룹 업데이트
|
||||
- `volume(group) -> f32` — 해당 그룹 현재 볼륨
|
||||
- `effective_volume(group) -> f32` — group.volume * master.volume (Master 그룹은 자기 자신만)
|
||||
|
||||
## Mixing Integration
|
||||
|
||||
### PlayingSound 변경
|
||||
|
||||
```rust
|
||||
pub group: MixGroup, // 기본 Sfx
|
||||
```
|
||||
|
||||
- `new()` → group = MixGroup::Sfx
|
||||
- `new_3d()` → group = MixGroup::Sfx
|
||||
- 기존 생성자에 group 파라미터 추가하지 않음 (기본값 사용). 필요 시 직접 설정.
|
||||
|
||||
### mix_sounds 변경
|
||||
|
||||
`mixer: &MixerState` 파라미터 추가.
|
||||
|
||||
각 사운드의 최종 볼륨 계산:
|
||||
```
|
||||
base_volume = sound.volume * mixer.effective_volume(sound.group)
|
||||
```
|
||||
이후 spatial gains 적용은 기존과 동일.
|
||||
|
||||
### AudioCommand 추가
|
||||
|
||||
```rust
|
||||
SetGroupVolume { group: MixGroup, volume: f32 },
|
||||
FadeGroup { group: MixGroup, target: f32, duration: f32 },
|
||||
```
|
||||
|
||||
### AudioSystem 메서드 추가
|
||||
|
||||
```rust
|
||||
pub fn set_group_volume(&self, group: MixGroup, volume: f32)
|
||||
pub fn fade_group(&self, group: MixGroup, target: f32, duration: f32)
|
||||
```
|
||||
|
||||
### 오디오 스레드
|
||||
|
||||
- `MixerState` 인스턴스 보유
|
||||
- 매 루프: `mixer.tick(dt)` 호출 (dt ≈ 5ms)
|
||||
- mix_sounds에 `&mixer` 전달
|
||||
|
||||
## Test Plan
|
||||
|
||||
### mix_group.rs
|
||||
- GroupState::tick: 페이드 진행, 목표 도달 시 정지
|
||||
- MixerState::set_volume: 즉시 반영
|
||||
- MixerState::fade: 여러 tick 후 목표 도달
|
||||
- MixerState::effective_volume: group * master
|
||||
- Master=0이면 모든 그룹 effective=0
|
||||
|
||||
### mixing.rs (통합)
|
||||
- group 볼륨 적용: Sfx volume=0.5 → 출력 절반
|
||||
- master=0 → 전체 무음
|
||||
- 기존 2D/3D 테스트는 mixer volume=1.0으로 변화 없음
|
||||
Reference in New Issue
Block a user