2022-11-18 21:18:12 +00:00
|
|
|
package ffmpeg
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
2022-11-19 16:37:49 +00:00
|
|
|
"log"
|
2022-11-18 21:18:12 +00:00
|
|
|
"math"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/faiface/beep"
|
|
|
|
)
|
|
|
|
|
|
|
|
type PCM struct {
|
|
|
|
f beep.Format
|
|
|
|
pos int
|
|
|
|
sr int
|
|
|
|
c int
|
|
|
|
Player *FFmpeg
|
|
|
|
Uri string
|
|
|
|
Base float64
|
|
|
|
Volume float64
|
|
|
|
}
|
|
|
|
|
2022-11-19 16:37:49 +00:00
|
|
|
func NewPCM(uri string, sampleRate int, channels int) (*PCM, error) {
|
2022-11-18 21:18:12 +00:00
|
|
|
out := new(PCM)
|
|
|
|
|
|
|
|
ff, err := NewFFmpeg(uri, sampleRate, channels)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
out.Player = ff
|
|
|
|
format := beep.Format{
|
|
|
|
SampleRate: beep.SampleRate(sampleRate),
|
|
|
|
NumChannels: channels,
|
|
|
|
Precision: 2,
|
|
|
|
}
|
|
|
|
|
|
|
|
return &PCM{
|
|
|
|
format,
|
|
|
|
0,
|
|
|
|
sampleRate,
|
|
|
|
channels,
|
|
|
|
ff,
|
|
|
|
uri,
|
|
|
|
2,
|
|
|
|
-2,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *PCM) Stream(samples [][2]float64) (n int, ok bool) {
|
|
|
|
tmp := make([]byte, d.c+2)
|
|
|
|
|
|
|
|
for i := range samples {
|
|
|
|
dn, err := d.Player.Out.Read(tmp)
|
|
|
|
if dn == len(tmp) {
|
|
|
|
samples[i], _ = d.f.DecodeSigned(tmp)
|
|
|
|
d.pos += dn
|
|
|
|
ok = true
|
|
|
|
}
|
|
|
|
if err == io.EOF {
|
|
|
|
ok = false
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if err != nil {
|
2022-11-19 16:37:49 +00:00
|
|
|
log.Println(err)
|
2022-11-18 21:18:12 +00:00
|
|
|
ok = false
|
|
|
|
break
|
|
|
|
}
|
|
|
|
gain := math.Pow(d.Base, d.Volume)
|
|
|
|
samples[i][0] *= gain
|
|
|
|
samples[i][1] *= gain
|
|
|
|
}
|
|
|
|
|
|
|
|
return len(samples), ok
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d PCM) Err() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d PCM) Position() int {
|
|
|
|
t, _ := time.ParseDuration(fmt.Sprintf("%ds", ((d.pos / d.sr) / 4)))
|
|
|
|
return int(t.Milliseconds())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d PCM) Close() error {
|
|
|
|
d.Player.Close()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d PCM) Len() int {
|
|
|
|
return int(d.Player.Len.Milliseconds())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d PCM) Seek(p int) error {
|
|
|
|
return nil
|
|
|
|
}
|