Use paplay
This commit is contained in:
parent
4364a9f137
commit
fc660f49a7
194
player/player.go
194
player/player.go
@ -6,19 +6,12 @@ import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/faiface/beep"
|
||||
"github.com/faiface/beep/effects"
|
||||
"github.com/faiface/beep/flac"
|
||||
"github.com/faiface/beep/mp3"
|
||||
"github.com/faiface/beep/speaker"
|
||||
"github.com/faiface/beep/wav"
|
||||
|
||||
"git.nemunai.re/nemunaire/reveil/config"
|
||||
"git.nemunai.re/nemunaire/reveil/model"
|
||||
)
|
||||
@ -26,11 +19,11 @@ import (
|
||||
var CommonPlayer *Player
|
||||
|
||||
type Player struct {
|
||||
Playlist []string
|
||||
MaxRunTime time.Duration
|
||||
Stopper chan bool
|
||||
|
||||
sampleRate beep.SampleRate
|
||||
Playlist []string
|
||||
MaxRunTime time.Duration
|
||||
Stopper chan bool
|
||||
currentCmd *exec.Cmd
|
||||
currentCmdCh chan bool
|
||||
|
||||
claironTime time.Duration
|
||||
claironFile string
|
||||
@ -38,7 +31,7 @@ type Player struct {
|
||||
ntick int64
|
||||
hasClaironed bool
|
||||
launched time.Time
|
||||
volume *effects.Volume
|
||||
volume uint16
|
||||
dontUpdateVolume bool
|
||||
reverseOrder bool
|
||||
playedItem int
|
||||
@ -66,11 +59,11 @@ func NewPlayer(cfg *config.Config) (*Player, error) {
|
||||
}
|
||||
|
||||
p := Player{
|
||||
Stopper: make(chan bool, 1),
|
||||
MaxRunTime: settings.MaxRunTime * time.Minute,
|
||||
sampleRate: beep.SampleRate(cfg.SampleRate),
|
||||
claironTime: settings.GongInterval * time.Minute,
|
||||
claironFile: reveil.CurrentGongPath(cfg),
|
||||
Stopper: make(chan bool, 1),
|
||||
currentCmdCh: make(chan bool, 1),
|
||||
MaxRunTime: settings.MaxRunTime * time.Minute,
|
||||
claironTime: settings.GongInterval * time.Minute,
|
||||
claironFile: reveil.CurrentGongPath(cfg),
|
||||
}
|
||||
|
||||
// Load our track list
|
||||
@ -100,95 +93,27 @@ func NewPlayer(cfg *config.Config) (*Player, error) {
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func loadFile(filepath string) (name string, s beep.StreamSeekCloser, format beep.Format, err error) {
|
||||
var fd *os.File
|
||||
|
||||
name = path.Base(filepath)
|
||||
|
||||
fd, err = os.Open(filepath)
|
||||
if err != nil {
|
||||
func (p *Player) playFile(filepath string) (err error) {
|
||||
p.currentCmd = exec.Command("paplay", filepath)
|
||||
if err = p.currentCmd.Start(); err != nil {
|
||||
log.Println("Running paplay err: ", err.Error())
|
||||
p.currentCmdCh <- true
|
||||
return
|
||||
}
|
||||
|
||||
switch strings.ToLower(path.Ext(filepath)) {
|
||||
case ".flac":
|
||||
s, format, err = flac.Decode(fd)
|
||||
case ".mp3":
|
||||
s, format, err = mp3.Decode(fd)
|
||||
default:
|
||||
s, format, err = wav.Decode(fd)
|
||||
}
|
||||
log.Println("Running paplay ", filepath)
|
||||
|
||||
if err != nil {
|
||||
fd.Close()
|
||||
return
|
||||
}
|
||||
err = p.currentCmd.Wait()
|
||||
p.currentCmdCh <- true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Player) WakeUp() {
|
||||
log.Println("RUN WAKEUP FUNC")
|
||||
|
||||
log.Println("Playlist in use:", strings.Join(p.Playlist, " ; "))
|
||||
|
||||
// Create infinite stream
|
||||
stream := beep.Iterate(func() beep.Streamer {
|
||||
if !p.hasClaironed && time.Since(p.launched) >= p.claironTime {
|
||||
log.Println("clairon time!")
|
||||
p.claironTime += p.claironTime / 2
|
||||
_, sample, format, err := loadFile(p.claironFile)
|
||||
if err == nil {
|
||||
p.volume.Volume = 0.1
|
||||
p.dontUpdateVolume = true
|
||||
if format.SampleRate != p.sampleRate {
|
||||
return beep.Resample(3, format.SampleRate, p.sampleRate, sample)
|
||||
} else {
|
||||
return sample
|
||||
}
|
||||
} else {
|
||||
log.Println("Error loading clairon:", err)
|
||||
}
|
||||
}
|
||||
|
||||
p.dontUpdateVolume = false
|
||||
p.volume.Volume = -2 - math.Log(5/float64(p.ntick))/3
|
||||
|
||||
if p.reverseOrder {
|
||||
p.playedItem -= 1
|
||||
} else {
|
||||
p.playedItem += 1
|
||||
}
|
||||
|
||||
if p.playedItem >= len(p.Playlist) {
|
||||
p.playedItem = 0
|
||||
} else if p.playedItem < 0 {
|
||||
p.playedItem = len(p.Playlist) - 1
|
||||
}
|
||||
|
||||
// Load our current item
|
||||
_, sample, format, err := loadFile(p.Playlist[p.playedItem])
|
||||
if err != nil {
|
||||
log.Println("Error loading audio file %s: %s", p.Playlist[p.playedItem], err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
// Resample if needed
|
||||
log.Println("playing list item:", p.playedItem, "/", len(p.Playlist), ":", p.Playlist[p.playedItem])
|
||||
if format.SampleRate != p.sampleRate {
|
||||
return beep.Resample(3, format.SampleRate, p.sampleRate, sample)
|
||||
} else {
|
||||
return sample
|
||||
}
|
||||
})
|
||||
|
||||
// Prepare sound player
|
||||
log.Println("Initializing sound player...")
|
||||
speaker.Init(p.sampleRate, p.sampleRate.N(time.Second/10))
|
||||
defer speaker.Close()
|
||||
|
||||
p.volume = &effects.Volume{stream, 10, -2, false}
|
||||
speaker.Play(p.volume)
|
||||
p.volume = 3500
|
||||
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
@ -200,20 +125,53 @@ func (p *Player) WakeUp() {
|
||||
interrupt := make(chan os.Signal, 1)
|
||||
signal.Notify(interrupt, os.Interrupt, syscall.SIGHUP)
|
||||
|
||||
p.currentCmdCh <- true
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case <-p.Stopper:
|
||||
log.Println("Stopper activated")
|
||||
break loop
|
||||
case <-maxRun:
|
||||
log.Println("Max run time exhausted")
|
||||
break loop
|
||||
case <-p.currentCmdCh:
|
||||
if !p.hasClaironed && time.Since(p.launched) >= p.claironTime {
|
||||
log.Println("clairon time!")
|
||||
p.claironTime += p.claironTime / 2
|
||||
p.SetVolume(65535)
|
||||
p.dontUpdateVolume = true
|
||||
go p.playFile(p.claironFile)
|
||||
} else {
|
||||
p.dontUpdateVolume = false
|
||||
p.volume = 3500 + uint16(math.Log(1+float64(p.ntick)/8)*9500)
|
||||
p.SetVolume(p.volume)
|
||||
|
||||
if p.reverseOrder {
|
||||
p.playedItem -= 1
|
||||
} else {
|
||||
p.playedItem += 1
|
||||
}
|
||||
|
||||
if p.playedItem >= len(p.Playlist) {
|
||||
p.playedItem = 0
|
||||
} else if p.playedItem < 0 {
|
||||
p.playedItem = len(p.Playlist) - 1
|
||||
}
|
||||
|
||||
log.Println("Next track: ", p.Playlist[p.playedItem])
|
||||
go p.playFile(p.Playlist[p.playedItem])
|
||||
}
|
||||
|
||||
case <-ticker.C:
|
||||
p.ntick += 1
|
||||
if !p.dontUpdateVolume {
|
||||
p.volume.Volume = -2 - math.Log(5/float64(p.ntick))/3
|
||||
p.volume = 3500 + uint16(math.Log(1+float64(p.ntick)/8)*9500)
|
||||
p.SetVolume(p.volume)
|
||||
}
|
||||
|
||||
case <-p.Stopper:
|
||||
log.Println("Stopper activated")
|
||||
break loop
|
||||
|
||||
case <-maxRun:
|
||||
log.Println("Max run time exhausted")
|
||||
break loop
|
||||
|
||||
case <-interrupt:
|
||||
break loop
|
||||
}
|
||||
@ -223,31 +181,47 @@ loop:
|
||||
|
||||
// Calm down music
|
||||
loopcalm:
|
||||
for i := 0; i < 2000; i += 1 {
|
||||
p.volume.Volume -= 0.001
|
||||
for i := 0; i < 128 && p.volume >= 15000; i += 1 {
|
||||
timer := time.NewTimer(40 * time.Millisecond)
|
||||
|
||||
p.volume -= 256
|
||||
p.SetVolume(p.volume)
|
||||
|
||||
timer := time.NewTimer(4 * time.Millisecond)
|
||||
select {
|
||||
case <-p.Stopper:
|
||||
log.Println("Hard stop received...")
|
||||
timer.Stop()
|
||||
p.volume.Volume = 0
|
||||
p.volume = 0
|
||||
break loopcalm
|
||||
case <-timer.C:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if p.currentCmd != nil && p.currentCmd.Process != nil {
|
||||
p.currentCmd.Process.Kill()
|
||||
}
|
||||
|
||||
p.SetVolume(65535)
|
||||
|
||||
if p == CommonPlayer {
|
||||
log.Println("Destoying common player")
|
||||
|
||||
CommonPlayer = nil
|
||||
|
||||
// TODO: find a better way to deallocate the card
|
||||
os.Exit(42)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Player) NextTrack() {
|
||||
if p.currentCmd != nil && p.currentCmd.Process != nil {
|
||||
p.currentCmd.Process.Kill()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Player) SetVolume(volume uint16) error {
|
||||
cmd := exec.Command("amixer", "-D", "pulse", "set", "Master", fmt.Sprintf("%d", volume))
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
func (p *Player) Stop() error {
|
||||
log.Println("Trying to stop the player")
|
||||
p.Stopper <- true
|
||||
|
Loading…
Reference in New Issue
Block a user