0.1.0 - Initial commit
This commit is contained in:
133
lib/audio/effects.go
Normal file
133
lib/audio/effects.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package audio
|
||||
|
||||
import (
|
||||
"git.atri.dad/atridad/muse/schema"
|
||||
)
|
||||
|
||||
// Defines the interface for audio effects
|
||||
type EffectProcessor interface {
|
||||
Process(samples []float64) []float64
|
||||
}
|
||||
|
||||
// Holds a sequence of effects to be applied
|
||||
type EffectChain struct {
|
||||
effects []EffectProcessor
|
||||
}
|
||||
|
||||
// Adds an effect to the chain
|
||||
func (ec *EffectChain) AddEffect(effect EffectProcessor) {
|
||||
ec.effects = append(ec.effects, effect)
|
||||
}
|
||||
|
||||
// Applies all effects in the chain sequentially
|
||||
func (ec *EffectChain) Process(samples []float64) []float64 {
|
||||
for _, effect := range ec.effects {
|
||||
samples = effect.Process(samples)
|
||||
}
|
||||
return samples
|
||||
}
|
||||
|
||||
// Implements a simple reverb effect
|
||||
type ReverbEffect struct {
|
||||
decay float64
|
||||
wet float64
|
||||
delayBuffer []float64
|
||||
delayIndex int
|
||||
sampleRate float64
|
||||
}
|
||||
|
||||
// Creates a new reverb effect with specified parameters
|
||||
func NewReverbEffect(decay, wet, sampleRate float64) *ReverbEffect {
|
||||
delaySize := int(0.1 * sampleRate)
|
||||
return &ReverbEffect{
|
||||
decay: decay,
|
||||
wet: wet,
|
||||
delayBuffer: make([]float64, delaySize),
|
||||
delayIndex: 0,
|
||||
sampleRate: sampleRate,
|
||||
}
|
||||
}
|
||||
|
||||
// Applies reverb effect to audio samples
|
||||
func (r *ReverbEffect) Process(samples []float64) []float64 {
|
||||
output := make([]float64, len(samples))
|
||||
|
||||
for i, sample := range samples {
|
||||
delayed := r.delayBuffer[r.delayIndex]
|
||||
r.delayBuffer[r.delayIndex] = sample + delayed*r.decay
|
||||
output[i] = sample*(1.0-r.wet) + delayed*r.wet
|
||||
r.delayIndex = (r.delayIndex + 1) % len(r.delayBuffer)
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
// Implements a simple delay effect
|
||||
type DelayEffect struct {
|
||||
delayTime float64
|
||||
feedback float64
|
||||
wet float64
|
||||
delayBuffer []float64
|
||||
delayIndex int
|
||||
}
|
||||
|
||||
// Creates a new delay effect with specified parameters
|
||||
func NewDelayEffect(delayTime, feedback, wet, sampleRate float64) *DelayEffect {
|
||||
delaySize := int(delayTime * sampleRate)
|
||||
return &DelayEffect{
|
||||
delayTime: delayTime,
|
||||
feedback: feedback,
|
||||
wet: wet,
|
||||
delayBuffer: make([]float64, delaySize),
|
||||
delayIndex: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// Applies delay effect to audio samples
|
||||
func (d *DelayEffect) Process(samples []float64) []float64 {
|
||||
output := make([]float64, len(samples))
|
||||
|
||||
for i, sample := range samples {
|
||||
delayed := d.delayBuffer[d.delayIndex]
|
||||
d.delayBuffer[d.delayIndex] = sample + delayed*d.feedback
|
||||
output[i] = sample*(1.0-d.wet) + delayed*d.wet
|
||||
d.delayIndex = (d.delayIndex + 1) % len(d.delayBuffer)
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
// Creates an effect chain from schema effect definitions
|
||||
func CreateEffectChain(effects []schema.Effect, sampleRate float64) *EffectChain {
|
||||
chain := &EffectChain{}
|
||||
|
||||
for _, effect := range effects {
|
||||
switch effect.Type {
|
||||
case "reverb":
|
||||
decay := getFloatParam(effect.Params, "decay", 0.5)
|
||||
wet := getFloatParam(effect.Params, "wet", 0.3)
|
||||
chain.AddEffect(NewReverbEffect(decay, wet, sampleRate))
|
||||
|
||||
case "delay":
|
||||
delayTime := getFloatParam(effect.Params, "time", 0.25)
|
||||
feedback := getFloatParam(effect.Params, "feedback", 0.4)
|
||||
wet := getFloatParam(effect.Params, "wet", 0.3)
|
||||
chain.AddEffect(NewDelayEffect(delayTime, feedback, wet, sampleRate))
|
||||
}
|
||||
}
|
||||
|
||||
return chain
|
||||
}
|
||||
|
||||
// Safely extracts a float parameter with default fallback
|
||||
func getFloatParam(params map[string]interface{}, key string, defaultValue float64) float64 {
|
||||
if val, exists := params[key]; exists {
|
||||
switch v := val.(type) {
|
||||
case float64:
|
||||
return v
|
||||
case int:
|
||||
return float64(v)
|
||||
}
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
Reference in New Issue
Block a user