Skip to content

Commit

Permalink
fix: improve audio processing and logging in AudioBuffer
Browse files Browse the repository at this point in the history
- Updated SaveAudioAction to use pcmData.Data for audio saving.
- Enhanced logging in Write method to include detailed buffer wrap information, including previous and new write indices, and last sample indices.
- Improved ReadSegment method to better handle discontinuities, with specific logging for wrapped buffer scenarios and sample index tracking.
- Added safety margin adjustment for startTime during buffer wrap events.
  • Loading branch information
tphakala committed Jan 3, 2025
1 parent 666c387 commit bf2a055
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 44 deletions.
2 changes: 1 addition & 1 deletion internal/analysis/processor/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func (a DatabaseAction) Execute(data interface{}) error {
saveAudioAction := SaveAudioAction{
Settings: a.Settings,
ClipName: a.Note.ClipName,
pcmData: pcmData,
pcmData: pcmData.Data,
}

if err := saveAudioAction.Execute(nil); err != nil {
Expand Down
131 changes: 88 additions & 43 deletions internal/myaudio/audiobuffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,10 @@ func (ab *AudioBuffer) Write(data []byte) {
ab.initialized = true
}

// Store the current write index to determine if we've wrapped around the buffer.
// Store previous state for debugging
prevWriteIndex := ab.writeIndex
prevLastSampleIdx := ab.lastSampleIdx

samplesWritten := 0

// Write data and sample indices
Expand Down Expand Up @@ -127,11 +129,16 @@ func (ab *AudioBuffer) Write(data []byte) {
ab.lastSampleIdx += uint64(samplesWritten)

if ab.writeIndex <= prevWriteIndex {
// If old data has been overwritten, adjust startTime to maintain accurate timekeeping.
ab.startTime = time.Now().Add(-ab.bufferDuration)
// Buffer wrapped - log more details
if conf.Setting().Realtime.Audio.Export.Debug {
log.Printf("Buffer wrapped during write, adjusting start time to %v", ab.startTime)
log.Printf("Buffer wrap details: prevWriteIndex=%d, newWriteIndex=%d, "+
"prevLastSampleIdx=%d, newLastSampleIdx=%d, samplesWritten=%d",
prevWriteIndex, ab.writeIndex,
prevLastSampleIdx, ab.lastSampleIdx,
samplesWritten)
}
// Adjust startTime with a small safety margin
ab.startTime = time.Now().Add(-ab.bufferDuration + 100*time.Millisecond)
}

if conf.Setting().Realtime.Audio.Export.Debug {
Expand Down Expand Up @@ -175,52 +182,74 @@ func (ab *AudioBuffer) ReadSegment(requestedStartTime time.Time, duration int) (
// Wait until the current time is past the requested end time
if time.Now().After(requestedEndTime) {
var segment []byte
var startSampleIdx, endSampleIdx uint64
discontinuities := make([]int, 0)

if startIndex < endIndex {
if conf.Setting().Realtime.Audio.Export.Debug {
log.Printf("Reading segment from %d to %d", startIndex, endIndex)
}
segmentSize := endIndex - startIndex
segment = make([]byte, segmentSize)
copy(segment, ab.data[startIndex:endIndex])
// Set the sample indices based on the buffer positions
startSampleIdx := ab.sampleIndices[startIndex/ab.bytesPerSample]
endSampleIdx := ab.sampleIndices[(endIndex-ab.bytesPerSample)/ab.bytesPerSample]

// Track sample indices
startSampleIdx = ab.sampleIndices[startIndex/ab.bytesPerSample]
endSampleIdx = ab.sampleIndices[(endIndex/ab.bytesPerSample)-1] + 1
discontinuities := make([]int, 0)

// Check for discontinuities
if startIndex < endIndex {
// Non-wrapped case - check discontinuities in one continuous block
for i := startIndex/ab.bytesPerSample + 1; i < endIndex/ab.bytesPerSample; i++ {
if ab.sampleIndices[i] != ab.sampleIndices[i-1]+1 {
discontinuities = append(discontinuities, (i*ab.bytesPerSample)-startIndex)
pos := (i * ab.bytesPerSample) - startIndex
if pos >= 0 {
discontinuities = append(discontinuities, pos)
if conf.Setting().Realtime.Audio.Export.Debug {
log.Printf("Discontinuity at sample %d: expected %d, got %d (gap=%d)",
i, ab.sampleIndices[i-1]+1, ab.sampleIndices[i],
ab.sampleIndices[i]-ab.sampleIndices[i-1]-1)
}
}
}
}
} else {
if conf.Setting().Realtime.Audio.Export.Debug {
log.Printf("Buffer wrapped during read, reading segment from %d to %d", startIndex, endIndex)
}
segmentSize := (ab.bufferSize - startIndex) + endIndex
segment = make([]byte, segmentSize)
firstPartSize := ab.bufferSize - startIndex
copy(segment[:firstPartSize], ab.data[startIndex:])
copy(segment[firstPartSize:], ab.data[:endIndex])

// Track sample indices for wrapped buffer
startSampleIdx = ab.sampleIndices[startIndex/ab.bytesPerSample]
endSampleIdx = ab.sampleIndices[(endIndex/ab.bytesPerSample)-1] + 1

// Check for discontinuities including wrap point
for i := startIndex / ab.bytesPerSample; i < ab.bufferSize/ab.bytesPerSample; i++ {
if i > startIndex/ab.bytesPerSample && i > 0 {
if ab.sampleIndices[i] != ab.sampleIndices[i-1]+1 {
discontinuities = append(discontinuities, (i*ab.bytesPerSample)-startIndex)
// Wrapped case - check each section separately
// First part: startIndex to buffer end
for i := startIndex/ab.bytesPerSample + 1; i < ab.bufferSize/ab.bytesPerSample; i++ {
if ab.sampleIndices[i] != ab.sampleIndices[i-1]+1 {
pos := (i * ab.bytesPerSample) - startIndex
if pos >= 0 {
discontinuities = append(discontinuities, pos)
if conf.Setting().Realtime.Audio.Export.Debug {
log.Printf("First part discontinuity at sample %d: expected %d, got %d (gap=%d)",
i, ab.sampleIndices[i-1]+1, ab.sampleIndices[i],
ab.sampleIndices[i]-ab.sampleIndices[i-1]-1)
}
}
}
}

// Second part: start to endIndex
// Skip the first sample after wrap as it's expected to be discontinuous
for i := 1; i < endIndex/ab.bytesPerSample; i++ {
if ab.sampleIndices[i] != ab.sampleIndices[i-1]+1 {
discontinuities = append(discontinuities, ((i*ab.bytesPerSample)+firstPartSize)-startIndex)
pos := ((i * ab.bytesPerSample) + (ab.bufferSize - startIndex))
if pos >= 0 {
discontinuities = append(discontinuities, pos)
if conf.Setting().Realtime.Audio.Export.Debug {
log.Printf("Second part discontinuity at sample %d: expected %d, got %d (gap=%d)",
i, ab.sampleIndices[i-1]+1, ab.sampleIndices[i],
ab.sampleIndices[i]-ab.sampleIndices[i-1]-1)
}
}
}
}

// Only check wrap point if there's a gap larger than expected
lastIdx := (ab.bufferSize / ab.bytesPerSample) - 1
firstWrappedIdx := 0
if lastIdx >= 0 && firstWrappedIdx < endIndex/ab.bytesPerSample {
expectedNext := ab.sampleIndices[lastIdx] + 1
actual := ab.sampleIndices[firstWrappedIdx]
// Allow for normal wrap progression
if actual != expectedNext && (actual < ab.sampleIndices[lastIdx]) {
discontinuities = append(discontinuities, ab.bufferSize-startIndex)
if conf.Setting().Realtime.Audio.Export.Debug {
log.Printf("Wrap point gap detected: expected %d, got %d (possible dropout)",
expectedNext, actual)
}
}
}
}
Expand All @@ -231,12 +260,20 @@ func (ab *AudioBuffer) ReadSegment(requestedStartTime time.Time, duration int) (
len(discontinuities), startSampleIdx, endSampleIdx)
for i, pos := range discontinuities {
sampleIdx := (startIndex + pos) / ab.bytesPerSample
log.Printf(" Discontinuity %d: position=%d, before=%d, after=%d, gap=%d samples",
i+1,
pos,
ab.sampleIndices[sampleIdx-1],
ab.sampleIndices[sampleIdx],
ab.sampleIndices[sampleIdx]-ab.sampleIndices[sampleIdx-1]-1)
before := ab.sampleIndices[sampleIdx-1]
after := ab.sampleIndices[sampleIdx]

// Use signed math to avoid wrap-around
gap := int64(after) - int64(before) - 1

// If gap < 0, treat it as a "wrapped" or "backward" jump
if gap < 0 {
log.Printf(" Discontinuity %d: position=%d, before=%d, after=%d (wrapped)",
i+1, pos, before, after)
} else {
log.Printf(" Discontinuity %d: position=%d, before=%d, after=%d, gap=%d samples",
i+1, pos, before, after, gap)
}
}
} else {
log.Printf("Sample sequence continuous from %d to %d",
Expand All @@ -263,3 +300,11 @@ func (ab *AudioBuffer) ReadSegment(requestedStartTime time.Time, duration int) (
time.Sleep(1 * time.Second) // Sleep briefly to avoid busy waiting
}
}

// Helper function for absolute duration
func absDuration(d time.Duration) time.Duration {
if d < 0 {
return -d
}
return d
}

0 comments on commit bf2a055

Please sign in to comment.