Using MicrophoneReader
MicrophoneReader captures raw microphone audio as PCM samples. Use it when you need audio data directly instead of recognized text: voice volume meters, waveform displays, pitch or beat analysis, custom recording pipelines, local voice effects, or sending captured samples to your own processing code.
The component reads mono 16-bit PCM from the Android microphone. When enableRecord is enabled, the engine starts capturing audio and publishes the captured samples as frame data.
The component works as a frame buffer:
framePCMis aNativeShortBufferthat stores the PCM samples available for the current frame.frameLengthis the number of valid samples inframePCMfor the current frame.sampleRateis the microphone sample rate currently used by the engine.- If no audio was captured for a frame,
frameLengthis0. - Read the component every update. The next frame replaces the current frame data.
- Only read samples from index
0toframeLength - 1. The buffer can have extra capacity, and old values outsideframeLengthare not part of the current frame.
Setup
- Add
MicrophoneReaderto a GameObject. - Enable
enableRecordwhen you want to capture microphone audio. - During update, check
frameLength. - Read samples from
framePCMor usegetFramePCMArray()when you want a regularshort[].
On Android, the app needs microphone permission. If permission has not been granted, the component asks for it when recording is enabled.
Example With Virtual Attributes
This version uses virtual attributes and calculates the peak absolute sample value for the current frame.
SpatialObject myObject = /* your object */ null;
MicrophoneReader mic = myObject.findComponent(MicrophoneReader.class);
if (mic != null) {
mic.enableRecord = true;
}
// Run this part every update.
if (mic != null && mic.enableRecord) {
int length = mic.frameLength;
NativeShortBuffer pcm = mic.framePCM;
if (pcm != null && length > 0) {
int peak = 0;
for (int i = 0; i < length; i++) {
int value = Math.abs(pcm.get(i));
if (value > peak) {
peak = value;
}
}
Terminal.log("Microphone peak: " + peak + " at " + mic.sampleRate + " Hz");
}
}
Example With Methods
Use methods directly when you prefer explicit calls or when you want a short[] copy of the current frame.
SpatialObject myObject = /* your object */ null;
MicrophoneReader mic = myObject.findComponent(MicrophoneReader.class);
if (mic != null) {
mic.setEnableRecord(true);
}
// Run this part every update.
if (mic != null && mic.isEnableRecord()) {
short[] samples = mic.getFramePCMArray();
if (samples.length > 0) {
long sum = 0;
for (int i = 0; i < samples.length; i++) {
sum += Math.abs(samples[i]);
}
long averageAmplitude = sum / samples.length;
Terminal.log("Average microphone amplitude: " + averageAmplitude);
}
}
Choosing framePCM or getFramePCMArray()
Use framePCM when you want to avoid allocating a new Java array every frame. This is better for frequent audio analysis.
Use getFramePCMArray() when convenience matters more than allocation cost. It returns a new array containing only the valid samples for the current frame.
Notes
frameLengthcounts samples, not bytes.- Samples are signed 16-bit PCM values, usually in the range
-32768to32767. - The amount of samples per frame can vary depending on device timing and engine frame rate.
- If recording is disabled,
frameLengthbecomes0and no new microphone samples are published. - For speech-to-text, use
SpeechRecognizerinstead.MicrophoneReaderprovides raw audio, not words.