summaryrefslogtreecommitdiffstats
path: root/kscd/libwm/cdinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'kscd/libwm/cdinfo.c')
-rw-r--r--kscd/libwm/cdinfo.c890
1 files changed, 890 insertions, 0 deletions
diff --git a/kscd/libwm/cdinfo.c b/kscd/libwm/cdinfo.c
new file mode 100644
index 00000000..b04dec69
--- /dev/null
+++ b/kscd/libwm/cdinfo.c
@@ -0,0 +1,890 @@
+/*
+ * $Id$
+ *
+ * This file is part of WorkMan, the civilized CD player library
+ * (c) 1991-1997 by Steven Grimm (original author)
+ * (c) by Dirk Försterling (current 'author' = maintainer)
+ * The maintainer can be contacted by his e-mail address:
+ * milliByte@DeathsDoor.com
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * Get information about a CD.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "include/wm_config.h"
+
+#include "include/wm_struct.h"
+#include "include/wm_cdrom.h"
+#include "include/wm_cdinfo.h"
+#include "include/wm_database.h"
+#include "include/wm_helpers.h"
+
+struct wm_play *playlist = NULL;
+struct wm_cdinfo thiscd, *cd = &thiscd;
+
+int cur_track = -1; /* Current track number, starting at 1 */
+int cur_index = 0; /* Current index mark */
+int cur_lasttrack = 999; /* Last track to play in current chunk */
+int cur_firsttrack = 0; /* First track of current chunk */
+int cur_pos_abs; /* Current absolute position in seconds */
+int cur_frame; /* Current frame number */
+int cur_pos_rel; /* Current track-relative position in seconds */
+int cur_tracklen; /* Length in seconds of current track */
+int cur_cdlen; /* Length in seconds of entire CD */
+int cur_ntracks; /* Number of tracks on CD (= tracks + sections) */
+int cur_nsections; /* Number of sections currently defined */
+
+int cur_listno; /* Current index into the play list, if playing */
+char * cur_artist; /* Name of current CD's artist */
+char * cur_cdname; /* Album name */
+char * cur_trackname; /* Take a guess */
+char cur_contd; /* Continued flag */
+char cur_avoid; /* Avoid flag */
+
+int exit_on_eject = 0;
+
+int cur_stopmode = -1;
+int info_modified;
+
+/*
+ * insert_trackinfo()
+ *
+ * Add a new track to the CD info structure. Pass the position of the new
+ * entry in the track list -- 0 will make this the first track, 1 the second,
+ * etc. The new entry will be zeroed out.
+ */
+static void
+insert_trackinfo(int num)
+{
+ struct wm_trackinfo *newtrk;
+
+ /* Easy case: the list is empty */
+ if (cd->trk == NULL) {
+ if ((cd->trk = (struct wm_trackinfo *) calloc(1,
+ sizeof(*newtrk))) == NULL)
+ {
+ perror("insert_trackinfo");
+ exit(1);
+ } else {
+ return;
+ } /* if() else */
+ } /* if() */
+ /* Stick the new entry in cd->trk[]. */
+ if ((newtrk = (struct wm_trackinfo *) malloc(sizeof(*newtrk) *
+ (cur_ntracks + 1))) == NULL)
+ {
+ perror("insert_trackinfo");
+ exit(1);
+ }
+
+ if (num)
+ memcpy(newtrk, cd->trk, sizeof(*newtrk) * num);
+ memset(&newtrk[num], 0, sizeof(*newtrk));
+ if (num < cur_ntracks)
+ memcpy(&newtrk[num + 1], &cd->trk[num], sizeof(*newtrk) *
+ (cur_ntracks - num));
+
+ free(cd->trk);
+ cd->trk = newtrk;
+}
+
+/*
+ * split_trackinfo()
+ *
+ * Split a track in two at a particular position (absolute, in frames). All
+ * internal data structures and variables will be adjusted to the new
+ * numbering scheme. Pass in the track number (>=1) to split, which is also
+ * the index into cd->trk[] of the new entry.
+ *
+ * If pos is within 1 second of the start of another track, the split fails.
+ *
+ * Returns 1 on success, 0 if the track couldn't be inserted.
+ *
+ * Note: updating user interface elements is up to the caller.
+ */
+int
+split_trackinfo( int pos )
+{
+ int i, l, num;
+
+ if (pos < cd->trk[0].start)
+ return (0);
+
+ /* First find the appropriate track. */
+ for (num = 0; num < cur_ntracks; num++)
+ if (cd->trk[num].start - 75 < pos &&
+ cd->trk[num].start + 75 > pos)
+ return (0);
+ else if (cd->trk[num].start > pos)
+ break;
+ if (num == 0)
+ return (0);
+
+ /* Insert the new entry into the track array. */
+ insert_trackinfo(num);
+
+ /* Update the easy variables. */
+ if (cur_track > num)
+ cur_track++;
+ if (cur_firsttrack > num)
+ cur_firsttrack++;
+ if (cur_lasttrack > num)
+ cur_lasttrack++;
+
+ /* Update the user-defined playlists. */
+ if (cd->lists != NULL)
+ for (l = 0; cd->lists[l].name != NULL; l++)
+ if (cd->lists[l].list != NULL)
+ for (i = 0; cd->lists[l].list[i]; i++)
+ if (cd->lists[l].list[i] > num)
+ cd->lists[l].list[i]++;
+
+ /* Update the internal playlist. */
+ if (playlist != NULL)
+ for (i = 0; playlist[i].start; i++)
+ {
+ if (playlist[i].start > num)
+ playlist[i].start++;
+ if (playlist[i].end > num)
+ playlist[i].end++;
+ }
+
+ /* Now adjust the information in cd->trk[]. */
+ cd->trk[num].start = pos;
+ if (num == cur_ntracks)
+ cd->trk[num].length = cur_cdlen - pos / 75;
+ else
+ cd->trk[num].length = (cd->trk[num + 1].start - pos) / 75;
+ cd->trk[num - 1].length -= cd->trk[num].length;
+ if (cur_track == num)
+ cur_tracklen -= cd->trk[num].length;
+ cd->trk[num].track = cd->trk[num - 1].track;
+ cd->trk[num].data = cd->trk[num - 1].data;
+ cd->trk[num].contd = 1;
+ cd->trk[num].volume = cd->trk[num - 1].volume;
+
+ if (cd->trk[num - 1].section == 0)
+ cd->trk[num - 1].section = 1;
+ cd->trk[num].section = cd->trk[num - 1].section + 1;
+
+ cur_ntracks++;
+ cur_nsections++;
+
+ for (i = num + 1; i < cur_ntracks; i++)
+ if (cd->trk[i].track == cd->trk[num].track)
+ cd->trk[i].section++;
+
+ return (1);
+}
+
+/*
+ * remove_trackinfo()
+ *
+ * Remove a track's internal data. This is similar to split_trackinfo()
+ * above, but simpler. A track's initial section can't be removed. Track
+ * numbers start at 0.
+ *
+ * Returns 1 on success, 0 on failure.
+ */
+int
+remove_trackinfo( int num )
+{
+ int i, l;
+
+ if (num < 1 || num >= cur_ntracks || cd->trk[num].section < 2)
+ return (0);
+
+ cd->trk[num - 1].length += cd->trk[num].length;
+
+ for (i = num; i < cur_ntracks - 1; i++)
+ memcpy(&cd->trk[i], &cd->trk[i + 1], sizeof(cd->trk[0]));
+
+ if (cur_track > num)
+ cur_track--;
+ if (cur_firsttrack > num)
+ cur_firsttrack--;
+ if (cur_lasttrack > num)
+ cur_lasttrack--;
+
+ /* Update the user-defined playlists. */
+ if (cd->lists != NULL)
+ for (l = 0; cd->lists[l].name != NULL; l++)
+ if (cd->lists[l].list != NULL)
+ for (i = 0; cd->lists[l].list[i]; i++)
+ if (cd->lists[l].list[i] > num)
+ cd->lists[l].list[i]--;
+
+ /* Update the internal playlist. */
+ if (playlist != NULL)
+ for (i = 0; playlist[i].start; i++)
+ {
+ if (playlist[i].start > num)
+ playlist[i].start--;
+ if (playlist[i].end > num)
+ playlist[i].end--;
+ }
+
+ cur_ntracks--;
+ cur_nsections--;
+
+ /*
+ * Update the section numbers for this track. If this is the only
+ * user-created section in a track, get rid of the section number
+ * in the track's entry.
+ */
+ if (num == cur_ntracks || cd->trk[num - 1].track != cd->trk[num].track)
+ {
+ if (cd->trk[num - 1].section == 1)
+ cd->trk[num - 1].section = 0;
+ }
+ else
+ for (i = num; i < cur_ntracks; i++)
+ if (cd->trk[i].track == cd->trk[num - 1].track)
+ cd->trk[i].section--;
+
+ return (1);
+}
+
+/*
+ * listentry()
+ *
+ * Return a scrolling list entry.
+ */
+char *
+listentry( int num )
+{
+ static char buf[600];
+ const char *name;
+ char tracknum[20];
+ int digits;
+ int sdigits;
+
+ if (num >= 0 && num < cur_ntracks)
+ {
+
+/*
+ if (big_spaces)
+ {
+ digits = 2;
+ sdigits = cur_nsections < 9 ? -1 : -2;
+ }
+ else
+ {
+ digits = cd->trk[num].track < 10 ? 3 : 2;
+ sdigits = cur_nsections < 9 ? -1 : -3;
+ }
+*/
+
+ digits = 2;
+ sdigits = cur_nsections < 9 ? -1 : -2;
+
+ name = cd->trk[num].songname ? cd->trk[num].songname : "";
+
+ if (cur_nsections)
+ {
+ if (cd->trk[num].section > 9)
+ {
+ sprintf(tracknum, "%*d.%d", digits,
+ cd->trk[num].track,
+ cd->trk[num].section);
+ } else {
+ if (cd->trk[num].section)
+ {
+ sprintf(tracknum, "%*d.%*d", digits,
+ cd->trk[num].track, sdigits,
+ cd->trk[num].section);
+ } else {
+ sprintf(tracknum, "%*d%*s", digits,
+ cd->trk[num].track,
+ 2 - sdigits, " ");
+/* 2 - sdigits - big_spaces, " ");*/
+ }
+ }
+ } else {
+ sprintf(tracknum, "%*d", digits, cd->trk[num].track);
+ }
+
+ if (cd->trk[num].data)
+ {
+ sprintf(buf, "%s) %3dMB %s", tracknum,
+ cd->trk[num].length / 1024, name);
+ } else {
+ sprintf(buf, "%s) %02d:%02d %s", tracknum,
+ cd->trk[num].length / 60,
+ cd->trk[num].length % 60, name);
+ }
+
+ return (buf);
+ } else {
+ return (NULL);
+ }
+} /* listentry() */
+
+/*
+ * trackname()
+ *
+ * Return a track's name.
+ */
+const char *
+trackname( int num )
+{
+ if (num >= 0 && num < cur_ntracks)
+ {
+ if (cd->trk[num].songname)
+ {
+ return (cd->trk[num].songname);
+ } else {
+ return ("");
+ }
+ } else {
+ return (NULL);
+ }
+} /* trackname() */
+
+/*
+ * tracklen()
+ *
+ * Return a track's length in seconds.
+ */
+int
+tracklen( int num )
+{
+ if (cd != NULL && num >= 0 && num < cur_ntracks)
+ return (cd->trk[num].length);
+ else
+ return (0);
+}
+
+/*
+ * get_default_volume()
+ *
+ * Return the default volume (0-32, 0=none) for the CD or a track.
+ */
+int
+get_default_volume( int track )
+{
+ if (! track)
+ return (cd->volume);
+ else if (track <= cur_ntracks)
+ return (cd->trk[track - 1].volume);
+ else
+ return (0);
+}
+
+/*
+ * get_contd()
+ *
+ * Return the contd value for a track.
+ */
+int
+get_contd( int num )
+{
+ if (num >= 0 && num < cur_ntracks)
+ return (cd->trk[num].contd);
+ else
+ return (0);
+}
+
+/*
+ * get_avoid()
+ *
+ * Return the avoid value for a track.
+ */
+int
+get_avoid( int num )
+{
+ if (num >= 0 && num < cur_ntracks)
+ return (cd->trk[num].avoid);
+ else
+ return (0);
+}
+
+/*
+ * get_autoplay()
+ *
+ * Is autoplay set on this disc?
+ */
+int
+get_autoplay( void )
+{
+ return ( cd->autoplay );
+}
+
+/*
+ * get_playmode()
+ *
+ * Return the default playmode for the CD.
+ */
+int
+get_playmode( void )
+{
+ return ( cd->playmode );
+}
+
+/*
+ * get_runtime()
+ *
+ * Return the total running time for the current playlist in seconds.
+ */
+int
+get_runtime( void )
+{
+ int i;
+
+ if (playlist == NULL || playlist[0].start == 0 || cur_firsttrack == -1)
+ return (cd == NULL ? 0 : cd->length);
+
+ for (i = 0; playlist[i].start; i++)
+ ;
+
+ return (playlist[i].starttime);
+}
+
+/*
+ * default_volume()
+ *
+ * Set the default volume for the CD or a track.
+ */
+void
+default_volume( int track, int vol )
+{
+ if (track == 0)
+ cd->volume = vol;
+ else if (track <= cur_ntracks)
+ cd->trk[track - 1].volume = vol;
+}
+
+/*
+ * Play the next thing on the playlist, if any.
+ */
+void
+play_next_entry( int forward )
+{
+ if (cd == NULL)
+ return;
+ if (playlist != NULL && playlist[cur_listno].start)
+ {
+ wm_cd_play(playlist[cur_listno].start, 0,
+ playlist[cur_listno].end);
+ cur_listno++;
+ }
+ else
+ wm_cd_stop();
+}
+
+/*
+ * Play the next track, following playlists as necessary.
+ */
+void
+play_next_track( int forward )
+{
+ if (cd == NULL)
+ return;
+
+ /* Is the current playlist entry done? Move on, if so. */
+ if (playlist == NULL || cur_track + 1 == playlist[cur_listno - 1].end)
+ play_next_entry( forward );
+ else
+ wm_cd_play(cur_track + 1, 0, playlist[cur_listno - 1].end);
+}
+
+/*
+ * Play the previous track, hopping around the playlist as necessary.
+ */
+void
+play_prev_track( int forward )
+{
+ if (cd == NULL)
+ return;
+
+ if (playlist == NULL)
+ return;
+
+ /* If we're in the middle of this playlist entry, go back one track */
+ if (cur_track > playlist[cur_listno - 1].start)
+ wm_cd_play(cur_track - 1, 0, playlist[cur_listno - 1].end);
+ else
+ if (cur_listno > 1)
+ {
+ cur_listno--;
+ wm_cd_play(playlist[cur_listno - 1].end - 1, 0,
+ playlist[cur_listno - 1].end);
+ }
+ else
+ wm_cd_play(playlist[0].start, 0, playlist[0].end);
+}
+
+/*
+ * stash_cdinfo(artist, cdname)
+ */
+void
+stash_cdinfo(char *artist, char *cdname, int autoplay, int playmode )
+{
+ if (cd != NULL)
+ {
+ if (strcmp(cd->artist, artist))
+ info_modified = 1;
+ strncpy(cd->artist, artist,sizeof(cd->artist)-1);
+ cd->artist[sizeof(cd->artist)-1]='\0';
+
+ if (strcmp(cd->cdname, cdname))
+ info_modified = 1;
+ strncpy(cd->cdname, cdname,sizeof(cd->cdname)-1);
+ cd->cdname[sizeof(cd->cdname)-1]='\0';
+
+ if (!!cd->autoplay != !!autoplay)
+ info_modified = 1;
+ cd->autoplay = autoplay;
+
+ if (!!cd->playmode != !!playmode)
+ info_modified = 1;
+ cd->playmode = playmode;
+ }
+} /* stash_cdinfo() */
+
+/*
+ * wipe_cdinfo()
+ *
+ * Clear out all a CD's soft information (presumably in preparation for
+ * reloading from the database.)
+ */
+void
+wipe_cdinfo( void )
+{
+ struct wm_playlist *l;
+ int i;
+
+ if (cd != NULL)
+ {
+ cd->artist[0] = cd->cdname[0] = '\0';
+ cd->autoplay = cd->playmode = cd->volume = 0;
+ cd->whichdb = NULL;
+ freeup(&cd->otherrc);
+ freeup(&cd->otherdb);
+
+ if (thiscd.lists != NULL)
+ {
+ for (l = thiscd.lists; l->name != NULL; l++)
+ {
+ free(l->name);
+ free(l->list);
+ }
+ free(thiscd.lists);
+ thiscd.lists = NULL;
+ }
+
+ for (i = 0; i < cur_ntracks; i++)
+ {
+ freeup(&cd->trk[i].songname);
+ freeup(&cd->trk[i].otherrc);
+ freeup(&cd->trk[i].otherdb);
+ cd->trk[i].avoid = cd->trk[i].contd = 0;
+ cd->trk[i].volume = 0;
+ if (cd->trk[i].section > 1)
+ remove_trackinfo(i--);
+ }
+ }
+}
+
+/*
+ * stash_trkinfo(track, songname, contd, avoid)
+ *
+ * Update information about a track on the current CD.
+ */
+void
+stash_trkinfo( int track, char *songname, int contd, int avoid )
+{
+ if (cd != NULL)
+ {
+ track--;
+ if (!!cd->trk[track].contd != !!contd)
+ info_modified = 1;
+ cd->trk[track].contd = track ? contd : 0;
+
+ if (!!cd->trk[track].avoid != !!avoid)
+ info_modified = 1;
+ cd->trk[track].avoid = avoid;
+
+ if ((cd->trk[track].songname == NULL && songname[0]) ||
+ (cd->trk[track].songname != NULL &&
+ strcmp(cd->trk[track].songname, songname)))
+ {
+ info_modified = 1;
+ wm_strmcpy(&cd->trk[track].songname, songname);
+ }
+ }
+}
+
+/*
+ * new_playlist()
+ *
+ * Add a playlist to a CD.
+ */
+struct wm_playlist *
+new_playlist(struct wm_cdinfo* cdinfo, char* listname)
+{
+ int nlists = 0;
+ struct wm_playlist *l;
+
+ if (cdinfo->lists != NULL)
+ {
+ for (nlists = 0; cdinfo->lists[nlists].name != NULL; nlists++)
+ ;
+ l = (struct wm_playlist *)realloc(cdinfo->lists, (nlists + 2) *
+ sizeof (struct wm_playlist));
+ }
+ else
+ l = (struct wm_playlist *)malloc(2 * sizeof (struct wm_playlist));
+
+ if (l == NULL)
+ return (NULL);
+
+ l[nlists + 1].name = NULL;
+ l[nlists].name = NULL; /* so wm_strmcpy doesn't free() it */
+ wm_strmcpy(&l[nlists].name, listname);
+ l[nlists].list = NULL;
+ cdinfo->lists = l;
+
+ return (&l[nlists]);
+}
+
+/*
+ * make_playlist()
+ *
+ * Construct a playlist for the current CD. If we're in shuffle mode, play
+ * each non-avoided track once, keeping continued tracks in the right order.
+ *
+ * If playmode is 2, use playlist number (playmode-2). XXX should do
+ * bounds checking on this, probably.
+ *
+ * If consecutive tracks are being played, only make one playlist entry for
+ * them, so the CD player won't pause between tracks while we wake up.
+ */
+void
+make_playlist( int playmode, int starttrack )
+{
+ int i, avoiding = 1, entry = 0, count, track,
+ *thislist;
+
+ cur_listno = 0;
+ if (playlist != NULL)
+ free(playlist);
+ playlist = malloc(sizeof (*playlist) * (cur_ntracks + 1));
+ if (playlist == NULL)
+ {
+ perror("playlist");
+ exit(1);
+ }
+
+ /* If this is a data-only CD, we can't play it. */
+ if ((starttrack && cd->trk[starttrack - 1].data) ||
+ (cur_ntracks == 1 && cd->trk[0].data))
+ {
+ playlist[0].start = 0;
+ playlist[0].end = 0;
+ playlist[1].start = 0;
+ return;
+ }
+
+ if (playmode == 1)
+ {
+ char *done = malloc(cur_ntracks);
+
+ if (done == NULL)
+ {
+ perror("randomizer");
+ exit(1);
+ }
+
+ count = cur_ntracks;
+ if (starttrack && cd->trk[starttrack - 1].avoid)
+ count++;
+ for (i = 0; i < cur_ntracks; i++)
+ if (cd->trk[i].contd || cd->trk[i].avoid ||
+ cd->trk[i].data)
+ {
+ done[i] = 1;
+ count--;
+ }
+ else
+ done[i] = 0;
+
+ for (i = 0; i < count; i++)
+ {
+ int end; /* for readability */
+ if (starttrack)
+ {
+ track = starttrack - 1;
+ starttrack = 0;
+ }
+ else
+ while (done[track = rand() % cur_ntracks])
+ ;
+
+ playlist[i].start = track + 1;
+
+ /* play all subsequent continuation tracks too */
+ for (end = track + 1; end < cur_ntracks + 1; end++)
+ if (! cd->trk[end].contd ||
+ cd->trk[end].avoid ||
+ cd->trk[end].data)
+ break;
+ playlist[i].end = end + 1;
+
+ done[track]++;
+ }
+ playlist[i].start = 0;
+
+ free(done);
+ }
+ else if (playmode >= 2 && cd->lists && cd->lists[playmode - 2].name)
+ {
+ count = 2; /* one terminating entry, and one for start */
+ thislist = cd->lists[playmode - 2].list;
+
+ for (i = 0; thislist[i]; i++)
+ if (thislist[i + 1] != thislist[i] + 1)
+ count++;
+
+ if (playlist != NULL)
+ free(playlist);
+ playlist = malloc(sizeof (*playlist) * count);
+ if (playlist == NULL)
+ {
+ perror("playlist");
+ exit(1);
+ }
+
+ count = 0;
+ if (starttrack)
+ {
+ playlist[0].start = starttrack;
+ for (track = 0; thislist[track]; track++)
+ if (starttrack == thislist[track])
+ break;
+ if (! thislist[track])
+ {
+ playlist[0].end = starttrack + 1;
+ playlist[1].start = thislist[0];
+ count = 1;
+ track = 0;
+ }
+ }
+ else
+ {
+ playlist[0].start = thislist[0];
+ track = 0;
+ }
+
+ for (i = track; thislist[i]; i++)
+ if (thislist[i + 1] != thislist[i] + 1)
+ {
+ playlist[count].end = thislist[i] + 1;
+ count++;
+ playlist[count].start = thislist[i + 1];
+ }
+ }
+ else
+ {
+ for (i = starttrack ? starttrack - 1 : 0; i < cur_ntracks; i++)
+ if (avoiding && ! (cd->trk[i].avoid || cd->trk[i].data))
+ {
+ playlist[entry].start = i + 1;
+ avoiding = 0;
+ }
+ else if (! avoiding && (cd->trk[i].avoid ||
+ cd->trk[i].data))
+ {
+ playlist[entry].end = i + 1;
+ avoiding = 1;
+ entry++;
+ }
+ if (! avoiding)
+ playlist[entry].end = i + 1;
+ playlist[entry + !avoiding].start = 0;
+ }
+
+ /*
+ * Now go through the list, whatever its source, and figure out
+ * cumulative starting times for each entry.
+ */
+ entry = count = 0;
+ do {
+ playlist[entry].starttime = count;
+
+ if (playlist[entry].start)
+ for (i = playlist[entry].start; i <
+ playlist[entry].end; i++)
+ count += cd->trk[i - 1].length;
+ } while (playlist[entry++].start);
+}
+
+/*
+ * Find a particular track's location in the current playlist. Sets the
+ * appropriate variables (cur_listno, cur_firsttrack, cur_lasttrack).
+ */
+void
+pl_find_track( int track )
+{
+ int i;
+
+ if (playlist == NULL)
+ {
+#ifndef NDEBUG
+ fprintf(stderr, "Null playlist! Huh?\n");
+#endif
+ return;
+ }
+
+ for (i = 0; playlist[i].start; i++)
+ if (track >= playlist[i].start && track < playlist[i].end)
+ {
+ cur_listno = i + 1;
+ cur_firsttrack = playlist[i].start;
+ cur_lasttrack = playlist[i].end - 1;
+ return;
+ }
+
+ /*
+ * Couldn't find the track in question. Make a special entry with
+ * just that track.
+ */
+ if (! playlist[i].start)
+ {
+ playlist = realloc(playlist, (i + 2) * sizeof(*playlist));
+ if (playlist == NULL)
+ {
+ perror("playlist realloc");
+ exit(1);
+ }
+
+ playlist[i + 1].start = playlist[i + 1].end = 0;
+ playlist[i + 1].starttime = playlist[i].starttime +
+ cd->trk[track - 1].length;
+ playlist[i].start = track;
+ playlist[i].end = track + 1;
+ cur_listno = i + 1;
+ cur_firsttrack = track;
+ cur_lasttrack = track;
+ }
+}