Add real-time voice effects for outgoing audio

Implements 7 voice effects that can be cycled through with F12:
- None (default)
- Echo: Single repeating delay with feedback (250ms)
- Reverb: Multiple short delays without feedback
- High Pitch: Chipmunk voice using cubic interpolation
- Low Pitch: Deep voice effect
- Robot: Ring modulation for robotic sound
- Chorus: Layered voices with pitch variations

The effects are applied after noise suppression and AGC in the audio
pipeline. Selected effect is persisted to config file. Includes
comprehensive documentation in README.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Storm Dragon
2025-10-13 16:27:08 -04:00
parent 82b308000d
commit f96cb1f79b
9 changed files with 493 additions and 8 deletions

View File

@@ -19,4 +19,5 @@ type Hotkeys struct {
ScrollToTop *uiterm.Key
ScrollToBottom *uiterm.Key
NoiseSuppressionToggle *uiterm.Key
CycleVoiceEffect *uiterm.Key
}

View File

@@ -28,6 +28,7 @@ type exportableConfig struct {
NotifyCommand *string
NoiseSuppressionEnabled *bool
NoiseSuppressionThreshold *float32
VoiceEffect *int
}
type server struct {
@@ -78,6 +79,7 @@ func (c *Config) LoadConfig() {
ScrollUp: key(uiterm.KeyPgup),
ScrollDown: key(uiterm.KeyPgdn),
NoiseSuppressionToggle: key(uiterm.KeyF9),
CycleVoiceEffect: key(uiterm.KeyF12),
}
if fileExists(c.fn) {
var data []byte
@@ -123,6 +125,10 @@ func (c *Config) LoadConfig() {
threshold := float32(0.02)
jc.NoiseSuppressionThreshold = &threshold
}
if c.config.VoiceEffect == nil {
effect := 0 // Default to EffectNone
jc.VoiceEffect = &effect
}
}
func (c *Config) findServer(address string) *server {
@@ -232,6 +238,18 @@ func (c *Config) SetNoiseSuppressionThreshold(threshold float32) {
c.SaveConfig()
}
func (c *Config) GetVoiceEffect() int {
if c.config.VoiceEffect == nil {
return 0
}
return *c.config.VoiceEffect
}
func (c *Config) SetVoiceEffect(effect int) {
c.config.VoiceEffect = &effect
c.SaveConfig()
}
func (c *Config) UpdateUser(u *gumble.User) {
var j *eUser
var uc *gumble.Client