sbooth / SFBAudioEngine

A powerhouse of audio functionality for macOS and iOS
https://sbooth.github.io/SFBAudioEngine/
MIT License
552 stars 87 forks source link

SFBFLACDecoder - decodeIntoBuffer - not decoding all frames #250

Closed BTRLabs closed 1 year ago

BTRLabs commented 1 year ago

This is only related to FLAC files and the SFBFLACDecoder, as no other SFB*Decoder has this issue.

Based on the following swift code, which is simply an example to prove a point, the print("WARNING...") is always executed. And listening to what is playing, there is definitely audio missing. The missing frame count ranges from as little as 140 missing frames to as much as 4096 frames across a set of tested FLAC files. All FLAC files have been verified using flac -t "file.flac".

do {
  let decoder = try AudioDecoder(url: URL("file.flac"))
  try decoder.open()
  let durationOfChunkToRead : TimeInterval = 1
  try decoder.seek(to: decoder.length - AVAudioFramePosition(decoder.processingFormat.sampleRate * durationOfChunkToRead))
  try decoder.decode(into: decodedBuffer)
  if decoder.inputSource.atEOF && decoder.position < decoder.length {
    print("WARNING - inputSource.atEOF is TRUE while decoder.position < decoder.length by \(decoder.length - decoder.position) frames")
  }
} catch {
  print(error.localizedDescription)
}

Have attempted to debug and fix, but without luck.

Thoughts??

sbooth commented 1 year ago

Could you show the definition of decodedBuffer?

BTRLabs commented 1 year ago

Sorry... both of these produce the same results and both should be big enough to hold the frames remaining:

//--- buffer is 1x the expected frames (i.e., equal in size)
let decodedBuffer = AVAudioPCMBuffer(pcmFormat: decoder.processingFormat, 
                    frameCapacity: AVAudioFrameCount(decoder.processingFormat.sampleRate * durationOfChunkToRead))!

or

//--- buffer is 2x the expected frames
let decodedBuffer = AVAudioPCMBuffer(pcmFormat: decoder.processingFormat, 
                    frameCapacity: AVAudioFrameCount(2 * decoder.processingFormat.sampleRate * durationOfChunkToRead))!

as in...

do {
  let decoder = try AudioDecoder(url: URL("file.flac"))
  try decoder.open()
  let frameCapacityForOneSecond = AVAudioFrameCount(decoder.processingFormat.sampleRate)
  let decodedBuffer = AVAudioPCMBuffer(pcmFormat: decoder.processingFormat, frameCapacity: frameCapacityForOneSecond)!
  try decoder.seek(to: decoder.length - AVAudioFramePosition(frameCapacityForOneSecond))
  try decoder.decode(into: decodedBuffer)
  if decoder.inputSource.atEOF && decoder.position < decoder.length {
    print("WARNING - inputSource.atEOF is TRUE while decoder.position < decoder.length, off by \(decoder.length - decoder.position) frames - decodedBuffer.frameLength is \(decodedBuffer.frameLength) instead of \(frameCapacityForOneSecond) off by \(frameCapacityForOneSecond - decodedBuffer.frameLength) frames")
  }
} catch {
  print(error.localizedDescription)
}

produces the following for an album

WARNING - inputSource.atEOF is TRUE while decoder.position < decoder.length, off by 2992 frames - decodedBuffer.frameLength is 41108 instead of 44100 off by 2992 frames
WARNING - inputSource.atEOF is TRUE while decoder.position < decoder.length, off by 3968 frames - decodedBuffer.frameLength is 40132 instead of 44100 off by 3968 frames
WARNING - inputSource.atEOF is TRUE while decoder.position < decoder.length, off by 3764 frames - decodedBuffer.frameLength is 40336 instead of 44100 off by 3764 frames
WARNING - inputSource.atEOF is TRUE while decoder.position < decoder.length, off by 4096 frames - decodedBuffer.frameLength is 40004 instead of 44100 off by 4096 frames
WARNING - inputSource.atEOF is TRUE while decoder.position < decoder.length, off by 1844 frames - decodedBuffer.frameLength is 42256 instead of 44100 off by 1844 frames
WARNING - inputSource.atEOF is TRUE while decoder.position < decoder.length, off by 3012 frames - decodedBuffer.frameLength is 41088 instead of 44100 off by 3012 frames
WARNING - inputSource.atEOF is TRUE while decoder.position < decoder.length, off by 2472 frames - decodedBuffer.frameLength is 41628 instead of 44100 off by 2472 frames
WARNING - inputSource.atEOF is TRUE while decoder.position < decoder.length, off by 3080 frames - decodedBuffer.frameLength is 41020 instead of 44100 off by 3080 frames
WARNING - inputSource.atEOF is TRUE while decoder.position < decoder.length, off by 2440 frames - decodedBuffer.frameLength is 41660 instead of 44100 off by 2440 frames
WARNING - inputSource.atEOF is TRUE while decoder.position < decoder.length, off by 740 frames - decodedBuffer.frameLength is 43360 instead of 44100 off by 740 frames
WARNING - inputSource.atEOF is TRUE while decoder.position < decoder.length, off by 3100 frames - decodedBuffer.frameLength is 41000 instead of 44100 off by 3100 frames
WARNING - inputSource.atEOF is TRUE while decoder.position < decoder.length, off by 512 frames - decodedBuffer.frameLength is 43588 instead of 44100 off by 512 frames
WARNING - inputSource.atEOF is TRUE while decoder.position < decoder.length, off by 2564 frames - decodedBuffer.frameLength is 41536 instead of 44100 off by 2564 frames
WARNING - inputSource.atEOF is TRUE while decoder.position < decoder.length, off by 268 frames - decodedBuffer.frameLength is 43832 instead of 44100 off by 268 frames
sbooth commented 1 year ago

Could you check out the proposed fix in #252 and see if it works for you?

BTRLabs commented 1 year ago

Yes, #252 in conjunction with using libFLAC 1.4.2 fixed the issue. Amazing turnaround. Thanks!

sbooth commented 1 year ago

I'm glad it's working now. Thanks for reporting this issue!