Kirika/audio/filter/filter.go
2022-05-20 17:23:50 +02:00

164 lines
3.2 KiB
Go

package filter
import (
"git.gammaspectra.live/S.O.N.G/Kirika/audio"
"git.gammaspectra.live/S.O.N.G/Kirika/cgo"
"log"
"time"
)
type Filter interface {
Process(source audio.Source) audio.Source
}
func NewFilterChain(source audio.Source, filters ...Filter) audio.Source {
for _, filter := range filters {
source = filter.Process(source)
}
return source
}
type BufferFilter struct {
blockBufferSize int
}
func NewBufferFilter(blockBufferSize int) BufferFilter {
return BufferFilter{
blockBufferSize: blockBufferSize,
}
}
func (f BufferFilter) Process(source audio.Source) audio.Source {
outBlocks := make(chan []float32, f.blockBufferSize)
go func() {
defer close(outBlocks)
for block := range source.Blocks {
outBlocks <- block
}
}()
return audio.Source{
Channels: source.Channels,
SampleRate: source.SampleRate,
Blocks: outBlocks,
}
}
type RealTimeFilter struct {
blocksPerSecond int
}
func NewRealTimeFilter(blocksPerSecond int) RealTimeFilter {
return RealTimeFilter{
blocksPerSecond: blocksPerSecond,
}
}
func (f RealTimeFilter) Process(source audio.Source) audio.Source {
outBlocks := make(chan []float32)
if source.SampleRate%f.blocksPerSecond != 0 {
log.Panicf("%d %% %d != 0", source.SampleRate, f.blocksPerSecond)
}
blockSize := (source.SampleRate / f.blocksPerSecond) * source.Channels
throttler := time.Tick(time.Second / time.Duration(f.blocksPerSecond))
go func() {
defer close(outBlocks)
var buf []float32
for block := range source.Blocks {
buf = append(buf, block...)
for len(buf) >= blockSize {
outBlocks <- buf[0:blockSize]
buf = buf[blockSize:]
<-throttler
}
}
outBlocks <- buf
}()
return audio.Source{
Channels: source.Channels,
SampleRate: source.SampleRate,
Blocks: outBlocks,
}
}
type VolumeFilter struct {
adjustment float32
}
func NewVolumeFilter(adjustment float32) VolumeFilter {
return VolumeFilter{
adjustment: adjustment,
}
}
func (f VolumeFilter) Process(source audio.Source) audio.Source {
outBlocks := make(chan []float32)
go func() {
defer close(outBlocks)
for block := range source.Blocks {
out := make([]float32, len(block))
for i := range block {
out[i] = block[i] * f.adjustment
}
outBlocks <- out
}
}()
return audio.Source{
Channels: source.Channels,
SampleRate: source.SampleRate,
Blocks: outBlocks,
}
}
type StereoFilter struct {
}
func (f StereoFilter) Process(source audio.Source) audio.Source {
if source.Channels == 2 { //no change
return source
}
outBlocks := make(chan []float32)
go func() {
defer close(outBlocks)
for block := range source.Blocks {
outBlocks <- cgo.MultipleChannelsToStereo(block, source.Channels)
}
}()
return audio.Source{
Channels: 2,
SampleRate: source.SampleRate,
Blocks: outBlocks,
}
}
type MonoFilter struct {
}
func (f MonoFilter) Process(source audio.Source) audio.Source {
if source.Channels == 1 { //no change
return source
}
outBlocks := make(chan []float32)
go func() {
defer close(outBlocks)
for block := range source.Blocks {
outBlocks <- cgo.MultipleChannelsToMono(block, source.Channels)
}
}()
return audio.Source{
Channels: 1,
SampleRate: source.SampleRate,
Blocks: outBlocks,
}
}