[Pkg-gtkpod-devel] r245 - in gtkpod/tags: . 0.99.10-3/debian 0.99.10-3/src

nion at alioth.debian.org nion at alioth.debian.org
Sun Sep 9 19:04:45 UTC 2007


Author: nion
Date: 2007-09-09 19:04:45 +0000 (Sun, 09 Sep 2007)
New Revision: 245

Added:
   gtkpod/tags/0.99.10-3/
   gtkpod/tags/0.99.10-3/debian/changelog
   gtkpod/tags/0.99.10-3/debian/gtkpod.desktop
   gtkpod/tags/0.99.10-3/src/mp3file.c
Removed:
   gtkpod/tags/0.99.10-3/debian/changelog
   gtkpod/tags/0.99.10-3/debian/gtkpod.desktop
   gtkpod/tags/0.99.10-3/src/mp3file.c
Log:
tagging 0.99.10-3

Copied: gtkpod/tags/0.99.10-3 (from rev 237, gtkpod/trunk)

Deleted: gtkpod/tags/0.99.10-3/debian/changelog
===================================================================
--- gtkpod/trunk/debian/changelog	2007-08-06 00:08:16 UTC (rev 237)
+++ gtkpod/tags/0.99.10-3/debian/changelog	2007-09-09 19:04:45 UTC (rev 245)
@@ -1,205 +0,0 @@
-gtkpod (0.99.10-2) unstable; urgency=low
-
-  * Upload to unstable
-  * Update menu entry according to new menu policy
-  * Lintian: Don't ignore all errors from "make distclean"
-
- -- Frank Lichtenheld <djpig at debian.org>  Tue, 10 Jul 2007 00:25:04 +0200
-
-gtkpod (0.99.10-1) experimental; urgency=low
-
-  * New upstream release
-    - Allows resizing the preferences dialog (Closes: #428011)
-  * Update man page debian/gtkpod.pod
-
- -- Frank Lichtenheld <djpig at debian.org>  Thu, 28 Jun 2007 02:12:56 +0200
-
-gtkpod (0.99.8-3) unstable; urgency=low
-
-  [ Frank Lichtenheld ]
-  * Upload to unstable (Closes: #391812)
-  * Change Maintainer to pkg-gtkpod-devel list. Add myself
-    and Nico as Uploaders
-  * Add Vcs-{Svn,Browser} fields
-
-  [ Nico Golde ]
-  * Added Homepage tag to control.
-  * Bumped compat level since debhelper >= 5 is in etch.
-
- -- Nico Golde <nion at debian.org>  Mon, 07 May 2007 17:40:39 +0200
-
-gtkpod (0.99.8-2) experimental; urgency=low
-
-  * Adapt for libgpod >= 0.4.2 (Patch by upstream).
-
- -- Frank Lichtenheld <djpig at debian.org>  Sat, 10 Feb 2007 14:22:53 +0100
-
-gtkpod (0.99.8-1) experimental; urgency=low
-
-  * New upstream release
-    + Update libgpod-dev build-dependency to (>= 0.4.0)
-      and remove conflict against libgpod0
-      (upload to experimental because this version isn't
-       available in unstable yet)
-    + Change /mnt/ipod to /media/ipod as usual in new scripts
-  * Bump Standards-Version to 3.7.2 (no changes).
-  * Remove glade file symlinks on clean. Found by Martin Zobel-Helas.
-    (Closes: #395120)
-
- -- Frank Lichtenheld <djpig at debian.org>  Fri, 22 Dec 2006 18:38:05 +0100
-
-gtkpod (0.99.4-2) unstable; urgency=low
-
-  * Add conflict against libgpod0 >= 0.4.0
-    to quiten up the BTS a bit.
-  * Bump Standards-Version to 3.7.2 (no changes).
-  * Remove glade file symlinks on clean. Found by Martin Zobel-Helas.
-    (Closes: #395120)
-
- -- Frank Lichtenheld <djpig at debian.org>  Thu, 30 Nov 2006 23:12:32 +0100
-
-gtkpod (0.99.4-1) unstable; urgency=low
-
-  * New upstream release
-
- -- Frank Lichtenheld <djpig at debian.org>  Sat,  8 Apr 2006 21:45:22 +0200
-
-gtkpod (0.99.2-1) unstable; urgency=low
-
-  * New upstream release (Closes: #343856)
-    + Fixes sorting bug (Closes: #330082)
-  * Add build-depends on libgpod-dev
-  * Add build-depends on flex
-  * Add suggests on python since one of the scripts uses it
-  * Update FSF address in debian/copyright
-
- -- Frank Lichtenheld <djpig at debian.org>  Thu, 29 Dec 2005 17:38:38 +0100
-
-gtkpod (0.94.0-1) unstable; urgency=low
-
-  * New upstream release (Closes: #319408)
-    - support for new iTunes and new firmware version
-      (Closes: #317701)
-  * Add watch file, by  Filippo Giunchedi (Closes: #318760)
-
- -- Frank Lichtenheld <djpig at debian.org>  Fri, 22 Jul 2005 13:23:13 +0200
-
-gtkpod (0.93.1-1) unstable; urgency=low
-
-  * New upstream release (Closes: #316399)
-    - New build-dependency libglade2-dev
-  * Bump Standards-Version to 3.6.2, no changes needed
-  * Don't create glade files as absolute links as that fails miserably
-    in a packaging situation
-
- -- Frank Lichtenheld <djpig at debian.org>  Fri,  1 Jul 2005 02:24:13 +0200
-
-gtkpod (0.88.2-1) unstable; urgency=low
-
-  * New upstream release
-    - Fixes typo in preferences dialog reported by Michael Shields
-      (Closes: #289087)
-    - Included additional sync script previously offered for
-      download separatly (Closes: #302361)
-  * Include typo fixes for the German translation by Jens Seidel
-    (Closes: #314053)
-  * Add build dependency on gettext even though many other build
-    dependecies already get it for us. We shouldn't rely on that
-  * Fix syntax error in sync-notes.sh and change paths from
-    /mnt/ipod to /media/ipod as usual
-  * Add Suggests on recode as it is used in the scripts
-  * Replace the outdated, buggy, and GFDL licensed man page written in
-    docbook by the former Debian maintainer with an updated, more
-    extensive, GPL licensed version written in POD by me. Replace
-    build-depends on docbook-to-man by build-depends on perl.
-  * Rework copyright file to be more precise about which file is
-    copyrighted by whom
-  * Fix path to scripts in preferences window
-  * Replace ScsiEject code in src/misc.c with my new version from the
-    eject package which uses the newer SG ioctl interface. Add new
-    header check for scsi/sg.h to configure.in and regenerate configure
-    and config.h.in.
-  
- -- Frank Lichtenheld <djpig at debian.org>  Thu, 16 Jun 2005 18:28:41 +0200
-
-gtkpod (0.88.1-1) unstable; urgency=low
-
-  * New upstream release
-    - fixes the iPod Shuffle support (Closes: #299768)
-      Thanks to Jörg Kurlbaum for pointing this out 
-
- -- Frank Lichtenheld <djpig at debian.org>  Fri, 18 Mar 2005 13:15:17 +0100
-
-gtkpod (0.88-1) unstable; urgency=low
-
-  * New upstream version (Closes: #299053)
-  * Fix FTBFS with gcc-4.0; patch by Andreas Jochens
-    (Closes: #298273)
-
- -- Frank Lichtenheld <djpig at debian.org>  Fri, 11 Mar 2005 18:50:52 +0100
-
-gtkpod (0.87.3-1) unstable; urgency=low
-
-  * New upstream version
-
- -- Frank Lichtenheld <djpig at debian.org>  Fri,  4 Mar 2005 14:35:13 -0800
-
-gtkpod (0.85.0-1) unstable; urgency=low
-
-  * New maintainer (Closes: #287988)
-    Acknowledge my own NMU (Closes: #264682, #268340, #230898, #275363)
-  * Apply patch by Andreas Jochens to let gtkpod compile
-    with gcc-4.0 (Closes: #286926)
-
- -- Frank Lichtenheld <djpig at debian.org>  Fri,  7 Jan 2005 01:01:58 +0100
-
-gtkpod (0.85.0-0.1) unstable; urgency=low
-
-  * NMU since maintainer is unresponsive to any contact
-    attempts for a log time now.
-  * New upstream release (Closes: #264682)
-  * debian/control:
-    + Shorten short description (Closes: #268340)
-    + Suggest mp3gain (Closes: #230898)
-    + Adjust debhelper build-dependency so that we can use dh_desktop
-  * debian/rules: Tidy up.
-  * debian/docs: Don't install empty NEWS file
-  * debian/menu:
-    + Quote values
-    + Use xpm icon created from the 32x32 icon
-  * debian/gtkpod.sgml: fix some <arg> vs. <option> mistakes
-  * debian/gtkpod.desktop: add .desktop file
-  * Change all occourences of /mnt/ipod to /media/ipod (Closes: #275363)
-    add a NEWS.Debian file to document this.
-  * Fix UTF-8 characters in several files
-  * Don't issue warning about not beeing able to "unsort" a table.
-    It's quite annyoing and the user has no possibility to fix it.
-
- -- Frank Lichtenheld <djpig at debian.org>  Thu,  9 Dec 2004 18:17:17 +0100
-
-gtkpod (0.72-2-2) unstable; urgency=low
-
-  * Fix build dependencies (libid3tag0-dev).
-  * Change priority to extra.
-
- -- Quôc Peyrot <chojin at debian.org>  Sat,  7 Feb 2004 05:14:03 +0000
-
-gtkpod (0.72-2-1) unstable; urgency=low
-
-  * New upstream release. Closes: #216155.
-  * Update policy revision to 3.6.1 (use UTF-8).
-  * Change the debian maintainer email to chojin at debian.org.
-
- -- Quôc Peyrot <chojin at debian.org>  Tue,  3 Feb 2004 07:15:04 +0000
-
-gtkpod (0.51-1) unstable; urgency=low
-
-  * New upstream release
-
- -- Quôc Peyrot <chojin at debian.org>  Sat, 17 May 2003 04:15:02 +0000
-
-gtkpod (0.50-1) unstable; urgency=low
-
-  * Initial Release. Closes: #182289.
-
- -- Quôc Peyrot <chojin at debian.org>  Tue, 22 Apr 2003 05:16:37 +0000

Copied: gtkpod/tags/0.99.10-3/debian/changelog (from rev 244, gtkpod/trunk/debian/changelog)
===================================================================
--- gtkpod/tags/0.99.10-3/debian/changelog	                        (rev 0)
+++ gtkpod/tags/0.99.10-3/debian/changelog	2007-09-09 19:04:45 UTC (rev 245)
@@ -0,0 +1,213 @@
+gtkpod (0.99.10-3) unstable; urgency=low
+
+  * Added missing fclose() call in mp3file.c to prevent too many open
+    file descriptors (Closes: #441308).
+  * Adapted .desktop file to current freedesktop standards.
+
+ -- Nico Golde <nion at debian.org>  Sun, 09 Sep 2007 20:13:31 +0200
+
+gtkpod (0.99.10-2) unstable; urgency=low
+
+  * Upload to unstable
+  * Update menu entry according to new menu policy
+  * Lintian: Don't ignore all errors from "make distclean"
+
+ -- Frank Lichtenheld <djpig at debian.org>  Tue, 10 Jul 2007 00:25:04 +0200
+
+gtkpod (0.99.10-1) experimental; urgency=low
+
+  * New upstream release
+    - Allows resizing the preferences dialog (Closes: #428011)
+  * Update man page debian/gtkpod.pod
+
+ -- Frank Lichtenheld <djpig at debian.org>  Thu, 28 Jun 2007 02:12:56 +0200
+
+gtkpod (0.99.8-3) unstable; urgency=low
+
+  [ Frank Lichtenheld ]
+  * Upload to unstable (Closes: #391812)
+  * Change Maintainer to pkg-gtkpod-devel list. Add myself
+    and Nico as Uploaders
+  * Add Vcs-{Svn,Browser} fields
+
+  [ Nico Golde ]
+  * Added Homepage tag to control.
+  * Bumped compat level since debhelper >= 5 is in etch.
+
+ -- Nico Golde <nion at debian.org>  Mon, 07 May 2007 17:40:39 +0200
+
+gtkpod (0.99.8-2) experimental; urgency=low
+
+  * Adapt for libgpod >= 0.4.2 (Patch by upstream).
+
+ -- Frank Lichtenheld <djpig at debian.org>  Sat, 10 Feb 2007 14:22:53 +0100
+
+gtkpod (0.99.8-1) experimental; urgency=low
+
+  * New upstream release
+    + Update libgpod-dev build-dependency to (>= 0.4.0)
+      and remove conflict against libgpod0
+      (upload to experimental because this version isn't
+       available in unstable yet)
+    + Change /mnt/ipod to /media/ipod as usual in new scripts
+  * Bump Standards-Version to 3.7.2 (no changes).
+  * Remove glade file symlinks on clean. Found by Martin Zobel-Helas.
+    (Closes: #395120)
+
+ -- Frank Lichtenheld <djpig at debian.org>  Fri, 22 Dec 2006 18:38:05 +0100
+
+gtkpod (0.99.4-2) unstable; urgency=low
+
+  * Add conflict against libgpod0 >= 0.4.0
+    to quiten up the BTS a bit.
+  * Bump Standards-Version to 3.7.2 (no changes).
+  * Remove glade file symlinks on clean. Found by Martin Zobel-Helas.
+    (Closes: #395120)
+
+ -- Frank Lichtenheld <djpig at debian.org>  Thu, 30 Nov 2006 23:12:32 +0100
+
+gtkpod (0.99.4-1) unstable; urgency=low
+
+  * New upstream release
+
+ -- Frank Lichtenheld <djpig at debian.org>  Sat,  8 Apr 2006 21:45:22 +0200
+
+gtkpod (0.99.2-1) unstable; urgency=low
+
+  * New upstream release (Closes: #343856)
+    + Fixes sorting bug (Closes: #330082)
+  * Add build-depends on libgpod-dev
+  * Add build-depends on flex
+  * Add suggests on python since one of the scripts uses it
+  * Update FSF address in debian/copyright
+
+ -- Frank Lichtenheld <djpig at debian.org>  Thu, 29 Dec 2005 17:38:38 +0100
+
+gtkpod (0.94.0-1) unstable; urgency=low
+
+  * New upstream release (Closes: #319408)
+    - support for new iTunes and new firmware version
+      (Closes: #317701)
+  * Add watch file, by  Filippo Giunchedi (Closes: #318760)
+
+ -- Frank Lichtenheld <djpig at debian.org>  Fri, 22 Jul 2005 13:23:13 +0200
+
+gtkpod (0.93.1-1) unstable; urgency=low
+
+  * New upstream release (Closes: #316399)
+    - New build-dependency libglade2-dev
+  * Bump Standards-Version to 3.6.2, no changes needed
+  * Don't create glade files as absolute links as that fails miserably
+    in a packaging situation
+
+ -- Frank Lichtenheld <djpig at debian.org>  Fri,  1 Jul 2005 02:24:13 +0200
+
+gtkpod (0.88.2-1) unstable; urgency=low
+
+  * New upstream release
+    - Fixes typo in preferences dialog reported by Michael Shields
+      (Closes: #289087)
+    - Included additional sync script previously offered for
+      download separatly (Closes: #302361)
+  * Include typo fixes for the German translation by Jens Seidel
+    (Closes: #314053)
+  * Add build dependency on gettext even though many other build
+    dependecies already get it for us. We shouldn't rely on that
+  * Fix syntax error in sync-notes.sh and change paths from
+    /mnt/ipod to /media/ipod as usual
+  * Add Suggests on recode as it is used in the scripts
+  * Replace the outdated, buggy, and GFDL licensed man page written in
+    docbook by the former Debian maintainer with an updated, more
+    extensive, GPL licensed version written in POD by me. Replace
+    build-depends on docbook-to-man by build-depends on perl.
+  * Rework copyright file to be more precise about which file is
+    copyrighted by whom
+  * Fix path to scripts in preferences window
+  * Replace ScsiEject code in src/misc.c with my new version from the
+    eject package which uses the newer SG ioctl interface. Add new
+    header check for scsi/sg.h to configure.in and regenerate configure
+    and config.h.in.
+  
+ -- Frank Lichtenheld <djpig at debian.org>  Thu, 16 Jun 2005 18:28:41 +0200
+
+gtkpod (0.88.1-1) unstable; urgency=low
+
+  * New upstream release
+    - fixes the iPod Shuffle support (Closes: #299768)
+      Thanks to Jörg Kurlbaum for pointing this out 
+
+ -- Frank Lichtenheld <djpig at debian.org>  Fri, 18 Mar 2005 13:15:17 +0100
+
+gtkpod (0.88-1) unstable; urgency=low
+
+  * New upstream version (Closes: #299053)
+  * Fix FTBFS with gcc-4.0; patch by Andreas Jochens
+    (Closes: #298273)
+
+ -- Frank Lichtenheld <djpig at debian.org>  Fri, 11 Mar 2005 18:50:52 +0100
+
+gtkpod (0.87.3-1) unstable; urgency=low
+
+  * New upstream version
+
+ -- Frank Lichtenheld <djpig at debian.org>  Fri,  4 Mar 2005 14:35:13 -0800
+
+gtkpod (0.85.0-1) unstable; urgency=low
+
+  * New maintainer (Closes: #287988)
+    Acknowledge my own NMU (Closes: #264682, #268340, #230898, #275363)
+  * Apply patch by Andreas Jochens to let gtkpod compile
+    with gcc-4.0 (Closes: #286926)
+
+ -- Frank Lichtenheld <djpig at debian.org>  Fri,  7 Jan 2005 01:01:58 +0100
+
+gtkpod (0.85.0-0.1) unstable; urgency=low
+
+  * NMU since maintainer is unresponsive to any contact
+    attempts for a log time now.
+  * New upstream release (Closes: #264682)
+  * debian/control:
+    + Shorten short description (Closes: #268340)
+    + Suggest mp3gain (Closes: #230898)
+    + Adjust debhelper build-dependency so that we can use dh_desktop
+  * debian/rules: Tidy up.
+  * debian/docs: Don't install empty NEWS file
+  * debian/menu:
+    + Quote values
+    + Use xpm icon created from the 32x32 icon
+  * debian/gtkpod.sgml: fix some <arg> vs. <option> mistakes
+  * debian/gtkpod.desktop: add .desktop file
+  * Change all occourences of /mnt/ipod to /media/ipod (Closes: #275363)
+    add a NEWS.Debian file to document this.
+  * Fix UTF-8 characters in several files
+  * Don't issue warning about not beeing able to "unsort" a table.
+    It's quite annyoing and the user has no possibility to fix it.
+
+ -- Frank Lichtenheld <djpig at debian.org>  Thu,  9 Dec 2004 18:17:17 +0100
+
+gtkpod (0.72-2-2) unstable; urgency=low
+
+  * Fix build dependencies (libid3tag0-dev).
+  * Change priority to extra.
+
+ -- Quôc Peyrot <chojin at debian.org>  Sat,  7 Feb 2004 05:14:03 +0000
+
+gtkpod (0.72-2-1) unstable; urgency=low
+
+  * New upstream release. Closes: #216155.
+  * Update policy revision to 3.6.1 (use UTF-8).
+  * Change the debian maintainer email to chojin at debian.org.
+
+ -- Quôc Peyrot <chojin at debian.org>  Tue,  3 Feb 2004 07:15:04 +0000
+
+gtkpod (0.51-1) unstable; urgency=low
+
+  * New upstream release
+
+ -- Quôc Peyrot <chojin at debian.org>  Sat, 17 May 2003 04:15:02 +0000
+
+gtkpod (0.50-1) unstable; urgency=low
+
+  * Initial Release. Closes: #182289.
+
+ -- Quôc Peyrot <chojin at debian.org>  Tue, 22 Apr 2003 05:16:37 +0000

Deleted: gtkpod/tags/0.99.10-3/debian/gtkpod.desktop
===================================================================
--- gtkpod/trunk/debian/gtkpod.desktop	2007-08-06 00:08:16 UTC (rev 237)
+++ gtkpod/tags/0.99.10-3/debian/gtkpod.desktop	2007-09-09 19:04:45 UTC (rev 245)
@@ -1,9 +0,0 @@
-[Desktop Entry]
-Encoding=UTF-8
-Name=gtkpod
-Icon=gtkpod-icon-32x32.png
-Comment=Manage songs and playlists on your Apple iPod
-Exec=gtkpod
-Terminal=false
-Type=Application
-Categories=Application;AudioVideo;

Copied: gtkpod/tags/0.99.10-3/debian/gtkpod.desktop (from rev 244, gtkpod/trunk/debian/gtkpod.desktop)
===================================================================
--- gtkpod/tags/0.99.10-3/debian/gtkpod.desktop	                        (rev 0)
+++ gtkpod/tags/0.99.10-3/debian/gtkpod.desktop	2007-09-09 19:04:45 UTC (rev 245)
@@ -0,0 +1,8 @@
+[Desktop Entry]
+Name=gtkpod
+Icon=gtkpod-icon-32x32.png
+Comment=Manage songs and playlists on your Apple iPod
+Exec=gtkpod
+Terminal=false
+Type=Application
+Categories=GTK;AudioVideo;

Deleted: gtkpod/tags/0.99.10-3/src/mp3file.c
===================================================================
--- gtkpod/trunk/src/mp3file.c	2007-08-06 00:08:16 UTC (rev 237)
+++ gtkpod/tags/0.99.10-3/src/mp3file.c	2007-09-09 19:04:45 UTC (rev 245)
@@ -1,2677 +0,0 @@
-/* Time-stamp: <2007-06-26 00:39:11 jcs>
-|
-|  Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net>
-|  Part of the gtkpod project.
-| 
-|  URL: http://www.gtkpod.org/
-|  URL: http://gtkpod.sourceforge.net/
-|
-|  This program is free software; you can redistribute it and/or modify
-|  it under the terms of the GNU General Public License as published by
-|  the Free Software Foundation; either version 2 of the License, or
-|  (at your option) any later version.
-|
-|  This program is distributed in the hope that it will be useful,
-|  but WITHOUT ANY WARRANTY; without even the implied warranty of
-|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-|  GNU General Public License for more details.
-|
-|  You should have received a copy of the GNU General Public License
-|  along with this program; if not, write to the Free Software
-|  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-|
-|  iTunes and iPod are trademarks of Apple
-|
-|  This product is not supported/written/published by Apple!
-|
-|  $Id: mp3file.c 1591 2007-06-26 03:33:25Z tmzullinger $
-*/
-
-
-#define LOCALDEBUG 0
-
-
-/* The code in the first section of this file is taken from the
- * mp3info (http://www.ibiblio.org/mp3info/) project. Only the code
- * needed for the playlength calculation has been extracted. */
-
-/* The code in the second section of this file is taken from the
- * mpg123 code used in xmms-1.2.7 (Input/mpg123). Only the code needed
- * for the playlength calculation has been extracted. */
-
-/* The code in the last section of this file is original gtkpod
- * code. */
-
-/****************
- * Declarations *
- ****************/
-
-#include <glib.h>
-#include <math.h>
-/*
- * Description of each item of the TagList list
- */
-typedef struct _File_Tag File_Tag;
-typedef struct _GainData GainData;
-typedef struct _GaplessData GaplessData;
-
-struct _File_Tag
-{
-    gchar *title;          /* Title of track */
-    gchar *artist;         /* Artist name */
-    gchar *album;          /* Album name */
-    gchar *year;           /* Year of track */
-    gchar *trackstring;    /* Position of track in the album */
-    gchar *track_total;    /* The number of tracks for the album (ex: 12/20) */
-    gchar *genre;          /* Genre of song */
-    gchar *comment;        /* Comment */
-    gchar *composer;	   /* Composer */
-    guint32 songlen;       /* Length of file in ms */
-    gchar *cdnostring;    /* Position of disc in the album */
-    gchar *cdno_total;    /* The number of discs in the album (ex: 1/2) */
-    gchar *compilation;   /* The track is a member of a compilation */
-    gchar *podcasturl;    /* The following are mainly used for podcasts */
-    gchar *sort_artist;
-    gchar *sort_title;
-    gchar *sort_album;
-    gchar *sort_albumartist;
-    gchar *sort_composer;
-    gchar *description;
-    gchar *podcastrss;
-    gchar *time_released;
-    gchar *subtitle;
-    gchar *BPM;           /* beats per minute */
-    gchar *lyrics;        /* does not appear to be the full lyrics --
-			     only used to set the flag 'lyrics_flag'
-			     of the Track structure */
-};
-
-
-struct _GainData
-{
-  guint32 peak_signal;	  /* LAME Peak Signal * 0x800000             */
-  gdouble radio_gain;	  /* RadioGain in dB
-			     (as defined by www.replaygain.org)      */
-  gdouble audiophile_gain;/* AudiophileGain in dB 
-			     (as defined by www.replaygain.org)      */
-  gboolean peak_signal_set;    /* has the peak signal been set?      */
-  gboolean radio_gain_set;     /* has the radio gain been set?       */
-  gboolean audiophile_gain_set;/* has the audiophile gain been set?  */
-};
-
-struct _GaplessData
-{
-    guint32 pregap;       /* number of pregap samples */
-    guint64 samplecount;  /* number of actual music samples */
-    guint32 postgap;      /* number of postgap samples */
-    guint32 gapless_data; /* number of bytes from the first sync frame to the 8th to last frame */
-};
-
-/* This code is taken from the mp3info code. Only the code needed for
- * the playlength calculation has been extracted */
-
-/*
-    mp3tech.c - Functions for handling MP3 files and most MP3 data
-		structure manipulation.
-
-    Copyright (C) 2000-2001  Cedric Tefft <cedric at earthling.net>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-  ***************************************************************************
-
-  This file is based in part on:
-
-	* MP3Info 0.5 by Ricardo Cerqueira <rmc at rccn.net>
-	* MP3Stat 0.9 by Ed Sweetman <safemode at voicenet.com> and
-			 Johannes Overmann <overmann at iname.com>
-
-*/
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "mp3file.h"
-#include "charset.h"
-#include "itdb.h"
-#include "file.h"
-#include "misc.h"
-
-
-/* MIN_CONSEC_GOOD_FRAMES defines how many consecutive valid MP3 frames
-   we need to see before we decide we are looking at a real MP3 file */
-#define MIN_CONSEC_GOOD_FRAMES 4
-#define FRAME_HEADER_SIZE 4
-#define MIN_FRAME_SIZE 21
-
-enum VBR_REPORT { VBR_VARIABLE, VBR_AVERAGE, VBR_MEDIAN };
-
-typedef struct {
-    gulong sync;
-    guint  version;
-    guint  layer;
-    guint  crc;
-    guint  bitrate;
-    guint  freq;
-    guint  padding;
-    guint  extension;
-    guint  mode;
-    guint  mode_extension;
-    guint  copyright;
-    guint  original;
-    guint  emphasis;
-} MP3Header;
-
-typedef struct {
-    gchar *filename;
-    FILE *file;
-    off_t datasize;
-    gint header_isvalid;
-    MP3Header header;
-    gint id3_isvalid;
-    gint vbr;
-    float vbr_average;
-    gint milliseconds;
-    gint frames;
-    gint badframes;
-} MP3Info;
-
-/* This is for xmms code */
-static guint get_track_time(gchar *path);
-
-
-
-/* ------------------------------------------------------------
-
-   start of first section
-
-   ------------------------------------------------------------ */
-void get_mp3_info(MP3Info *mp3);
-
-gint frequencies[3][4] = {
-   {22050,24000,16000,50000},  /* MPEG 2.0 */
-   {44100,48000,32000,50000},  /* MPEG 1.0 */
-   {11025,12000,8000,50000}    /* MPEG 2.5 */
-};
-
-/* "0" added by JCS */
-gint bitrate[2][3][16] = {
-  { /* MPEG 2.0 */
-    {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,0},/* layer 1 */
-    {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0},     /* layer 2 */
-    {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0}      /* layer 3 */
-  },
-
-  { /* MPEG 1.0 */
-    {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},/* layer 1 */
-    {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0},   /* layer 2 */
-    {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}     /* layer 3 */
-  }
-};
-
-gint frame_size_index[] = {24000, 72000, 72000};
-
-
-gchar *mode_text[] = {
-   "stereo", "joint stereo", "dual channel", "mono"
-};
-
-gchar *emphasis_text[] = {
-  "none", "50/15 microsecs", "reserved", "CCITT J 17"
-};
-
-
-static gint mp3file_header_bitrate(MP3Header *h) {
-    return bitrate[h->version & 1][3-h->layer][h->bitrate];
-}
-
-
-static gint mp3file_header_frequency(MP3Header *h) {
-    return frequencies[h->version][h->freq];
-}
-
-
-gint frame_length(MP3Header *header) {
-	return header->sync == 0xFFE ?
-		    (frame_size_index[3-header->layer]*((header->version&1)+1)*
-		    mp3file_header_bitrate(header)/(float)mp3file_header_frequency(header))+
-		    header->padding : 1;
-}
-
-/* Get next MP3 frame header.
-   Return codes:
-   positive value = Frame Length of this header
-   0 = No, we did not retrieve a valid frame header
-*/
-gint get_header(FILE *file,MP3Header *header)
-{
-    guchar buffer[FRAME_HEADER_SIZE];
-    gint fl;
-
-    if(fread(&buffer,FRAME_HEADER_SIZE,1,file)<1) {
-	header->sync=0;
-	return 0;
-    }
-    header->sync=(((gint)buffer[0]<<4) | ((gint)(buffer[1]&0xE0)>>4));
-    if(buffer[1] & 0x10) header->version=(buffer[1] >> 3) & 1;
-		    else header->version=2;
-    header->layer=(buffer[1] >> 1) & 3;
-    if (header->layer == 0)
-    {
-	header->layer = 1; /* sanity added by JCS */
-    }
-    if((header->sync != 0xFFE) || (header->layer != 1)) {
-	header->sync=0;
-	return 0;
-    }
-    header->crc=buffer[1] & 1;
-    header->bitrate=(buffer[2] >> 4) & 0x0F;
-    header->freq=(buffer[2] >> 2) & 0x3;
-    header->padding=(buffer[2] >>1) & 0x1;
-    header->extension=(buffer[2]) & 0x1;
-    header->mode=(buffer[3] >> 6) & 0x3;
-    header->mode_extension=(buffer[3] >> 4) & 0x3;
-    header->copyright=(buffer[3] >> 3) & 0x1;
-    header->original=(buffer[3] >> 2) & 0x1;
-    header->emphasis=(buffer[3]) & 0x3;
-
-    return ((fl=frame_length(header)) >= MIN_FRAME_SIZE ? fl : 0);
-}
-
-gint sameConstant(MP3Header *h1, MP3Header *h2) {
-    if((*(guint*)h1) == (*(guint*)h2)) return 1;
-
-    if((h1->version       == h2->version         ) &&
-       (h1->layer         == h2->layer           ) &&
-       (h1->crc           == h2->crc             ) &&
-       (h1->freq          == h2->freq            ) &&
-       (h1->mode          == h2->mode            ) &&
-       (h1->copyright     == h2->copyright       ) &&
-       (h1->original      == h2->original        ) &&
-       (h1->emphasis      == h2->emphasis        ))
-		return 1;
-    else return 0;
-}
-
-
-gint get_first_header(MP3Info *mp3, long startpos)
-{
-  gint k, l=0,c;
-  MP3Header h, h2;
-  long valid_start=0;
-
-  fseek(mp3->file,startpos,SEEK_SET);
-  while (1) {
-     while((c=fgetc(mp3->file)) != 255 && (c != EOF));
-     if(c == 255) {
-	ungetc(c,mp3->file);
-	valid_start=ftell(mp3->file);
-	if((l=get_header(mp3->file,&h))) {
-	  fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
-	  for(k=1; (k < MIN_CONSEC_GOOD_FRAMES) && (mp3->datasize-ftell(mp3->file) >= FRAME_HEADER_SIZE); k++) {
-	    if(!(l=get_header(mp3->file,&h2))) break;
-	    if(!sameConstant(&h,&h2)) break;
-	    fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
-	  }
-	  if(k == MIN_CONSEC_GOOD_FRAMES) {
-		fseek(mp3->file,valid_start,SEEK_SET);
-		memcpy(&(mp3->header),&h2,sizeof(MP3Header));
-		mp3->header_isvalid=1;
-		return 1;
-	  }
-	}
-     } else {
-	return 0;
-     }
-   }
-
-  return 0;
-}
-
-
-/* get_next_header() - read header at current position or look for
-   the next valid header if there isn't one at the current position
-*/
-gint get_next_header(MP3Info *mp3)
-{
-  gint l=0,c,skip_bytes=0;
-  MP3Header h;
-
-   while(1) {
-     while((c=fgetc(mp3->file)) != 255 && (ftell(mp3->file) < mp3->datasize)) skip_bytes++;
-     if(c == 255) {
-	ungetc(c,mp3->file);
-	if((l=get_header(mp3->file,&h))) {
-	  if(skip_bytes) mp3->badframes++;
-	  fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
-	  return 15-h.bitrate;
-	} else {
-		skip_bytes += FRAME_HEADER_SIZE;
-	}
-     } else {
-	  if(skip_bytes) mp3->badframes++;
-	  return 0;
-     }
-  }
-}
-
-
-void get_mp3_info(MP3Info *mp3)
-{
-  gint frame_type[15]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-  float milliseconds=0,total_rate=0;
-  gint frames=0,frame_types=0,frames_so_far=0;
-  gint vbr_median=-1;
-  guint bitrate;
-  gint counter=0;
-  MP3Header header;
-  struct stat filestat;
-  off_t data_start=0;
-
-
-  stat(mp3->filename,&filestat);
-  mp3->datasize=filestat.st_size;
-
-  if(get_first_header(mp3,0L)) {
-      data_start=ftell(mp3->file);
-      while((bitrate=get_next_header(mp3))) {
-	  if (bitrate < 15)  /* sanity added by JCS */
-	      frame_type[15-bitrate]++;
-	  frames++;
-      }
-      memcpy(&header,&(mp3->header),sizeof(MP3Header));
-      for(counter=0;counter<15;counter++) {
-	  if(frame_type[counter]) {
-	      float header_bitrate; /* introduced by JCS to speed up */
-	      frame_types++;
-	      header.bitrate=counter;
-	      frames_so_far += frame_type[counter];
-	      header_bitrate = mp3file_header_bitrate(&header);
-	      if (header_bitrate != 0)
-		  milliseconds += (float)(8*frame_length(&header)*frame_type[counter])/header_bitrate;
-	      total_rate += header_bitrate*frame_type[counter];
-	      if((vbr_median == -1) && (frames_so_far >= frames/2))
-		  vbr_median=counter;
-	  }
-      }
-      mp3->milliseconds=(gint)(milliseconds+0.5);
-      mp3->header.bitrate=vbr_median;
-      mp3->vbr_average=total_rate/(float)frames;
-      mp3->frames=frames;
-      if(frame_types > 1) {
-	  mp3->vbr=1;
-      }
-  }
-}
-
-
-
-
-/* ------------------------------------------------------------
-
-	 xmms code
-
-
-   ------------------------------------------------------------ */
-
-/*
-|  Changed by Jorg Schuler <jcsjcs at users.sourceforge.net> to
-|  compile with the gtkpod project. 2003/04/01
-*/
-
-/* This code is taken from the mpg123 code used in xmms-1.2.7
- * (Input/mpg123). Only the code needed for the playlength calculation
- * has been extracted */
-
-#include "mp3file.h"
-#include <stdio.h>
-#include <string.h>
-
-#define FRAMES_FLAG     0x0001
-#define BYTES_FLAG      0x0002
-#define TOC_FLAG        0x0004
-#define VBR_SCALE_FLAG  0x0008
-
-#define         SBLIMIT                 32
-#define         SCALE_BLOCK             12
-#define         SSLIMIT                 18
-
-#define         MPG_MD_STEREO           0
-#define         MPG_MD_JOINT_STEREO     1
-#define         MPG_MD_DUAL_CHANNEL     2
-#define         MPG_MD_MONO             3
-#define MAXFRAMESIZE 1792
-#define real float
-
-struct bitstream_info
-{
-	int bitindex;
-	unsigned char *wordpointer;
-};
-
-struct bitstream_info bsi;
-
-real mpg123_muls[27][64];	/* also used by layer 1 */
-
-int tabsel_123[2][3][16] =
-{
-	{
-    {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,},
-       {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,},
-       {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,}},
-
-	{
-       {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256,},
-	    {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,},
-	    {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,}}
-};
-
-long mpg123_freqs[9] =
-{44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000};
-
-/*
- * structure to receive extracted header
- */
-typedef struct
-{
-	int frames;		/* total bit stream frames from Xing header data */
-	int bytes;		/* total bit stream bytes from Xing header data */
-	unsigned char toc[100];	/* "table of contents" */
-} xing_header_t;
-
-struct al_table
-{
-	short bits;
-	short d;
-};
-
-struct frame
-{
-	struct al_table *alloc;
-	int (*synth) (real *, int, unsigned char *, int *);
-	int (*synth_mono) (real *, unsigned char *, int *);
-#ifdef USE_3DNOW
-	void (*dct36)(real *,real *,real *,real *,real *);
-#endif
-	int stereo;
-	int jsbound;
-	int single;
-	int II_sblimit;
-	int down_sample_sblimit;
-	int lsf;
-	int mpeg25;
-	int down_sample;
-	int header_change;
-	int lay;
-	int (*do_layer) (struct frame * fr);
-	int error_protection;
-	int bitrate_index;
-	int sampling_frequency;
-	int padding;
-	int extension;
-	int mode;
-	int mode_ext;
-	int copyright;
-	int original;
-	int emphasis;
-	int framesize;		/* computed framesize */
-};
-
-static guint32 convert_to_header(guint8 * buf)
-{
-
-	return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
-}
-
-static int mpg123_head_check(unsigned long head)
-{
-	if ((head & 0xffe00000) != 0xffe00000)
-		return FALSE;
-	if (!((head >> 17) & 3))
-		return FALSE;
-	if (((head >> 12) & 0xf) == 0xf)
-		return FALSE;
-	if (!((head >> 12) & 0xf))
-		return FALSE;
-	if (((head >> 10) & 0x3) == 0x3)
-		return FALSE;
-	if (((head >> 19) & 1) == 1 && ((head >> 17) & 3) == 3 && ((head >> 16) & 1) == 1)
-		return FALSE;
-	if ((head & 0xffff0000) == 0xfffe0000)
-		return FALSE;
-
-	return TRUE;
-}
-
-
-/*
- * the code a header and write the information
- * into the frame structure
- */
-static int mpg123_decode_header(struct frame *fr, unsigned long newhead)
-{
-    int ssize;
-
-	if (newhead & (1 << 20))
-	{
-		fr->lsf = (newhead & (1 << 19)) ? 0x0 : 0x1;
-		fr->mpeg25 = 0;
-	}
-	else
-	{
-		fr->lsf = 1;
-		fr->mpeg25 = 1;
-	}
-	fr->lay = 4 - ((newhead >> 17) & 3);
-	if (fr->mpeg25)
-	{
-		fr->sampling_frequency = 6 + ((newhead >> 10) & 0x3);
-	}
-	else
-		fr->sampling_frequency = ((newhead >> 10) & 0x3) + (fr->lsf * 3);
-	fr->error_protection = ((newhead >> 16) & 0x1) ^ 0x1;
-
-	fr->bitrate_index = ((newhead >> 12) & 0xf);
-	fr->padding = ((newhead >> 9) & 0x1);
-	fr->extension = ((newhead >> 8) & 0x1);
-	fr->mode = ((newhead >> 6) & 0x3);
-	fr->mode_ext = ((newhead >> 4) & 0x3);
-	fr->copyright = ((newhead >> 3) & 0x1);
-	fr->original = ((newhead >> 2) & 0x1);
-	fr->emphasis = newhead & 0x3;
-
-	fr->stereo = (fr->mode == MPG_MD_MONO) ? 1 : 2;
-
-	ssize = 0;
-
-	if (!fr->bitrate_index)
-		return (0);
-
-	switch (fr->lay)
-	{
-		case 1:
-/*			fr->do_layer = mpg123_do_layer1; */
-/*			mpg123_init_layer2();	/\* inits also shared tables with layer1 *\/ */
-			fr->framesize = (long) tabsel_123[fr->lsf][0][fr->bitrate_index] * 12000;
-			fr->framesize /= mpg123_freqs[fr->sampling_frequency];
-			fr->framesize = ((fr->framesize + fr->padding) << 2) - 4;
-			break;
-		case 2:
-/*			fr->do_layer = mpg123_do_layer2; */
-/*			mpg123_init_layer2();	/\* inits also shared tables with layer1 *\/ */
-			fr->framesize = (long) tabsel_123[fr->lsf][1][fr->bitrate_index] * 144000;
-			fr->framesize /= mpg123_freqs[fr->sampling_frequency];
-			fr->framesize += fr->padding - 4;
-			break;
-		case 3:
-/*			fr->do_layer = mpg123_do_layer3; */
-			if (fr->lsf)
-				ssize = (fr->stereo == 1) ? 9 : 17;
-			else
-				ssize = (fr->stereo == 1) ? 17 : 32;
-			if (fr->error_protection)
-				ssize += 2;
-			fr->framesize = (long) tabsel_123[fr->lsf][2][fr->bitrate_index] * 144000;
-			fr->framesize /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf);
-			fr->framesize = fr->framesize + fr->padding - 4;
-			break;
-		default:
-			return (0);
-	}
-	if(fr->framesize > MAXFRAMESIZE)
-		return 0;
-	return 1;
-}
-
-#define GET_INT32BE(b) \
-(i = (b[0] << 24) | (b[1] << 16) | b[2] << 8 | b[3], b += 4, i)
-
-static int mpg123_get_xing_header(xing_header_t * xing, unsigned char *buf)
-{
-	int i, head_flags;
-	int id, mode;
-
-	memset(xing, 0, sizeof(xing_header_t));
-
-	/* get selected MPEG header data */
-	id = (buf[1] >> 3) & 1;
-	mode = (buf[3] >> 6) & 3;
-	buf += 4;
-
-	/* Skip the sub band data */
-	if (id)
-	{
-		/* mpeg1 */
-		if (mode != 3)
-			buf += 32;
-		else
-			buf += 17;
-	}
-	else
-	{
-		/* mpeg2 */
-		if (mode != 3)
-			buf += 17;
-		else
-			buf += 9;
-	}
-
-	if (strncmp(buf, "Xing", 4))
-		return 0;
-	buf += 4;
-
-	head_flags = GET_INT32BE(buf);
-
-	if (head_flags & FRAMES_FLAG)
-		xing->frames = GET_INT32BE(buf);
-	if (xing->frames < 1)
-		xing->frames = 1;
-	if (head_flags & BYTES_FLAG)
-		xing->bytes = GET_INT32BE(buf);
-
-	if (head_flags & TOC_FLAG)
-	{
-		for (i = 0; i < 100; i++)
-			xing->toc[i] = buf[i];
-		buf += 100;
-	}
-
-#ifdef XING_DEBUG
-	for (i = 0; i < 100; i++)
-	{
-		if ((i % 10) == 0)
-			fprintf(stderr, "\n");
-		fprintf(stderr, " %3d", xing->toc[i]);
-	}
-#endif
-
-	return 1;
-}
-
-static double mpg123_compute_tpf(struct frame *fr)
-{
-	const int bs[4] = {0, 384, 1152, 1152};
-	double tpf;
-
-	tpf = bs[fr->lay];
-	tpf /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf);
-	return tpf;
-}
-
-static double mpg123_compute_bpf(struct frame *fr)
-{
-	double bpf;
-
-	switch (fr->lay)
-	{
-		case 1:
-			bpf = tabsel_123[fr->lsf][0][fr->bitrate_index];
-			bpf *= 12000.0 * 4.0;
-			bpf /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf);
-			break;
-		case 2:
-		case 3:
-			bpf = tabsel_123[fr->lsf][fr->lay - 1][fr->bitrate_index];
-			bpf *= 144000;
-			bpf /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf);
-			break;
-		default:
-			bpf = 1.0;
-	}
-
-	return bpf;
-}
-
-
-unsigned int mpg123_getbits(int number_of_bits)
-{
-	unsigned long rval;
-
-#ifdef DEBUG_GETBITS
-	fprintf(stderr, "g%d", number_of_bits);
-#endif
-
-	if(!number_of_bits)
-		return 0;
-
-#if 0
-	check_buffer_range(number_of_bits + bsi.bitindex);
-#endif
-
-	{
-		rval = bsi.wordpointer[0];
-		rval <<= 8;
-		rval |= bsi.wordpointer[1];
-		rval <<= 8;
-		rval |= bsi.wordpointer[2];
-
-		rval <<= bsi.bitindex;
-		rval &= 0xffffff;
-
-		bsi.bitindex += number_of_bits;
-
-		rval >>= (24-number_of_bits);
-
-		bsi.wordpointer += (bsi.bitindex >> 3);
-		bsi.bitindex &= 7;
-	}
-
-#ifdef DEBUG_GETBITS
-	fprintf(stderr,":%x ",rval);
-#endif
-
-	return rval;
-}
-
-
-void I_step_one(unsigned int balloc[], unsigned int scale_index[2][SBLIMIT], struct frame *fr)
-{
-	unsigned int *ba = balloc;
-	unsigned int *sca = (unsigned int *) scale_index;
-
-	if (fr->stereo)
-	{
-		int i;
-		int jsbound = fr->jsbound;
-
-		for (i = 0; i < jsbound; i++)
-		{
-			*ba++ = mpg123_getbits(4);
-			*ba++ = mpg123_getbits(4);
-		}
-		for (i = jsbound; i < SBLIMIT; i++)
-			*ba++ = mpg123_getbits(4);
-
-		ba = balloc;
-
-		for (i = 0; i < jsbound; i++)
-		{
-			if ((*ba++))
-				*sca++ = mpg123_getbits(6);
-			if ((*ba++))
-				*sca++ = mpg123_getbits(6);
-		}
-		for (i = jsbound; i < SBLIMIT; i++)
-			if ((*ba++))
-			{
-				*sca++ = mpg123_getbits(6);
-				*sca++ = mpg123_getbits(6);
-			}
-	}
-	else
-	{
-		int i;
-
-		for (i = 0; i < SBLIMIT; i++)
-			*ba++ = mpg123_getbits(4);
-		ba = balloc;
-		for (i = 0; i < SBLIMIT; i++)
-			if ((*ba++))
-				*sca++ = mpg123_getbits(6);
-	}
-}
-
-void I_step_two(real fraction[2][SBLIMIT], unsigned int balloc[2 * SBLIMIT],
-		unsigned int scale_index[2][SBLIMIT], struct frame *fr)
-{
-	int i, n;
-	int smpb[2 * SBLIMIT];	/* values: 0-65535 */
-	int *sample;
-	register unsigned int *ba;
-	register unsigned int *sca = (unsigned int *) scale_index;
-
-	if (fr->stereo)
-	{
-		int jsbound = fr->jsbound;
-		register real *f0 = fraction[0];
-		register real *f1 = fraction[1];
-
-		ba = balloc;
-		for (sample = smpb, i = 0; i < jsbound; i++)
-		{
-			if ((n = *ba++))
-				*sample++ = mpg123_getbits(n + 1);
-			if ((n = *ba++))
-				*sample++ = mpg123_getbits(n + 1);
-		}
-		for (i = jsbound; i < SBLIMIT; i++)
-			if ((n = *ba++))
-				*sample++ = mpg123_getbits(n + 1);
-
-		ba = balloc;
-		for (sample = smpb, i = 0; i < jsbound; i++)
-		{
-			if ((n = *ba++))
-				*f0++ = (real) (((-1) << n) + (*sample++) + 1) * mpg123_muls[n + 1][*sca++];
-			else
-				*f0++ = 0.0;
-			if ((n = *ba++))
-				*f1++ = (real) (((-1) << n) + (*sample++) + 1) * mpg123_muls[n + 1][*sca++];
-			else
-				*f1++ = 0.0;
-		}
-		for (i = jsbound; i < SBLIMIT; i++)
-		{
-			if ((n = *ba++))
-			{
-				real samp = (((-1) << n) + (*sample++) + 1);
-
-				*f0++ = samp * mpg123_muls[n + 1][*sca++];
-				*f1++ = samp * mpg123_muls[n + 1][*sca++];
-			}
-			else
-				*f0++ = *f1++ = 0.0;
-		}
-		for (i = fr->down_sample_sblimit; i < 32; i++)
-			fraction[0][i] = fraction[1][i] = 0.0;
-	}
-	else
-	{
-		register real *f0 = fraction[0];
-
-		ba = balloc;
-		for (sample = smpb, i = 0; i < SBLIMIT; i++)
-			if ((n = *ba++))
-				*sample++ = mpg123_getbits(n + 1);
-		ba = balloc;
-		for (sample = smpb, i = 0; i < SBLIMIT; i++)
-		{
-			if ((n = *ba++))
-				*f0++ = (real) (((-1) << n) + (*sample++) + 1) * mpg123_muls[n + 1][*sca++];
-			else
-				*f0++ = 0.0;
-		}
-		for (i = fr->down_sample_sblimit; i < 32; i++)
-			fraction[0][i] = 0.0;
-	}
-}
-
-static guint get_track_time_file(FILE * file)
-{
-	guint32 head;
-	guchar tmp[4], *buf;
-	struct frame frm;
-	xing_header_t xing_header;
-	double tpf, bpf;
-	guint32 len;
-
-	if (!file)
-		return -1;
-
-	fseek(file, 0, SEEK_SET);
-	if (fread(tmp, 1, 4, file) != 4)
-		return 0;
-	head = convert_to_header(tmp);
-	while (!mpg123_head_check(head))
-	{
-		head <<= 8;
-		if (fread(tmp, 1, 1, file) != 1)
-			return 0;
-		head |= tmp[0];
-	}
-	if (mpg123_decode_header(&frm, head))
-	{
-		buf = g_malloc(frm.framesize + 4);
-		fseek(file, -4, SEEK_CUR);
-		fread(buf, 1, frm.framesize + 4, file);
-		tpf = mpg123_compute_tpf(&frm);
-		if (mpg123_get_xing_header(&xing_header, buf))
-		{
-			g_free(buf);
-			return ((guint) (tpf * xing_header.frames * 1000));
-		}
-		g_free(buf);
-		bpf = mpg123_compute_bpf(&frm);
-		fseek(file, 0, SEEK_END);
-		len = ftell(file);
-		fseek(file, -128, SEEK_END);
-		fread(tmp, 1, 3, file);
-		if (!strncmp(tmp, "TAG", 3))
-			len -= 128;
-		return ((guint) ((guint)(len / bpf) * tpf * 1000));
-	}
-	return 0;
-}
-
-static guint get_track_time (gchar *path)
-{
-    guint result = 0;
-
-    if (path)
-    {
-	FILE *file = fopen (path, "r");
-	result = get_track_time_file (file);
-	if (file) fclose (file);
-    }
-    return result;
-}
-
-
-/* libid3tag stuff */
-
-#include <id3tag.h>
-#include "prefs.h"
-
-#ifndef ID3_FRAME_GROUP
-#define ID3_FRAME_GROUP "TPE2"
-#endif
-
-
-
-static const gchar* id3_get_binary (struct id3_tag *tag,
-				    char *frame_name,
-				    id3_length_t *len,
-				    int index)
-{
-    const id3_byte_t *binary = NULL;
-    struct id3_frame *frame;
-    union id3_field *field;
-
-    g_return_val_if_fail (len, NULL);
-
-    *len = 0;
-
-    frame = id3_tag_findframe (tag, frame_name, index);
-#if LOCALDEBUG
-    printf ("frame: %p\n", frame); 
-#endif
-
-    if (!frame) return NULL;
-
-#if LOCALDEBUG
-    printf (" nfields: %d\n", frame->nfields);
-    if (strncmp (frame_name, "APIC",  4) == 0)
-    {
-	field = id3_frame_field (frame, 2);
-	printf (" picture type: %ld\n", field->number.value);
-    }
-#endif
-
-
-#if 0
-/*-----------------*/
-/* just to show that this field (before last) contains the d8 ff e0 ff
-   part of the start of a jpeg file when the coverart war embedded by iTunes */
-
-    const id3_ucs4_t *string = NULL;
-    gchar *raw = NULL;
-
-    /* The last field contains the data */
-    field = id3_frame_field (frame, frame->nfields-2);
-
-#if LOCALDEBUG
-     printf (" field: %p\n", field);
-#endif
-
-    if (!field) return NULL;
-
-#if LOCALDEBUG
-     printf (" type: %d\n", field->type);
-#endif
-
-    switch (field->type)
-    {
-    case ID3_FIELD_TYPE_STRING:
-	string = id3_field_getstring (field);
-	break;
-    default:
-	break;
-    }
-  
-    /* ISO_8859_1 is just a "marker" -- most people just drop
-       whatever coding system they are using into it, so we use
-       charset_to_utf8() to convert to utf8 */
-
-    if (string)
-    {
-	raw = id3_ucs4_latin1duplicate (string);
-    }
-
-
-#if LOCALDEBUG
-    {
-	FILE *file;
-	printf (" string len: %d\n", raw?strlen(raw):0);
-	file = fopen ("/tmp/folder1.jpg", "w");
-	fwrite (raw, 1, raw?strlen(raw):0, file);
-	fclose (file);
-    }
-#endif
-    g_free (raw);
-
-/*-----------------*/
-#endif
-
-    /* The last field contains the data */
-    field = id3_frame_field (frame, frame->nfields-1);
-
-#if LOCALDEBUG
-     printf (" field: %p\n", field);
-#endif
-
-    if (!field) return NULL;
-
-#if LOCALDEBUG
-     printf (" type: %d\n", field->type);
-#endif
-
-    switch (field->type)
-    {
-    case ID3_FIELD_TYPE_BINARYDATA:
-	binary = id3_field_getbinarydata(field, len);
-	break;
-    default:
-	break;
-    }
-
-#if LOCALDEBUG
-    {
-	FILE *file;
-	printf (" binary len: %ld\n", *len);
-	file = fopen ("/tmp/folder2.jpg", "w");
-	fwrite (binary, 1, *len, file);
-	fclose (file);
-    }
-#endif
-
-
-
-    return binary;
-}
-
-
-
-static gchar* id3_get_string (struct id3_tag *tag, char *frame_name)
-{
-    const id3_ucs4_t *string = NULL;
-    const id3_byte_t *binary = NULL;
-    id3_length_t len = 0;
-    struct id3_frame *frame;
-    union id3_field *field;
-    gchar *utf8 = NULL;
-    enum id3_field_textencoding encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;
-
-    frame = id3_tag_findframe (tag, frame_name, 0);
-#if LOCALDEGUB
-    printf ("frame: %p\n", frame); 
-#endif
-
-    if (!frame) return NULL;
-
-    /* Find the encoding used for the field */
-    field = id3_frame_field (frame, 0);
-#if LOCALDEBUG
-    printf ("field: %p\n", field); 
-    printf ("type: %d\n", id3_field_type (field));
-#endif
-
-    if (field && (id3_field_type (field) == ID3_FIELD_TYPE_TEXTENCODING))
-    {
-	encoding = field->number.value;
-#if LOCALDEBUG
-	printf ("encoding: %d\n", encoding);
-#endif
-    }
-
-    /* The last field contains the data */
-    field = id3_frame_field (frame, frame->nfields-1);
-
-#if LOCALDEBUG
-     printf ("field: %p\n", field);
-#endif
-
-    if (!field) return NULL;
-
-#if LOCALDEBUG
-     printf ("type: %d\n", field->type);
-#endif
-
-
-    switch (field->type)
-    {
-    case ID3_FIELD_TYPE_STRINGLIST:
-	string = id3_field_getstrings (field, 0);
-	break;
-    case ID3_FIELD_TYPE_STRINGFULL:
-	string = id3_field_getfullstring (field);
-	break;
-    case ID3_FIELD_TYPE_BINARYDATA:
-	binary = id3_field_getbinarydata(field, &len);
-#if LOCALDEBUG
-	printf ("len: %ld\nbinary: %s\n", len, binary+1);
-#endif
-	if (len > 0)
-	    return charset_to_utf8 (binary+1);
-	break;
-    default:
-	break;
-    }
-
-/*     printf ("string: %p\n", string); */
-
-    if (!string) return NULL;
-
-    if (strcmp (frame_name, ID3_FRAME_GENRE) == 0)
-       string = id3_genre_name (string);
-
-    if (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1)
-    {
-	/* ISO_8859_1 is just a "marker" -- most people just drop
-	   whatever coding system they are using into it, so we use
-	   charset_to_utf8() to convert to utf8 */
-	id3_latin1_t *raw = id3_ucs4_latin1duplicate (string);
-	utf8 = charset_to_utf8 (raw);
-	g_free (raw);
-    }
-    else
-    {
-	/* Standard unicode is being used -- we won't have to worry
-	   about charsets then. */
-	utf8 = id3_ucs4_utf8duplicate (string);
-    }
-    return utf8;
-}
-
-static void id3_set_string (struct id3_tag *tag,
-			    const char *frame_name,
-			    const char *data,
-			    enum id3_field_textencoding encoding)
-{
-    int res;
-    struct id3_frame *frame;
-    union id3_field *field;
-    id3_ucs4_t *ucs4;
-
-    /* clear the frame, because of bug in libid3tag see
-       http://www.mars.org/mailman/public/mad-dev/2004-October/001113.html
-    */
-    while ((frame = id3_tag_findframe (tag, frame_name, 0)))
-    {
-	id3_tag_detachframe (tag, frame);
-        id3_frame_delete (frame);
-    }
-
-    if ((data == NULL) || (strlen(data) == 0))
-	return;
-
-    frame = id3_frame_new (frame_name);
-    id3_tag_attachframe (tag, frame);
-
-    /* Use the specified text encoding */
-    field = id3_frame_field (frame, 0);
-    id3_field_settextencoding(field, encoding);
-   
-    if (strcmp (frame_name, ID3_FRAME_COMMENT) == 0)
-    {
-	field = id3_frame_field (frame, 3);
-	field->type = ID3_FIELD_TYPE_STRINGFULL;
-    }
-    else
-    {
-	field = id3_frame_field (frame, 1);
-	field->type = ID3_FIELD_TYPE_STRINGLIST;
-    }
-
-
-    /* maybe could be optimized see
-       http://www.mars.org/mailman/public/mad-dev/2002-October/000739.html
-    */
-    if (strcmp (frame_name, ID3_FRAME_GENRE) == 0)
-    {
-	id3_ucs4_t *tmp_ucs4 = id3_utf8_ucs4duplicate ((id3_utf8_t *)data);
-	int index = id3_genre_number (tmp_ucs4);
-	if (index != -1)
-	{
-	    /* valid genre -- simply store the genre number */
-	    gchar *tmp = g_strdup_printf("%d", index);
-	    ucs4 = id3_latin1_ucs4duplicate (tmp);
-	    g_free (tmp);
-	}
-	else
-	{
-	    /* oups -- not a valid genre -- save the entire genre string */
-	    if (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1)
-	    {
-		/* we read 'ISO_8859_1' to stand for 'any locale
-		   charset' -- most programs seem to work that way */
-		id3_latin1_t *raw = charset_from_utf8 (data);
-		ucs4 = id3_latin1_ucs4duplicate (raw);
-		g_free (raw);
-	    }
-	    else
-	    {
-		/* Yeah! We use unicode encoding and won't have to
-		   worry about charsets */
-		ucs4 = tmp_ucs4;
-		tmp_ucs4 = NULL;
-	    }
-	}
-	g_free (tmp_ucs4);
-    }
-    else
-    {
-	if (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1)
-	{
-	    /* we read 'ISO_8859_1' to stand for 'any locale charset'
-	       -- most programs seem to work that way */
-	    id3_latin1_t *raw = charset_from_utf8 (data);
-	    ucs4 = id3_latin1_ucs4duplicate (raw);
-	    g_free (raw);
-	}
-	else
-	{
-	    /* Yeah! We use unicode encoding and won't have to
-	       worry about charsets */
-	    ucs4 = id3_utf8_ucs4duplicate ((id3_utf8_t *)data);
-	}
-    }
-
-    if (strcmp (frame_name, ID3_FRAME_COMMENT) == 0)
-	res = id3_field_setfullstring (field, ucs4);
-    else
-	res = id3_field_setstrings (field, 1, &ucs4);
-
-    g_free (ucs4);
-
-    if (res != 0)
-	g_print(_("Error setting ID3 field: %s\n"), frame_name);
-}
-
-
-/***
- * Reads id3v1.x / id3v2 apic data
- * @returns: TRUE on success, else FALSE.
- */
-static gboolean id3_apic_read (gchar *filename,
-			       guchar **image_data, gsize *image_data_len)
-{
-    struct id3_file *id3file;
-    struct id3_tag *id3tag;
-
-    g_return_val_if_fail (filename, FALSE);
-    g_return_val_if_fail (image_data, FALSE);
-    g_return_val_if_fail (image_data_len, FALSE);
-
-    *image_data = NULL;
-    *image_data_len = 0;
-
-    if (!(id3file = id3_file_open (filename, ID3_FILE_MODE_READONLY)))
-    {
-	gchar *fbuf = charset_to_utf8 (filename);
-	g_print(_("ERROR while opening file: '%s' (%s).\n"),
-		fbuf, g_strerror(errno));
-	g_free (fbuf);
-	return FALSE;
-    }
-
-    if ((id3tag = id3_file_tag(id3file)))
-    {
-	id3_length_t len;
-	const guchar *coverart = NULL;
-	int i;
-	struct id3_frame *frame;
-
-	/* Loop through APIC tags and set coverart.  The picture type should be
-	 * 3 -- Cover (front), but iTunes has been known to use 0 -- Other. */
-	for (i = 0; (frame = id3_tag_findframe(id3tag, "APIC", i)) != NULL; i++)
-	{
-	    union id3_field *field = id3_frame_field (frame, 2);
-	    int pictype = field->number.value;
-/*	    printf ("%s: found apic type %d\n", filename, pictype);*/
-
-	    /* We'll prefer type 3 (cover) over type 0 (other) */
-	    if (pictype == 3)
-	    {
-		coverart = id3_get_binary (id3tag, "APIC", &len, i);
-		break;
-	    }
-	    if ((pictype == 0) && !coverart)
-	    {
-		coverart = id3_get_binary (id3tag, "APIC", &len, i);
-	    }
-	}
-
-	if (coverart)
-	{   /* I guess iTunes is doing something wrong -- the
-	     * beginning of the coverart data ends up in a different
-	       field... We'll just add the missing data manually. */
-	    const guchar itunes_broken_jfif_marker[] =
-		{ 0x10, 'J', 'F', 'I', 'F'};
-	    if (len >= 5)
-	    {
-		if (strncmp (itunes_broken_jfif_marker, coverart,  5) == 0)
-		{
-		    const guchar itunes_missing_header[] =
-			{ 0xff, 0xd8, 0xff, 0xe0, 0x00 };
-		    *image_data = g_malloc (len+5);
-		    memcpy (*image_data, itunes_missing_header, 5);
-		    memcpy ((*image_data)+5, coverart, len);
-		    *image_data_len = len+5;
-		}
-	    }
-	    if (!*image_data)
-	    {
-		*image_data = g_malloc (len);
-		memcpy (*image_data, coverart, len);
-		*image_data_len = len;
-	    }
-#if LOCALDEBUG
-	    if (*image_data)
-	    {
-		FILE *file;
-		file = fopen ("/tmp/folder.jpg", "w");
-		fwrite (*image_data, 1, *image_data_len, file);
-		fclose (file);
-	    }
-#endif
-	}    
-    }
-    id3_file_close (id3file);
-    return TRUE;
-}
-
-/***
- * Reads id3v1.x / id3v2 tag and load data into the Id3tag structure.
- * If a tag entry exists (ex: title), we allocate memory, else value
- * stays to NULL
- * @returns: TRUE on success, else FALSE.
- */
-gboolean id3_tag_read (gchar *filename, File_Tag *tag)
-{
-    struct id3_file *id3file;
-    struct id3_tag *id3tag;
-    gchar* string;
-    gchar* string2;
-
-    g_return_val_if_fail (filename, FALSE);
-    g_return_val_if_fail (tag, FALSE);
-
-    memset (tag, 0, sizeof (File_Tag));
-
-    if (!(id3file = id3_file_open (filename, ID3_FILE_MODE_READONLY)))
-    {
-	gchar *fbuf = charset_to_utf8 (filename);
-	g_print(_("ERROR while opening file: '%s' (%s).\n"),
-		fbuf, g_strerror(errno));
-	g_free (fbuf);
-	return FALSE;
-    }
-
-    if ((id3tag = id3_file_tag(id3file)))
-    {
-	tag->title = id3_get_string (id3tag, ID3_FRAME_TITLE);
-	tag->artist = id3_get_string (id3tag, ID3_FRAME_GROUP);
-	if (!tag->artist || !*tag->artist)
-	{
-	    g_free (tag->artist);
-	    tag->artist = id3_get_string (id3tag, ID3_FRAME_ARTIST);
-	}
-	tag->album = id3_get_string (id3tag, ID3_FRAME_ALBUM);
-	tag->year = id3_get_string (id3tag, ID3_FRAME_YEAR);
-	tag->composer = id3_get_string (id3tag, "TCOM");
-	tag->comment = id3_get_string (id3tag, ID3_FRAME_COMMENT);
-	tag->genre = id3_get_string (id3tag, ID3_FRAME_GENRE);
-	tag->compilation = id3_get_string (id3tag, "TCMP");
-	tag->subtitle = id3_get_string (id3tag, "TIT3");
-	tag->lyrics = id3_get_string (id3tag, "USLT");
-	tag->podcasturl = id3_get_string (id3tag, "YTID");
-	tag->podcastrss = id3_get_string (id3tag, "YWFD");
-	tag->description = id3_get_string (id3tag, "YTDS");
-	tag->time_released = id3_get_string (id3tag, "YTDR");
-	tag->BPM = id3_get_string (id3tag, "TBPM");
-	tag->sort_artist = id3_get_string (id3tag, "TSOP");
-	tag->sort_album = id3_get_string (id3tag, "TSOA");
-	tag->sort_title = id3_get_string (id3tag, "TSOT");
-	tag->sort_albumartist = id3_get_string (id3tag, "TSO2");
-	tag->sort_composer = id3_get_string (id3tag, "TSOC");
-
-	string = id3_get_string (id3tag, "TLEN");
-	if (string)
-	{
-	    tag->songlen = (guint32) strtoul (string, 0, 10);
-	    g_free (string);
-	}
-
-	string = id3_get_string (id3tag, ID3_FRAME_TRACK);
-	if (string)
-	{
-	    string2 = strchr(string,'/');
-	    if (string2)
-	    {
-		tag->track_total = g_strdup_printf ("%.2d", atoi (string2+1));
-		*string2 = '\0';
-	    }
-	    tag->trackstring = g_strdup_printf ("%.2d", atoi (string));
-	    g_free(string);
-	}
-	
-	/* CD/disc number tag handling */
-	string = id3_get_string (id3tag, "TPOS");
-	if (string)
-	{
-	    string2 = strchr(string,'/');
-	    if (string2)
-	    {
-		tag->cdno_total = g_strdup_printf ("%.2d", atoi (string2+1));
-		*string2 = '\0';
-	    }
-	    tag->cdnostring = g_strdup_printf ("%.2d", atoi (string));
-	    g_free(string);
-	}
-    }
-
-    id3_file_close (id3file);
-    return TRUE;
-}
-
-
-
-static enum id3_field_textencoding get_encoding_of (struct id3_tag *tag, const char *frame_name)
-{
-    struct id3_frame *frame;
-    enum id3_field_textencoding encoding = -1;
-
-    frame = id3_tag_findframe (tag, frame_name, 0);
-    if (frame)
-    {
-	union id3_field *field = id3_frame_field (frame, 0);
-	if (field && (id3_field_type (field) == ID3_FIELD_TYPE_TEXTENCODING))
-	    encoding = field->number.value;
-    }
-    return encoding;
-}
-
-/* Find out which encoding is being used. If in doubt, return
- * latin1. This code assumes that the same encoding is used in all
- * fields.  */
-static enum id3_field_textencoding get_encoding (struct id3_tag *tag)
-{
-    enum id3_field_textencoding enc;
-
-    enc = get_encoding_of (tag, ID3_FRAME_TITLE);
-    if (enc != -1) return enc;
-    enc = get_encoding_of (tag, ID3_FRAME_ARTIST);
-    if (enc != -1) return enc;
-    enc = get_encoding_of (tag, ID3_FRAME_ALBUM);
-    if (enc != -1) return enc;
-    enc = get_encoding_of (tag, "TCOM");
-    if (enc != -1) return enc;
-    enc = get_encoding_of (tag, ID3_FRAME_COMMENT);
-    if (enc != -1) return enc;
-    enc = get_encoding_of (tag, ID3_FRAME_YEAR);
-    if (enc != -1) return enc;
-    return ID3_FIELD_TEXTENCODING_ISO_8859_1;
-}
-
-
-/* I'm not really sure about this: The original TAG identifier was
-   "TID", but no matter what I do I end up writing "YTID" */
-void set_uncommon_tag (struct id3_tag *id3tag,
-		       const gchar *id,
-		       const gchar *text,
-		       enum id3_field_textencoding encoding)
-{
-#if 0
-    struct id3_frame *frame;
-
-    frame = id3_tag_findframe (id3tag, id, 0);
-	union id3_field *field;
-	frame->flags = 0;
-	field = id3_frame_field (frame, 0);
-	    if (field)
-	    {
-		string1 = g_strdup_printf ("%c%s", '\0',
-					   track->podcasturl);
-		id3_field_setbinarydata (field, string1,
-					 strlen(track->podcasturl)+1);
-		g_free (string1);
-	    }
-
-#endif
-}
-
-
-
-/**
- * Write the ID3 tags to the file.
- * @returns: TRUE on success, else FALSE.
- */
-gboolean mp3_write_file_info (gchar *filename, Track *track)
-{
-    struct id3_tag* id3tag;
-    struct id3_file* id3file;
-    gint error = 0;
-
-    id3file = id3_file_open (filename, ID3_FILE_MODE_READWRITE);
-    if (!id3file)
-    {
-	gchar *fbuf = charset_to_utf8 (filename);
-	g_print(_("ERROR while opening file: '%s' (%s).\n"),
-		fbuf, g_strerror(errno));
-	g_free (fbuf);
-	return FALSE;
-    }
-
-    if ((id3tag = id3_file_tag(id3file)))
-    {
-	char *string1;
-
-	enum id3_field_textencoding encoding;
-
-	/* use the same coding as before... */
-	encoding = get_encoding (id3tag);
-	/* ...unless it's ISO_8859_1 and prefs say we should use
-	   unicode (i.e. ID3v2.4) */
-	if (prefs_get_int("id3_write_id3v24") &&
-	    (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1))
-	    encoding = ID3_FIELD_TEXTENCODING_UTF_8;
-
-	/* always render id3v1 to prevent dj studio from crashing */
-	id3_tag_options(id3tag, ID3_TAG_OPTION_ID3V1, ~0);
-
-        /* turn off frame compression and crc information to let
-	   itunes read tags see
-	   http://www.mars.org/mailman/public/mad-dev/2002-October/000742.html
-	*/
-	id3_tag_options(id3tag, ID3_TAG_OPTION_COMPRESSION, 0);
-	id3_tag_options(id3tag, ID3_TAG_OPTION_CRC, 0);
-
-	id3_set_string (id3tag, ID3_FRAME_TITLE, track->title, encoding);
-	id3_set_string (id3tag, ID3_FRAME_ARTIST, track->artist, encoding);
-	id3_set_string (id3tag, ID3_FRAME_ALBUM, track->album, encoding);
-	id3_set_string (id3tag, ID3_FRAME_GENRE, track->genre, encoding);
-	id3_set_string (id3tag, ID3_FRAME_COMMENT, track->comment, encoding);
-	id3_set_string (id3tag, "TIT3", track->subtitle, encoding);
-	id3_set_string (id3tag, "TSOP", track->sort_artist, encoding);
-	id3_set_string (id3tag, "TSOA", track->sort_album, encoding);
-	id3_set_string (id3tag, "TSOT", track->sort_title, encoding);
-	id3_set_string (id3tag, "TSO2", track->sort_albumartist, encoding);
-	id3_set_string (id3tag, "TSOC", track->sort_composer, encoding);
-
-	set_uncommon_tag (id3tag, "YTID", track->podcasturl, encoding);
-	set_uncommon_tag (id3tag, "YTDS", track->description, encoding);
-	set_uncommon_tag (id3tag, "YWFD", track->podcastrss, encoding);
-
-	id3_set_string (id3tag, "TCOM", track->composer, encoding);
-
-	string1 = g_strdup_printf("%d", track->year);
-	id3_set_string(id3tag, ID3_FRAME_YEAR, string1, encoding);
-	g_free(string1);
-
-	string1 = g_strdup_printf("%d", track->BPM);
-	id3_set_string(id3tag, "TBPM", string1, encoding);
-	g_free(string1);
-
-	if (track->tracks)
-	    string1 = g_strdup_printf ("%d/%d",
-				       track->track_nr, track->tracks);
-	else
-	    string1 = g_strdup_printf ("%d", track->track_nr);
-	id3_set_string (id3tag, ID3_FRAME_TRACK, string1, encoding);
-	g_free(string1);
-
-	if (track->cds)
-	    string1 = g_strdup_printf ("%d/%d",
-				       track->cd_nr, track->cds);
-	else
-	    string1 = g_strdup_printf ("%d", track->cd_nr);
-	id3_set_string (id3tag, "TPOS", string1, encoding);
-	g_free(string1);
-        
-       string1 = g_strdup_printf ("%d", track->compilation);
-       id3_set_string (id3tag, "TCMP", string1, encoding);
-       g_free(string1);
-    } 
-
-    if (id3_file_update(id3file) != 0)
-    {
-	gchar *fbuf = charset_to_utf8 (filename);
-	g_print(_("ERROR while writing tag to file: '%s' (%s).\n"),
-		fbuf, g_strerror(errno));
-	g_free (fbuf);
-	return FALSE;
-    }
-
-    id3_file_close (id3file);
-
-    if (error) return FALSE;
-    else       return TRUE;
-}
-
-
-/*
- * Code to read the ReplayGain Values stored by LAME in its own tag.
- *
- * Most of the relevant information has been extracted from them LAME sources
- * (http://lame.sourceforge.net/).
- * The "Mp3 info Tag rev 1 specifications - draft 0"
- * (http://gabriel.mp3-tech.org/mp3infotag.html) by Gabriel Bouvigne describes
- * the actual Tag (except for small changes).
- * Details on the actual ReplayGain fields have been obtained from
- * http://www.replaygain.org .
- *
- * Apart from that, some information has been derived from phwip's LameTag
- * (http://www.silisoftware.com/applets/?scriptname=LameTag)
- *
- * 
- * Code to read the ReplayGain Values stored in an Ape tag.
- *
- * Info on Lyrics3 V2.00 can be found at:
- * http://www.id3.org/lyrics3200.html
- * On the actual Ape Tag V2.0:
- * http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html
- *
- * Copyright (C) 2004 Jens Taprogge <jens.taprogge at post.rwth-aachen.de>
- *
- * Provided under GPL according to Jens Taprogge. (JCS -- 12 March 2004)
- */
-
-#define TAG_FOOTER		0x10
-#define LAME_OFFSET		0x74
-#define SIDEINFO_MPEG1_MONO	17
-#define SIDEINFO_MPEG1_MULTI	32
-#define SIDEINFO_MPEG2_MONO	9
-#define SIDEINFO_MPEG2_MULTI	17
-#define ID3V1_SIZE		0x80
-#define APE_FOOTER_SIZE 	0x20
-#define LYRICS_FOOTER_SIZE 	0x0f
-
-
-static gint lame_vcmp(gchar a[5], gchar b[5]) {
-	int r;
-
-	r = strncmp(a, b, 4);
-	if (r) return r;
-
-	if (a[4] == b[4]) return 0;
-
-	/* check for '.': indicates subminor version */
-	if (a[4] == '.') return 1;
-	if (b[4] == '.') return -1;
-	
-	/* check for alpha or beta versions */
-	if (a[4] == ' ') return 1;
-	if (b[4] == ' ') return -1;
-
-	/* check for alpha, beta etc. indicated by a, b... */
-	return strncmp(&a[4], &b[4], 1);
-}
-
-
-/* buf[] must be declared unsigned -- otherwise the casts, shifts and
-   additions below produce funny results */             
-static void read_lame_replaygain(unsigned char buf[],
-				 GainData *gd, int gain_adjust) {
-	char oc, nc;
-	gint gain;
-
-	g_return_if_fail (gd);
-
-	/* buf[0] and buf[1] are a bit field:
-	   3 bits: name  (mask: 0xe0 = 11100000)
-	   3 bits: originator (mask: 0x1c = 00011100)
-	   1 bit: negative if set (mask: 0x02 = 00000010)
-	   9 bits: value
-	*/
-
-	/* check originator */
-	oc = (buf[0] & 0x1c) >> 2;
-	if ((oc <= 0) || (oc > 3)) return;
-
-	/* check name code */
-	nc = buf[0] & 0xe0;
-	if (!((nc == 0x20) || (nc == 0x40))) return;
-	
-	gain = ((((guint)buf[0]) & 0x1) << 8) + buf[1];
-	
-	/* This would be a value of -0.
-	 * That value however is illegal by current standards and reserved for
-	 * future use. */
-	if ((!gain) && (buf[0] & 0x02)) return;
-	
-	if (buf[0] & 2) gain = -gain;
-	
-	gain += gain_adjust;
-
-	switch (nc) {
-		case 0x20:
-			if (gd->radio_gain_set) return;
-			gd->radio_gain = (gdouble)gain / 10;
-			gd->radio_gain_set = TRUE;
-/*			printf("radio_gain (lame): %i\n", gd->radio_gain); */
-			break;
-		case 0x40:
-			if (gd->audiophile_gain_set) return;
-			gd->audiophile_gain = (gdouble)gain / 10;
-			gd->audiophile_gain_set = TRUE;
-/*			printf("audiophile_gain (lame): %i\n", 
-					gd->audiophile_gain);*/
-			break;
-	}
-}
-
-
-static inline guint32 parse_ape_uint32(char *buf) {
-	return (buf[0] & 0xff) | (buf[1] & 0xff) << 8 
-		| (buf[2] & 0xff) << 16 | (buf[3] & 0xff) << 24;
-}
-
-static inline guint32 parse_lame_uint32(char *buf) {
-	return (buf[0] & 0xff) << 24 | (buf[1] & 0xff) << 16 
-		| (buf[2] & 0xff) << 8 | (buf[3] & 0xff);
-}
-
-
-/* 
- * mp3_get_track_lame_replaygain - read the specified file and scan for LAME Tag
- * ReplayGain information.
- *
- * @path: localtion of the file
- * @track: structure holding track information
- *
- * FIXME: Are there other encoders writing a LAME Tag using a different magic
- * string?
- * TODO: Check CRC.
- */
-
-gboolean mp3_get_track_lame_replaygain (gchar *path, GainData *gd)
-{
-	struct {
-		/* All members are defined in terms of chars so padding does not
-		 * occur. Is there a cleaner way to keep the compiler from
-		 * padding? */
-		
-		char     id[3];
-		char     version[2];
-		char     flags;
-		char     size[4];
-	} id3head;
-
-	FILE *file = NULL;
-	char buf[4], version[5];
-	int gain_adjust = 0;
-	int sideinfo;
-	guint32 ps;
-
-	g_return_val_if_fail (gd, FALSE);
-
-	gd->radio_gain = 0;
-	gd->audiophile_gain = 0;
-	gd->peak_signal = 0;
-	gd->radio_gain_set = FALSE;
-	gd->audiophile_gain_set = FALSE;
-	gd->peak_signal_set = FALSE;
-	
-	if (!path)
-		goto rg_fail;
-	
-	file = fopen (path, "r");
-
-	if (!file)
-	    goto rg_fail;
-
-	/* Skip ID3 header if appropriate */
-	if (fread(&id3head, 1, sizeof(id3head), file) != 
-			sizeof(id3head))
-		goto rg_fail;
-	
-	if (!strncmp(id3head.id, "ID3", 3)) {
-		int realsize = 0;
-		
-		realsize = (id3head.size[0] & 0x7f) << 21 
-			| (id3head.size[1] & 0x7f) << 14 
-			| (id3head.size[2] & 0x7f) << 7 
-			| (id3head.size[3] & 0x7f);
-
-		if (id3head.flags & TAG_FOOTER) {
-			/* footer is copy of header */
-			realsize += sizeof(id3head);
-		}
-
-		if (fseek(file, realsize-1, SEEK_CUR) ||
-				(!fread(&buf[0], 1, 1, file)))
-			goto rg_fail;
-	} else {
-		/* no ID3 Tag - go back */
-		fseek(file, -sizeof(id3head), SEEK_CUR);
-	}
-
-	/* Search Xing header. The location is dependant on the MPEG Layer and
-	 * whether the stream is mono or not. */
-	if (fread(buf, 1, 4, file) != 4) goto rg_fail;
-	
-	/* should start with 0xff 0xf? (synch) */
-	if (((buf[0] & 0xff) != 0xff) 
-			|| ((buf[1] & 0xf0) != 0xf0)) goto rg_fail;
-	
-	/* determine the length of the sideinfo */
-	if (buf[1] & 0x08) {
-		sideinfo = ((buf[3] & 0xc0) == 0xc0) ? 
-			SIDEINFO_MPEG1_MONO : SIDEINFO_MPEG1_MULTI;
-	} else {
-		sideinfo = ((buf[3] & 0xc0) == 0xc0) ? 
-			SIDEINFO_MPEG2_MONO : SIDEINFO_MPEG2_MULTI;
-	}
-	
-	if (fseek(file, sideinfo, SEEK_CUR) ||
-			(fread(&buf[0], 1, 4, file) != 4))
-		goto rg_fail;
-	
-	/* Is this really a Xing or Info Header? 
-	 * FIXME: Apparently (according to madplay sources) there is a different
-	 * possible location for the Xing header ("due to an unfortunate
-	 * historical event"). I do not thing we need to care though since
-	 * RaplayGain information is only conatined in recent files.  */
-	if (strncmp(buf, "Xing", 4) && strncmp(buf, "Info", 4))
-		goto rg_fail;
-
-	/* Check for LAME Tag */
-	if (fseek(file, LAME_OFFSET, SEEK_CUR) ||
-				(fread(&buf[0], 1, 4, file) != 4))
-		goto rg_fail;
-	if (strncmp(buf, "LAME", 4))
-		goto rg_fail;
-	
-	/* Check LAME Version */
-	if (fread(version, 1, 5, file) != 5)
-		goto rg_fail;
-	
-	/* Skip really old versions altogether. I am not sure when radio_gain
-	 * information was introduced. 3.89 does not seem to supprt it though.
-	 * */
-	if (lame_vcmp(version, "3.90") < 0) {
-/*		fprintf(stderr, "Old lame version (%c%c%c%c%c). Not used.\n",
-				version[0], version[1], version[2], version[3], version[4]); */
-		goto rg_fail;
-	}
-		
-	if (fseek(file, 0x2, SEEK_CUR) || (fread(buf, 1, 4, file) != 4))
-		goto rg_fail;
-
-	/* get the peak signal. */
-	ps = parse_lame_uint32(buf);
-	
-	/* Don't know when fixed-point PeakSingleAmplitude
-	 * was introduced exactly. 3.94b will be used for now.) */
-	if ((lame_vcmp(version, "3.94b") >= 0)) {
-		if ((!gd->peak_signal_set) && ps) {
-			gd->peak_signal = ps;
-			gd->peak_signal_set = TRUE;
-/*			printf("peak_signal (lame): %f\n", (double)
-					gd->peak_signal / 0x800000);*/
-		}
-	} else {
-		float f = *((float *) (void *) (&ps)) * 0x800000;
-		gd->peak_signal = (guint32) f;
-		/* I would like to see an example of that. */
-/*		printf("peak_signal (lame floating point): %f. PLEASE report.\n", 
-				(double) gd->peak_signal / 0x800000);*/
-	}
-
-	/*
-	 * Versions prior to 3.95.1 used a reference volume of 83dB.
-	 * (As compared to the currently used 89dB.)
-	 */
-	if ((lame_vcmp(version, "3.95.") < 0)) {
-		gain_adjust = 60;
-/*		fprintf(stderr, "Old lame version (%c%c%c%c%c). Adjusting gain.\n",
-				version[0], version[1], version[2], version[3], version[4]); */
-	}
-
-	if (fread(&buf[0], 1, 2, file) != 2)
-		goto rg_fail;
-
-	/* radio gain */
-	read_lame_replaygain (buf, gd, gain_adjust);
-
-	if (fread(&buf[0], 1, 2, file) != 2)
-		goto rg_fail;
-
-	/* audiophile gain */
-	read_lame_replaygain (buf, gd, gain_adjust);
-
-	fclose(file);
-	return TRUE;
-
-rg_fail:
-	if (file)
-		fclose(file);
-	return FALSE;
-}
-
-
-/* 
- * mp3_get_track_ape_replaygain - read the specified file and scan for Ape Tag
- * ReplayGain information.
- *
- * @path: localtion of the file
- * @track: structure holding track information
- *
- * The function only modifies the gains if they have not previously been set.
- */
-
-gboolean mp3_get_track_ape_replaygain(gchar *path, GainData *gd)
-{
-	/* The Ape Tag is located a t the end of the file. Or at least that
-	 * seems where it can most likely be found. Either it is at the very end
-	 * or before a trailing ID3v1 Tag. Sometimes a Lyrics3 Tag is placed
-	 * between the ID3v1 and the Ape Tag.
-	 * If you find files that have the Tags located in different
-	 * positions please let me know. */
-
-	FILE *file = NULL;
-	char buf[16];
-	char *dbuf = NULL, *ep;
-
-	int offset = 0;
-	int i;
-	int pos = 0, pos2 = 0;
-	guint32 version;
-	guint32 data_length;
-	guint32 entry_length = 0;
-	guint32 entries;
-	double d;
-
-	g_return_val_if_fail (gd, FALSE);
-	g_return_val_if_fail (path, FALSE);
-
-	file = fopen (path, "r");
-
-	if (!file)
-	    goto rg_fail;
-
-	/* check for ID3v1 Tag */
-	if (fseek(file, -ID3V1_SIZE, SEEK_END) ||
-			fread(&buf, 1, 3, file) != 3)
-		goto rg_fail;
-	if (!strncmp(buf, "TAG", 3)) offset -= ID3V1_SIZE;
-
-	/* check for Lyrics3 Tag */
-	if (fseek(file, -9 + offset, SEEK_END) ||
-			fread(&buf, 1, 9, file) != 9)
-		goto rg_fail;
-	if (!strncmp(buf, "LYRICS200", 9)) {
-		if (fseek(file, -LYRICS_FOOTER_SIZE + offset, SEEK_END) ||
-				fread(&buf, 1, 9, file) != 9)
-			goto rg_fail;
-		data_length = buf[0] - '0';
-		for (i = 1; i < 6; i++) {
-			data_length *= 10;
-			data_length += buf[i] - '0';
-		}
-		if (fseek(file, -LYRICS_FOOTER_SIZE - data_length + offset,
-					SEEK_END) ||
-				fread(&buf, 1, 11, file) != 11)
-			goto rg_fail;
-		if (!strncmp(buf, "LYRICSBEGIN", 11)) 
-			offset -= LYRICS_FOOTER_SIZE + data_length;
-	}
-
-	/* check for APE Tag */
-	if (fseek(file, -APE_FOOTER_SIZE + offset, SEEK_END) ||
-			fread(&buf, 1, 8, file) != 8)
-		goto rg_fail;
-	if (strncmp(buf, "APETAGEX", 8)) goto rg_fail;
-
-	/* Check the version of the tag. 1000 and 2000 (v1.0 and 2.0) are the
-	 * only ones I know about. Make suer things do not break in the future.
-	 * */
-	if (fread(&buf, 1, 4, file) != 4)
-		goto rg_fail;
-	version = parse_ape_uint32(buf);
-	if (version != 1000 && version != 2000)
-		goto rg_fail;
-
-	/* determine data length */
-	if (fread(&buf, 1, 4, file) != 4)
-		goto rg_fail;
-	data_length = parse_ape_uint32(buf) - APE_FOOTER_SIZE;
-
-	/* determine number of entries */
-	if (fread(&buf, 1, 4, file) != 4)
-		goto rg_fail;
-	entries = parse_ape_uint32(buf);
-
-	/* seek to first entry and read the whole buffer*/
-	if (fseek(file, -APE_FOOTER_SIZE + offset - data_length, SEEK_END))
-		goto rg_fail;
-	if (!(dbuf = malloc(data_length)))
-		goto rg_fail;
-	if (fread(dbuf, 1, data_length, file) != data_length)
-		goto rg_fail;
-	
-	for (i = 0; i < entries; i++) {
-		if (gd->radio_gain_set && gd->peak_signal_set) break;
-		pos = pos2 + entry_length;
-		if (pos > data_length - 10) break;
-		
-		entry_length = parse_ape_uint32(&dbuf[pos]); pos += 4;
-		pos += 4;
-		
-		pos2 = pos;
-		while (dbuf[pos2] && pos2 < data_length) pos2++;
-		if (pos2 == data_length) break;
-		pos2++;
-		
-		if (entry_length + 1 > sizeof(buf))
-			continue;
-/* 		printf ("%s:%d:%d\n",&dbuf[pos], pos2, pos); */
-		if (!gd->radio_gain_set && !strcasecmp(&dbuf[pos],
-					"REPLAYGAIN_TRACK_GAIN")) {
-			memcpy(buf, &dbuf[pos2], entry_length);
-			buf[entry_length] = '\0';
-			
-			d = g_ascii_strtod(buf, &ep);
-/* 			printf("%f\n", d); */
-			if ((ep == buf + entry_length - 3) 
-					&& (!strncasecmp(ep, " dB", 3))) {
-			    gd->radio_gain = d;
-				gd->radio_gain_set = TRUE;
-/*				printf("radio_gain (ape): %i\n", gd->radio_gain);*/
-			}
-			
-			continue;
-		}
-		if (!gd->peak_signal_set && !strcasecmp(&dbuf[pos],
-					"REPLAYGAIN_TRACK_PEAK")) {
-			memcpy(buf, &dbuf[pos2], entry_length);
-			buf[entry_length] = '\0';
-			
-			d = g_ascii_strtod(buf, &ep);
-			if (ep == buf + entry_length) {
-				d *= 0x800000;
-				gd->peak_signal = (guint32) floor(d + 0.5);
-				gd->peak_signal_set = TRUE;
-/*				printf("peak_signal (ape): %f\n", (double) gd->peak_signal / 0x800000);*/
-			}
-
-			continue;
-		}
-	}
-
-	free(dbuf);
-	fclose(file);
-	return TRUE;
-
-rg_fail:
-	if (dbuf)
-		free(dbuf);
-	if (file)
-		fclose(file);
-	return FALSE;
-}
-
-
-/* ----------------------------------------------------------------------
-
-	      mp3gain code
-
----------------------------------------------------------------------- */
-
-#include <sys/wait.h>
-#include <fcntl.h>
-
-
-
-
-
-
-/** 
- * mp3_read_soundcheck:
- *
- * try to read the ReplayGain values from the LAME or Ape Tags and set
- * the track's soundcheck field accordingly.
- *
- * @path: localtion of the file
- * @track: structure holding track information
- *
- * The function always rereads the gain from the file.
- *
- * Returns TRUE if the soundcheck field could be set.
- */
-gboolean mp3_read_soundcheck (gchar *path, Track *track)
-{
-    GainData gd;
-
-    g_return_val_if_fail (track, FALSE);
-
-    memset (&gd, 0, sizeof (GainData));
-
-    gd.radio_gain_set = FALSE;
-    gd.audiophile_gain_set = FALSE;
-    gd.peak_signal_set = FALSE;
-
-    mp3_get_track_lame_replaygain (path, &gd);
-    if (gd.radio_gain_set)
-    {
-	track->soundcheck = replaygain_to_soundcheck (gd.radio_gain);
-	return TRUE;
-    }
-
-    mp3_get_track_ape_replaygain (path, &gd);
-    if (gd.radio_gain_set)
-    {
-	track->soundcheck = replaygain_to_soundcheck (gd.radio_gain);
-	return TRUE;
-    }
-
-    return FALSE;
-}
-
-
-
-
-
-
-/* mp3 slot size in bytes */
-int slotsize[3] = {4,1,1}; /* layer 1, layer 2, layer 3 */
-
-int samplesperframe[2][3] = {
-  { /* MPEG 2.0 */
-    384,1152,576 /* layer 1, layer 2, layer 3 */
-  },
-
-  { /* MPEG 1.0 */
-    384,1152,1152 /* layer 1, layer 2, layer 3 */
-  }
-};
-
-
-/* 
- * mp3_get_track_lame_gapless - read the specified file and scan for LAME Tag
- * gapless information.
- *
- * @path: localtion of the file
- * @track: structure holding track information
- *
- * TODO: Split off non-LAME stuff (samplecount, gapless_data) to a separate function since it's generic
- */
-gboolean mp3_get_track_lame_gapless (gchar *path, GaplessData *gd)
-{
-    FILE *file = NULL;
-    char buf[4], version[5];
-    unsigned char ubuf[4];
-    int sideinfo;
-    int i;
-
-    g_return_val_if_fail (gd, FALSE);
-
-    if (!path)
-	goto gp_fail;
-
-    file = fopen (path, "rb");
-
-    if (!file)
-	goto gp_fail;
-
-    /* use get_first_header() to seek to the first mp3 header */
-    MP3Info *mp3i = NULL;
-    mp3i = g_malloc0 (sizeof (MP3Info));
-    mp3i->filename = path;
-    mp3i->file = file;
-    get_mp3_info (mp3i);
-    get_first_header (mp3i, 0);
-
-    int xing_header_offset = ftell (file);
-
-    MP3Header h;
-    if (!get_header (file, &h))
-	goto gp_fail;
-
-    int mysamplesperframe = samplesperframe[h.version & 1][3 - h.layer];
-
-    /* Determine offset of Xing header based on sideinfo size */
-    if (h.version & 0x1)
-    {
-	sideinfo = (h.mode & 0x2) ?
-	    SIDEINFO_MPEG1_MONO : SIDEINFO_MPEG1_MULTI;
-    }
-    else
-    {
-	sideinfo = (h.mode & 0x2) ?
-	    SIDEINFO_MPEG2_MONO : SIDEINFO_MPEG2_MULTI;
-    }
-
-    if (fseek (file, sideinfo, SEEK_CUR) ||
-	(fread (&buf[0], 1, 4, file) != 4))
-	goto gp_fail;
-
-    /* Is this really a Xing or Info Header? 
-     * FIXME: Apparently (according to madplay sources) there is a different
-     * possible location for the Xing header ("due to an unfortunate
-     * historical event"). I do not thing we need to care though since
-     * ReplayGain information is only contained in recent files.  */
-    if (strncmp (buf, "Xing", 4) && strncmp (buf, "Info", 4))
-	goto gp_fail;
-
-    /* Determine the offset of the LAME tag based on contents of the Xing header */
-    int flags;
-    fread (&flags, 4, 1, file);
-    int toskip = 0;
-    if (flags | 0x1)
-    {				/* frames field is set */
-	toskip += 4;
-    }
-    if (flags | 0x2)
-    {				/* bytes field is set */
-	toskip += 4;
-    }
-    if (flags | 0x4)
-    {				/* TOC field is set */
-	toskip += 100;
-    }
-    if (flags | 0x8)
-    {				/* quality field is set */
-	toskip += 4;
-    }
-
-    /* Check for LAME Tag */
-    if (fseek (file, toskip, SEEK_CUR) || (fread (&buf[0], 1, 4, file) != 4))
-	goto gp_fail;
-    if (strncmp (buf, "LAME", 4))
-	goto gp_fail;
-
-    /* Check LAME Version */
-    if (fread (version, 1, 5, file) != 5)
-	goto gp_fail;
-
-    /* XXX skip old LAME versions, or just assume that pre/postgap
-     * turn out zeros anyway, or check the CRC to vaidate the tag? */
-
-    gboolean cbr = FALSE;
-    if (fread (ubuf, 1, 1, file) != 1)
-	goto gp_fail;
-
-    if ((ubuf[0] & 0xf) == 0x1)
-	cbr = TRUE;
-
-    if (fseek (file, 0xB, SEEK_CUR) || (fread (ubuf, 1, 4, file) != 4))
-	goto gp_fail;
-
-    /* set pregap and postgap directly from LAME header */
-    gd->pregap = (ubuf[0] << 4) + (ubuf[1] >> 4);
-    gd->postgap = ((ubuf[1] & 0xf) << 8) + ubuf[2];
-
-    /* jump the end of the frame with the xing header */
-    if (fseek (file, xing_header_offset + frame_length (&h), SEEK_SET))
-	goto gp_fail;
-
-    /* counts bytes from the start of the 1st sync frame */
-    int totaldatasize = frame_length (&h);
-
-    /* keeps track of the last 8 frame sizes */
-    int lastframes[8];
-
-    /* counts number of music frames */
-    int totalframes = 0;
-
-    /* quickly parse the file, reading only frame headers */
-    int l = 0;
-    while ((l = get_header (file, &h)) != 0)
-    {
-	for (i = 7; i > 0; i--)
-	{
-	    lastframes[i] = lastframes[i - 1];
-	}
-	lastframes[0] = l;
-	totaldatasize += l;
-	totalframes++;
-
-	if (fseek (file, l - FRAME_HEADER_SIZE, SEEK_CUR))
-	    goto gp_fail;
-
-    }
-
-    int finaleight = 0;
-    for (i = 0; i < 8; i++)
-    {
-	finaleight += lastframes[i];
-    }
-
-    if (cbr)
-	totalframes++;
-
-    /* all but last eight frames */
-    gd->gapless_data = totaldatasize - finaleight;
-    /* total samples minus pre/postgap */
-    gd->samplecount = totalframes * mysamplesperframe - gd->pregap - gd->postgap;
-
-    return TRUE;
-
-
-  gp_fail:
-    if (file)
-	fclose (file);
-    return FALSE;
-
-}
-
-
-
-/** 
- * mp3_read_gapless:
- *
- * try to read the gapless values from the LAME Tag and set
- * the track's pregap, postgap, samplecount, and gapless_data fields
- * accordingly.
- *
- * @path: location of the file
- * @track: structure holding track information
- *
- * The function always rereads the data from the file.
- *
- * Returns TRUE if all four gapless fields could be
- * set. etrack->tchanged is set to TRUE if data has been changed,
- * FALSE otherwise.
- */
-gboolean mp3_read_gapless (char *path, Track *track)
-{
-    GaplessData gd;
-    ExtraTrackData *etr;
-
-    g_return_val_if_fail (track, FALSE);
-
-    etr = track->userdata;
-
-    memset (&gd, 0, sizeof (GaplessData));
-
-    gd.pregap = 0;
-    gd.samplecount = 0;
-    gd.postgap = 0;
-    gd.gapless_data = 0;
-
-    mp3_get_track_lame_gapless (path, &gd);
-
-    etr->tchanged = FALSE;
-
-    if ((gd.pregap) && (gd.samplecount) && (gd.postgap) && (gd.gapless_data))
-    {
-	if ((track->pregap != gd.pregap) ||
-	    (track->samplecount != gd.samplecount) ||
-	    (track->postgap != gd.postgap) ||
-	    (track->gapless_data != gd.gapless_data) ||
-	    (track->gapless_track_flag == FALSE))
-	{
-	    etr->tchanged = TRUE;
-	    track->pregap = gd.pregap;
-	    track->samplecount = gd.samplecount;
-	    track->postgap = gd.postgap;
-	    track->gapless_data = gd.gapless_data;
-	    track->gapless_track_flag = TRUE;
-	}
-    }
-    return FALSE;
-}
-
-
-
-/* ----------------------------------------------------------------------
-
-	      From here starts original gtkpod code
-
----------------------------------------------------------------------- */
-
-/* Return a Track structure with all information read from the mp3
-   file filled in */
-Track *mp3_get_file_info (gchar *name)
-{
-    Track *track = NULL;
-    File_Tag filetag;
-    MP3Info *mp3i=NULL;
-    FILE *file;
-    guchar *image_data = NULL;
-    gsize image_data_len = 0;
-
-    g_return_val_if_fail (name, NULL);
-
-    /* Attempt to open the file */
-    file = fopen (name, "r");
-    if (file)
-    {
-	mp3i = g_malloc0 (sizeof (MP3Info));
-	mp3i->filename = name;
-	mp3i->file = file;
-	get_mp3_info (mp3i);
-	mp3i->file = NULL;
-	fclose (file);
-    }
-    else
-    {
-	gchar *fbuf = charset_to_utf8 (name);
-    	gtkpod_warning(_("ERROR while opening file: '%s' (%s).\n"),
-		       fbuf, g_strerror(errno));
-	g_free (fbuf);
-	return NULL;
-    }
-
-    track = gp_track_new ();
-    track->filetype = g_strdup ("MPEG audio file");
-
-    if (prefs_get_int("readtags") && (id3_tag_read (name, &filetag) == TRUE))
-    {
-
-	if (filetag.album)
-	{
-	    track->album = filetag.album;
-	}
-
-	if (filetag.artist)
-	{
-	    track->artist = filetag.artist;
-	}
-
-	if (filetag.title)
-	{
-	    track->title = filetag.title;
-	}
-
-	if (filetag.genre)
-	{
-	    track->genre = filetag.genre;
-	}
-
-	if (filetag.composer)
-	{
-	    track->composer = filetag.composer;
-	}
-
-	if (filetag.comment)
-	{
-	    track->comment = filetag.comment;
-	}
-
-	if (filetag.podcasturl)
-	{
-	    track->podcasturl = filetag.podcasturl;
-	}
-
-	if (filetag.podcastrss)
-	{
-	    track->podcastrss = filetag.podcastrss;
-	}
-
-	if (filetag.subtitle)
-	{
-	    track->subtitle = filetag.subtitle;
-	}
-
-	if (filetag.description)
-	{
-	    track->description = filetag.description;
-	}
-
-	if (filetag.sort_artist)
-	{
-	    track->sort_artist = filetag.sort_artist;
-	}
-
-	if (filetag.sort_title)
-	{
-	    track->sort_title = filetag.sort_title;
-	}
-
-	if (filetag.sort_album)
-	{
-	    track->sort_album = filetag.sort_album;
-	}
-
-	if (filetag.sort_albumartist)
-	{
-	    track->sort_albumartist = filetag.sort_albumartist;
-	}
-
-	if (filetag.sort_composer)
-	{
-	    track->sort_composer = filetag.sort_composer;
-	}
-
-	if (filetag.year == NULL)
-	{
-	    track->year = 0;
-	}
-	else
-	{
-	    track->year = atoi(filetag.year);
-	    g_free (filetag.year);
-	}
-
-	if (filetag.trackstring == NULL)
-	{
-	    track->track_nr = 0;
-	}
-	else
-	{
-	    track->track_nr = atoi(filetag.trackstring);
-	    g_free (filetag.trackstring);
-	}
-
-	if (filetag.track_total == NULL)
-	{
-	    track->tracks = 0;
-	}
-	else
-	{
-	    track->tracks = atoi(filetag.track_total);
-	    g_free (filetag.track_total);
-	}
-	/* CD/disc number handling */
-	if (filetag.cdnostring == NULL)
-	{
-	    track->cd_nr = 0;
-	}
-	else
-	{
-	    track->cd_nr = atoi(filetag.cdnostring);
-	    g_free (filetag.cdnostring);
-	}
-	
-	if (filetag.cdno_total == NULL)
-	{
-	    track->cds = 0;
-	}
-	else
-	{
-	    track->cds = atoi(filetag.cdno_total);
-	    g_free (filetag.cdno_total);
-	}
-
-	if (filetag.compilation == NULL)
-	{
-	    track->compilation = 0;
-	}
-	else
-	{
-	    track->compilation = atoi(filetag.compilation);
-	    g_free (filetag.compilation);
-	}
-
-	if (filetag.BPM == NULL)
-	{
-	    track->BPM = 0;
-	}
-	else
-	{
-	    track->BPM = atoi(filetag.BPM);
-	    g_free (filetag.BPM);
-	}
-
-	if (filetag.lyrics)
-	{
-	    track->lyrics_flag = 0x01;
-	    g_free (filetag.lyrics);
-	}
-	else
-	{
-	    track->lyrics_flag = 0x00;
-	}
-    }
-
-    if (prefs_get_int("coverart_apic") &&
-	(id3_apic_read (name, &image_data, &image_data_len) == TRUE))
-    {
-	if (image_data)
-	{
-	    gp_track_set_thumbnails_from_data (track,
-					       image_data,
-					       image_data_len);
-	    g_free (image_data);
-	}
-    }
-
-    mp3_read_soundcheck (name, track);
-
-    mp3_read_gapless (name, track);
-
-#if LOCALDEBUG
-	printf("%s\n", name);
-    printf("\tpregap: %i\n", track->pregap);
-    printf("\tpostgap: %i\n", track->postgap);
-    printf("\tsamplecount: %li\n", track->samplecount);
-    printf("\tgaplessdata: %i\n", track->gapless_data);
-#endif
-
-
-    /* Get additional info (play time and bitrate */
-    if (mp3i)
-    {
-	track->tracklen = mp3i->milliseconds;
-	track->bitrate = (gint)(mp3i->vbr_average);
- 	track->samplerate = mp3file_header_frequency (&mp3i->header);
-	g_free (mp3i);
-    }
-    /* Fall back to xmms code if tracklen is 0 */
-    if (track->tracklen == 0)
-    {
-	track->tracklen = get_track_time (name);
-	if (track->tracklen)
-	    track->bitrate = (float)track->size*8/track->tracklen;
-    }
-
-    if (track->tracklen == 0)
-    {
-	/* Tracks with zero play length are ignored by iPod... */
-	gtkpod_warning (_("File \"%s\" has zero play length. Ignoring.\n"),
-			name);
-	gp_track_free (track);
-	track = NULL;
-    }
-    return track;
-}

Copied: gtkpod/tags/0.99.10-3/src/mp3file.c (from rev 243, gtkpod/trunk/src/mp3file.c)
===================================================================
--- gtkpod/tags/0.99.10-3/src/mp3file.c	                        (rev 0)
+++ gtkpod/tags/0.99.10-3/src/mp3file.c	2007-09-09 19:04:45 UTC (rev 245)
@@ -0,0 +1,2678 @@
+/* Time-stamp: <2007-06-26 00:39:11 jcs>
+|
+|  Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net>
+|  Part of the gtkpod project.
+| 
+|  URL: http://www.gtkpod.org/
+|  URL: http://gtkpod.sourceforge.net/
+|
+|  This program is free software; you can redistribute it and/or modify
+|  it under the terms of the GNU General Public License as published by
+|  the Free Software Foundation; either version 2 of the License, or
+|  (at your option) any later version.
+|
+|  This program is distributed in the hope that it will be useful,
+|  but WITHOUT ANY WARRANTY; without even the implied warranty of
+|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+|  GNU General Public License for more details.
+|
+|  You should have received a copy of the GNU General Public License
+|  along with this program; if not, write to the Free Software
+|  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+|
+|  iTunes and iPod are trademarks of Apple
+|
+|  This product is not supported/written/published by Apple!
+|
+|  $Id: mp3file.c 1591 2007-06-26 03:33:25Z tmzullinger $
+*/
+
+
+#define LOCALDEBUG 0
+
+
+/* The code in the first section of this file is taken from the
+ * mp3info (http://www.ibiblio.org/mp3info/) project. Only the code
+ * needed for the playlength calculation has been extracted. */
+
+/* The code in the second section of this file is taken from the
+ * mpg123 code used in xmms-1.2.7 (Input/mpg123). Only the code needed
+ * for the playlength calculation has been extracted. */
+
+/* The code in the last section of this file is original gtkpod
+ * code. */
+
+/****************
+ * Declarations *
+ ****************/
+
+#include <glib.h>
+#include <math.h>
+/*
+ * Description of each item of the TagList list
+ */
+typedef struct _File_Tag File_Tag;
+typedef struct _GainData GainData;
+typedef struct _GaplessData GaplessData;
+
+struct _File_Tag
+{
+    gchar *title;          /* Title of track */
+    gchar *artist;         /* Artist name */
+    gchar *album;          /* Album name */
+    gchar *year;           /* Year of track */
+    gchar *trackstring;    /* Position of track in the album */
+    gchar *track_total;    /* The number of tracks for the album (ex: 12/20) */
+    gchar *genre;          /* Genre of song */
+    gchar *comment;        /* Comment */
+    gchar *composer;	   /* Composer */
+    guint32 songlen;       /* Length of file in ms */
+    gchar *cdnostring;    /* Position of disc in the album */
+    gchar *cdno_total;    /* The number of discs in the album (ex: 1/2) */
+    gchar *compilation;   /* The track is a member of a compilation */
+    gchar *podcasturl;    /* The following are mainly used for podcasts */
+    gchar *sort_artist;
+    gchar *sort_title;
+    gchar *sort_album;
+    gchar *sort_albumartist;
+    gchar *sort_composer;
+    gchar *description;
+    gchar *podcastrss;
+    gchar *time_released;
+    gchar *subtitle;
+    gchar *BPM;           /* beats per minute */
+    gchar *lyrics;        /* does not appear to be the full lyrics --
+			     only used to set the flag 'lyrics_flag'
+			     of the Track structure */
+};
+
+
+struct _GainData
+{
+  guint32 peak_signal;	  /* LAME Peak Signal * 0x800000             */
+  gdouble radio_gain;	  /* RadioGain in dB
+			     (as defined by www.replaygain.org)      */
+  gdouble audiophile_gain;/* AudiophileGain in dB 
+			     (as defined by www.replaygain.org)      */
+  gboolean peak_signal_set;    /* has the peak signal been set?      */
+  gboolean radio_gain_set;     /* has the radio gain been set?       */
+  gboolean audiophile_gain_set;/* has the audiophile gain been set?  */
+};
+
+struct _GaplessData
+{
+    guint32 pregap;       /* number of pregap samples */
+    guint64 samplecount;  /* number of actual music samples */
+    guint32 postgap;      /* number of postgap samples */
+    guint32 gapless_data; /* number of bytes from the first sync frame to the 8th to last frame */
+};
+
+/* This code is taken from the mp3info code. Only the code needed for
+ * the playlength calculation has been extracted */
+
+/*
+    mp3tech.c - Functions for handling MP3 files and most MP3 data
+		structure manipulation.
+
+    Copyright (C) 2000-2001  Cedric Tefft <cedric at earthling.net>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+  ***************************************************************************
+
+  This file is based in part on:
+
+	* MP3Info 0.5 by Ricardo Cerqueira <rmc at rccn.net>
+	* MP3Stat 0.9 by Ed Sweetman <safemode at voicenet.com> and
+			 Johannes Overmann <overmann at iname.com>
+
+*/
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "mp3file.h"
+#include "charset.h"
+#include "itdb.h"
+#include "file.h"
+#include "misc.h"
+
+
+/* MIN_CONSEC_GOOD_FRAMES defines how many consecutive valid MP3 frames
+   we need to see before we decide we are looking at a real MP3 file */
+#define MIN_CONSEC_GOOD_FRAMES 4
+#define FRAME_HEADER_SIZE 4
+#define MIN_FRAME_SIZE 21
+
+enum VBR_REPORT { VBR_VARIABLE, VBR_AVERAGE, VBR_MEDIAN };
+
+typedef struct {
+    gulong sync;
+    guint  version;
+    guint  layer;
+    guint  crc;
+    guint  bitrate;
+    guint  freq;
+    guint  padding;
+    guint  extension;
+    guint  mode;
+    guint  mode_extension;
+    guint  copyright;
+    guint  original;
+    guint  emphasis;
+} MP3Header;
+
+typedef struct {
+    gchar *filename;
+    FILE *file;
+    off_t datasize;
+    gint header_isvalid;
+    MP3Header header;
+    gint id3_isvalid;
+    gint vbr;
+    float vbr_average;
+    gint milliseconds;
+    gint frames;
+    gint badframes;
+} MP3Info;
+
+/* This is for xmms code */
+static guint get_track_time(gchar *path);
+
+
+
+/* ------------------------------------------------------------
+
+   start of first section
+
+   ------------------------------------------------------------ */
+void get_mp3_info(MP3Info *mp3);
+
+gint frequencies[3][4] = {
+   {22050,24000,16000,50000},  /* MPEG 2.0 */
+   {44100,48000,32000,50000},  /* MPEG 1.0 */
+   {11025,12000,8000,50000}    /* MPEG 2.5 */
+};
+
+/* "0" added by JCS */
+gint bitrate[2][3][16] = {
+  { /* MPEG 2.0 */
+    {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,0},/* layer 1 */
+    {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0},     /* layer 2 */
+    {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0}      /* layer 3 */
+  },
+
+  { /* MPEG 1.0 */
+    {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},/* layer 1 */
+    {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0},   /* layer 2 */
+    {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}     /* layer 3 */
+  }
+};
+
+gint frame_size_index[] = {24000, 72000, 72000};
+
+
+gchar *mode_text[] = {
+   "stereo", "joint stereo", "dual channel", "mono"
+};
+
+gchar *emphasis_text[] = {
+  "none", "50/15 microsecs", "reserved", "CCITT J 17"
+};
+
+
+static gint mp3file_header_bitrate(MP3Header *h) {
+    return bitrate[h->version & 1][3-h->layer][h->bitrate];
+}
+
+
+static gint mp3file_header_frequency(MP3Header *h) {
+    return frequencies[h->version][h->freq];
+}
+
+
+gint frame_length(MP3Header *header) {
+	return header->sync == 0xFFE ?
+		    (frame_size_index[3-header->layer]*((header->version&1)+1)*
+		    mp3file_header_bitrate(header)/(float)mp3file_header_frequency(header))+
+		    header->padding : 1;
+}
+
+/* Get next MP3 frame header.
+   Return codes:
+   positive value = Frame Length of this header
+   0 = No, we did not retrieve a valid frame header
+*/
+gint get_header(FILE *file,MP3Header *header)
+{
+    guchar buffer[FRAME_HEADER_SIZE];
+    gint fl;
+
+    if(fread(&buffer,FRAME_HEADER_SIZE,1,file)<1) {
+	header->sync=0;
+	return 0;
+    }
+    header->sync=(((gint)buffer[0]<<4) | ((gint)(buffer[1]&0xE0)>>4));
+    if(buffer[1] & 0x10) header->version=(buffer[1] >> 3) & 1;
+		    else header->version=2;
+    header->layer=(buffer[1] >> 1) & 3;
+    if (header->layer == 0)
+    {
+	header->layer = 1; /* sanity added by JCS */
+    }
+    if((header->sync != 0xFFE) || (header->layer != 1)) {
+	header->sync=0;
+	return 0;
+    }
+    header->crc=buffer[1] & 1;
+    header->bitrate=(buffer[2] >> 4) & 0x0F;
+    header->freq=(buffer[2] >> 2) & 0x3;
+    header->padding=(buffer[2] >>1) & 0x1;
+    header->extension=(buffer[2]) & 0x1;
+    header->mode=(buffer[3] >> 6) & 0x3;
+    header->mode_extension=(buffer[3] >> 4) & 0x3;
+    header->copyright=(buffer[3] >> 3) & 0x1;
+    header->original=(buffer[3] >> 2) & 0x1;
+    header->emphasis=(buffer[3]) & 0x3;
+
+    return ((fl=frame_length(header)) >= MIN_FRAME_SIZE ? fl : 0);
+}
+
+gint sameConstant(MP3Header *h1, MP3Header *h2) {
+    if((*(guint*)h1) == (*(guint*)h2)) return 1;
+
+    if((h1->version       == h2->version         ) &&
+       (h1->layer         == h2->layer           ) &&
+       (h1->crc           == h2->crc             ) &&
+       (h1->freq          == h2->freq            ) &&
+       (h1->mode          == h2->mode            ) &&
+       (h1->copyright     == h2->copyright       ) &&
+       (h1->original      == h2->original        ) &&
+       (h1->emphasis      == h2->emphasis        ))
+		return 1;
+    else return 0;
+}
+
+
+gint get_first_header(MP3Info *mp3, long startpos)
+{
+  gint k, l=0,c;
+  MP3Header h, h2;
+  long valid_start=0;
+
+  fseek(mp3->file,startpos,SEEK_SET);
+  while (1) {
+     while((c=fgetc(mp3->file)) != 255 && (c != EOF));
+     if(c == 255) {
+	ungetc(c,mp3->file);
+	valid_start=ftell(mp3->file);
+	if((l=get_header(mp3->file,&h))) {
+	  fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
+	  for(k=1; (k < MIN_CONSEC_GOOD_FRAMES) && (mp3->datasize-ftell(mp3->file) >= FRAME_HEADER_SIZE); k++) {
+	    if(!(l=get_header(mp3->file,&h2))) break;
+	    if(!sameConstant(&h,&h2)) break;
+	    fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
+	  }
+	  if(k == MIN_CONSEC_GOOD_FRAMES) {
+		fseek(mp3->file,valid_start,SEEK_SET);
+		memcpy(&(mp3->header),&h2,sizeof(MP3Header));
+		mp3->header_isvalid=1;
+		return 1;
+	  }
+	}
+     } else {
+	return 0;
+     }
+   }
+
+  return 0;
+}
+
+
+/* get_next_header() - read header at current position or look for
+   the next valid header if there isn't one at the current position
+*/
+gint get_next_header(MP3Info *mp3)
+{
+  gint l=0,c,skip_bytes=0;
+  MP3Header h;
+
+   while(1) {
+     while((c=fgetc(mp3->file)) != 255 && (ftell(mp3->file) < mp3->datasize)) skip_bytes++;
+     if(c == 255) {
+	ungetc(c,mp3->file);
+	if((l=get_header(mp3->file,&h))) {
+	  if(skip_bytes) mp3->badframes++;
+	  fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
+	  return 15-h.bitrate;
+	} else {
+		skip_bytes += FRAME_HEADER_SIZE;
+	}
+     } else {
+	  if(skip_bytes) mp3->badframes++;
+	  return 0;
+     }
+  }
+}
+
+
+void get_mp3_info(MP3Info *mp3)
+{
+  gint frame_type[15]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+  float milliseconds=0,total_rate=0;
+  gint frames=0,frame_types=0,frames_so_far=0;
+  gint vbr_median=-1;
+  guint bitrate;
+  gint counter=0;
+  MP3Header header;
+  struct stat filestat;
+  off_t data_start=0;
+
+
+  stat(mp3->filename,&filestat);
+  mp3->datasize=filestat.st_size;
+
+  if(get_first_header(mp3,0L)) {
+      data_start=ftell(mp3->file);
+      while((bitrate=get_next_header(mp3))) {
+	  if (bitrate < 15)  /* sanity added by JCS */
+	      frame_type[15-bitrate]++;
+	  frames++;
+      }
+      memcpy(&header,&(mp3->header),sizeof(MP3Header));
+      for(counter=0;counter<15;counter++) {
+	  if(frame_type[counter]) {
+	      float header_bitrate; /* introduced by JCS to speed up */
+	      frame_types++;
+	      header.bitrate=counter;
+	      frames_so_far += frame_type[counter];
+	      header_bitrate = mp3file_header_bitrate(&header);
+	      if (header_bitrate != 0)
+		  milliseconds += (float)(8*frame_length(&header)*frame_type[counter])/header_bitrate;
+	      total_rate += header_bitrate*frame_type[counter];
+	      if((vbr_median == -1) && (frames_so_far >= frames/2))
+		  vbr_median=counter;
+	  }
+      }
+      mp3->milliseconds=(gint)(milliseconds+0.5);
+      mp3->header.bitrate=vbr_median;
+      mp3->vbr_average=total_rate/(float)frames;
+      mp3->frames=frames;
+      if(frame_types > 1) {
+	  mp3->vbr=1;
+      }
+  }
+}
+
+
+
+
+/* ------------------------------------------------------------
+
+	 xmms code
+
+
+   ------------------------------------------------------------ */
+
+/*
+|  Changed by Jorg Schuler <jcsjcs at users.sourceforge.net> to
+|  compile with the gtkpod project. 2003/04/01
+*/
+
+/* This code is taken from the mpg123 code used in xmms-1.2.7
+ * (Input/mpg123). Only the code needed for the playlength calculation
+ * has been extracted */
+
+#include "mp3file.h"
+#include <stdio.h>
+#include <string.h>
+
+#define FRAMES_FLAG     0x0001
+#define BYTES_FLAG      0x0002
+#define TOC_FLAG        0x0004
+#define VBR_SCALE_FLAG  0x0008
+
+#define         SBLIMIT                 32
+#define         SCALE_BLOCK             12
+#define         SSLIMIT                 18
+
+#define         MPG_MD_STEREO           0
+#define         MPG_MD_JOINT_STEREO     1
+#define         MPG_MD_DUAL_CHANNEL     2
+#define         MPG_MD_MONO             3
+#define MAXFRAMESIZE 1792
+#define real float
+
+struct bitstream_info
+{
+	int bitindex;
+	unsigned char *wordpointer;
+};
+
+struct bitstream_info bsi;
+
+real mpg123_muls[27][64];	/* also used by layer 1 */
+
+int tabsel_123[2][3][16] =
+{
+	{
+    {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,},
+       {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,},
+       {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,}},
+
+	{
+       {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256,},
+	    {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,},
+	    {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,}}
+};
+
+long mpg123_freqs[9] =
+{44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000};
+
+/*
+ * structure to receive extracted header
+ */
+typedef struct
+{
+	int frames;		/* total bit stream frames from Xing header data */
+	int bytes;		/* total bit stream bytes from Xing header data */
+	unsigned char toc[100];	/* "table of contents" */
+} xing_header_t;
+
+struct al_table
+{
+	short bits;
+	short d;
+};
+
+struct frame
+{
+	struct al_table *alloc;
+	int (*synth) (real *, int, unsigned char *, int *);
+	int (*synth_mono) (real *, unsigned char *, int *);
+#ifdef USE_3DNOW
+	void (*dct36)(real *,real *,real *,real *,real *);
+#endif
+	int stereo;
+	int jsbound;
+	int single;
+	int II_sblimit;
+	int down_sample_sblimit;
+	int lsf;
+	int mpeg25;
+	int down_sample;
+	int header_change;
+	int lay;
+	int (*do_layer) (struct frame * fr);
+	int error_protection;
+	int bitrate_index;
+	int sampling_frequency;
+	int padding;
+	int extension;
+	int mode;
+	int mode_ext;
+	int copyright;
+	int original;
+	int emphasis;
+	int framesize;		/* computed framesize */
+};
+
+static guint32 convert_to_header(guint8 * buf)
+{
+
+	return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
+}
+
+static int mpg123_head_check(unsigned long head)
+{
+	if ((head & 0xffe00000) != 0xffe00000)
+		return FALSE;
+	if (!((head >> 17) & 3))
+		return FALSE;
+	if (((head >> 12) & 0xf) == 0xf)
+		return FALSE;
+	if (!((head >> 12) & 0xf))
+		return FALSE;
+	if (((head >> 10) & 0x3) == 0x3)
+		return FALSE;
+	if (((head >> 19) & 1) == 1 && ((head >> 17) & 3) == 3 && ((head >> 16) & 1) == 1)
+		return FALSE;
+	if ((head & 0xffff0000) == 0xfffe0000)
+		return FALSE;
+
+	return TRUE;
+}
+
+
+/*
+ * the code a header and write the information
+ * into the frame structure
+ */
+static int mpg123_decode_header(struct frame *fr, unsigned long newhead)
+{
+    int ssize;
+
+	if (newhead & (1 << 20))
+	{
+		fr->lsf = (newhead & (1 << 19)) ? 0x0 : 0x1;
+		fr->mpeg25 = 0;
+	}
+	else
+	{
+		fr->lsf = 1;
+		fr->mpeg25 = 1;
+	}
+	fr->lay = 4 - ((newhead >> 17) & 3);
+	if (fr->mpeg25)
+	{
+		fr->sampling_frequency = 6 + ((newhead >> 10) & 0x3);
+	}
+	else
+		fr->sampling_frequency = ((newhead >> 10) & 0x3) + (fr->lsf * 3);
+	fr->error_protection = ((newhead >> 16) & 0x1) ^ 0x1;
+
+	fr->bitrate_index = ((newhead >> 12) & 0xf);
+	fr->padding = ((newhead >> 9) & 0x1);
+	fr->extension = ((newhead >> 8) & 0x1);
+	fr->mode = ((newhead >> 6) & 0x3);
+	fr->mode_ext = ((newhead >> 4) & 0x3);
+	fr->copyright = ((newhead >> 3) & 0x1);
+	fr->original = ((newhead >> 2) & 0x1);
+	fr->emphasis = newhead & 0x3;
+
+	fr->stereo = (fr->mode == MPG_MD_MONO) ? 1 : 2;
+
+	ssize = 0;
+
+	if (!fr->bitrate_index)
+		return (0);
+
+	switch (fr->lay)
+	{
+		case 1:
+/*			fr->do_layer = mpg123_do_layer1; */
+/*			mpg123_init_layer2();	/\* inits also shared tables with layer1 *\/ */
+			fr->framesize = (long) tabsel_123[fr->lsf][0][fr->bitrate_index] * 12000;
+			fr->framesize /= mpg123_freqs[fr->sampling_frequency];
+			fr->framesize = ((fr->framesize + fr->padding) << 2) - 4;
+			break;
+		case 2:
+/*			fr->do_layer = mpg123_do_layer2; */
+/*			mpg123_init_layer2();	/\* inits also shared tables with layer1 *\/ */
+			fr->framesize = (long) tabsel_123[fr->lsf][1][fr->bitrate_index] * 144000;
+			fr->framesize /= mpg123_freqs[fr->sampling_frequency];
+			fr->framesize += fr->padding - 4;
+			break;
+		case 3:
+/*			fr->do_layer = mpg123_do_layer3; */
+			if (fr->lsf)
+				ssize = (fr->stereo == 1) ? 9 : 17;
+			else
+				ssize = (fr->stereo == 1) ? 17 : 32;
+			if (fr->error_protection)
+				ssize += 2;
+			fr->framesize = (long) tabsel_123[fr->lsf][2][fr->bitrate_index] * 144000;
+			fr->framesize /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf);
+			fr->framesize = fr->framesize + fr->padding - 4;
+			break;
+		default:
+			return (0);
+	}
+	if(fr->framesize > MAXFRAMESIZE)
+		return 0;
+	return 1;
+}
+
+#define GET_INT32BE(b) \
+(i = (b[0] << 24) | (b[1] << 16) | b[2] << 8 | b[3], b += 4, i)
+
+static int mpg123_get_xing_header(xing_header_t * xing, unsigned char *buf)
+{
+	int i, head_flags;
+	int id, mode;
+
+	memset(xing, 0, sizeof(xing_header_t));
+
+	/* get selected MPEG header data */
+	id = (buf[1] >> 3) & 1;
+	mode = (buf[3] >> 6) & 3;
+	buf += 4;
+
+	/* Skip the sub band data */
+	if (id)
+	{
+		/* mpeg1 */
+		if (mode != 3)
+			buf += 32;
+		else
+			buf += 17;
+	}
+	else
+	{
+		/* mpeg2 */
+		if (mode != 3)
+			buf += 17;
+		else
+			buf += 9;
+	}
+
+	if (strncmp(buf, "Xing", 4))
+		return 0;
+	buf += 4;
+
+	head_flags = GET_INT32BE(buf);
+
+	if (head_flags & FRAMES_FLAG)
+		xing->frames = GET_INT32BE(buf);
+	if (xing->frames < 1)
+		xing->frames = 1;
+	if (head_flags & BYTES_FLAG)
+		xing->bytes = GET_INT32BE(buf);
+
+	if (head_flags & TOC_FLAG)
+	{
+		for (i = 0; i < 100; i++)
+			xing->toc[i] = buf[i];
+		buf += 100;
+	}
+
+#ifdef XING_DEBUG
+	for (i = 0; i < 100; i++)
+	{
+		if ((i % 10) == 0)
+			fprintf(stderr, "\n");
+		fprintf(stderr, " %3d", xing->toc[i]);
+	}
+#endif
+
+	return 1;
+}
+
+static double mpg123_compute_tpf(struct frame *fr)
+{
+	const int bs[4] = {0, 384, 1152, 1152};
+	double tpf;
+
+	tpf = bs[fr->lay];
+	tpf /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf);
+	return tpf;
+}
+
+static double mpg123_compute_bpf(struct frame *fr)
+{
+	double bpf;
+
+	switch (fr->lay)
+	{
+		case 1:
+			bpf = tabsel_123[fr->lsf][0][fr->bitrate_index];
+			bpf *= 12000.0 * 4.0;
+			bpf /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf);
+			break;
+		case 2:
+		case 3:
+			bpf = tabsel_123[fr->lsf][fr->lay - 1][fr->bitrate_index];
+			bpf *= 144000;
+			bpf /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf);
+			break;
+		default:
+			bpf = 1.0;
+	}
+
+	return bpf;
+}
+
+
+unsigned int mpg123_getbits(int number_of_bits)
+{
+	unsigned long rval;
+
+#ifdef DEBUG_GETBITS
+	fprintf(stderr, "g%d", number_of_bits);
+#endif
+
+	if(!number_of_bits)
+		return 0;
+
+#if 0
+	check_buffer_range(number_of_bits + bsi.bitindex);
+#endif
+
+	{
+		rval = bsi.wordpointer[0];
+		rval <<= 8;
+		rval |= bsi.wordpointer[1];
+		rval <<= 8;
+		rval |= bsi.wordpointer[2];
+
+		rval <<= bsi.bitindex;
+		rval &= 0xffffff;
+
+		bsi.bitindex += number_of_bits;
+
+		rval >>= (24-number_of_bits);
+
+		bsi.wordpointer += (bsi.bitindex >> 3);
+		bsi.bitindex &= 7;
+	}
+
+#ifdef DEBUG_GETBITS
+	fprintf(stderr,":%x ",rval);
+#endif
+
+	return rval;
+}
+
+
+void I_step_one(unsigned int balloc[], unsigned int scale_index[2][SBLIMIT], struct frame *fr)
+{
+	unsigned int *ba = balloc;
+	unsigned int *sca = (unsigned int *) scale_index;
+
+	if (fr->stereo)
+	{
+		int i;
+		int jsbound = fr->jsbound;
+
+		for (i = 0; i < jsbound; i++)
+		{
+			*ba++ = mpg123_getbits(4);
+			*ba++ = mpg123_getbits(4);
+		}
+		for (i = jsbound; i < SBLIMIT; i++)
+			*ba++ = mpg123_getbits(4);
+
+		ba = balloc;
+
+		for (i = 0; i < jsbound; i++)
+		{
+			if ((*ba++))
+				*sca++ = mpg123_getbits(6);
+			if ((*ba++))
+				*sca++ = mpg123_getbits(6);
+		}
+		for (i = jsbound; i < SBLIMIT; i++)
+			if ((*ba++))
+			{
+				*sca++ = mpg123_getbits(6);
+				*sca++ = mpg123_getbits(6);
+			}
+	}
+	else
+	{
+		int i;
+
+		for (i = 0; i < SBLIMIT; i++)
+			*ba++ = mpg123_getbits(4);
+		ba = balloc;
+		for (i = 0; i < SBLIMIT; i++)
+			if ((*ba++))
+				*sca++ = mpg123_getbits(6);
+	}
+}
+
+void I_step_two(real fraction[2][SBLIMIT], unsigned int balloc[2 * SBLIMIT],
+		unsigned int scale_index[2][SBLIMIT], struct frame *fr)
+{
+	int i, n;
+	int smpb[2 * SBLIMIT];	/* values: 0-65535 */
+	int *sample;
+	register unsigned int *ba;
+	register unsigned int *sca = (unsigned int *) scale_index;
+
+	if (fr->stereo)
+	{
+		int jsbound = fr->jsbound;
+		register real *f0 = fraction[0];
+		register real *f1 = fraction[1];
+
+		ba = balloc;
+		for (sample = smpb, i = 0; i < jsbound; i++)
+		{
+			if ((n = *ba++))
+				*sample++ = mpg123_getbits(n + 1);
+			if ((n = *ba++))
+				*sample++ = mpg123_getbits(n + 1);
+		}
+		for (i = jsbound; i < SBLIMIT; i++)
+			if ((n = *ba++))
+				*sample++ = mpg123_getbits(n + 1);
+
+		ba = balloc;
+		for (sample = smpb, i = 0; i < jsbound; i++)
+		{
+			if ((n = *ba++))
+				*f0++ = (real) (((-1) << n) + (*sample++) + 1) * mpg123_muls[n + 1][*sca++];
+			else
+				*f0++ = 0.0;
+			if ((n = *ba++))
+				*f1++ = (real) (((-1) << n) + (*sample++) + 1) * mpg123_muls[n + 1][*sca++];
+			else
+				*f1++ = 0.0;
+		}
+		for (i = jsbound; i < SBLIMIT; i++)
+		{
+			if ((n = *ba++))
+			{
+				real samp = (((-1) << n) + (*sample++) + 1);
+
+				*f0++ = samp * mpg123_muls[n + 1][*sca++];
+				*f1++ = samp * mpg123_muls[n + 1][*sca++];
+			}
+			else
+				*f0++ = *f1++ = 0.0;
+		}
+		for (i = fr->down_sample_sblimit; i < 32; i++)
+			fraction[0][i] = fraction[1][i] = 0.0;
+	}
+	else
+	{
+		register real *f0 = fraction[0];
+
+		ba = balloc;
+		for (sample = smpb, i = 0; i < SBLIMIT; i++)
+			if ((n = *ba++))
+				*sample++ = mpg123_getbits(n + 1);
+		ba = balloc;
+		for (sample = smpb, i = 0; i < SBLIMIT; i++)
+		{
+			if ((n = *ba++))
+				*f0++ = (real) (((-1) << n) + (*sample++) + 1) * mpg123_muls[n + 1][*sca++];
+			else
+				*f0++ = 0.0;
+		}
+		for (i = fr->down_sample_sblimit; i < 32; i++)
+			fraction[0][i] = 0.0;
+	}
+}
+
+static guint get_track_time_file(FILE * file)
+{
+	guint32 head;
+	guchar tmp[4], *buf;
+	struct frame frm;
+	xing_header_t xing_header;
+	double tpf, bpf;
+	guint32 len;
+
+	if (!file)
+		return -1;
+
+	fseek(file, 0, SEEK_SET);
+	if (fread(tmp, 1, 4, file) != 4)
+		return 0;
+	head = convert_to_header(tmp);
+	while (!mpg123_head_check(head))
+	{
+		head <<= 8;
+		if (fread(tmp, 1, 1, file) != 1)
+			return 0;
+		head |= tmp[0];
+	}
+	if (mpg123_decode_header(&frm, head))
+	{
+		buf = g_malloc(frm.framesize + 4);
+		fseek(file, -4, SEEK_CUR);
+		fread(buf, 1, frm.framesize + 4, file);
+		tpf = mpg123_compute_tpf(&frm);
+		if (mpg123_get_xing_header(&xing_header, buf))
+		{
+			g_free(buf);
+			return ((guint) (tpf * xing_header.frames * 1000));
+		}
+		g_free(buf);
+		bpf = mpg123_compute_bpf(&frm);
+		fseek(file, 0, SEEK_END);
+		len = ftell(file);
+		fseek(file, -128, SEEK_END);
+		fread(tmp, 1, 3, file);
+		if (!strncmp(tmp, "TAG", 3))
+			len -= 128;
+		return ((guint) ((guint)(len / bpf) * tpf * 1000));
+	}
+	return 0;
+}
+
+static guint get_track_time (gchar *path)
+{
+    guint result = 0;
+
+    if (path)
+    {
+	FILE *file = fopen (path, "r");
+	result = get_track_time_file (file);
+	if (file) fclose (file);
+    }
+    return result;
+}
+
+
+/* libid3tag stuff */
+
+#include <id3tag.h>
+#include "prefs.h"
+
+#ifndef ID3_FRAME_GROUP
+#define ID3_FRAME_GROUP "TPE2"
+#endif
+
+
+
+static const gchar* id3_get_binary (struct id3_tag *tag,
+				    char *frame_name,
+				    id3_length_t *len,
+				    int index)
+{
+    const id3_byte_t *binary = NULL;
+    struct id3_frame *frame;
+    union id3_field *field;
+
+    g_return_val_if_fail (len, NULL);
+
+    *len = 0;
+
+    frame = id3_tag_findframe (tag, frame_name, index);
+#if LOCALDEBUG
+    printf ("frame: %p\n", frame); 
+#endif
+
+    if (!frame) return NULL;
+
+#if LOCALDEBUG
+    printf (" nfields: %d\n", frame->nfields);
+    if (strncmp (frame_name, "APIC",  4) == 0)
+    {
+	field = id3_frame_field (frame, 2);
+	printf (" picture type: %ld\n", field->number.value);
+    }
+#endif
+
+
+#if 0
+/*-----------------*/
+/* just to show that this field (before last) contains the d8 ff e0 ff
+   part of the start of a jpeg file when the coverart war embedded by iTunes */
+
+    const id3_ucs4_t *string = NULL;
+    gchar *raw = NULL;
+
+    /* The last field contains the data */
+    field = id3_frame_field (frame, frame->nfields-2);
+
+#if LOCALDEBUG
+     printf (" field: %p\n", field);
+#endif
+
+    if (!field) return NULL;
+
+#if LOCALDEBUG
+     printf (" type: %d\n", field->type);
+#endif
+
+    switch (field->type)
+    {
+    case ID3_FIELD_TYPE_STRING:
+	string = id3_field_getstring (field);
+	break;
+    default:
+	break;
+    }
+  
+    /* ISO_8859_1 is just a "marker" -- most people just drop
+       whatever coding system they are using into it, so we use
+       charset_to_utf8() to convert to utf8 */
+
+    if (string)
+    {
+	raw = id3_ucs4_latin1duplicate (string);
+    }
+
+
+#if LOCALDEBUG
+    {
+	FILE *file;
+	printf (" string len: %d\n", raw?strlen(raw):0);
+	file = fopen ("/tmp/folder1.jpg", "w");
+	fwrite (raw, 1, raw?strlen(raw):0, file);
+	fclose (file);
+    }
+#endif
+    g_free (raw);
+
+/*-----------------*/
+#endif
+
+    /* The last field contains the data */
+    field = id3_frame_field (frame, frame->nfields-1);
+
+#if LOCALDEBUG
+     printf (" field: %p\n", field);
+#endif
+
+    if (!field) return NULL;
+
+#if LOCALDEBUG
+     printf (" type: %d\n", field->type);
+#endif
+
+    switch (field->type)
+    {
+    case ID3_FIELD_TYPE_BINARYDATA:
+	binary = id3_field_getbinarydata(field, len);
+	break;
+    default:
+	break;
+    }
+
+#if LOCALDEBUG
+    {
+	FILE *file;
+	printf (" binary len: %ld\n", *len);
+	file = fopen ("/tmp/folder2.jpg", "w");
+	fwrite (binary, 1, *len, file);
+	fclose (file);
+    }
+#endif
+
+
+
+    return binary;
+}
+
+
+
+static gchar* id3_get_string (struct id3_tag *tag, char *frame_name)
+{
+    const id3_ucs4_t *string = NULL;
+    const id3_byte_t *binary = NULL;
+    id3_length_t len = 0;
+    struct id3_frame *frame;
+    union id3_field *field;
+    gchar *utf8 = NULL;
+    enum id3_field_textencoding encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;
+
+    frame = id3_tag_findframe (tag, frame_name, 0);
+#if LOCALDEGUB
+    printf ("frame: %p\n", frame); 
+#endif
+
+    if (!frame) return NULL;
+
+    /* Find the encoding used for the field */
+    field = id3_frame_field (frame, 0);
+#if LOCALDEBUG
+    printf ("field: %p\n", field); 
+    printf ("type: %d\n", id3_field_type (field));
+#endif
+
+    if (field && (id3_field_type (field) == ID3_FIELD_TYPE_TEXTENCODING))
+    {
+	encoding = field->number.value;
+#if LOCALDEBUG
+	printf ("encoding: %d\n", encoding);
+#endif
+    }
+
+    /* The last field contains the data */
+    field = id3_frame_field (frame, frame->nfields-1);
+
+#if LOCALDEBUG
+     printf ("field: %p\n", field);
+#endif
+
+    if (!field) return NULL;
+
+#if LOCALDEBUG
+     printf ("type: %d\n", field->type);
+#endif
+
+
+    switch (field->type)
+    {
+    case ID3_FIELD_TYPE_STRINGLIST:
+	string = id3_field_getstrings (field, 0);
+	break;
+    case ID3_FIELD_TYPE_STRINGFULL:
+	string = id3_field_getfullstring (field);
+	break;
+    case ID3_FIELD_TYPE_BINARYDATA:
+	binary = id3_field_getbinarydata(field, &len);
+#if LOCALDEBUG
+	printf ("len: %ld\nbinary: %s\n", len, binary+1);
+#endif
+	if (len > 0)
+	    return charset_to_utf8 (binary+1);
+	break;
+    default:
+	break;
+    }
+
+/*     printf ("string: %p\n", string); */
+
+    if (!string) return NULL;
+
+    if (strcmp (frame_name, ID3_FRAME_GENRE) == 0)
+       string = id3_genre_name (string);
+
+    if (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1)
+    {
+	/* ISO_8859_1 is just a "marker" -- most people just drop
+	   whatever coding system they are using into it, so we use
+	   charset_to_utf8() to convert to utf8 */
+	id3_latin1_t *raw = id3_ucs4_latin1duplicate (string);
+	utf8 = charset_to_utf8 (raw);
+	g_free (raw);
+    }
+    else
+    {
+	/* Standard unicode is being used -- we won't have to worry
+	   about charsets then. */
+	utf8 = id3_ucs4_utf8duplicate (string);
+    }
+    return utf8;
+}
+
+static void id3_set_string (struct id3_tag *tag,
+			    const char *frame_name,
+			    const char *data,
+			    enum id3_field_textencoding encoding)
+{
+    int res;
+    struct id3_frame *frame;
+    union id3_field *field;
+    id3_ucs4_t *ucs4;
+
+    /* clear the frame, because of bug in libid3tag see
+       http://www.mars.org/mailman/public/mad-dev/2004-October/001113.html
+    */
+    while ((frame = id3_tag_findframe (tag, frame_name, 0)))
+    {
+	id3_tag_detachframe (tag, frame);
+        id3_frame_delete (frame);
+    }
+
+    if ((data == NULL) || (strlen(data) == 0))
+	return;
+
+    frame = id3_frame_new (frame_name);
+    id3_tag_attachframe (tag, frame);
+
+    /* Use the specified text encoding */
+    field = id3_frame_field (frame, 0);
+    id3_field_settextencoding(field, encoding);
+   
+    if (strcmp (frame_name, ID3_FRAME_COMMENT) == 0)
+    {
+	field = id3_frame_field (frame, 3);
+	field->type = ID3_FIELD_TYPE_STRINGFULL;
+    }
+    else
+    {
+	field = id3_frame_field (frame, 1);
+	field->type = ID3_FIELD_TYPE_STRINGLIST;
+    }
+
+
+    /* maybe could be optimized see
+       http://www.mars.org/mailman/public/mad-dev/2002-October/000739.html
+    */
+    if (strcmp (frame_name, ID3_FRAME_GENRE) == 0)
+    {
+	id3_ucs4_t *tmp_ucs4 = id3_utf8_ucs4duplicate ((id3_utf8_t *)data);
+	int index = id3_genre_number (tmp_ucs4);
+	if (index != -1)
+	{
+	    /* valid genre -- simply store the genre number */
+	    gchar *tmp = g_strdup_printf("%d", index);
+	    ucs4 = id3_latin1_ucs4duplicate (tmp);
+	    g_free (tmp);
+	}
+	else
+	{
+	    /* oups -- not a valid genre -- save the entire genre string */
+	    if (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1)
+	    {
+		/* we read 'ISO_8859_1' to stand for 'any locale
+		   charset' -- most programs seem to work that way */
+		id3_latin1_t *raw = charset_from_utf8 (data);
+		ucs4 = id3_latin1_ucs4duplicate (raw);
+		g_free (raw);
+	    }
+	    else
+	    {
+		/* Yeah! We use unicode encoding and won't have to
+		   worry about charsets */
+		ucs4 = tmp_ucs4;
+		tmp_ucs4 = NULL;
+	    }
+	}
+	g_free (tmp_ucs4);
+    }
+    else
+    {
+	if (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1)
+	{
+	    /* we read 'ISO_8859_1' to stand for 'any locale charset'
+	       -- most programs seem to work that way */
+	    id3_latin1_t *raw = charset_from_utf8 (data);
+	    ucs4 = id3_latin1_ucs4duplicate (raw);
+	    g_free (raw);
+	}
+	else
+	{
+	    /* Yeah! We use unicode encoding and won't have to
+	       worry about charsets */
+	    ucs4 = id3_utf8_ucs4duplicate ((id3_utf8_t *)data);
+	}
+    }
+
+    if (strcmp (frame_name, ID3_FRAME_COMMENT) == 0)
+	res = id3_field_setfullstring (field, ucs4);
+    else
+	res = id3_field_setstrings (field, 1, &ucs4);
+
+    g_free (ucs4);
+
+    if (res != 0)
+	g_print(_("Error setting ID3 field: %s\n"), frame_name);
+}
+
+
+/***
+ * Reads id3v1.x / id3v2 apic data
+ * @returns: TRUE on success, else FALSE.
+ */
+static gboolean id3_apic_read (gchar *filename,
+			       guchar **image_data, gsize *image_data_len)
+{
+    struct id3_file *id3file;
+    struct id3_tag *id3tag;
+
+    g_return_val_if_fail (filename, FALSE);
+    g_return_val_if_fail (image_data, FALSE);
+    g_return_val_if_fail (image_data_len, FALSE);
+
+    *image_data = NULL;
+    *image_data_len = 0;
+
+    if (!(id3file = id3_file_open (filename, ID3_FILE_MODE_READONLY)))
+    {
+	gchar *fbuf = charset_to_utf8 (filename);
+	g_print(_("ERROR while opening file: '%s' (%s).\n"),
+		fbuf, g_strerror(errno));
+	g_free (fbuf);
+	return FALSE;
+    }
+
+    if ((id3tag = id3_file_tag(id3file)))
+    {
+	id3_length_t len;
+	const guchar *coverart = NULL;
+	int i;
+	struct id3_frame *frame;
+
+	/* Loop through APIC tags and set coverart.  The picture type should be
+	 * 3 -- Cover (front), but iTunes has been known to use 0 -- Other. */
+	for (i = 0; (frame = id3_tag_findframe(id3tag, "APIC", i)) != NULL; i++)
+	{
+	    union id3_field *field = id3_frame_field (frame, 2);
+	    int pictype = field->number.value;
+/*	    printf ("%s: found apic type %d\n", filename, pictype);*/
+
+	    /* We'll prefer type 3 (cover) over type 0 (other) */
+	    if (pictype == 3)
+	    {
+		coverart = id3_get_binary (id3tag, "APIC", &len, i);
+		break;
+	    }
+	    if ((pictype == 0) && !coverart)
+	    {
+		coverart = id3_get_binary (id3tag, "APIC", &len, i);
+	    }
+	}
+
+	if (coverart)
+	{   /* I guess iTunes is doing something wrong -- the
+	     * beginning of the coverart data ends up in a different
+	       field... We'll just add the missing data manually. */
+	    const guchar itunes_broken_jfif_marker[] =
+		{ 0x10, 'J', 'F', 'I', 'F'};
+	    if (len >= 5)
+	    {
+		if (strncmp (itunes_broken_jfif_marker, coverart,  5) == 0)
+		{
+		    const guchar itunes_missing_header[] =
+			{ 0xff, 0xd8, 0xff, 0xe0, 0x00 };
+		    *image_data = g_malloc (len+5);
+		    memcpy (*image_data, itunes_missing_header, 5);
+		    memcpy ((*image_data)+5, coverart, len);
+		    *image_data_len = len+5;
+		}
+	    }
+	    if (!*image_data)
+	    {
+		*image_data = g_malloc (len);
+		memcpy (*image_data, coverart, len);
+		*image_data_len = len;
+	    }
+#if LOCALDEBUG
+	    if (*image_data)
+	    {
+		FILE *file;
+		file = fopen ("/tmp/folder.jpg", "w");
+		fwrite (*image_data, 1, *image_data_len, file);
+		fclose (file);
+	    }
+#endif
+	}    
+    }
+    id3_file_close (id3file);
+    return TRUE;
+}
+
+/***
+ * Reads id3v1.x / id3v2 tag and load data into the Id3tag structure.
+ * If a tag entry exists (ex: title), we allocate memory, else value
+ * stays to NULL
+ * @returns: TRUE on success, else FALSE.
+ */
+gboolean id3_tag_read (gchar *filename, File_Tag *tag)
+{
+    struct id3_file *id3file;
+    struct id3_tag *id3tag;
+    gchar* string;
+    gchar* string2;
+
+    g_return_val_if_fail (filename, FALSE);
+    g_return_val_if_fail (tag, FALSE);
+
+    memset (tag, 0, sizeof (File_Tag));
+
+    if (!(id3file = id3_file_open (filename, ID3_FILE_MODE_READONLY)))
+    {
+	gchar *fbuf = charset_to_utf8 (filename);
+	g_print(_("ERROR while opening file: '%s' (%s).\n"),
+		fbuf, g_strerror(errno));
+	g_free (fbuf);
+	return FALSE;
+    }
+
+    if ((id3tag = id3_file_tag(id3file)))
+    {
+	tag->title = id3_get_string (id3tag, ID3_FRAME_TITLE);
+	tag->artist = id3_get_string (id3tag, ID3_FRAME_GROUP);
+	if (!tag->artist || !*tag->artist)
+	{
+	    g_free (tag->artist);
+	    tag->artist = id3_get_string (id3tag, ID3_FRAME_ARTIST);
+	}
+	tag->album = id3_get_string (id3tag, ID3_FRAME_ALBUM);
+	tag->year = id3_get_string (id3tag, ID3_FRAME_YEAR);
+	tag->composer = id3_get_string (id3tag, "TCOM");
+	tag->comment = id3_get_string (id3tag, ID3_FRAME_COMMENT);
+	tag->genre = id3_get_string (id3tag, ID3_FRAME_GENRE);
+	tag->compilation = id3_get_string (id3tag, "TCMP");
+	tag->subtitle = id3_get_string (id3tag, "TIT3");
+	tag->lyrics = id3_get_string (id3tag, "USLT");
+	tag->podcasturl = id3_get_string (id3tag, "YTID");
+	tag->podcastrss = id3_get_string (id3tag, "YWFD");
+	tag->description = id3_get_string (id3tag, "YTDS");
+	tag->time_released = id3_get_string (id3tag, "YTDR");
+	tag->BPM = id3_get_string (id3tag, "TBPM");
+	tag->sort_artist = id3_get_string (id3tag, "TSOP");
+	tag->sort_album = id3_get_string (id3tag, "TSOA");
+	tag->sort_title = id3_get_string (id3tag, "TSOT");
+	tag->sort_albumartist = id3_get_string (id3tag, "TSO2");
+	tag->sort_composer = id3_get_string (id3tag, "TSOC");
+
+	string = id3_get_string (id3tag, "TLEN");
+	if (string)
+	{
+	    tag->songlen = (guint32) strtoul (string, 0, 10);
+	    g_free (string);
+	}
+
+	string = id3_get_string (id3tag, ID3_FRAME_TRACK);
+	if (string)
+	{
+	    string2 = strchr(string,'/');
+	    if (string2)
+	    {
+		tag->track_total = g_strdup_printf ("%.2d", atoi (string2+1));
+		*string2 = '\0';
+	    }
+	    tag->trackstring = g_strdup_printf ("%.2d", atoi (string));
+	    g_free(string);
+	}
+	
+	/* CD/disc number tag handling */
+	string = id3_get_string (id3tag, "TPOS");
+	if (string)
+	{
+	    string2 = strchr(string,'/');
+	    if (string2)
+	    {
+		tag->cdno_total = g_strdup_printf ("%.2d", atoi (string2+1));
+		*string2 = '\0';
+	    }
+	    tag->cdnostring = g_strdup_printf ("%.2d", atoi (string));
+	    g_free(string);
+	}
+    }
+
+    id3_file_close (id3file);
+    return TRUE;
+}
+
+
+
+static enum id3_field_textencoding get_encoding_of (struct id3_tag *tag, const char *frame_name)
+{
+    struct id3_frame *frame;
+    enum id3_field_textencoding encoding = -1;
+
+    frame = id3_tag_findframe (tag, frame_name, 0);
+    if (frame)
+    {
+	union id3_field *field = id3_frame_field (frame, 0);
+	if (field && (id3_field_type (field) == ID3_FIELD_TYPE_TEXTENCODING))
+	    encoding = field->number.value;
+    }
+    return encoding;
+}
+
+/* Find out which encoding is being used. If in doubt, return
+ * latin1. This code assumes that the same encoding is used in all
+ * fields.  */
+static enum id3_field_textencoding get_encoding (struct id3_tag *tag)
+{
+    enum id3_field_textencoding enc;
+
+    enc = get_encoding_of (tag, ID3_FRAME_TITLE);
+    if (enc != -1) return enc;
+    enc = get_encoding_of (tag, ID3_FRAME_ARTIST);
+    if (enc != -1) return enc;
+    enc = get_encoding_of (tag, ID3_FRAME_ALBUM);
+    if (enc != -1) return enc;
+    enc = get_encoding_of (tag, "TCOM");
+    if (enc != -1) return enc;
+    enc = get_encoding_of (tag, ID3_FRAME_COMMENT);
+    if (enc != -1) return enc;
+    enc = get_encoding_of (tag, ID3_FRAME_YEAR);
+    if (enc != -1) return enc;
+    return ID3_FIELD_TEXTENCODING_ISO_8859_1;
+}
+
+
+/* I'm not really sure about this: The original TAG identifier was
+   "TID", but no matter what I do I end up writing "YTID" */
+void set_uncommon_tag (struct id3_tag *id3tag,
+		       const gchar *id,
+		       const gchar *text,
+		       enum id3_field_textencoding encoding)
+{
+#if 0
+    struct id3_frame *frame;
+
+    frame = id3_tag_findframe (id3tag, id, 0);
+	union id3_field *field;
+	frame->flags = 0;
+	field = id3_frame_field (frame, 0);
+	    if (field)
+	    {
+		string1 = g_strdup_printf ("%c%s", '\0',
+					   track->podcasturl);
+		id3_field_setbinarydata (field, string1,
+					 strlen(track->podcasturl)+1);
+		g_free (string1);
+	    }
+
+#endif
+}
+
+
+
+/**
+ * Write the ID3 tags to the file.
+ * @returns: TRUE on success, else FALSE.
+ */
+gboolean mp3_write_file_info (gchar *filename, Track *track)
+{
+    struct id3_tag* id3tag;
+    struct id3_file* id3file;
+    gint error = 0;
+
+    id3file = id3_file_open (filename, ID3_FILE_MODE_READWRITE);
+    if (!id3file)
+    {
+	gchar *fbuf = charset_to_utf8 (filename);
+	g_print(_("ERROR while opening file: '%s' (%s).\n"),
+		fbuf, g_strerror(errno));
+	g_free (fbuf);
+	return FALSE;
+    }
+
+    if ((id3tag = id3_file_tag(id3file)))
+    {
+	char *string1;
+
+	enum id3_field_textencoding encoding;
+
+	/* use the same coding as before... */
+	encoding = get_encoding (id3tag);
+	/* ...unless it's ISO_8859_1 and prefs say we should use
+	   unicode (i.e. ID3v2.4) */
+	if (prefs_get_int("id3_write_id3v24") &&
+	    (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1))
+	    encoding = ID3_FIELD_TEXTENCODING_UTF_8;
+
+	/* always render id3v1 to prevent dj studio from crashing */
+	id3_tag_options(id3tag, ID3_TAG_OPTION_ID3V1, ~0);
+
+        /* turn off frame compression and crc information to let
+	   itunes read tags see
+	   http://www.mars.org/mailman/public/mad-dev/2002-October/000742.html
+	*/
+	id3_tag_options(id3tag, ID3_TAG_OPTION_COMPRESSION, 0);
+	id3_tag_options(id3tag, ID3_TAG_OPTION_CRC, 0);
+
+	id3_set_string (id3tag, ID3_FRAME_TITLE, track->title, encoding);
+	id3_set_string (id3tag, ID3_FRAME_ARTIST, track->artist, encoding);
+	id3_set_string (id3tag, ID3_FRAME_ALBUM, track->album, encoding);
+	id3_set_string (id3tag, ID3_FRAME_GENRE, track->genre, encoding);
+	id3_set_string (id3tag, ID3_FRAME_COMMENT, track->comment, encoding);
+	id3_set_string (id3tag, "TIT3", track->subtitle, encoding);
+	id3_set_string (id3tag, "TSOP", track->sort_artist, encoding);
+	id3_set_string (id3tag, "TSOA", track->sort_album, encoding);
+	id3_set_string (id3tag, "TSOT", track->sort_title, encoding);
+	id3_set_string (id3tag, "TSO2", track->sort_albumartist, encoding);
+	id3_set_string (id3tag, "TSOC", track->sort_composer, encoding);
+
+	set_uncommon_tag (id3tag, "YTID", track->podcasturl, encoding);
+	set_uncommon_tag (id3tag, "YTDS", track->description, encoding);
+	set_uncommon_tag (id3tag, "YWFD", track->podcastrss, encoding);
+
+	id3_set_string (id3tag, "TCOM", track->composer, encoding);
+
+	string1 = g_strdup_printf("%d", track->year);
+	id3_set_string(id3tag, ID3_FRAME_YEAR, string1, encoding);
+	g_free(string1);
+
+	string1 = g_strdup_printf("%d", track->BPM);
+	id3_set_string(id3tag, "TBPM", string1, encoding);
+	g_free(string1);
+
+	if (track->tracks)
+	    string1 = g_strdup_printf ("%d/%d",
+				       track->track_nr, track->tracks);
+	else
+	    string1 = g_strdup_printf ("%d", track->track_nr);
+	id3_set_string (id3tag, ID3_FRAME_TRACK, string1, encoding);
+	g_free(string1);
+
+	if (track->cds)
+	    string1 = g_strdup_printf ("%d/%d",
+				       track->cd_nr, track->cds);
+	else
+	    string1 = g_strdup_printf ("%d", track->cd_nr);
+	id3_set_string (id3tag, "TPOS", string1, encoding);
+	g_free(string1);
+        
+       string1 = g_strdup_printf ("%d", track->compilation);
+       id3_set_string (id3tag, "TCMP", string1, encoding);
+       g_free(string1);
+    } 
+
+    if (id3_file_update(id3file) != 0)
+    {
+	gchar *fbuf = charset_to_utf8 (filename);
+	g_print(_("ERROR while writing tag to file: '%s' (%s).\n"),
+		fbuf, g_strerror(errno));
+	g_free (fbuf);
+	return FALSE;
+    }
+
+    id3_file_close (id3file);
+
+    if (error) return FALSE;
+    else       return TRUE;
+}
+
+
+/*
+ * Code to read the ReplayGain Values stored by LAME in its own tag.
+ *
+ * Most of the relevant information has been extracted from them LAME sources
+ * (http://lame.sourceforge.net/).
+ * The "Mp3 info Tag rev 1 specifications - draft 0"
+ * (http://gabriel.mp3-tech.org/mp3infotag.html) by Gabriel Bouvigne describes
+ * the actual Tag (except for small changes).
+ * Details on the actual ReplayGain fields have been obtained from
+ * http://www.replaygain.org .
+ *
+ * Apart from that, some information has been derived from phwip's LameTag
+ * (http://www.silisoftware.com/applets/?scriptname=LameTag)
+ *
+ * 
+ * Code to read the ReplayGain Values stored in an Ape tag.
+ *
+ * Info on Lyrics3 V2.00 can be found at:
+ * http://www.id3.org/lyrics3200.html
+ * On the actual Ape Tag V2.0:
+ * http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html
+ *
+ * Copyright (C) 2004 Jens Taprogge <jens.taprogge at post.rwth-aachen.de>
+ *
+ * Provided under GPL according to Jens Taprogge. (JCS -- 12 March 2004)
+ */
+
+#define TAG_FOOTER		0x10
+#define LAME_OFFSET		0x74
+#define SIDEINFO_MPEG1_MONO	17
+#define SIDEINFO_MPEG1_MULTI	32
+#define SIDEINFO_MPEG2_MONO	9
+#define SIDEINFO_MPEG2_MULTI	17
+#define ID3V1_SIZE		0x80
+#define APE_FOOTER_SIZE 	0x20
+#define LYRICS_FOOTER_SIZE 	0x0f
+
+
+static gint lame_vcmp(gchar a[5], gchar b[5]) {
+	int r;
+
+	r = strncmp(a, b, 4);
+	if (r) return r;
+
+	if (a[4] == b[4]) return 0;
+
+	/* check for '.': indicates subminor version */
+	if (a[4] == '.') return 1;
+	if (b[4] == '.') return -1;
+	
+	/* check for alpha or beta versions */
+	if (a[4] == ' ') return 1;
+	if (b[4] == ' ') return -1;
+
+	/* check for alpha, beta etc. indicated by a, b... */
+	return strncmp(&a[4], &b[4], 1);
+}
+
+
+/* buf[] must be declared unsigned -- otherwise the casts, shifts and
+   additions below produce funny results */             
+static void read_lame_replaygain(unsigned char buf[],
+				 GainData *gd, int gain_adjust) {
+	char oc, nc;
+	gint gain;
+
+	g_return_if_fail (gd);
+
+	/* buf[0] and buf[1] are a bit field:
+	   3 bits: name  (mask: 0xe0 = 11100000)
+	   3 bits: originator (mask: 0x1c = 00011100)
+	   1 bit: negative if set (mask: 0x02 = 00000010)
+	   9 bits: value
+	*/
+
+	/* check originator */
+	oc = (buf[0] & 0x1c) >> 2;
+	if ((oc <= 0) || (oc > 3)) return;
+
+	/* check name code */
+	nc = buf[0] & 0xe0;
+	if (!((nc == 0x20) || (nc == 0x40))) return;
+	
+	gain = ((((guint)buf[0]) & 0x1) << 8) + buf[1];
+	
+	/* This would be a value of -0.
+	 * That value however is illegal by current standards and reserved for
+	 * future use. */
+	if ((!gain) && (buf[0] & 0x02)) return;
+	
+	if (buf[0] & 2) gain = -gain;
+	
+	gain += gain_adjust;
+
+	switch (nc) {
+		case 0x20:
+			if (gd->radio_gain_set) return;
+			gd->radio_gain = (gdouble)gain / 10;
+			gd->radio_gain_set = TRUE;
+/*			printf("radio_gain (lame): %i\n", gd->radio_gain); */
+			break;
+		case 0x40:
+			if (gd->audiophile_gain_set) return;
+			gd->audiophile_gain = (gdouble)gain / 10;
+			gd->audiophile_gain_set = TRUE;
+/*			printf("audiophile_gain (lame): %i\n", 
+					gd->audiophile_gain);*/
+			break;
+	}
+}
+
+
+static inline guint32 parse_ape_uint32(char *buf) {
+	return (buf[0] & 0xff) | (buf[1] & 0xff) << 8 
+		| (buf[2] & 0xff) << 16 | (buf[3] & 0xff) << 24;
+}
+
+static inline guint32 parse_lame_uint32(char *buf) {
+	return (buf[0] & 0xff) << 24 | (buf[1] & 0xff) << 16 
+		| (buf[2] & 0xff) << 8 | (buf[3] & 0xff);
+}
+
+
+/* 
+ * mp3_get_track_lame_replaygain - read the specified file and scan for LAME Tag
+ * ReplayGain information.
+ *
+ * @path: localtion of the file
+ * @track: structure holding track information
+ *
+ * FIXME: Are there other encoders writing a LAME Tag using a different magic
+ * string?
+ * TODO: Check CRC.
+ */
+
+gboolean mp3_get_track_lame_replaygain (gchar *path, GainData *gd)
+{
+	struct {
+		/* All members are defined in terms of chars so padding does not
+		 * occur. Is there a cleaner way to keep the compiler from
+		 * padding? */
+		
+		char     id[3];
+		char     version[2];
+		char     flags;
+		char     size[4];
+	} id3head;
+
+	FILE *file = NULL;
+	char buf[4], version[5];
+	int gain_adjust = 0;
+	int sideinfo;
+	guint32 ps;
+
+	g_return_val_if_fail (gd, FALSE);
+
+	gd->radio_gain = 0;
+	gd->audiophile_gain = 0;
+	gd->peak_signal = 0;
+	gd->radio_gain_set = FALSE;
+	gd->audiophile_gain_set = FALSE;
+	gd->peak_signal_set = FALSE;
+	
+	if (!path)
+		goto rg_fail;
+	
+	file = fopen (path, "r");
+
+	if (!file)
+	    goto rg_fail;
+
+	/* Skip ID3 header if appropriate */
+	if (fread(&id3head, 1, sizeof(id3head), file) != 
+			sizeof(id3head))
+		goto rg_fail;
+	
+	if (!strncmp(id3head.id, "ID3", 3)) {
+		int realsize = 0;
+		
+		realsize = (id3head.size[0] & 0x7f) << 21 
+			| (id3head.size[1] & 0x7f) << 14 
+			| (id3head.size[2] & 0x7f) << 7 
+			| (id3head.size[3] & 0x7f);
+
+		if (id3head.flags & TAG_FOOTER) {
+			/* footer is copy of header */
+			realsize += sizeof(id3head);
+		}
+
+		if (fseek(file, realsize-1, SEEK_CUR) ||
+				(!fread(&buf[0], 1, 1, file)))
+			goto rg_fail;
+	} else {
+		/* no ID3 Tag - go back */
+		fseek(file, -sizeof(id3head), SEEK_CUR);
+	}
+
+	/* Search Xing header. The location is dependant on the MPEG Layer and
+	 * whether the stream is mono or not. */
+	if (fread(buf, 1, 4, file) != 4) goto rg_fail;
+	
+	/* should start with 0xff 0xf? (synch) */
+	if (((buf[0] & 0xff) != 0xff) 
+			|| ((buf[1] & 0xf0) != 0xf0)) goto rg_fail;
+	
+	/* determine the length of the sideinfo */
+	if (buf[1] & 0x08) {
+		sideinfo = ((buf[3] & 0xc0) == 0xc0) ? 
+			SIDEINFO_MPEG1_MONO : SIDEINFO_MPEG1_MULTI;
+	} else {
+		sideinfo = ((buf[3] & 0xc0) == 0xc0) ? 
+			SIDEINFO_MPEG2_MONO : SIDEINFO_MPEG2_MULTI;
+	}
+	
+	if (fseek(file, sideinfo, SEEK_CUR) ||
+			(fread(&buf[0], 1, 4, file) != 4))
+		goto rg_fail;
+	
+	/* Is this really a Xing or Info Header? 
+	 * FIXME: Apparently (according to madplay sources) there is a different
+	 * possible location for the Xing header ("due to an unfortunate
+	 * historical event"). I do not thing we need to care though since
+	 * RaplayGain information is only conatined in recent files.  */
+	if (strncmp(buf, "Xing", 4) && strncmp(buf, "Info", 4))
+		goto rg_fail;
+
+	/* Check for LAME Tag */
+	if (fseek(file, LAME_OFFSET, SEEK_CUR) ||
+				(fread(&buf[0], 1, 4, file) != 4))
+		goto rg_fail;
+	if (strncmp(buf, "LAME", 4))
+		goto rg_fail;
+	
+	/* Check LAME Version */
+	if (fread(version, 1, 5, file) != 5)
+		goto rg_fail;
+	
+	/* Skip really old versions altogether. I am not sure when radio_gain
+	 * information was introduced. 3.89 does not seem to supprt it though.
+	 * */
+	if (lame_vcmp(version, "3.90") < 0) {
+/*		fprintf(stderr, "Old lame version (%c%c%c%c%c). Not used.\n",
+				version[0], version[1], version[2], version[3], version[4]); */
+		goto rg_fail;
+	}
+		
+	if (fseek(file, 0x2, SEEK_CUR) || (fread(buf, 1, 4, file) != 4))
+		goto rg_fail;
+
+	/* get the peak signal. */
+	ps = parse_lame_uint32(buf);
+	
+	/* Don't know when fixed-point PeakSingleAmplitude
+	 * was introduced exactly. 3.94b will be used for now.) */
+	if ((lame_vcmp(version, "3.94b") >= 0)) {
+		if ((!gd->peak_signal_set) && ps) {
+			gd->peak_signal = ps;
+			gd->peak_signal_set = TRUE;
+/*			printf("peak_signal (lame): %f\n", (double)
+					gd->peak_signal / 0x800000);*/
+		}
+	} else {
+		float f = *((float *) (void *) (&ps)) * 0x800000;
+		gd->peak_signal = (guint32) f;
+		/* I would like to see an example of that. */
+/*		printf("peak_signal (lame floating point): %f. PLEASE report.\n", 
+				(double) gd->peak_signal / 0x800000);*/
+	}
+
+	/*
+	 * Versions prior to 3.95.1 used a reference volume of 83dB.
+	 * (As compared to the currently used 89dB.)
+	 */
+	if ((lame_vcmp(version, "3.95.") < 0)) {
+		gain_adjust = 60;
+/*		fprintf(stderr, "Old lame version (%c%c%c%c%c). Adjusting gain.\n",
+				version[0], version[1], version[2], version[3], version[4]); */
+	}
+
+	if (fread(&buf[0], 1, 2, file) != 2)
+		goto rg_fail;
+
+	/* radio gain */
+	read_lame_replaygain (buf, gd, gain_adjust);
+
+	if (fread(&buf[0], 1, 2, file) != 2)
+		goto rg_fail;
+
+	/* audiophile gain */
+	read_lame_replaygain (buf, gd, gain_adjust);
+
+	fclose(file);
+	return TRUE;
+
+rg_fail:
+	if (file)
+		fclose(file);
+	return FALSE;
+}
+
+
+/* 
+ * mp3_get_track_ape_replaygain - read the specified file and scan for Ape Tag
+ * ReplayGain information.
+ *
+ * @path: localtion of the file
+ * @track: structure holding track information
+ *
+ * The function only modifies the gains if they have not previously been set.
+ */
+
+gboolean mp3_get_track_ape_replaygain(gchar *path, GainData *gd)
+{
+	/* The Ape Tag is located a t the end of the file. Or at least that
+	 * seems where it can most likely be found. Either it is at the very end
+	 * or before a trailing ID3v1 Tag. Sometimes a Lyrics3 Tag is placed
+	 * between the ID3v1 and the Ape Tag.
+	 * If you find files that have the Tags located in different
+	 * positions please let me know. */
+
+	FILE *file = NULL;
+	char buf[16];
+	char *dbuf = NULL, *ep;
+
+	int offset = 0;
+	int i;
+	int pos = 0, pos2 = 0;
+	guint32 version;
+	guint32 data_length;
+	guint32 entry_length = 0;
+	guint32 entries;
+	double d;
+
+	g_return_val_if_fail (gd, FALSE);
+	g_return_val_if_fail (path, FALSE);
+
+	file = fopen (path, "r");
+
+	if (!file)
+	    goto rg_fail;
+
+	/* check for ID3v1 Tag */
+	if (fseek(file, -ID3V1_SIZE, SEEK_END) ||
+			fread(&buf, 1, 3, file) != 3)
+		goto rg_fail;
+	if (!strncmp(buf, "TAG", 3)) offset -= ID3V1_SIZE;
+
+	/* check for Lyrics3 Tag */
+	if (fseek(file, -9 + offset, SEEK_END) ||
+			fread(&buf, 1, 9, file) != 9)
+		goto rg_fail;
+	if (!strncmp(buf, "LYRICS200", 9)) {
+		if (fseek(file, -LYRICS_FOOTER_SIZE + offset, SEEK_END) ||
+				fread(&buf, 1, 9, file) != 9)
+			goto rg_fail;
+		data_length = buf[0] - '0';
+		for (i = 1; i < 6; i++) {
+			data_length *= 10;
+			data_length += buf[i] - '0';
+		}
+		if (fseek(file, -LYRICS_FOOTER_SIZE - data_length + offset,
+					SEEK_END) ||
+				fread(&buf, 1, 11, file) != 11)
+			goto rg_fail;
+		if (!strncmp(buf, "LYRICSBEGIN", 11)) 
+			offset -= LYRICS_FOOTER_SIZE + data_length;
+	}
+
+	/* check for APE Tag */
+	if (fseek(file, -APE_FOOTER_SIZE + offset, SEEK_END) ||
+			fread(&buf, 1, 8, file) != 8)
+		goto rg_fail;
+	if (strncmp(buf, "APETAGEX", 8)) goto rg_fail;
+
+	/* Check the version of the tag. 1000 and 2000 (v1.0 and 2.0) are the
+	 * only ones I know about. Make suer things do not break in the future.
+	 * */
+	if (fread(&buf, 1, 4, file) != 4)
+		goto rg_fail;
+	version = parse_ape_uint32(buf);
+	if (version != 1000 && version != 2000)
+		goto rg_fail;
+
+	/* determine data length */
+	if (fread(&buf, 1, 4, file) != 4)
+		goto rg_fail;
+	data_length = parse_ape_uint32(buf) - APE_FOOTER_SIZE;
+
+	/* determine number of entries */
+	if (fread(&buf, 1, 4, file) != 4)
+		goto rg_fail;
+	entries = parse_ape_uint32(buf);
+
+	/* seek to first entry and read the whole buffer*/
+	if (fseek(file, -APE_FOOTER_SIZE + offset - data_length, SEEK_END))
+		goto rg_fail;
+	if (!(dbuf = malloc(data_length)))
+		goto rg_fail;
+	if (fread(dbuf, 1, data_length, file) != data_length)
+		goto rg_fail;
+	
+	for (i = 0; i < entries; i++) {
+		if (gd->radio_gain_set && gd->peak_signal_set) break;
+		pos = pos2 + entry_length;
+		if (pos > data_length - 10) break;
+		
+		entry_length = parse_ape_uint32(&dbuf[pos]); pos += 4;
+		pos += 4;
+		
+		pos2 = pos;
+		while (dbuf[pos2] && pos2 < data_length) pos2++;
+		if (pos2 == data_length) break;
+		pos2++;
+		
+		if (entry_length + 1 > sizeof(buf))
+			continue;
+/* 		printf ("%s:%d:%d\n",&dbuf[pos], pos2, pos); */
+		if (!gd->radio_gain_set && !strcasecmp(&dbuf[pos],
+					"REPLAYGAIN_TRACK_GAIN")) {
+			memcpy(buf, &dbuf[pos2], entry_length);
+			buf[entry_length] = '\0';
+			
+			d = g_ascii_strtod(buf, &ep);
+/* 			printf("%f\n", d); */
+			if ((ep == buf + entry_length - 3) 
+					&& (!strncasecmp(ep, " dB", 3))) {
+			    gd->radio_gain = d;
+				gd->radio_gain_set = TRUE;
+/*				printf("radio_gain (ape): %i\n", gd->radio_gain);*/
+			}
+			
+			continue;
+		}
+		if (!gd->peak_signal_set && !strcasecmp(&dbuf[pos],
+					"REPLAYGAIN_TRACK_PEAK")) {
+			memcpy(buf, &dbuf[pos2], entry_length);
+			buf[entry_length] = '\0';
+			
+			d = g_ascii_strtod(buf, &ep);
+			if (ep == buf + entry_length) {
+				d *= 0x800000;
+				gd->peak_signal = (guint32) floor(d + 0.5);
+				gd->peak_signal_set = TRUE;
+/*				printf("peak_signal (ape): %f\n", (double) gd->peak_signal / 0x800000);*/
+			}
+
+			continue;
+		}
+	}
+
+	free(dbuf);
+	fclose(file);
+	return TRUE;
+
+rg_fail:
+	if (dbuf)
+		free(dbuf);
+	if (file)
+		fclose(file);
+	return FALSE;
+}
+
+
+/* ----------------------------------------------------------------------
+
+	      mp3gain code
+
+---------------------------------------------------------------------- */
+
+#include <sys/wait.h>
+#include <fcntl.h>
+
+
+
+
+
+
+/** 
+ * mp3_read_soundcheck:
+ *
+ * try to read the ReplayGain values from the LAME or Ape Tags and set
+ * the track's soundcheck field accordingly.
+ *
+ * @path: localtion of the file
+ * @track: structure holding track information
+ *
+ * The function always rereads the gain from the file.
+ *
+ * Returns TRUE if the soundcheck field could be set.
+ */
+gboolean mp3_read_soundcheck (gchar *path, Track *track)
+{
+    GainData gd;
+
+    g_return_val_if_fail (track, FALSE);
+
+    memset (&gd, 0, sizeof (GainData));
+
+    gd.radio_gain_set = FALSE;
+    gd.audiophile_gain_set = FALSE;
+    gd.peak_signal_set = FALSE;
+
+    mp3_get_track_lame_replaygain (path, &gd);
+    if (gd.radio_gain_set)
+    {
+	track->soundcheck = replaygain_to_soundcheck (gd.radio_gain);
+	return TRUE;
+    }
+
+    mp3_get_track_ape_replaygain (path, &gd);
+    if (gd.radio_gain_set)
+    {
+	track->soundcheck = replaygain_to_soundcheck (gd.radio_gain);
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
+
+
+
+
+
+/* mp3 slot size in bytes */
+int slotsize[3] = {4,1,1}; /* layer 1, layer 2, layer 3 */
+
+int samplesperframe[2][3] = {
+  { /* MPEG 2.0 */
+    384,1152,576 /* layer 1, layer 2, layer 3 */
+  },
+
+  { /* MPEG 1.0 */
+    384,1152,1152 /* layer 1, layer 2, layer 3 */
+  }
+};
+
+
+/* 
+ * mp3_get_track_lame_gapless - read the specified file and scan for LAME Tag
+ * gapless information.
+ *
+ * @path: localtion of the file
+ * @track: structure holding track information
+ *
+ * TODO: Split off non-LAME stuff (samplecount, gapless_data) to a separate function since it's generic
+ */
+gboolean mp3_get_track_lame_gapless (gchar *path, GaplessData *gd)
+{
+    FILE *file = NULL;
+    char buf[4], version[5];
+    unsigned char ubuf[4];
+    int sideinfo;
+    int i;
+
+    g_return_val_if_fail (gd, FALSE);
+
+    if (!path)
+	goto gp_fail;
+
+    file = fopen (path, "rb");
+
+    if (!file)
+	goto gp_fail;
+
+    /* use get_first_header() to seek to the first mp3 header */
+    MP3Info *mp3i = NULL;
+    mp3i = g_malloc0 (sizeof (MP3Info));
+    mp3i->filename = path;
+    mp3i->file = file;
+    get_mp3_info (mp3i);
+    get_first_header (mp3i, 0);
+
+    int xing_header_offset = ftell (file);
+
+    MP3Header h;
+    if (!get_header (file, &h))
+	goto gp_fail;
+
+    int mysamplesperframe = samplesperframe[h.version & 1][3 - h.layer];
+
+    /* Determine offset of Xing header based on sideinfo size */
+    if (h.version & 0x1)
+    {
+	sideinfo = (h.mode & 0x2) ?
+	    SIDEINFO_MPEG1_MONO : SIDEINFO_MPEG1_MULTI;
+    }
+    else
+    {
+	sideinfo = (h.mode & 0x2) ?
+	    SIDEINFO_MPEG2_MONO : SIDEINFO_MPEG2_MULTI;
+    }
+
+    if (fseek (file, sideinfo, SEEK_CUR) ||
+	(fread (&buf[0], 1, 4, file) != 4))
+	goto gp_fail;
+
+    /* Is this really a Xing or Info Header? 
+     * FIXME: Apparently (according to madplay sources) there is a different
+     * possible location for the Xing header ("due to an unfortunate
+     * historical event"). I do not thing we need to care though since
+     * ReplayGain information is only contained in recent files.  */
+    if (strncmp (buf, "Xing", 4) && strncmp (buf, "Info", 4))
+	goto gp_fail;
+
+    /* Determine the offset of the LAME tag based on contents of the Xing header */
+    int flags;
+    fread (&flags, 4, 1, file);
+    int toskip = 0;
+    if (flags | 0x1)
+    {				/* frames field is set */
+	toskip += 4;
+    }
+    if (flags | 0x2)
+    {				/* bytes field is set */
+	toskip += 4;
+    }
+    if (flags | 0x4)
+    {				/* TOC field is set */
+	toskip += 100;
+    }
+    if (flags | 0x8)
+    {				/* quality field is set */
+	toskip += 4;
+    }
+
+    /* Check for LAME Tag */
+    if (fseek (file, toskip, SEEK_CUR) || (fread (&buf[0], 1, 4, file) != 4))
+	goto gp_fail;
+    if (strncmp (buf, "LAME", 4))
+	goto gp_fail;
+
+    /* Check LAME Version */
+    if (fread (version, 1, 5, file) != 5)
+	goto gp_fail;
+
+    /* XXX skip old LAME versions, or just assume that pre/postgap
+     * turn out zeros anyway, or check the CRC to vaidate the tag? */
+
+    gboolean cbr = FALSE;
+    if (fread (ubuf, 1, 1, file) != 1)
+	goto gp_fail;
+
+    if ((ubuf[0] & 0xf) == 0x1)
+	cbr = TRUE;
+
+    if (fseek (file, 0xB, SEEK_CUR) || (fread (ubuf, 1, 4, file) != 4))
+	goto gp_fail;
+
+    /* set pregap and postgap directly from LAME header */
+    gd->pregap = (ubuf[0] << 4) + (ubuf[1] >> 4);
+    gd->postgap = ((ubuf[1] & 0xf) << 8) + ubuf[2];
+
+    /* jump the end of the frame with the xing header */
+    if (fseek (file, xing_header_offset + frame_length (&h), SEEK_SET))
+	goto gp_fail;
+
+    /* counts bytes from the start of the 1st sync frame */
+    int totaldatasize = frame_length (&h);
+
+    /* keeps track of the last 8 frame sizes */
+    int lastframes[8];
+
+    /* counts number of music frames */
+    int totalframes = 0;
+
+    /* quickly parse the file, reading only frame headers */
+    int l = 0;
+    while ((l = get_header (file, &h)) != 0)
+    {
+	for (i = 7; i > 0; i--)
+	{
+	    lastframes[i] = lastframes[i - 1];
+	}
+	lastframes[0] = l;
+	totaldatasize += l;
+	totalframes++;
+
+	if (fseek (file, l - FRAME_HEADER_SIZE, SEEK_CUR))
+	    goto gp_fail;
+
+    }
+
+    int finaleight = 0;
+    for (i = 0; i < 8; i++)
+    {
+	finaleight += lastframes[i];
+    }
+
+    if (cbr)
+	totalframes++;
+
+    /* all but last eight frames */
+    gd->gapless_data = totaldatasize - finaleight;
+    /* total samples minus pre/postgap */
+    gd->samplecount = totalframes * mysamplesperframe - gd->pregap - gd->postgap;
+	fclose(file);
+
+    return TRUE;
+
+
+  gp_fail:
+    if (file)
+	fclose (file);
+    return FALSE;
+
+}
+
+
+
+/** 
+ * mp3_read_gapless:
+ *
+ * try to read the gapless values from the LAME Tag and set
+ * the track's pregap, postgap, samplecount, and gapless_data fields
+ * accordingly.
+ *
+ * @path: location of the file
+ * @track: structure holding track information
+ *
+ * The function always rereads the data from the file.
+ *
+ * Returns TRUE if all four gapless fields could be
+ * set. etrack->tchanged is set to TRUE if data has been changed,
+ * FALSE otherwise.
+ */
+gboolean mp3_read_gapless (char *path, Track *track)
+{
+    GaplessData gd;
+    ExtraTrackData *etr;
+
+    g_return_val_if_fail (track, FALSE);
+
+    etr = track->userdata;
+
+    memset (&gd, 0, sizeof (GaplessData));
+
+    gd.pregap = 0;
+    gd.samplecount = 0;
+    gd.postgap = 0;
+    gd.gapless_data = 0;
+
+    mp3_get_track_lame_gapless (path, &gd);
+
+    etr->tchanged = FALSE;
+
+    if ((gd.pregap) && (gd.samplecount) && (gd.postgap) && (gd.gapless_data))
+    {
+	if ((track->pregap != gd.pregap) ||
+	    (track->samplecount != gd.samplecount) ||
+	    (track->postgap != gd.postgap) ||
+	    (track->gapless_data != gd.gapless_data) ||
+	    (track->gapless_track_flag == FALSE))
+	{
+	    etr->tchanged = TRUE;
+	    track->pregap = gd.pregap;
+	    track->samplecount = gd.samplecount;
+	    track->postgap = gd.postgap;
+	    track->gapless_data = gd.gapless_data;
+	    track->gapless_track_flag = TRUE;
+	}
+    }
+    return FALSE;
+}
+
+
+
+/* ----------------------------------------------------------------------
+
+	      From here starts original gtkpod code
+
+---------------------------------------------------------------------- */
+
+/* Return a Track structure with all information read from the mp3
+   file filled in */
+Track *mp3_get_file_info (gchar *name)
+{
+    Track *track = NULL;
+    File_Tag filetag;
+    MP3Info *mp3i=NULL;
+    FILE *file;
+    guchar *image_data = NULL;
+    gsize image_data_len = 0;
+
+    g_return_val_if_fail (name, NULL);
+
+    /* Attempt to open the file */
+    file = fopen (name, "r");
+    if (file)
+    {
+	mp3i = g_malloc0 (sizeof (MP3Info));
+	mp3i->filename = name;
+	mp3i->file = file;
+	get_mp3_info (mp3i);
+	mp3i->file = NULL;
+	fclose (file);
+    }
+    else
+    {
+	gchar *fbuf = charset_to_utf8 (name);
+    	gtkpod_warning(_("ERROR while opening file: '%s' (%s).\n"),
+		       fbuf, g_strerror(errno));
+	g_free (fbuf);
+	return NULL;
+    }
+
+    track = gp_track_new ();
+    track->filetype = g_strdup ("MPEG audio file");
+
+    if (prefs_get_int("readtags") && (id3_tag_read (name, &filetag) == TRUE))
+    {
+
+	if (filetag.album)
+	{
+	    track->album = filetag.album;
+	}
+
+	if (filetag.artist)
+	{
+	    track->artist = filetag.artist;
+	}
+
+	if (filetag.title)
+	{
+	    track->title = filetag.title;
+	}
+
+	if (filetag.genre)
+	{
+	    track->genre = filetag.genre;
+	}
+
+	if (filetag.composer)
+	{
+	    track->composer = filetag.composer;
+	}
+
+	if (filetag.comment)
+	{
+	    track->comment = filetag.comment;
+	}
+
+	if (filetag.podcasturl)
+	{
+	    track->podcasturl = filetag.podcasturl;
+	}
+
+	if (filetag.podcastrss)
+	{
+	    track->podcastrss = filetag.podcastrss;
+	}
+
+	if (filetag.subtitle)
+	{
+	    track->subtitle = filetag.subtitle;
+	}
+
+	if (filetag.description)
+	{
+	    track->description = filetag.description;
+	}
+
+	if (filetag.sort_artist)
+	{
+	    track->sort_artist = filetag.sort_artist;
+	}
+
+	if (filetag.sort_title)
+	{
+	    track->sort_title = filetag.sort_title;
+	}
+
+	if (filetag.sort_album)
+	{
+	    track->sort_album = filetag.sort_album;
+	}
+
+	if (filetag.sort_albumartist)
+	{
+	    track->sort_albumartist = filetag.sort_albumartist;
+	}
+
+	if (filetag.sort_composer)
+	{
+	    track->sort_composer = filetag.sort_composer;
+	}
+
+	if (filetag.year == NULL)
+	{
+	    track->year = 0;
+	}
+	else
+	{
+	    track->year = atoi(filetag.year);
+	    g_free (filetag.year);
+	}
+
+	if (filetag.trackstring == NULL)
+	{
+	    track->track_nr = 0;
+	}
+	else
+	{
+	    track->track_nr = atoi(filetag.trackstring);
+	    g_free (filetag.trackstring);
+	}
+
+	if (filetag.track_total == NULL)
+	{
+	    track->tracks = 0;
+	}
+	else
+	{
+	    track->tracks = atoi(filetag.track_total);
+	    g_free (filetag.track_total);
+	}
+	/* CD/disc number handling */
+	if (filetag.cdnostring == NULL)
+	{
+	    track->cd_nr = 0;
+	}
+	else
+	{
+	    track->cd_nr = atoi(filetag.cdnostring);
+	    g_free (filetag.cdnostring);
+	}
+	
+	if (filetag.cdno_total == NULL)
+	{
+	    track->cds = 0;
+	}
+	else
+	{
+	    track->cds = atoi(filetag.cdno_total);
+	    g_free (filetag.cdno_total);
+	}
+
+	if (filetag.compilation == NULL)
+	{
+	    track->compilation = 0;
+	}
+	else
+	{
+	    track->compilation = atoi(filetag.compilation);
+	    g_free (filetag.compilation);
+	}
+
+	if (filetag.BPM == NULL)
+	{
+	    track->BPM = 0;
+	}
+	else
+	{
+	    track->BPM = atoi(filetag.BPM);
+	    g_free (filetag.BPM);
+	}
+
+	if (filetag.lyrics)
+	{
+	    track->lyrics_flag = 0x01;
+	    g_free (filetag.lyrics);
+	}
+	else
+	{
+	    track->lyrics_flag = 0x00;
+	}
+    }
+
+    if (prefs_get_int("coverart_apic") &&
+	(id3_apic_read (name, &image_data, &image_data_len) == TRUE))
+    {
+	if (image_data)
+	{
+	    gp_track_set_thumbnails_from_data (track,
+					       image_data,
+					       image_data_len);
+	    g_free (image_data);
+	}
+    }
+
+    mp3_read_soundcheck (name, track);
+
+    mp3_read_gapless (name, track);
+
+#if LOCALDEBUG
+	printf("%s\n", name);
+    printf("\tpregap: %i\n", track->pregap);
+    printf("\tpostgap: %i\n", track->postgap);
+    printf("\tsamplecount: %li\n", track->samplecount);
+    printf("\tgaplessdata: %i\n", track->gapless_data);
+#endif
+
+
+    /* Get additional info (play time and bitrate */
+    if (mp3i)
+    {
+	track->tracklen = mp3i->milliseconds;
+	track->bitrate = (gint)(mp3i->vbr_average);
+ 	track->samplerate = mp3file_header_frequency (&mp3i->header);
+	g_free (mp3i);
+    }
+    /* Fall back to xmms code if tracklen is 0 */
+    if (track->tracklen == 0)
+    {
+	track->tracklen = get_track_time (name);
+	if (track->tracklen)
+	    track->bitrate = (float)track->size*8/track->tracklen;
+    }
+
+    if (track->tracklen == 0)
+    {
+	/* Tracks with zero play length are ignored by iPod... */
+	gtkpod_warning (_("File \"%s\" has zero play length. Ignoring.\n"),
+			name);
+	gp_track_free (track);
+	track = NULL;
+    }
+    return track;
+}




More information about the Pkg-gtkpod-devel mailing list