Ariver
2026-06-07 605a6b2b280c0b2d555f0e2fad56b289361ce29c
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()