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"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path"
|
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"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/config"
|
||||||
"git.nemunai.re/nemunaire/reveil/model"
|
"git.nemunai.re/nemunaire/reveil/model"
|
||||||
)
|
)
|
||||||
@ -26,11 +19,11 @@ import (
|
|||||||
var CommonPlayer *Player
|
var CommonPlayer *Player
|
||||||
|
|
||||||
type Player struct {
|
type Player struct {
|
||||||
Playlist []string
|
Playlist []string
|
||||||
MaxRunTime time.Duration
|
MaxRunTime time.Duration
|
||||||
Stopper chan bool
|
Stopper chan bool
|
||||||
|
currentCmd *exec.Cmd
|
||||||
sampleRate beep.SampleRate
|
currentCmdCh chan bool
|
||||||
|
|
||||||
claironTime time.Duration
|
claironTime time.Duration
|
||||||
claironFile string
|
claironFile string
|
||||||
@ -38,7 +31,7 @@ type Player struct {
|
|||||||
ntick int64
|
ntick int64
|
||||||
hasClaironed bool
|
hasClaironed bool
|
||||||
launched time.Time
|
launched time.Time
|
||||||
volume *effects.Volume
|
volume uint16
|
||||||
dontUpdateVolume bool
|
dontUpdateVolume bool
|
||||||
reverseOrder bool
|
reverseOrder bool
|
||||||
playedItem int
|
playedItem int
|
||||||
@ -66,11 +59,11 @@ func NewPlayer(cfg *config.Config) (*Player, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
p := Player{
|
p := Player{
|
||||||
Stopper: make(chan bool, 1),
|
Stopper: make(chan bool, 1),
|
||||||
MaxRunTime: settings.MaxRunTime * time.Minute,
|
currentCmdCh: make(chan bool, 1),
|
||||||
sampleRate: beep.SampleRate(cfg.SampleRate),
|
MaxRunTime: settings.MaxRunTime * time.Minute,
|
||||||
claironTime: settings.GongInterval * time.Minute,
|
claironTime: settings.GongInterval * time.Minute,
|
||||||
claironFile: reveil.CurrentGongPath(cfg),
|
claironFile: reveil.CurrentGongPath(cfg),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load our track list
|
// Load our track list
|
||||||
@ -100,95 +93,27 @@ func NewPlayer(cfg *config.Config) (*Player, error) {
|
|||||||
return &p, nil
|
return &p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadFile(filepath string) (name string, s beep.StreamSeekCloser, format beep.Format, err error) {
|
func (p *Player) playFile(filepath string) (err error) {
|
||||||
var fd *os.File
|
p.currentCmd = exec.Command("paplay", filepath)
|
||||||
|
if err = p.currentCmd.Start(); err != nil {
|
||||||
name = path.Base(filepath)
|
log.Println("Running paplay err: ", err.Error())
|
||||||
|
p.currentCmdCh <- true
|
||||||
fd, err = os.Open(filepath)
|
|
||||||
if err != nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch strings.ToLower(path.Ext(filepath)) {
|
log.Println("Running paplay ", filepath)
|
||||||
case ".flac":
|
|
||||||
s, format, err = flac.Decode(fd)
|
|
||||||
case ".mp3":
|
|
||||||
s, format, err = mp3.Decode(fd)
|
|
||||||
default:
|
|
||||||
s, format, err = wav.Decode(fd)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
err = p.currentCmd.Wait()
|
||||||
fd.Close()
|
p.currentCmdCh <- true
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) WakeUp() {
|
func (p *Player) WakeUp() {
|
||||||
log.Println("RUN WAKEUP FUNC")
|
|
||||||
|
|
||||||
log.Println("Playlist in use:", strings.Join(p.Playlist, " ; "))
|
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
|
// Prepare sound player
|
||||||
log.Println("Initializing sound player...")
|
p.volume = 3500
|
||||||
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)
|
|
||||||
|
|
||||||
ticker := time.NewTicker(time.Second)
|
ticker := time.NewTicker(time.Second)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
@ -200,20 +125,53 @@ func (p *Player) WakeUp() {
|
|||||||
interrupt := make(chan os.Signal, 1)
|
interrupt := make(chan os.Signal, 1)
|
||||||
signal.Notify(interrupt, os.Interrupt, syscall.SIGHUP)
|
signal.Notify(interrupt, os.Interrupt, syscall.SIGHUP)
|
||||||
|
|
||||||
|
p.currentCmdCh <- true
|
||||||
loop:
|
loop:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-p.Stopper:
|
case <-p.currentCmdCh:
|
||||||
log.Println("Stopper activated")
|
if !p.hasClaironed && time.Since(p.launched) >= p.claironTime {
|
||||||
break loop
|
log.Println("clairon time!")
|
||||||
case <-maxRun:
|
p.claironTime += p.claironTime / 2
|
||||||
log.Println("Max run time exhausted")
|
p.SetVolume(65535)
|
||||||
break loop
|
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:
|
case <-ticker.C:
|
||||||
p.ntick += 1
|
p.ntick += 1
|
||||||
if !p.dontUpdateVolume {
|
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:
|
case <-interrupt:
|
||||||
break loop
|
break loop
|
||||||
}
|
}
|
||||||
@ -223,31 +181,47 @@ loop:
|
|||||||
|
|
||||||
// Calm down music
|
// Calm down music
|
||||||
loopcalm:
|
loopcalm:
|
||||||
for i := 0; i < 2000; i += 1 {
|
for i := 0; i < 128 && p.volume >= 15000; i += 1 {
|
||||||
p.volume.Volume -= 0.001
|
timer := time.NewTimer(40 * time.Millisecond)
|
||||||
|
|
||||||
|
p.volume -= 256
|
||||||
|
p.SetVolume(p.volume)
|
||||||
|
|
||||||
timer := time.NewTimer(4 * time.Millisecond)
|
|
||||||
select {
|
select {
|
||||||
case <-p.Stopper:
|
case <-p.Stopper:
|
||||||
log.Println("Hard stop received...")
|
log.Println("Hard stop received...")
|
||||||
timer.Stop()
|
timer.Stop()
|
||||||
p.volume.Volume = 0
|
p.volume = 0
|
||||||
break loopcalm
|
break loopcalm
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.currentCmd != nil && p.currentCmd.Process != nil {
|
||||||
|
p.currentCmd.Process.Kill()
|
||||||
|
}
|
||||||
|
|
||||||
|
p.SetVolume(65535)
|
||||||
|
|
||||||
if p == CommonPlayer {
|
if p == CommonPlayer {
|
||||||
log.Println("Destoying common player")
|
log.Println("Destoying common player")
|
||||||
|
|
||||||
CommonPlayer = nil
|
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 {
|
func (p *Player) Stop() error {
|
||||||
log.Println("Trying to stop the player")
|
log.Println("Trying to stop the player")
|
||||||
p.Stopper <- true
|
p.Stopper <- true
|
||||||
|
Loading…
Reference in New Issue
Block a user