Skip to content

Commit

Permalink
Implement temporary fix for mewkiz/flac frame.Position() bug
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkKremer committed Aug 12, 2024
1 parent e66b286 commit f595a79
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 1 deletion.
44 changes: 43 additions & 1 deletion flac/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func Decode(r io.Reader) (s beep.StreamSeekCloser, format beep.Format, err error
if err != nil {
return nil, beep.Format{}, errors.Wrap(err, "flac")
}
d.hasFixedBlockSize = d.frame.HasFixedBlockSize

format = beep.Format{
SampleRate: beep.SampleRate(d.stream.Info.SampleRate),
Expand All @@ -57,6 +58,8 @@ type decoder struct {
posInFrame int
err error
seekEnabled bool

hasFixedBlockSize bool
}

func (d *decoder) Stream(samples [][2]float64) (n int, ok bool) {
Expand Down Expand Up @@ -126,6 +129,15 @@ func (d *decoder) Len() int {
}

func (d *decoder) Position() int {
if d.frame == nil {
return d.Len()
}

// Temporary workaround until https://github.com/mewkiz/flac/pull/73 is resolved.
if d.hasFixedBlockSize {
return int(d.frame.Num)*int(d.stream.Info.BlockSizeMax) + d.posInFrame
}

return int(d.frame.SampleNumber()) + d.posInFrame
}

Expand All @@ -134,6 +146,36 @@ func (d *decoder) Seek(p int) error {
return errors.New("flac.decoder.Seek: not enabled")
}

// Temporary workaround until https://github.com/mewkiz/flac/pull/73 is resolved.
// frame.SampleNumber() doesn't work for the last frame of a fixed block size stream
// with the result that seeking to that frame doesn't work either. Therefore, if such
// a seek is requested, we seek to one of the frames before it and consume until the
// desired position is reached.
if d.hasFixedBlockSize {
lastFrameStartLowerBound := d.Len() - int(d.stream.Info.BlockSizeMax)
if p >= lastFrameStartLowerBound {
// Seek to & consume an earlier frame.
_, err := d.stream.Seek(uint64(lastFrameStartLowerBound - 1))
if err != nil {
return errors.Wrap(err, "flac")
}
for {
d.frame, err = d.stream.ParseNext()
if err != nil {
return errors.Wrap(err, "flac")
}
// Calculate the frame start position manually, because this doesn't
// work for the last frame.
frameStart := d.frame.Num * uint64(d.stream.Info.BlockSizeMax)
if frameStart+uint64(d.frame.BlockSize) >= d.stream.Info.NSamples {
// Found the desired frame.
d.posInFrame = p - int(frameStart)
return nil
}
}
}
}

// d.stream.Seek() doesn't seek to the exact position p, instead
// it seeks to the start of the frame p is in. The frame position
// is returned and stored in pos.
Expand All @@ -148,7 +190,7 @@ func (d *decoder) Seek(p int) error {
return errors.Wrap(err, "flac")
}

return err
return nil
}

func (d *decoder) Close() error {
Expand Down
26 changes: 26 additions & 0 deletions flac/decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,32 @@ func TestDecoder_Seek(t *testing.T) {
wavSamples = testtools.CollectNum(100, wavStream)
flacSamples = testtools.CollectNum(100, flacStream)
testtools.AssertSamplesEqual(t, wavSamples, flacSamples)

// Test end of stream.
seekPos = wavStream.Len() - 1
err = wavStream.Seek(seekPos)
assert.NoError(t, err)
assert.Equal(t, seekPos, wavStream.Position())
err = flacStream.Seek(seekPos)
assert.NoError(t, err)
assert.Equal(t, seekPos, flacStream.Position())

wavSamples = testtools.CollectNum(100, wavStream)
flacSamples = testtools.CollectNum(100, flacStream)
testtools.AssertSamplesEqual(t, wavSamples, flacSamples)

// Test after end of stream.
seekPos = wavStream.Len()
err = wavStream.Seek(seekPos)
assert.NoError(t, err)
assert.Equal(t, seekPos, wavStream.Position())
err = flacStream.Seek(seekPos)
assert.NoError(t, err)
assert.Equal(t, seekPos, flacStream.Position())

wavSamples = testtools.CollectNum(100, wavStream)
flacSamples = testtools.CollectNum(100, flacStream)
testtools.AssertSamplesEqual(t, wavSamples, flacSamples)
}

func getFlacFrameStartPositions(r io.Reader) ([]uint64, error) {
Expand Down

0 comments on commit f595a79

Please sign in to comment.