Compare commits
No commits in common. "045a18c3c8587d17de0e64736102e3963f205834" and "4364a9f13701ed678ffd552b537106b631ebe49a" have entirely different histories.
045a18c3c8
...
4364a9f137
11
.drone.yml
11
.drone.yml
@ -47,17 +47,6 @@ steps:
|
||||
event:
|
||||
- tag
|
||||
|
||||
- name: gitea release
|
||||
image: plugins/gitea-release
|
||||
settings:
|
||||
api_key:
|
||||
from_secret: gitea_api_key
|
||||
base_url: https://git.nemunai.re/
|
||||
files: deploy/reveil-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
|
||||
- name: docker
|
||||
image: plugins/docker
|
||||
settings:
|
||||
|
11
api/alarm.go
11
api/alarm.go
@ -33,17 +33,6 @@ func declareAlarmRoutes(cfg *config.Config, router *gin.RouterGroup) {
|
||||
c.JSON(http.StatusOK, true)
|
||||
})
|
||||
|
||||
router.POST("/alarm/next", func(c *gin.Context) {
|
||||
if player.CommonPlayer == nil {
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "No player currently playing"})
|
||||
return
|
||||
} else {
|
||||
player.CommonPlayer.NextTrack()
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, true)
|
||||
})
|
||||
|
||||
router.DELETE("/alarm", func(c *gin.Context) {
|
||||
if player.CommonPlayer != nil {
|
||||
err := player.CommonPlayer.Stop()
|
||||
|
158
player/player.go
158
player/player.go
@ -6,12 +6,19 @@ 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"
|
||||
)
|
||||
@ -22,8 +29,8 @@ type Player struct {
|
||||
Playlist []string
|
||||
MaxRunTime time.Duration
|
||||
Stopper chan bool
|
||||
currentCmd *exec.Cmd
|
||||
currentCmdCh chan bool
|
||||
|
||||
sampleRate beep.SampleRate
|
||||
|
||||
claironTime time.Duration
|
||||
claironFile string
|
||||
@ -31,7 +38,7 @@ type Player struct {
|
||||
ntick int64
|
||||
hasClaironed bool
|
||||
launched time.Time
|
||||
volume uint16
|
||||
volume *effects.Volume
|
||||
dontUpdateVolume bool
|
||||
reverseOrder bool
|
||||
playedItem int
|
||||
@ -60,8 +67,8 @@ func NewPlayer(cfg *config.Config) (*Player, error) {
|
||||
|
||||
p := Player{
|
||||
Stopper: make(chan bool, 1),
|
||||
currentCmdCh: make(chan bool, 1),
|
||||
MaxRunTime: settings.MaxRunTime * time.Minute,
|
||||
sampleRate: beep.SampleRate(cfg.SampleRate),
|
||||
claironTime: settings.GongInterval * time.Minute,
|
||||
claironFile: reveil.CurrentGongPath(cfg),
|
||||
}
|
||||
@ -93,53 +100,59 @@ func NewPlayer(cfg *config.Config) (*Player, error) {
|
||||
return &p, 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
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("Running paplay ", filepath)
|
||||
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)
|
||||
}
|
||||
|
||||
err = p.currentCmd.Wait()
|
||||
p.currentCmdCh <- true
|
||||
if err != nil {
|
||||
fd.Close()
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Player) WakeUp() {
|
||||
log.Println("RUN WAKEUP FUNC")
|
||||
|
||||
log.Println("Playlist in use:", strings.Join(p.Playlist, " ; "))
|
||||
|
||||
// Prepare sound player
|
||||
p.volume = 3500
|
||||
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
p.launched = time.Now()
|
||||
|
||||
// Prepare graceful shutdown
|
||||
maxRun := time.After(p.MaxRunTime)
|
||||
interrupt := make(chan os.Signal, 1)
|
||||
signal.Notify(interrupt, os.Interrupt, syscall.SIGHUP)
|
||||
|
||||
p.currentCmdCh <- true
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case <-p.currentCmdCh:
|
||||
// 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
|
||||
p.SetVolume(65535)
|
||||
_, sample, format, err := loadFile(p.claironFile)
|
||||
if err == nil {
|
||||
p.volume.Volume = 0.1
|
||||
p.dontUpdateVolume = true
|
||||
go p.playFile(p.claironFile)
|
||||
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 = 3500 + uint16(math.Log(1+float64(p.ntick)/8)*9500)
|
||||
p.SetVolume(p.volume)
|
||||
p.volume.Volume = -2 - math.Log(5/float64(p.ntick))/3
|
||||
|
||||
if p.reverseOrder {
|
||||
p.playedItem -= 1
|
||||
@ -153,25 +166,54 @@ loop:
|
||||
p.playedItem = len(p.Playlist) - 1
|
||||
}
|
||||
|
||||
log.Println("Next track: ", p.Playlist[p.playedItem])
|
||||
go p.playFile(p.Playlist[p.playedItem])
|
||||
// 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
|
||||
}
|
||||
|
||||
case <-ticker.C:
|
||||
p.ntick += 1
|
||||
if !p.dontUpdateVolume {
|
||||
p.volume = 3500 + uint16(math.Log(1+float64(p.ntick)/8)*9500)
|
||||
p.SetVolume(p.volume)
|
||||
// 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)
|
||||
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
p.launched = time.Now()
|
||||
|
||||
// Prepare graceful shutdown
|
||||
maxRun := time.After(p.MaxRunTime)
|
||||
interrupt := make(chan os.Signal, 1)
|
||||
signal.Notify(interrupt, os.Interrupt, syscall.SIGHUP)
|
||||
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case <-p.Stopper:
|
||||
log.Println("Stopper activated")
|
||||
break loop
|
||||
|
||||
case <-maxRun:
|
||||
log.Println("Max run time exhausted")
|
||||
break loop
|
||||
|
||||
case <-ticker.C:
|
||||
p.ntick += 1
|
||||
if !p.dontUpdateVolume {
|
||||
p.volume.Volume = -2 - math.Log(5/float64(p.ntick))/3
|
||||
}
|
||||
case <-interrupt:
|
||||
break loop
|
||||
}
|
||||
@ -181,47 +223,31 @@ loop:
|
||||
|
||||
// Calm down music
|
||||
loopcalm:
|
||||
for i := 0; i < 128 && p.volume >= 15000; i += 1 {
|
||||
timer := time.NewTimer(40 * time.Millisecond)
|
||||
|
||||
p.volume -= 256
|
||||
p.SetVolume(p.volume)
|
||||
for i := 0; i < 2000; i += 1 {
|
||||
p.volume.Volume -= 0.001
|
||||
|
||||
timer := time.NewTimer(4 * time.Millisecond)
|
||||
select {
|
||||
case <-p.Stopper:
|
||||
log.Println("Hard stop received...")
|
||||
timer.Stop()
|
||||
p.volume = 0
|
||||
p.volume.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
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Player) NextTrack() {
|
||||
if p.currentCmd != nil && p.currentCmd.Process != nil {
|
||||
p.currentCmd.Process.Kill()
|
||||
// TODO: find a better way to deallocate the card
|
||||
os.Exit(42)
|
||||
}
|
||||
}
|
||||
|
||||
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…
x
Reference in New Issue
Block a user