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:
@@ -17,6 +17,12 @@ type NoiseProcessor interface {
|
||||
IsEnabled() bool
|
||||
}
|
||||
|
||||
// EffectsProcessor interface for voice effects
|
||||
type EffectsProcessor interface {
|
||||
ProcessSamples(samples []int16)
|
||||
IsEnabled() bool
|
||||
}
|
||||
|
||||
const (
|
||||
maxBufferSize = 11520 // Max frame size (2880) * bytes per stereo sample (4)
|
||||
)
|
||||
@@ -49,9 +55,10 @@ type Stream struct {
|
||||
|
||||
deviceSink *openal.Device
|
||||
contextSink *openal.Context
|
||||
|
||||
noiseProcessor NoiseProcessor
|
||||
micAGC *audio.AGC
|
||||
|
||||
noiseProcessor NoiseProcessor
|
||||
micAGC *audio.AGC
|
||||
effectsProcessor EffectsProcessor
|
||||
}
|
||||
|
||||
func New(client *gumble.Client, inputDevice *string, outputDevice *string, test bool) (*Stream, error) {
|
||||
@@ -112,6 +119,14 @@ func (s *Stream) SetNoiseProcessor(np NoiseProcessor) {
|
||||
s.noiseProcessor = np
|
||||
}
|
||||
|
||||
func (s *Stream) SetEffectsProcessor(ep EffectsProcessor) {
|
||||
s.effectsProcessor = ep
|
||||
}
|
||||
|
||||
func (s *Stream) GetEffectsProcessor() EffectsProcessor {
|
||||
return s.effectsProcessor
|
||||
}
|
||||
|
||||
|
||||
func (s *Stream) Destroy() {
|
||||
if s.link != nil {
|
||||
@@ -342,12 +357,17 @@ func (s *Stream) sourceRoutine(inputDevice *string) {
|
||||
if s.noiseProcessor != nil && s.noiseProcessor.IsEnabled() {
|
||||
s.noiseProcessor.ProcessSamples(int16Buffer)
|
||||
}
|
||||
|
||||
|
||||
// Apply AGC to outgoing microphone audio (always enabled)
|
||||
if s.micAGC != nil {
|
||||
s.micAGC.ProcessSamples(int16Buffer)
|
||||
}
|
||||
|
||||
|
||||
// Apply voice effects if available and enabled
|
||||
if s.effectsProcessor != nil && s.effectsProcessor.IsEnabled() {
|
||||
s.effectsProcessor.ProcessSamples(int16Buffer)
|
||||
}
|
||||
|
||||
outgoing <- gumble.AudioBuffer(int16Buffer)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user