1 /*
2 * $Id: cdinfo.c,v 1.6 1999/02/14 16:47:40 dirk Exp $
3 *
4 * This file is part of WorkMan, the civilized CD player library
5 * (c) 1991-1997 by Steven Grimm (original author)
6 * (c) by Dirk F�rsterling (current 'author' = maintainer)
7 * The maintainer can be contacted by his e-mail address:
8 * milliByte@DeathsDoor.com
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the Free
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 *
25 * Get information about a CD.
26 */
27
28 static char cdinfo_id[] = "$Id: cdinfo.c,v 1.6 1999/02/14 16:47:40 dirk Exp $";
29
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/types.h>
35
36 #include "include/wm_config.h"
37
38 #include "include/wm_struct.h"
39 #include "include/wm_cdrom.h"
40 #include "include/wm_cdinfo.h"
41 #include "include/wm_database.h"
42 #include "include/wm_helpers.h"
43
44 struct wm_play *playlist = NULL;
45 struct wm_cdinfo thiscd, *cd = &thiscd;
46
47 int cur_track = -1; /* Current track number, starting at 1 */
48 int cur_index = 0; /* Current index mark */
49 int cur_lasttrack = 999; /* Last track to play in current chunk */
50 int cur_firsttrack = 0; /* First track of current chunk */
51 int cur_pos_abs; /* Current absolute position in seconds */
52 int cur_frame; /* Current frame number */
53 int cur_pos_rel; /* Current track-relative position in seconds */
54 int cur_tracklen; /* Length in seconds of current track */
55 int cur_cdlen; /* Length in seconds of entire CD */
56 int cur_ntracks; /* Number of tracks on CD (= tracks + sections) */
57 int cur_nsections; /* Number of sections currently defined */
58 enum wm_cd_modes cur_cdmode = WM_CDM_EJECTED;
59 int cur_listno; /* Current index into the play list, if playing */
60 char * cur_artist; /* Name of current CD's artist */
61 char * cur_cdname; /* Album name */
62 char * cur_trackname; /* Take a guess */
63 char cur_contd; /* Continued flag */
64 char cur_avoid; /* Avoid flag */
65
66 int exit_on_eject = 0;
67
68 int cur_stopmode = -1;
69 extern int info_modified;
70
71 /*
72 * insert_trackinfo()
73 *
74 * Add a new track to the CD info structure. Pass the position of the new
75 * entry in the track list -- 0 will make this the first track, 1 the second,
76 * etc. The new entry will be zeroed out.
77 */
78 void
insert_trackinfo(num)79 insert_trackinfo(num)
80 int num;
81 {
82 struct wm_trackinfo *newtrk;
83
84 /* Easy case: the list is empty */
85 if (cd->trk == NULL) {
86 if ((cd->trk = (struct wm_trackinfo *) calloc(1,
87 sizeof(*newtrk))) == NULL)
88 {
89 nomem:
90 perror("insert_trackinfo");
91 exit(1);
92 } else {
93 return;
94 } /* if() else */
95 } /* if() */
96 /* Stick the new entry in cd->trk[]. */
97 if ((newtrk = (struct wm_trackinfo *) malloc(sizeof(*newtrk) *
98 (cur_ntracks + 1))) == NULL)
99 goto nomem;
100
101 if (num)
102 memcpy(newtrk, cd->trk, sizeof(*newtrk) * num);
103 memset(&newtrk[num], 0, sizeof(*newtrk));
104 if (num < cur_ntracks)
105 memcpy(&newtrk[num + 1], &cd->trk[num], sizeof(*newtrk) *
106 (cur_ntracks - num));
107
108 free(cd->trk);
109 cd->trk = newtrk;
110 }
111
112 /*
113 * split_trackinfo()
114 *
115 * Split a track in two at a particular position (absolute, in frames). All
116 * internal data structures and variables will be adjusted to the new
117 * numbering scheme. Pass in the track number (>=1) to split, which is also
118 * the index into cd->trk[] of the new entry.
119 *
120 * If pos is within 1 second of the start of another track, the split fails.
121 *
122 * Returns 1 on success, 0 if the track couldn't be inserted.
123 *
124 * Note: updating user interface elements is up to the caller.
125 */
126 int
split_trackinfo(int pos)127 split_trackinfo( int pos )
128 {
129 int i, l, num;
130
131 if (pos < cd->trk[0].start)
132 return (0);
133
134 /* First find the appropriate track. */
135 for (num = 0; num < cur_ntracks; num++)
136 if (cd->trk[num].start - 75 < pos &&
137 cd->trk[num].start + 75 > pos)
138 return (0);
139 else if (cd->trk[num].start > pos)
140 break;
141 if (num == 0)
142 return (0);
143
144 /* Insert the new entry into the track array. */
145 insert_trackinfo(num);
146
147 /* Update the easy variables. */
148 if (cur_track > num)
149 cur_track++;
150 if (cur_firsttrack > num)
151 cur_firsttrack++;
152 if (cur_lasttrack > num)
153 cur_lasttrack++;
154
155 /* Update the user-defined playlists. */
156 if (cd->lists != NULL)
157 for (l = 0; cd->lists[l].name != NULL; l++)
158 if (cd->lists[l].list != NULL)
159 for (i = 0; cd->lists[l].list[i]; i++)
160 if (cd->lists[l].list[i] > num)
161 cd->lists[l].list[i]++;
162
163 /* Update the internal playlist. */
164 if (playlist != NULL)
165 for (i = 0; playlist[i].start; i++)
166 {
167 if (playlist[i].start > num)
168 playlist[i].start++;
169 if (playlist[i].end > num)
170 playlist[i].end++;
171 }
172
173 /* Now adjust the information in cd->trk[]. */
174 cd->trk[num].start = pos;
175 if (num == cur_ntracks)
176 cd->trk[num].length = cur_cdlen - pos / 75;
177 else
178 cd->trk[num].length = (cd->trk[num + 1].start - pos) / 75;
179 cd->trk[num - 1].length -= cd->trk[num].length;
180 if (cur_track == num)
181 cur_tracklen -= cd->trk[num].length;
182 cd->trk[num].track = cd->trk[num - 1].track;
183 cd->trk[num].data = cd->trk[num - 1].data;
184 cd->trk[num].contd = 1;
185 cd->trk[num].volume = cd->trk[num - 1].volume;
186
187 if (cd->trk[num - 1].section == 0)
188 cd->trk[num - 1].section = 1;
189 cd->trk[num].section = cd->trk[num - 1].section + 1;
190
191 cur_ntracks++;
192 cur_nsections++;
193
194 for (i = num + 1; i < cur_ntracks; i++)
195 if (cd->trk[i].track == cd->trk[num].track)
196 cd->trk[i].section++;
197
198 return (1);
199 }
200
201 /*
202 * remove_trackinfo()
203 *
204 * Remove a track's internal data. This is similar to split_trackinfo()
205 * above, but simpler. A track's initial section can't be removed. Track
206 * numbers start at 0.
207 *
208 * Returns 1 on success, 0 on failure.
209 */
210 int
remove_trackinfo(int num)211 remove_trackinfo( int num )
212 {
213 int i, l;
214
215 if (num < 1 || num >= cur_ntracks || cd->trk[num].section < 2)
216 return (0);
217
218 cd->trk[num - 1].length += cd->trk[num].length;
219
220 for (i = num; i < cur_ntracks - 1; i++)
221 memcpy(&cd->trk[i], &cd->trk[i + 1], sizeof(cd->trk[0]));
222
223 if (cur_track > num)
224 cur_track--;
225 if (cur_firsttrack > num)
226 cur_firsttrack--;
227 if (cur_lasttrack > num)
228 cur_lasttrack--;
229
230 /* Update the user-defined playlists. */
231 if (cd->lists != NULL)
232 for (l = 0; cd->lists[l].name != NULL; l++)
233 if (cd->lists[l].list != NULL)
234 for (i = 0; cd->lists[l].list[i]; i++)
235 if (cd->lists[l].list[i] > num)
236 cd->lists[l].list[i]--;
237
238 /* Update the internal playlist. */
239 if (playlist != NULL)
240 for (i = 0; playlist[i].start; i++)
241 {
242 if (playlist[i].start > num)
243 playlist[i].start--;
244 if (playlist[i].end > num)
245 playlist[i].end--;
246 }
247
248 cur_ntracks--;
249 cur_nsections--;
250
251 /*
252 * Update the section numbers for this track. If this is the only
253 * user-created section in a track, get rid of the section number
254 * in the track's entry.
255 */
256 if (num == cur_ntracks || cd->trk[num - 1].track != cd->trk[num].track)
257 {
258 if (cd->trk[num - 1].section == 1)
259 cd->trk[num - 1].section = 0;
260 }
261 else
262 for (i = num; i < cur_ntracks; i++)
263 if (cd->trk[i].track == cd->trk[num - 1].track)
264 cd->trk[i].section--;
265
266 return (1);
267 }
268
269 /*
270 * listentry()
271 *
272 * Return a scrolling list entry.
273 */
274 char *
listentry(int num)275 listentry( int num )
276 {
277 static char buf[600];
278 char *name, tracknum[20];
279 int digits;
280 int sdigits;
281
282 if (num >= 0 && num < cur_ntracks)
283 {
284
285 /*
286 if (big_spaces)
287 {
288 digits = 2;
289 sdigits = cur_nsections < 9 ? -1 : -2;
290 }
291 else
292 {
293 digits = cd->trk[num].track < 10 ? 3 : 2;
294 sdigits = cur_nsections < 9 ? -1 : -3;
295 }
296 */
297
298 digits = 2;
299 sdigits = cur_nsections < 9 ? -1 : -2;
300
301 name = cd->trk[num].songname ? cd->trk[num].songname : "";
302
303 if (cur_nsections)
304 {
305 if (cd->trk[num].section > 9)
306 {
307 sprintf(tracknum, "%*d.%d", digits,
308 cd->trk[num].track,
309 cd->trk[num].section);
310 } else {
311 if (cd->trk[num].section)
312 {
313 sprintf(tracknum, "%*d.%*d", digits,
314 cd->trk[num].track, sdigits,
315 cd->trk[num].section);
316 } else {
317 sprintf(tracknum, "%*d%*s", digits,
318 cd->trk[num].track,
319 2 - sdigits, " ");
320 /* 2 - sdigits - big_spaces, " ");*/
321 }
322 }
323 } else {
324 sprintf(tracknum, "%*d", digits, cd->trk[num].track);
325 }
326
327 if (cd->trk[num].data)
328 {
329 sprintf(buf, "%s) %3dMB %s", tracknum,
330 cd->trk[num].length / 1024, name);
331 } else {
332 sprintf(buf, "%s) %02d:%02d %s", tracknum,
333 cd->trk[num].length / 60,
334 cd->trk[num].length % 60, name);
335 }
336
337 return (buf);
338 } else {
339 return (NULL);
340 }
341 } /* listentry() */
342
343 /*
344 * trackname()
345 *
346 * Return a track's name.
347 */
348 char *
trackname(int num)349 trackname( int num )
350 {
351 if (num >= 0 && num < cur_ntracks)
352 {
353 if (cd->trk[num].songname)
354 {
355 return (cd->trk[num].songname);
356 } else {
357 return ("");
358 }
359 } else {
360 return (NULL);
361 }
362 } /* trackname() */
363
364 /*
365 * tracklen()
366 *
367 * Return a track's length in seconds.
368 */
369 int
tracklen(int num)370 tracklen( int num )
371 {
372 if (cd != NULL && num >= 0 && num < cur_ntracks)
373 return (cd->trk[num].length);
374 else
375 return (0);
376 }
377
378 /*
379 * get_default_volume()
380 *
381 * Return the default volume (0-32, 0=none) for the CD or a track.
382 */
383 int
get_default_volume(int track)384 get_default_volume( int track )
385 {
386 if (! track)
387 return (cd->volume);
388 else if (track <= cur_ntracks)
389 return (cd->trk[track - 1].volume);
390 else
391 return (0);
392 }
393
394 /*
395 * get_contd()
396 *
397 * Return the contd value for a track.
398 */
399 int
get_contd(int num)400 get_contd( int num )
401 {
402 if (num >= 0 && num < cur_ntracks)
403 return (cd->trk[num].contd);
404 else
405 return (0);
406 }
407
408 /*
409 * get_avoid()
410 *
411 * Return the avoid value for a track.
412 */
413 int
get_avoid(int num)414 get_avoid( int num )
415 {
416 if (num >= 0 && num < cur_ntracks)
417 return (cd->trk[num].avoid);
418 else
419 return (0);
420 }
421
422 /*
423 * get_autoplay()
424 *
425 * Is autoplay set on this disc?
426 */
427 int
get_autoplay(void)428 get_autoplay( void )
429 {
430 return ( cd->autoplay );
431 }
432
433 /*
434 * get_playmode()
435 *
436 * Return the default playmode for the CD.
437 */
438 int
get_playmode(void)439 get_playmode( void )
440 {
441 return ( cd->playmode );
442 }
443
444 /*
445 * get_runtime()
446 *
447 * Return the total running time for the current playlist in seconds.
448 */
449 int
get_runtime(void)450 get_runtime( void )
451 {
452 int i;
453
454 if (playlist == NULL || playlist[0].start == 0 || cur_firsttrack == -1)
455 return (cd == NULL ? 0 : cd->length);
456
457 for (i = 0; playlist[i].start; i++)
458 ;
459
460 return (playlist[i].starttime);
461 }
462
463 /*
464 * default_volume()
465 *
466 * Set the default volume for the CD or a track.
467 */
468 void
default_volume(int track,int vol)469 default_volume( int track, int vol )
470 {
471 if (track == 0)
472 cd->volume = vol;
473 else if (track <= cur_ntracks)
474 cd->trk[track - 1].volume = vol;
475 }
476
477 /*
478 * Play the next thing on the playlist, if any.
479 */
480 void
play_next_entry(int forward)481 play_next_entry( int forward )
482 {
483 if (cd == NULL)
484 return;
485 if (playlist != NULL && playlist[cur_listno].start)
486 {
487 wm_cd_play(playlist[cur_listno].start, 0,
488 playlist[cur_listno].end);
489 cur_listno++;
490 }
491 else
492 wm_cd_stop();
493 }
494
495 /*
496 * Play the next track, following playlists as necessary.
497 */
498 void
play_next_track(int forward)499 play_next_track( int forward )
500 {
501 if (cd == NULL)
502 return;
503
504 /* Is the current playlist entry done? Move on, if so. */
505 if (playlist == NULL || cur_track + 1 == playlist[cur_listno - 1].end)
506 play_next_entry( forward );
507 else
508 wm_cd_play(cur_track + 1, 0, playlist[cur_listno - 1].end);
509 }
510
511 /*
512 * Play the previous track, hopping around the playlist as necessary.
513 */
514 void
play_prev_track(int forward)515 play_prev_track( int forward )
516 {
517 if (cd == NULL)
518 return;
519
520 if (playlist == NULL)
521 return;
522
523 /* If we're in the middle of this playlist entry, go back one track */
524 if (cur_track > playlist[cur_listno - 1].start)
525 wm_cd_play(cur_track - 1, 0, playlist[cur_listno - 1].end);
526 else
527 if (cur_listno > 1)
528 {
529 cur_listno--;
530 wm_cd_play(playlist[cur_listno - 1].end - 1, 0,
531 playlist[cur_listno - 1].end);
532 }
533 else
534 wm_cd_play(playlist[0].start, 0, playlist[0].end);
535 }
536
537 /*
538 * stash_cdinfo(artist, cdname)
539 */
540 void
stash_cdinfo(char * artist,char * cdname,int autoplay,int playmode)541 stash_cdinfo(char *artist, char *cdname, int autoplay, int playmode )
542 {
543 if (cd != NULL)
544 {
545 if (strcmp(cd->artist, artist))
546 info_modified = 1;
547 strcpy(cd->artist, artist);
548
549 if (strcmp(cd->cdname, cdname))
550 info_modified = 1;
551 strcpy(cd->cdname, cdname);
552
553 if (!!cd->autoplay != !!autoplay)
554 info_modified = 1;
555 cd->autoplay = autoplay;
556
557 if (!!cd->playmode != !!playmode)
558 info_modified = 1;
559 cd->playmode = playmode;
560 }
561 } /* stash_cdinfo() */
562
563 /*
564 * wipe_cdinfo()
565 *
566 * Clear out all a CD's soft information (presumably in preparation for
567 * reloading from the database.)
568 */
569 void
wipe_cdinfo(void)570 wipe_cdinfo( void )
571 {
572 struct wm_playlist *l;
573 int i;
574
575 if (cd != NULL)
576 {
577 cd->artist[0] = cd->cdname[0] = '\0';
578 cd->autoplay = cd->playmode = cd->volume = 0;
579 cd->whichdb = NULL;
580 freeup(&cd->otherrc);
581 freeup(&cd->otherdb);
582
583 if (thiscd.lists != NULL)
584 {
585 for (l = thiscd.lists; l->name != NULL; l++)
586 {
587 free(l->name);
588 free(l->list);
589 }
590 freeup( (char **)&thiscd.lists );
591 }
592
593 for (i = 0; i < cur_ntracks; i++)
594 {
595 freeup(&cd->trk[i].songname);
596 freeup(&cd->trk[i].otherrc);
597 freeup(&cd->trk[i].otherdb);
598 cd->trk[i].avoid = cd->trk[i].contd = 0;
599 cd->trk[i].volume = 0;
600 if (cd->trk[i].section > 1)
601 remove_trackinfo(i--);
602 }
603 }
604 }
605
606 /*
607 * stash_trkinfo(track, songname, contd, avoid)
608 *
609 * Update information about a track on the current CD.
610 */
611 void
stash_trkinfo(int track,char * songname,int contd,int avoid)612 stash_trkinfo( int track, char *songname, int contd, int avoid )
613 {
614 if (cd != NULL)
615 {
616 track--;
617 if (!!cd->trk[track].contd != !!contd)
618 info_modified = 1;
619 cd->trk[track].contd = track ? contd : 0;
620
621 if (!!cd->trk[track].avoid != !!avoid)
622 info_modified = 1;
623 cd->trk[track].avoid = avoid;
624
625 if ((cd->trk[track].songname == NULL && songname[0]) ||
626 (cd->trk[track].songname != NULL &&
627 strcmp(cd->trk[track].songname, songname)))
628 {
629 info_modified = 1;
630 wm_strmcpy(&cd->trk[track].songname, songname);
631 }
632 }
633 }
634
635 /*
636 * new_list()
637 *
638 * Add a playlist to a CD.
639 */
640 struct wm_playlist *
new_list(cd,listname)641 new_list(cd, listname)
642 struct wm_cdinfo *cd;
643 char *listname;
644 {
645 int nlists = 0;
646 struct wm_playlist *l;
647
648 if (cd->lists != NULL)
649 {
650 for (nlists = 0; cd->lists[nlists].name != NULL; nlists++)
651 ;
652 l = (struct wm_playlist *)realloc(cd->lists, (nlists + 2) *
653 sizeof (struct wm_playlist));
654 }
655 else
656 l = (struct wm_playlist *)malloc(2 * sizeof (struct wm_playlist));
657
658 if (l == NULL)
659 return (NULL);
660
661 l[nlists + 1].name = NULL;
662 l[nlists].name = NULL; /* so wm_strmcpy doesn't free() it */
663 wm_strmcpy(&l[nlists].name, listname);
664 l[nlists].list = NULL;
665 cd->lists = l;
666
667 return (&l[nlists]);
668 }
669
670 /*
671 * make_playlist()
672 *
673 * Construct a playlist for the current CD. If we're in shuffle mode, play
674 * each non-avoided track once, keeping continued tracks in the right order.
675 *
676 * If playmode is 2, use playlist number (playmode-2). XXX should do
677 * bounds checking on this, probably.
678 *
679 * If consecutive tracks are being played, only make one playlist entry for
680 * them, so the CD player won't pause between tracks while we wake up.
681 */
682 void
make_playlist(int playmode,int starttrack)683 make_playlist( int playmode, int starttrack )
684 {
685 int i, avoiding = 1, entry = 0, count, track,
686 *thislist;
687
688 cur_listno = 0;
689 if (playlist != NULL)
690 free(playlist);
691 playlist = malloc(sizeof (*playlist) * (cur_ntracks + 1));
692 if (playlist == NULL)
693 {
694 perror("playlist");
695 exit(1);
696 }
697
698 /* If this is a data-only CD, we can't play it. */
699 if ((starttrack && cd->trk[starttrack - 1].data) ||
700 (cur_ntracks == 1 && cd->trk[0].data))
701 {
702 playlist[0].start = 0;
703 playlist[0].end = 0;
704 playlist[1].start = 0;
705 return;
706 }
707
708 if (playmode == 1)
709 {
710 char *done = malloc(cur_ntracks);
711
712 if (done == NULL)
713 {
714 perror("randomizer");
715 exit(1);
716 }
717
718 count = cur_ntracks;
719 if (starttrack && cd->trk[starttrack - 1].avoid)
720 count++;
721 for (i = 0; i < cur_ntracks; i++)
722 if (cd->trk[i].contd || cd->trk[i].avoid ||
723 cd->trk[i].data)
724 {
725 done[i] = 1;
726 count--;
727 }
728 else
729 done[i] = 0;
730
731 for (i = 0; i < count; i++)
732 {
733 int end; /* for readability */
734 if (starttrack)
735 {
736 track = starttrack - 1;
737 starttrack = 0;
738 }
739 else
740 while (done[track = rand() % cur_ntracks])
741 ;
742
743 playlist[i].start = track + 1;
744
745 /* play all subsequent continuation tracks too */
746 for (end = track + 1; end < cur_ntracks + 1; end++)
747 if (! cd->trk[end].contd ||
748 cd->trk[end].avoid ||
749 cd->trk[end].data)
750 break;
751 playlist[i].end = end + 1;
752
753 done[track]++;
754 }
755 playlist[i].start = 0;
756
757 free(done);
758 }
759 else if (playmode >= 2 && cd->lists && cd->lists[playmode - 2].name)
760 {
761 count = 2; /* one terminating entry, and one for start */
762 thislist = cd->lists[playmode - 2].list;
763
764 for (i = 0; thislist[i]; i++)
765 if (thislist[i + 1] != thislist[i] + 1)
766 count++;
767
768 if (playlist != NULL)
769 free(playlist);
770 playlist = malloc(sizeof (*playlist) * count);
771 if (playlist == NULL)
772 {
773 perror("playlist");
774 exit(1);
775 }
776
777 count = 0;
778 if (starttrack)
779 {
780 playlist[0].start = starttrack;
781 for (track = 0; thislist[track]; track++)
782 if (starttrack == thislist[track])
783 break;
784 if (! thislist[track])
785 {
786 playlist[0].end = starttrack + 1;
787 playlist[1].start = thislist[0];
788 count = 1;
789 track = 0;
790 }
791 }
792 else
793 {
794 playlist[0].start = thislist[0];
795 track = 0;
796 }
797
798 for (i = track; thislist[i]; i++)
799 if (thislist[i + 1] != thislist[i] + 1)
800 {
801 playlist[count].end = thislist[i] + 1;
802 count++;
803 playlist[count].start = thislist[i + 1];
804 }
805 }
806 else
807 {
808 for (i = starttrack ? starttrack - 1 : 0; i < cur_ntracks; i++)
809 if (avoiding && ! (cd->trk[i].avoid || cd->trk[i].data))
810 {
811 playlist[entry].start = i + 1;
812 avoiding = 0;
813 }
814 else if (! avoiding && (cd->trk[i].avoid ||
815 cd->trk[i].data))
816 {
817 playlist[entry].end = i + 1;
818 avoiding = 1;
819 entry++;
820 }
821 if (! avoiding)
822 playlist[entry].end = i + 1;
823 playlist[entry + !avoiding].start = 0;
824 }
825
826 /*
827 * Now go through the list, whatever its source, and figure out
828 * cumulative starting times for each entry.
829 */
830 entry = count = 0;
831 do {
832 playlist[entry].starttime = count;
833
834 if (playlist[entry].start)
835 for (i = playlist[entry].start; i <
836 playlist[entry].end; i++)
837 count += cd->trk[i - 1].length;
838 } while (playlist[entry++].start);
839 }
840
841 /*
842 * Find a particular track's location in the current playlist. Sets the
843 * appropriate variables (cur_listno, cur_firsttrack, cur_lasttrack).
844 */
845 void
pl_find_track(int track)846 pl_find_track( int track )
847 {
848 int i;
849
850 if (playlist == NULL)
851 {
852 fprintf(stderr, "Null playlist! Huh?\n");
853 return;
854 }
855
856 for (i = 0; playlist[i].start; i++)
857 if (track >= playlist[i].start && track < playlist[i].end)
858 {
859 cur_listno = i + 1;
860 cur_firsttrack = playlist[i].start;
861 cur_lasttrack = playlist[i].end - 1;
862 return;
863 }
864
865 /*
866 * Couldn't find the track in question. Make a special entry with
867 * just that track.
868 */
869 if (! playlist[i].start)
870 {
871 playlist = realloc(playlist, (i + 2) * sizeof(*playlist));
872 if (playlist == NULL)
873 {
874 perror("playlist realloc");
875 exit(1);
876 }
877
878 playlist[i + 1].start = playlist[i + 1].end = 0;
879 playlist[i + 1].starttime = playlist[i].starttime +
880 cd->trk[track - 1].length;
881 playlist[i].start = track;
882 playlist[i].end = track + 1;
883 cur_listno = i + 1;
884 cur_firsttrack = track;
885 cur_lasttrack = track;
886 }
887 }
888