/// <summary>
        /// Renders the VGMSTREAM to byte buffer.
        /// </summary>
        /// <param name="buffer">Destination byte buffer.</param>
        /// <param name="offset">Offset within buffer to write to.</param>
        /// <param name="count">Count of bytes to render.</param>
        /// <returns>Number of bytes read.</returns>
        public override int Read(byte[] buffer, int offset, int count)
        {
            if (cache == null || cache.Length < buffer.Length)
            {
                cache = new byte[buffer.Length];
            }

            int currentSample         = VGMStreamNative.GetCurrentSample(vgmstream);
            int sampleCount_vgmstream = count / waveFormat.Channels / 2;

            if (currentSample >= sampleCount && !loopFlag)
            {
                return(0);
            }

            if (!loopFlag && currentSample + sampleCount_vgmstream > sampleCount)
            {
                sampleCount_vgmstream = sampleCount - currentSample;
            }

            count = sampleCount_vgmstream * waveFormat.Channels * 2;

            VGMStreamNative.Render8(cache, sampleCount_vgmstream, vgmstream);
            Array.Copy(cache, 0, buffer, offset, count);

            return(count);
        }
        /// <summary>
        /// Forces the VGMSTREAM to loop from start to end.
        /// This method destroys the previous loop points.
        /// </summary>
        public void ForceLoop()
        {
            VGMStreamNative.SetLoopFlag(vgmstream, true);
            VGMStreamNative.SetLoopStartSample(vgmstream, 0);
            VGMStreamNative.SetLoopEndSample(vgmstream, sampleCount);

            loopFlag = true;
        }
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                VGMStreamNative.Close(vgmstream);
            }

            base.Dispose(disposing);
        }
        private void FromPtr(IntPtr vgmstream)
        {
            if (vgmstream == IntPtr.Zero)
            {
                throw new NullReferenceException("VGMSTREAM pointer is set to null!");
            }

            waveFormat  = new WaveFormat(VGMStreamNative.GetSampleRate(vgmstream), 16, VGMStreamNative.GetChannelCount(vgmstream));
            sampleCount = VGMStreamNative.GetSampleCount(vgmstream);
            loopFlag    = VGMStreamNative.GetLoopFlag(vgmstream);

            cache = new byte[4096];
        }
        /// <summary>
        /// Constructs from source file name.
        /// </summary>
        /// <param name="sourceFileName">Source file name to load.</param>
        public VGMStreamReader(string sourceFileName)
        {
            if (!File.Exists(sourceFileName))
            {
                throw new FileNotFoundException($"VGMStream could not find file: {sourceFileName}");
            }

            vgmstream = VGMStreamNative.Initialize(sourceFileName);
            if (vgmstream == IntPtr.Zero)
            {
                throw new NullReferenceException($"VGMStream could not initialize file: {sourceFileName}");
            }

            FromPtr(vgmstream);
        }
 /// <summary>
 /// Resets the VGMSTREAM to beginning.
 /// </summary>
 public void Reset()
 {
     VGMStreamNative.Reset(vgmstream);
 }
 /// <summary>
 /// Disables the loop for this VGMSTREAM.
 /// </summary>
 public void DisableLoop()
 {
     loopFlag = false;
     VGMStreamNative.SetLoopFlag(vgmstream, false);
 }