/// <summary>
        /// Initializes an object that reads informations from an mp3 file and stores them into the given database.
        /// </summary>
        public Id3SongCreator(ShauniDatabase database)
        {
            this.database       = database;
            this.id3v1          = new ID3TagV1();
            this.id3v2          = new ID3TagV2();
            this.mpegHeader     = new MpegHeader();
            this.UseNewStandard = false;

            this.idwav = new IDWav();
        }
            public MpegFrame(Stream stream, MP3 mp3)
            {
                var streamPos = stream.Position;

                Header = new MpegHeader(stream);
                Data   = new UInt8[0];

                mp3.bitrate = 0;

                if (Header.FrameSync < 0xFFE || Header.LayerId == 0 || Header.BitrateIndex == 0 ||
                    Header.BitrateIndex == 15 || Header.FrequencyIndex == 3)
                {
                    stream.Position = streamPos;
                    throw new Exception("MPEG header is invalid!");
                }
                else
                {
                    if (Header.MpegId == 1)
                    {
                        mp3.bitrate = (1U << (Int32)(5U + ((UInt32)Header.BitrateIndex - 1U) / 4U)) +
                                      (((UInt32)Header.BitrateIndex - 1U & 3U) <<
                                       (Int32)(3U + ((UInt32)Header.BitrateIndex - 1U) / 4U));
                    }
                    else // MPEG-2
                    {
                        Int32 bi  = Header.BitrateIndex;
                        Int32 bil = 4 + Header.BitrateIndex / 4;

                        mp3.bitrate = (UInt32)(bi < 4
                            ? 8 * bi
                            : (1 << bil) + ((bi & 3) == 0
                                  ? 0
                                  : (bi & 3) == 1
                                      ? (1 << bil)
                                      : (bi & 3) == 2
                                          ? (1 << bil) + ((1 << bil) >> 1)
                                          : (1 << bil) - ((1 << bil) >> 2)
                                            ));
                    }
                }

                if (mp3.bitrate != 0)
                {
                    var freq = new UInt16[] { 2205, 2400, 1600 };

                    mp3.samplingFreq = freq[Header.FrequencyIndex];

                    if (Header.MpegId == 1) // MPEG-1
                    {
                        mp3.samplingFreq <<= 1;
                    }

                    mp3.frameSize = (mp3.bitrate * 14400) / mp3.samplingFreq;

                    if (Header.ChannelMode == 3)
                    {
                        mp3.frameSize >>= 1;
                    }

                    mp3.frameSize -= 4U + (Header.ProtectionBit == 0 ? 2U : 0U) - Header.PaddingBit;

                    mp3.frameHeaderOffset = (UInt64)stream.Position - 4UL - (Header.ProtectionBit == 0 ? 2UL : 0UL);

                    if (stream.Position + mp3.frameSize > stream.Length)
                    {
                        throw new Exception("MPEG frame abruptly terminated");
                    }
                    else
                    {
                        Data = new UInt8[mp3.frameSize];
                        stream.Read(Data, 0, (Int32)mp3.frameSize);
                    }

                    mp3.sumBitrate += mp3.bitrate;

                    ++mp3.framesCount;
                }
            }
      //////////////////////////////////////////////////////////////////////////
      // private methods
      //////////////////////////////////////////////////////////////////////////

      private void Read ()
      {
         // Since we've likely just looked for the ID3v1 tag, start at the end of the
         // file where we're least likely to have to have to move the disk head.

         long last = file.LastFrameOffset;

         if (last < 0)
         {
            TagLibDebugger.Debug ("Mpeg.Properties.Read() -- Could not find a valid last MPEG frame in the stream.");
            return;
         }

         file.Seek (last);
         MpegHeader last_header = new MpegHeader (file.ReadBlock (4));

         long first = file.FirstFrameOffset;

         if (first < 0)
         {
            TagLibDebugger.Debug ("Mpeg.Properties.Read() -- Could not find a valid first MPEG frame in the stream.");
            return;
         }

         if(!last_header.IsValid)
         {
            long pos = last;

            while (pos > first)
            {
               pos = file.PreviousFrameOffset (pos);

               if(pos < 0)
                  break;

               file.Seek (pos);
               MpegHeader header = new MpegHeader (file.ReadBlock (4));

               if (header.IsValid)
               {
                  last_header = header;
                  last = pos;
                  break;
               }
            }
         }

         // Now jump back to the front of the file and read what we need from there.

         file.Seek (first);
         MpegHeader first_header = new MpegHeader (file.ReadBlock (4));

         if (!first_header.IsValid || !last_header.IsValid)
         {
            TagLibDebugger.Debug ("Mpeg.Properties.Read() -- Page headers were invalid.");
            return;
         }

         // Check for a Xing header that will help us in gathering information about a
         // VBR stream.

         int xing_header_offset = MpegXingHeader.XingHeaderOffset (first_header.Version,
                                      first_header.ChannelMode);

         file.Seek (first + xing_header_offset);
         MpegXingHeader xing_header = new MpegXingHeader (file.ReadBlock (16));

         // Read the length and the bitrate from the Xing header.

         if(xing_header.IsValid && first_header.SampleRate > 0 && xing_header.TotalFrames > 0)
         {
            int [] block_size = {0, 384, 1152, 1152};
            
            double time_per_frame = block_size [first_header.Layer];
            time_per_frame = first_header.SampleRate > 0 ? time_per_frame / first_header.SampleRate : 0;
            duration = new TimeSpan((int)(time_per_frame * xing_header.TotalFrames) * TimeSpan.TicksPerSecond);
            bitrate = (int) (duration > TimeSpan.Zero ? ((xing_header.TotalSize * 8L) / duration.TotalSeconds) / 1000 : 0);
         }

         // Since there was no valid Xing header found, we hope that we're in a constant
         // bitrate file.

         // TODO: Make this more robust with audio property detection for VBR without a
         // Xing header.

         else if (first_header.FrameLength > 0 && first_header.Bitrate > 0)
         {
            int frames = (int) ((last - first) / first_header.FrameLength + 1);

            duration = TimeSpan.FromSeconds ((double) (first_header.FrameLength * frames) / (double) (first_header.Bitrate * 125) + 0.5);
            bitrate = first_header.Bitrate;
         }
         
         
         sample_rate    = first_header.SampleRate;
         channels       = first_header.ChannelMode == MpegChannelMode.SingleChannel ? 1 : 2;
         version        = first_header.Version;
         layer          = first_header.Layer;
         channel_mode   = first_header.ChannelMode;
         is_copyrighted = first_header.IsCopyrighted;
         is_original    = first_header.IsOriginal;
      }