97 lines
1.4 KiB
Go
97 lines
1.4 KiB
Go
|
package ffmpeg
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"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
|
||
|
}
|
||
|
|
||
|
func NewPCM(uri string, sampleRate int, channels int) (beep.StreamSeekCloser, error) {
|
||
|
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 {
|
||
|
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
|
||
|
}
|