From 605a6b2b280c0b2d555f0e2fad56b289361ce29c Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Sun, 07 Jun 2026 11:28:52 +0800
Subject: [PATCH] Add X-ASR live captions
---
privatevoice.src/internal/audio/recorder.go | 45 ++++++++++++++++++++++++++++++++++++---------
1 files changed, 36 insertions(+), 9 deletions(-)
diff --git a/privatevoice.src/internal/audio/recorder.go b/privatevoice.src/internal/audio/recorder.go
index bef4072..5842248 100755
--- a/privatevoice.src/internal/audio/recorder.go
+++ b/privatevoice.src/internal/audio/recorder.go
@@ -165,16 +165,30 @@
return nil
}
- // Convert 16-bit PCM to float32
- numSamples := len(pcm) / 2
- samples := make([]float32, numSamples)
- for i := 0; i < numSamples; i++ {
- sample := int16(pcm[i*2]) | int16(pcm[i*2+1])<<8
- samples[i] = float32(sample) / 32768.0
- }
-
- logger.Info("Recording stopped, %d samples captured", numSamples)
+ samples := pcm16LEToFloat32(pcm)
+ logger.Info("Recording stopped, %d samples captured", len(samples))
return samples
+}
+
+// ReadSamplesSince returns newly captured samples after sampleOffset and the
+// next offset to pass on the following call. It is safe to call while recording.
+func (r *Recorder) ReadSamplesSince(sampleOffset int) ([]float32, int) {
+ r.mu.Lock()
+ totalSamples := len(r.pcmBuf) / 2
+ if sampleOffset < 0 {
+ sampleOffset = 0
+ }
+ if sampleOffset > totalSamples {
+ sampleOffset = totalSamples
+ }
+ startByte := sampleOffset * 2
+ pcm := append([]byte(nil), r.pcmBuf[startByte:]...)
+ r.mu.Unlock()
+
+ if len(pcm) < 2 {
+ return nil, totalSamples
+ }
+ return pcm16LEToFloat32(pcm), totalSamples
}
// HasVoiceActivity returns true if the max volume exceeded the silence threshold.
@@ -260,6 +274,19 @@
logger.Info("Audio device uninitialized")
}
+func pcm16LEToFloat32(pcm []byte) []float32 {
+ numSamples := len(pcm) / 2
+ if numSamples == 0 {
+ return nil
+ }
+ samples := make([]float32, numSamples)
+ for i := 0; i < numSamples; i++ {
+ sample := int16(pcm[i*2]) | int16(pcm[i*2+1])<<8
+ samples[i] = float32(sample) / 32768.0
+ }
+ return samples
+}
+
func (r *Recorder) onData(input []byte) {
r.mu.Lock()
--
Gitblit v1.9.3