155 lines
3.8 KiB
Go
155 lines
3.8 KiB
Go
package audio
|
||
|
||
import (
|
||
"math"
|
||
"os"
|
||
"path/filepath"
|
||
"testing"
|
||
)
|
||
|
||
func TestAttenuation(t *testing.T) {
|
||
if a := attenuation(0, 16); a != 1 {
|
||
t.Fatalf("零距离衰减期望 1,实际 %v", a)
|
||
}
|
||
if a := attenuation(8, 16); a != 0.5 {
|
||
t.Fatalf("8 格衰减期望 0.5,实际 %v", a)
|
||
}
|
||
if a := attenuation(16, 16); a != 0 {
|
||
t.Fatalf("16 格衰减期望 0,实际 %v", a)
|
||
}
|
||
if a := attenuation(30, 16); a != 0 {
|
||
t.Fatalf("超距衰减期望 0,实际 %v", a)
|
||
}
|
||
}
|
||
|
||
func TestPlayParams(t *testing.T) {
|
||
if p := PlayParams("block.stone.hit"); p.Volume != 0.25 || p.Pitch != 0.5 {
|
||
t.Fatalf("hit 参数 %+v", p)
|
||
}
|
||
if p := PlayParams("block.stone.break"); p.Volume != 1 || p.Pitch != 0.8 {
|
||
t.Fatalf("break 参数 %+v", p)
|
||
}
|
||
if p := PlayParams("block.grass.step"); p.Volume != 0.15 || p.Pitch != 1 {
|
||
t.Fatalf("step 参数 %+v", p)
|
||
}
|
||
p := PlayParams("entity.sheep.hurt")
|
||
if p.Volume != 1 || p.Pitch < 0.8 || p.Pitch > 1.2 {
|
||
t.Fatalf("hurt 音调应在 0.8–1.2,实际 %+v", p)
|
||
}
|
||
}
|
||
|
||
func TestBurstStreamer(t *testing.T) {
|
||
b := sineBurst(440, 0.05)
|
||
samples := make([][2]float64, 1024)
|
||
total := 0
|
||
for {
|
||
n, ok := b.Stream(samples)
|
||
total += n
|
||
if ok {
|
||
break
|
||
}
|
||
}
|
||
if total != b.Len() {
|
||
t.Fatalf("流长度期望 %d,实际 %d", b.Len(), total)
|
||
}
|
||
if total < 1000 {
|
||
t.Fatalf("采样数异常: %d", total)
|
||
}
|
||
}
|
||
|
||
func TestManagerSilent(t *testing.T) {
|
||
m := New()
|
||
defer m.Close()
|
||
m.SetVolumes(1, 1, 1, 1)
|
||
m.SetListener(0, 0, 0, 0)
|
||
for i := 0; i < 100; i++ {
|
||
m.Play("block.stone.break", float64(i), 0, 0)
|
||
}
|
||
}
|
||
|
||
func TestLoadSoundsFields(t *testing.T) {
|
||
dir := t.TempDir()
|
||
ogg := filepath.Join(dir, "stone1.ogg")
|
||
if err := os.WriteFile(ogg, []byte("not-ogg"), 0o644); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
m := New()
|
||
defer m.Close()
|
||
js := []byte(`{
|
||
"block.stone.break":{"sounds":[{"name":"dig/stone1","weight":2}],"subtitle":"subtitles.block.generic.break"},
|
||
"block.alias":{"sounds":[{"name":"block.stone.break","type":"event"}]}
|
||
}`)
|
||
m.LoadSounds(js, func(name string) (string, bool) {
|
||
if name == "dig/stone1" {
|
||
return ogg, true
|
||
}
|
||
return "", false
|
||
})
|
||
if m.EventCount() != 2 {
|
||
t.Fatalf("事件数=%d", m.EventCount())
|
||
}
|
||
if !m.HasOgg("block.stone.break") || !m.HasOgg("block.alias") {
|
||
t.Fatal("应解析到 ogg 与 event 重定向")
|
||
}
|
||
if g := m.Subtitle("block.stone.break"); g != "subtitles.block.generic.break" {
|
||
t.Fatalf("subtitle=%q", g)
|
||
}
|
||
}
|
||
|
||
func TestLoadSoundsMissingOgg(t *testing.T) {
|
||
m := New()
|
||
defer m.Close()
|
||
js := []byte(`{"block.stone.break":{"sounds":["dig/stone1"]}}`)
|
||
m.LoadSounds(js, func(string) (string, bool) { return "", false })
|
||
if m.EventCount() != 0 {
|
||
t.Fatal("无 ogg 时事件表应为空(回退合成器)")
|
||
}
|
||
m.Play("block.grass.step", 0, 0, 0)
|
||
}
|
||
|
||
func TestCaptionsEnqueue(t *testing.T) {
|
||
m := New()
|
||
defer m.Close()
|
||
m.SetListener(0, 0, 0, 0)
|
||
m.Play("entity.sheep.ambient", 1, 0, 0)
|
||
m.Play("entity.sheep.ambient", 1, 0, 0)
|
||
m.Play("block.stone.break", 2, 0, 0)
|
||
m.Play("block.stone.break", 40, 0, 0) // 超距
|
||
got := m.Captions()
|
||
if len(got) != 2 {
|
||
t.Fatalf("字幕行数=%d %+v", len(got), got)
|
||
}
|
||
}
|
||
|
||
func TestStereoPan(t *testing.T) {
|
||
if p := stereoPan(0, 0, -5, 0); math.Abs(p) > 1e-9 {
|
||
t.Fatalf("正前方 pan=%v", p)
|
||
}
|
||
if p := stereoPan(0, 0, 0, 0); p != 0 {
|
||
t.Fatalf("听者自身 pan=%v", p)
|
||
}
|
||
if p := stereoPan(5, 0, 0, 0); p < 0.99 {
|
||
t.Fatalf("右侧 pan=%v", p)
|
||
}
|
||
if p := stereoPan(-5, 0, 0, 0); p > -0.99 {
|
||
t.Fatalf("左侧 pan=%v", p)
|
||
}
|
||
// yaw=0 朝 -Z,源在 +X 应右声道更大
|
||
l, r := (1-1.0)/2, (1+1.0)/2
|
||
src := sineBurst(440, 0.02)
|
||
p := &panStreamer{Streamer: src, l: l, r: r}
|
||
samples := make([][2]float64, 64)
|
||
n, _ := p.Stream(samples)
|
||
if n == 0 {
|
||
t.Fatal("应有采样")
|
||
}
|
||
var sl, sr float64
|
||
for i := 0; i < n; i++ {
|
||
sl += math.Abs(samples[i][0])
|
||
sr += math.Abs(samples[i][1])
|
||
}
|
||
if sr <= sl {
|
||
t.Fatalf("右侧声源应右声道更大 L=%v R=%v", sl, sr)
|
||
}
|
||
}
|