Update Kirika, allow configuring queue sample format and bitdepth
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
c25d374cef
commit
bf1b5265f3
|
@ -22,6 +22,8 @@ type Config struct {
|
|||
ReplayGain bool `toml:"replaygain"`
|
||||
Length int `toml:"length"`
|
||||
SampleRate int `toml:"samplerate"`
|
||||
SampleFormat string `toml:"sampleformat"`
|
||||
BitDepth int `toml:"bitdepth"`
|
||||
} `toml:"queue"`
|
||||
Radio struct {
|
||||
Port int `toml:"port"`
|
||||
|
|
|
@ -58,9 +58,17 @@ buffer_duration=0
|
|||
replaygain=false
|
||||
|
||||
# Set the sample rate of the queue. Default is 44100
|
||||
# Some codecs (example: Opus) will output at a different samplerate.
|
||||
# If incoming audio is different than this sample rate, it will be resampled.
|
||||
# Some codecs (example: Opus) will output at a different samplerates.
|
||||
#samplerate=44100
|
||||
|
||||
# Set the sample format and bit depth of the queue. Default is int16 for sample format, and sample format size for bit depth.
|
||||
# If incoming audio has a different format / bitdepth than this sample rate, it will be converted.
|
||||
# See Kirika's Codec table (Decoder Sample Format) column. Conversion from int32 to int16 is fast.
|
||||
# Possible values (plus other aliases): i16, s16, int16, s16le, i32, s32, int32, int, s32le, f32, float, float32, f32le
|
||||
#sampleformat=int16
|
||||
#bitdepth=0
|
||||
|
||||
[radio]
|
||||
#
|
||||
# The port to stream actual audio on. MeteorLight will listen on localhost.
|
||||
|
|
2
go.mod
2
go.mod
|
@ -3,7 +3,7 @@ module git.gammaspectra.live/S.O.N.G/MeteorLight
|
|||
go 1.18
|
||||
|
||||
require (
|
||||
git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220716231852-431f8e745cde
|
||||
git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220719151756-674b19a2bcc9
|
||||
github.com/BurntSushi/toml v1.1.0
|
||||
github.com/dhowden/tag v0.0.0-20220618230019-adf36e896086
|
||||
github.com/enriquebris/goconcurrentqueue v0.6.3
|
||||
|
|
4
go.sum
4
go.sum
|
@ -1,5 +1,5 @@
|
|||
git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220716231852-431f8e745cde h1:7BKRV5h8Oh68KYpDqtcvL68NaVLROYXOKt14G5vBCCM=
|
||||
git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220716231852-431f8e745cde/go.mod h1:HrYZb1M5dv2hOfpUhLOYkK4qQqBu+7hg7p14R19ebvs=
|
||||
git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220719151756-674b19a2bcc9 h1:DQqURP3MFbMTqWl/rGyvJh7k6+3HTTxpqT2KvkZ009E=
|
||||
git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220719151756-674b19a2bcc9/go.mod h1:HrYZb1M5dv2hOfpUhLOYkK4qQqBu+7hg7p14R19ebvs=
|
||||
git.gammaspectra.live/S.O.N.G/go-alac v0.0.0-20220421115623-d0b3bfe57e0f h1:CxN7zlk5FdAieyRKQSbwBGBsvQ2cDF8JVCODZpzcRkA=
|
||||
git.gammaspectra.live/S.O.N.G/go-alac v0.0.0-20220421115623-d0b3bfe57e0f/go.mod h1:f1+h7KOnuM9zcEQp7ri4UaVvgX4m1NFFIXgReIyjGMA=
|
||||
git.gammaspectra.live/S.O.N.G/go-ebur128 v0.0.0-20220418202343-73a167e76255 h1:BWRx2ZFyhp5+rsXhdDZtk5Gld+L44lxlN9ASqB9Oj0M=
|
||||
|
|
8
mount.go
8
mount.go
|
@ -57,9 +57,9 @@ func NewStreamMount(source audio.Source, config *StreamConfig) *StreamMount {
|
|||
|
||||
bitrate := config.GetOption("bitrate", nil)
|
||||
|
||||
sampleRate := config.GetIntOption("samplerate", source.SampleRate)
|
||||
sampleRate := config.GetIntOption("samplerate", source.GetSampleRate())
|
||||
|
||||
channels := config.GetIntOption("channels", source.Channels)
|
||||
channels := config.GetIntOption("channels", source.GetChannels())
|
||||
|
||||
switch config.Codec {
|
||||
case "vorbis":
|
||||
|
@ -160,7 +160,7 @@ func NewStreamMount(source audio.Source, config *StreamConfig) *StreamMount {
|
|||
go func() {
|
||||
defer writer.Close()
|
||||
|
||||
if channels != source.Channels {
|
||||
if channels != source.GetChannels() {
|
||||
if channels == 1 {
|
||||
source = filter.MonoFilter{}.Process(source)
|
||||
} else if channels == 2 {
|
||||
|
@ -168,7 +168,7 @@ func NewStreamMount(source audio.Source, config *StreamConfig) *StreamMount {
|
|||
}
|
||||
}
|
||||
|
||||
if sampleRate != source.SampleRate {
|
||||
if sampleRate != source.GetSampleRate() {
|
||||
source = filter.NewResampleFilter(sampleRate, filter.QualityFastest, 0).Process(source)
|
||||
}
|
||||
|
||||
|
|
28
queue.go
28
queue.go
|
@ -49,7 +49,7 @@ type QueueTrackEntry struct {
|
|||
}
|
||||
|
||||
func (e *QueueTrackEntry) Load() error {
|
||||
if e.source.Blocks != nil {
|
||||
if e.source != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ func (e *QueueTrackEntry) Load() error {
|
|||
return err
|
||||
}
|
||||
|
||||
if source.Blocks == nil {
|
||||
if source == nil {
|
||||
return fmt.Errorf("could not find decoder for %s", e.Path)
|
||||
}
|
||||
|
||||
|
@ -194,15 +194,33 @@ func NewQueue(config *Config) *Queue {
|
|||
if config.Queue.SampleRate <= 0 {
|
||||
config.Queue.SampleRate = 44100
|
||||
}
|
||||
|
||||
sampleFormat := audio.SourceInt16
|
||||
bitDepth := 16
|
||||
switch config.Queue.SampleFormat {
|
||||
case "f32", "float", "float32", "f32le":
|
||||
sampleFormat = audio.SourceFloat32
|
||||
bitDepth = 0
|
||||
case "i32", "s32", "int32", "int", "s32le":
|
||||
sampleFormat = audio.SourceInt32
|
||||
bitDepth = 32
|
||||
case "i16", "s16", "int16", "s16le":
|
||||
sampleFormat = audio.SourceInt16
|
||||
bitDepth = 16
|
||||
}
|
||||
if config.Queue.BitDepth > 0 {
|
||||
bitDepth = config.Queue.BitDepth
|
||||
}
|
||||
|
||||
q := &Queue{
|
||||
NowPlaying: make(chan *QueueTrackEntry, 1),
|
||||
QueueEmpty: make(chan *QueueTrackEntry),
|
||||
config: config,
|
||||
audioQueue: queue.NewQueue(config.Queue.SampleRate, 2),
|
||||
audioQueue: queue.NewQueue(sampleFormat, bitDepth, config.Queue.SampleRate, 2),
|
||||
}
|
||||
blocksPerSecond := 20
|
||||
|
||||
sources := SplitAudioSource(filter.NewFilterChain(q.audioQueue.GetSource(), filter.NewBufferFilter(16), filter.NewRealTimeFilter(blocksPerSecond), filter.NewBufferFilter(maxBufferSize*blocksPerSecond)), len(config.Streams))
|
||||
sources := filter.NewFilterChain(q.audioQueue.GetSource(), filter.NewBufferFilter(16), filter.NewRealTimeFilter(blocksPerSecond), filter.NewBufferFilter(maxBufferSize*blocksPerSecond)).Split(len(config.Streams))
|
||||
for i, s := range q.config.Streams {
|
||||
mount := NewStreamMount(sources[i], s)
|
||||
if mount == nil {
|
||||
|
@ -248,7 +266,7 @@ func (q *Queue) AddTrack(entry *QueueTrackEntry, tail bool) error {
|
|||
}
|
||||
|
||||
removeCallback := func(queue *queue.Queue, entry *queue.QueueEntry) {
|
||||
atomic.AddInt64((*int64)(&q.Duration), int64((time.Second*time.Duration(entry.ReadSamples))/time.Duration(entry.Source.SampleRate)))
|
||||
atomic.AddInt64((*int64)(&q.Duration), int64((time.Second*time.Duration(entry.ReadSamples))/time.Duration(entry.Source.GetSampleRate())))
|
||||
|
||||
q.Remove(entry.Identifier)
|
||||
q.HandleQueue()
|
||||
|
|
30
utilities.go
30
utilities.go
|
@ -1,30 +0,0 @@
|
|||
package main
|
||||
|
||||
import "git.gammaspectra.live/S.O.N.G/Kirika/audio"
|
||||
|
||||
func SplitAudioSource(source audio.Source, split int) (sources []audio.Source) {
|
||||
for i := 0; i < split; i++ {
|
||||
sources = append(sources, audio.Source{
|
||||
SampleRate: source.SampleRate,
|
||||
Channels: source.Channels,
|
||||
Blocks: make(chan []float32),
|
||||
})
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
for _, s := range sources {
|
||||
close(s.Blocks)
|
||||
}
|
||||
}()
|
||||
|
||||
for block := range source.Blocks {
|
||||
//TODO: this might block?
|
||||
for _, s := range sources {
|
||||
s.Blocks <- block
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return
|
||||
}
|
Loading…
Reference in a new issue