/// <summary> /// Reads decompressed PCM data from our MP3 file. /// </summary> public override int Read(byte[] sampleBuffer, int offset, int numBytes) { int bytesRead = 0; lock (repositionLock) { if (decompressLeftovers != 0) { int toCopy = Math.Min(decompressLeftovers, numBytes); Array.Copy(decompressBuffer, decompressBufferOffset, sampleBuffer, offset, toCopy); decompressLeftovers -= toCopy; if (decompressLeftovers == 0) { decompressBufferOffset = 0; } else { decompressBufferOffset += toCopy; } bytesRead += toCopy; offset += toCopy; } while (bytesRead < numBytes) { Mp3Frame frame = ReadNextFrame(); if (frame != null) { if (repositionedFlag) { decompressor.Reset(); repositionedFlag = false; } int decompressed = decompressor.DecompressFrame(frame, decompressBuffer, 0); int toCopy = Math.Min(decompressed, numBytes - bytesRead); Array.Copy(decompressBuffer, 0, sampleBuffer, offset, toCopy); if (toCopy < decompressed) { decompressBufferOffset = toCopy; decompressLeftovers = decompressed - toCopy; } else { // no lefovers decompressBufferOffset = 0; decompressLeftovers = 0; } offset += toCopy; bytesRead += toCopy; } else { break; } } } Debug.Assert(bytesRead <= numBytes, "MP3 File Reader read too much"); return(bytesRead); }
/// <summary> /// Reads decompressed PCM data from our MP3 file. /// </summary> public override int Read(byte[] sampleBuffer, int offset, int numBytes) { int bytesRead = 0; lock (repositionLock) { if (decompressLeftovers != 0) { int toCopy = Math.Min(decompressLeftovers, numBytes); Array.Copy(decompressBuffer, decompressBufferOffset, sampleBuffer, offset, toCopy); decompressLeftovers -= toCopy; if (decompressLeftovers == 0) { decompressBufferOffset = 0; } else { decompressBufferOffset += toCopy; } bytesRead += toCopy; offset += toCopy; } int targetTocIndex = tocIndex; // the frame index that contains the requested data if (repositionedFlag) { decompressor.Reset(); // Seek back a few frames of the stream to get the reset decoder decode a few // warm-up frames before reading the requested data. Without the warm-up phase, // the first half of the frame after the reset is attenuated and does not resemble // the data as it would be when reading sequentially from the beginning, because // the decoder is missing the required overlap from the previous frame. tocIndex = Math.Max(0, tocIndex - 3); // no warm-up at the beginning of the stream mp3Stream.Position = tableOfContents[tocIndex].FilePosition; repositionedFlag = false; } while (bytesRead < numBytes) { Mp3Frame frame = ReadNextFrame(); if (frame != null) { int decompressed = decompressor.DecompressFrame(frame, decompressBuffer, 0); if (tocIndex <= targetTocIndex || decompressed == 0) { // The first frame after a reset usually does not immediately yield decoded samples. // Because the next instructions will fail if a buffer offset is set and the frame // decoding didn't return data, we skip the part. // We skip the following instructions also after decoding a warm-up frame. continue; } // Two special cases can happen here: // 1. We are interested in the first frame of the stream, but need to read the second frame too // for the decoder to return decoded data // 2. We are interested in the second frame of the stream, but because reading the first frame // as warm-up didn't yield any data (because the decoder needs two frames to return data), we // get data from the first and second frame. // This case needs special handling, and we have to purge the data of the first frame. else if (tocIndex == targetTocIndex + 1 && decompressed == bytesPerDecodedFrame * 2) { // Purge the first frame's data Array.Copy(decompressBuffer, bytesPerDecodedFrame, decompressBuffer, 0, bytesPerDecodedFrame); decompressed = bytesPerDecodedFrame; } int toCopy = Math.Min(decompressed - decompressBufferOffset, numBytes - bytesRead); Array.Copy(decompressBuffer, decompressBufferOffset, sampleBuffer, offset, toCopy); if ((toCopy + decompressBufferOffset) < decompressed) { decompressBufferOffset = toCopy + decompressBufferOffset; decompressLeftovers = decompressed - decompressBufferOffset; } else { // no lefovers decompressBufferOffset = 0; decompressLeftovers = 0; } offset += toCopy; bytesRead += toCopy; } else { break; } } } Debug.Assert(bytesRead <= numBytes, "MP3 File Reader read too much"); position += bytesRead; return(bytesRead); }