70 lines
1.5 KiB
Go
70 lines
1.5 KiB
Go
// 程序化音效合成:正弦脉冲与噪声脉冲(无音频文件的占位实现,音频.md §6)。
|
||
package audio
|
||
|
||
import (
|
||
"math"
|
||
"math/rand"
|
||
"time"
|
||
|
||
"github.com/faiface/beep"
|
||
)
|
||
|
||
// sineBurst 正弦脉冲(频率 Hz、时长秒)。
|
||
func sineBurst(freq float64, dur float64) *burst {
|
||
n := int(44100 * dur)
|
||
return &burst{n: n, gen: func(t int) float64 {
|
||
env := 1 - float64(t)/float64(n) // 线性衰减包络
|
||
return env * 0.5 * math.Sin(2*math.Pi*freq*float64(t)/44100)
|
||
}}
|
||
}
|
||
|
||
// noiseBurst 噪声脉冲(破坏音效感)。
|
||
func noiseBurst(dur float64) *burst {
|
||
n := int(44100 * dur)
|
||
rng := rand.New(rand.NewSource(42))
|
||
return &burst{n: n, gen: func(t int) float64 {
|
||
env := 1 - float64(t)/float64(n)
|
||
return env * 0.4 * (rng.Float64()*2 - 1)
|
||
}}
|
||
}
|
||
|
||
// burst 有限长度合成流。
|
||
type burst struct {
|
||
n int
|
||
pos int
|
||
gen func(t int) float64
|
||
}
|
||
|
||
// Stream beep.Streamer:填充采样。
|
||
func (b *burst) Stream(samples [][2]float64) (int, bool) {
|
||
i := 0
|
||
for ; i < len(samples) && b.pos < b.n; i++ {
|
||
v := b.gen(b.pos)
|
||
samples[i][0] = v
|
||
samples[i][1] = v
|
||
b.pos++
|
||
}
|
||
return i, b.pos >= b.n
|
||
}
|
||
|
||
// Err 无错误。
|
||
func (b *burst) Err() error { return nil }
|
||
|
||
// Len 时长采样数。
|
||
func (b *burst) Len() int { return b.n }
|
||
|
||
// Position 当前位置。
|
||
func (b *burst) Position() int { return b.pos }
|
||
|
||
// Seek 跳转。
|
||
func (b *burst) Seek(p int) error {
|
||
if p < 0 || p > b.n {
|
||
p = 0
|
||
}
|
||
b.pos = p
|
||
return nil
|
||
}
|
||
|
||
var _ beep.StreamSeeker = (*burst)(nil)
|
||
var _ = time.Second
|