forked from cgvr/DeltaVR
radio particle emission rate corresponds with mic input volume
This commit is contained in:
@@ -64,6 +64,11 @@ public class FMODWhisperBridge : MonoBehaviour
|
||||
private bool isRecordingActivated = false;
|
||||
private bool _skipOneFeedFrame = false;
|
||||
|
||||
// --- Speech Volume Measurement ---
|
||||
private float currentVolumeRms = 0f; // Smoothed RMS for external access
|
||||
private float volumeSmoothing = 0.15f; // How fast the meter reacts (0.1–0.3 good)
|
||||
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (!whisper) whisper = FindObjectOfType<WhisperManager>();
|
||||
@@ -254,6 +259,29 @@ public class FMODWhisperBridge : MonoBehaviour
|
||||
Debug.Log("[FMOD→Whisper] Stream deactivated (Whisper stopped; FMOD still recording).");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns current microphone level in dBFS (decibels relative to full-scale).
|
||||
/// 0 dBFS = digital clipping; normal speech is typically around -35 to -20 dBFS.
|
||||
/// </summary>
|
||||
public float GetCurrentVolumeDb()
|
||||
{
|
||||
// Guard from log(0)
|
||||
const float minRms = 1e-7f;
|
||||
float rms = Mathf.Clamp(currentVolumeRms, minRms, 1f);
|
||||
return 20f * Mathf.Log10(rms);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a UI-friendly 0..1 loudness from the current dBFS value.
|
||||
/// Adjust the dB range to your content/environment if needed.
|
||||
/// </summary>
|
||||
public float GetNormalizedVolume01()
|
||||
{
|
||||
float db = GetCurrentVolumeDb(); // typically ~ -60 .. -15 during use
|
||||
return Mathf.Clamp01(Mathf.InverseLerp(-60f, -15f, db));
|
||||
}
|
||||
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// Always tick FMOD
|
||||
@@ -295,11 +323,35 @@ public class FMODWhisperBridge : MonoBehaviour
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
float rmsAccumulator = 0f;
|
||||
int rmsSampleCount = 0;
|
||||
|
||||
// 1) Measure volume
|
||||
if (len1 > 0)
|
||||
{
|
||||
ComputeRmsFromPcm16(p1, len1, ref rmsAccumulator, ref rmsSampleCount);
|
||||
}
|
||||
if (len2 > 0)
|
||||
{
|
||||
ComputeRmsFromPcm16(p2, len2, ref rmsAccumulator, ref rmsSampleCount);
|
||||
}
|
||||
|
||||
if (rmsSampleCount > 0)
|
||||
{
|
||||
float rms = Mathf.Sqrt(rmsAccumulator / rmsSampleCount);
|
||||
|
||||
// Smooth the value
|
||||
currentVolumeRms = Mathf.Lerp(currentVolumeRms, rms, 1f - Mathf.Pow(1f - volumeSmoothing, Time.deltaTime * 60f));
|
||||
}
|
||||
|
||||
// 2) Feed audio to Whisper ONLY when active
|
||||
if (shouldFeed && !_skipOneFeedFrame)
|
||||
{
|
||||
if (len1 > 0) CopyPcm16ToFloatAndFeed(p1, len1);
|
||||
if (len2 > 0) CopyPcm16ToFloatAndFeed(p2, len2);
|
||||
}
|
||||
|
||||
// If skipping, we just discard this frame to ensure no stale data leaks.
|
||||
}
|
||||
finally
|
||||
@@ -427,4 +479,30 @@ public class FMODWhisperBridge : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes RMS (root mean square) from a PCM16 block using only safe code.
|
||||
/// Uses the shared _shortOverlay buffer (no allocations).
|
||||
/// Accumulates results into accumulator + sampleCount.
|
||||
/// </summary>
|
||||
private void ComputeRmsFromPcm16(IntPtr src, uint byteLen, ref float accumulator, ref int sampleCount)
|
||||
{
|
||||
// Number of PCM16 samples (2 bytes per sample)
|
||||
int samples = (int)(byteLen / 2);
|
||||
if (samples <= 0) return;
|
||||
|
||||
// Ensure overlay buffer exists & is large enough
|
||||
EnsureShortOverlay(samples, out short[] sBuf);
|
||||
|
||||
// Copy PCM16 into managed buffer (safe)
|
||||
Marshal.Copy(src, sBuf, 0, samples);
|
||||
|
||||
// Accumulate squared amplitude
|
||||
for (int i = 0; i < samples; i++)
|
||||
{
|
||||
float v = sBuf[i] / 32768f; // normalize to [-1..1]
|
||||
accumulator += v * v;
|
||||
}
|
||||
|
||||
sampleCount += samples;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user