Skip to Content

Events

VoiceReact provides both UnityEvents (Inspector-friendly) and C# events (code-based) for maximum flexibility.

VoiceReactController Events

VoiceReactController fires high-level gameplay events.

OnSpeechStart (UnityEvent)

Fires when player starts speaking.

using UnityEngine; using Peek.VoiceReact; public class GameplayController : MonoBehaviour { [SerializeField] private VoiceReactController voiceController; void Start() { voiceController.OnSpeechStart.AddListener(OnPlayerStartedSpeaking); } void OnPlayerStartedSpeaking() { Debug.Log("Player started speaking!"); // Trigger gameplay events } }

Inspector Setup:

  1. Select GameObject with script
  2. In Inspector, find OnSpeechStart event
  3. Click + to add listener
  4. Drag target GameObject
  5. Select function to call

OnSpeechEnd (UnityEvent<float>)

Fires when player stops speaking. Provides speech duration.

void Start() { voiceController.OnSpeechEnd.AddListener(OnPlayerStoppedSpeaking); } void OnPlayerStoppedSpeaking(float duration) { Debug.Log($"Player spoke for {duration} seconds"); if (duration > 2f) { // Long speech - big noise event AlertNearbyEnemies(); } }

OnTranscriptionReady (UnityEvent<string>)

Fires when speech-to-text transcription is ready (requires Whisper integration).

void Start() { voiceController.OnTranscriptionReady.AddListener(OnTranscriptionReceived); } void OnTranscriptionReceived(string text) { Debug.Log($"Player said: {text}"); // Voice command system ProcessVoiceCommand(text); }

Advanced C# Events

For custom processing with access to detailed event data, use advanced C# events.

OnSpeechStartAdvanced

Provides detailed speech start information:

using System; using Peek.VoiceReact; void Start() { voiceController.OnSpeechStartAdvanced += HandleSpeechStart; } void OnDestroy() { voiceController.OnSpeechStartAdvanced -= HandleSpeechStart; } void HandleSpeechStart(object sender, VoiceReactEventArgs e) { Debug.Log($"Speech started at {e.DecibelLevel} dB"); Debug.Log($"Normalized volume: {e.NormalizedVolume}"); // Access to raw audio data if (e.AudioData != null) { ProcessAudioData(e.AudioData, e.SampleRate); } }

VoiceReactEventArgs Properties:

  • DecibelLevel - Current audio level in dB
  • NormalizedVolume - 0-1 volume for UI displays
  • Duration - Speech duration (only in OnSpeechEnd)
  • AudioData - Raw audio samples (float array)
  • SampleRate - Audio sample rate in Hz
  • Transcription - Speech-to-text result (if available)

OnSpeechEndAdvanced

Provides detailed speech end information including recorded audio:

void Start() { voiceController.OnSpeechEndAdvanced += HandleSpeechEnd; } void HandleSpeechEnd(object sender, VoiceReactEventArgs e) { Debug.Log($"Speech ended. Duration: {e.Duration}s"); Debug.Log($"Final volume: {e.DecibelLevel} dB"); // Save audio recording if (e.AudioData != null) { SaveAudioClip(e.AudioData, e.SampleRate); } }

OnSpeechDataAdvanced

Fires during speech with real-time audio data. Use for live processing or visualization.

void Start() { voiceController.OnSpeechDataAdvanced += HandleSpeechData; } void HandleSpeechData(object sender, VoiceReactEventArgs e) { // Real-time audio processing UpdateAudioVisualization(e.AudioData); // Current speech duration Debug.Log($"Speaking for {e.Duration}s at {e.DecibelLevel} dB"); }

VoiceListener Events

VoiceListener provides events for enemy/NPC hearing.

OnPlayerHeard (UnityEvent<Vector3, float>)

Fires when player becomes audible to this listener.

[SerializeField] private VoiceListener listener; void Start() { listener.OnPlayerHeard.AddListener(OnHeardPlayer); } void OnHeardPlayer(Vector3 playerPosition, float decibelLevel) { Debug.Log($"Heard player at {playerPosition}"); Debug.Log($"Volume: {decibelLevel} dB"); // React to player voice InvestigatePosition(playerPosition); }

Event Parameters:

  • playerPosition - Player’s 3D world position
  • decibelLevel - Volume in decibels (-60 to 0 dB)

OnPlayerLost (UnityEvent)

Fires when player becomes inaudible (went silent or out of range).

void Start() { listener.OnPlayerLost.AddListener(OnLostPlayer); } void OnLostPlayer() { Debug.Log("Can no longer hear player"); ReturnToPatrol(); }

OnDecibelLevelChanged (UnityEvent<float>)

Fires when player’s volume changes significantly while being heard.

void Start() { listener.OnDecibelLevelChanged.AddListener(OnVolumeChanged); } void OnVolumeChanged(float newDecibelLevel) { Debug.Log($"Player volume changed to {newDecibelLevel} dB"); // React to volume changes AdjustBehaviorBasedOnVolume(newDecibelLevel); }

Low-Level Audio Events

MicrophoneInputHandler provides low-level audio capture events. Use these for custom audio processing.

OnVoiceCaptureStarted

Fires when voice capture begins (low-level).

var inputHandler = GetComponent<MicrophoneInputHandler>(); void Start() { inputHandler.OnVoiceCaptureStarted += HandleCaptureStarted; } void OnDestroy() { inputHandler.OnVoiceCaptureStarted -= HandleCaptureStarted; } void HandleCaptureStarted(object sender, AudioCaptureEventArgs e) { Debug.Log($"Voice capture started"); Debug.Log($"Sample rate: {e.SampleRate} Hz"); Debug.Log($"Noise floor: {e.NoiseFloor} dB"); }

AudioCaptureEventArgs Properties:

  • AudioData - Raw audio samples (float array)
  • SampleRate - Audio sample rate in Hz
  • DecibelLevel - Current dB level
  • NoiseFloor - Background noise level in dB
  • IsVoiceDetected - Is voice currently detected

OnVoiceCaptureStopped

Fires when voice capture ends.

void Start() { inputHandler.OnVoiceCaptureStopped += HandleCaptureStopped; } void HandleCaptureStopped(object sender, AudioCaptureEventArgs e) { Debug.Log("Voice capture stopped"); // Process final audio buffer ProcessRecording(e.AudioData, e.SampleRate); }

OnVoiceCaptureData

Fires during capture with real-time audio data chunks.

void Start() { inputHandler.OnVoiceCaptureData += HandleCaptureData; } void HandleCaptureData(object sender, AudioCaptureEventArgs e) { // Live audio processing AnalyzeAudioChunk(e.AudioData); }

Common Event Patterns

UI Feedback

Show visual feedback when player speaks:

using UnityEngine; using UnityEngine.UI; public class VoiceFeedbackUI : MonoBehaviour { [SerializeField] private VoiceReactController voiceController; [SerializeField] private Image micIndicator; void Start() { voiceController.OnSpeechStart.AddListener(ShowMicActive); voiceController.OnSpeechEnd.AddListener(HideMicActive); } void ShowMicActive() { micIndicator.color = Color.red; } void HideMicActive(float duration) { micIndicator.color = Color.gray; } }

Audio Recording

Save player speech recordings:

using System.IO; public class SpeechRecorder : MonoBehaviour { [SerializeField] private VoiceReactController voiceController; void Start() { voiceController.OnSpeechEndAdvanced += RecordSpeech; } void RecordSpeech(object sender, VoiceReactEventArgs e) { if (e.AudioData == null || e.AudioData.Length == 0) return; // Create AudioClip from samples var clip = AudioClip.Create( "Recording", e.AudioData.Length, 1, // mono e.SampleRate, false ); clip.SetData(e.AudioData, 0); // Save to file (requires additional WAV encoding) SaveClipToFile(clip); } }

Volume-Based Animations

Animate character based on volume:

public class VoiceAnimator : MonoBehaviour { [SerializeField] private VoiceReactController voiceController; [SerializeField] private Animator animator; void Start() { voiceController.OnSpeechStart.AddListener(OnStartSpeaking); voiceController.OnSpeechEnd.AddListener(OnStopSpeaking); } void Update() { if (voiceController.IsPlayerSpeaking) { // Animate based on volume float volume = voiceController.NormalizedVolume; animator.SetFloat("VoiceIntensity", volume); } } void OnStartSpeaking() { animator.SetBool("IsSpeaking", true); } void OnStopSpeaking(float duration) { animator.SetBool("IsSpeaking", false); } }

Event Chaining

Chain events for complex behavior:

public class ChainedEventExample : MonoBehaviour { [SerializeField] private VoiceReactController voiceController; private int consecutiveSpeechCount = 0; void Start() { voiceController.OnSpeechEnd.AddListener(OnSpeechEnded); } void OnSpeechEnded(float duration) { // Count consecutive short speeches if (duration < 1f) { consecutiveSpeechCount++; if (consecutiveSpeechCount >= 3) { Debug.Log("Player is spamming short noises!"); TriggerPenalty(); consecutiveSpeechCount = 0; } } else { consecutiveSpeechCount = 0; } } }

Multi-Listener Coordination

Coordinate multiple listeners:

public class ListenerCoordinator : MonoBehaviour { private VoiceListener[] allListeners; void Start() { allListeners = FindObjectsByType<VoiceListener>(FindObjectsSortMode.None); foreach (var listener in allListeners) { listener.OnPlayerHeard.AddListener(OnAnyListenerHeard); } } void OnAnyListenerHeard(Vector3 position, float db) { // Count how many can hear int hearingCount = 0; foreach (var listener in allListeners) { if (listener.CanHearPlayer) hearingCount++; } Debug.Log($"{hearingCount} enemies can hear the player!"); if (hearingCount >= 3) { TriggerSurroundedEvent(); } } }

Event Cleanup

Always unsubscribe from C# events to prevent memory leaks:

void Start() { voiceController.OnSpeechStartAdvanced += HandleSpeechStart; } void OnDestroy() { // IMPORTANT: Unsubscribe when destroyed if (voiceController != null) { voiceController.OnSpeechStartAdvanced -= HandleSpeechStart; } }

UnityEvents are automatically cleaned up by Unity, but C# events require manual unsubscription.

Performance Considerations

Event Rate Limiting

Limit how often events are processed:

private float lastEventTime = 0f; private float eventCooldown = 0.5f; void HandleSpeechData(object sender, VoiceReactEventArgs e) { if (Time.time - lastEventTime < eventCooldown) return; lastEventTime = Time.time; // Process event DoExpensiveOperation(e.AudioData); }

Conditional Event Processing

Only process events when needed:

void HandleSpeechStart(object sender, VoiceReactEventArgs e) { // Only process if player is in dangerous area if (!IsInDangerZone()) return; // Process event AlertEnemies(); }

Next Steps

Last updated on