1 /*
2     TiMidity -- Experimental MIDI to WAVE converter
3     Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4     Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif /* HAVE_CONFIG_H */
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <windows.h>
28 #include <windowsx.h>
29 #undef RC_NONE
30 #include "timidity.h"
31 #include "common.h"
32 #include "instrum.h"
33 #include "playmidi.h"
34 #include "readmidi.h"
35 #include "controls.h"
36 #include "w32g.h"
37 #include "w32g_res.h"
38 
39 #define W32G_RANDOM_IS_SHUFFLE
40 
41 void SetNumListWnd(int cursel, int nfiles);
42 
43 // playlist
44 typedef struct _PlayListEntry {
45     char *filename;	// malloc
46     char *title;	// shared with midi_file_info
47     struct midi_file_info *info;
48 } PlayListEntry;
49 static struct {
50     int nfiles;
51     int selected; /* 0..nfiles-1 */
52     int allocated; /* number of PlayListEntry is allocated */
53     PlayListEntry *list;
54 } playlist = {0, 0, 0, NULL};
55 
playlist_box(void)56 static HWND playlist_box(void)
57 {
58     if(!hListWnd)
59 	return 0;
60     return GetDlgItem(hListWnd, IDC_LISTBOX_PLAYLIST);
61 }
62 
w32g_add_playlist1(char * filename,int uniq,int refine)63 static int w32g_add_playlist1(char *filename, int uniq, int refine)
64 {
65     PlayListEntry *entry;
66     char *title;
67     struct midi_file_info *info;
68 
69     if(uniq)
70     {
71 	int i;
72 	for(i = 0; i < playlist.nfiles; i++)
73 	    if(pathcmp(filename, playlist.list[i].filename, 0) == 0)
74 		return 0;
75     }
76 
77     title = get_midi_title(filename);
78     info = get_midi_file_info(filename, 1);
79     if(refine && info->format < 0)
80 	return 0;
81 
82     if(playlist.allocated == 0)
83     {
84 	playlist.allocated = 32;
85 	playlist.list = (PlayListEntry *)safe_malloc(playlist.allocated *
86 						     sizeof(PlayListEntry));
87     }
88     else if(playlist.nfiles == playlist.allocated)
89     {
90 	playlist.allocated *= 2;
91 	playlist.list = (PlayListEntry *)safe_realloc(playlist.list,
92 						      playlist.allocated *
93 						      sizeof(PlayListEntry));
94     }
95 
96     entry = &playlist.list[playlist.nfiles];
97     entry->filename = safe_strdup(filename);
98     entry->title = title;
99     entry->info = info;
100     playlist.nfiles++;
101 	w32g_shuffle_playlist_reset(1);
102     return 1;
103 }
104 
w32g_add_playlist(int nfiles,char ** files,int expand_flag,int uniq,int refine)105 int w32g_add_playlist(int nfiles, char **files, int expand_flag,
106 		      int uniq, int refine)
107 {
108     char **new_files1;
109     char **new_files2;
110     int i, n;
111     extern int SeachDirRecursive;
112     extern char **FilesExpandDir(int *, char **);
113 
114     if(nfiles == 0)
115 	return 0;
116 
117     if(SeachDirRecursive)
118     {
119 	new_files1 = FilesExpandDir(&nfiles, files);
120 	if(new_files1 == NULL)
121 	    return 0;
122 	expand_flag = 1;
123     }
124     else
125 	new_files1 = files;
126 
127     if(!expand_flag)
128 	new_files2 = new_files1;
129     else
130     {
131 	new_files2 = expand_file_archives(new_files1, &nfiles);
132 	if(new_files2 == NULL)
133 	{
134 	    if(new_files1 != files)
135 	    {
136 		free(new_files1[0]);
137 		free(new_files1);
138 	    }
139 	    return 0;
140 	}
141     }
142 
143     n = 0;
144     for(i = 0; i < nfiles; i++)
145 	n += w32g_add_playlist1(new_files2[i], uniq, refine);
146 
147     if(new_files2 != new_files1)
148     {
149 	free(new_files2[0]);
150 	free(new_files2);
151     }
152     if(new_files1 != files)
153     {
154 	free(new_files1[0]);
155 	free(new_files1);
156     }
157 
158     if(n > 0)
159 	w32g_update_playlist();
160     return n;
161 }
162 
w32g_next_playlist(int skip_invalid_file)163 int w32g_next_playlist(int skip_invalid_file)
164 {
165     while(playlist.selected + 1 < playlist.nfiles)
166     {
167 	playlist.selected++;
168 	if(!skip_invalid_file ||
169 	   playlist.list[playlist.selected].info->file_type != IS_ERROR_FILE)
170 	{
171 	    w32g_update_playlist();
172 	    return 1;
173 	}
174     }
175     return 0;
176 }
177 
w32g_prev_playlist(int skip_invalid_file)178 int w32g_prev_playlist(int skip_invalid_file)
179 {
180     while(playlist.selected > 0)
181     {
182 	playlist.selected--;
183 	if(!skip_invalid_file ||
184 	   playlist.list[playlist.selected].info->file_type != IS_ERROR_FILE)
185 	{
186 	    w32g_update_playlist();
187 	    return 1;
188 	}
189     }
190     return 0;
191 }
192 
w32g_random_playlist(int skip_invalid_file)193 int w32g_random_playlist(int skip_invalid_file)
194 {
195 	int old_selected_index = playlist.selected;
196 	int select;
197 	int err = 0;
198 	for(;;) {
199 		if ( playlist.nfiles == 1) {
200 			select = old_selected_index;
201 		} else {
202 			if ( playlist.nfiles <= 1 )
203 				select = 0;
204 			else if ( playlist.nfiles == 2 )
205 				select = 1;
206 			else
207 				select = int_rand(playlist.nfiles - 1);
208 			select += old_selected_index;
209 			if ( select >= playlist.nfiles )
210 				select -= playlist.nfiles;
211 			if ( select < 0 )
212 				select = 0;
213 		}
214 		playlist.selected = select;
215 		if(!skip_invalid_file ||
216 			playlist.list[playlist.selected].info->file_type != IS_ERROR_FILE) {
217 			w32g_update_playlist();
218 			return 1;
219 		}
220 		if ( playlist.nfiles == 2 ) {
221 			playlist.selected = old_selected_index;
222 			if(!skip_invalid_file ||
223 				playlist.list[playlist.selected].info->file_type != IS_ERROR_FILE) {
224 				w32g_update_playlist();
225 				return 1;
226 			}
227 		}
228 		// for safety.
229 		if (playlist.selected == old_selected_index)
230 			break;
231 		err++;
232 		if (err > playlist.nfiles + 10)
233 			break;
234 	}
235   return 0;
236 }
237 
238 static struct playlist_shuffle_ {
239 	int * volatile list;
240 	int volatile cur;
241 	int volatile allocated;
242 	int volatile max;
243 } playlist_shuffle;
244 static int playlist_shuffle_init = 0;
245 
246 #define PLAYLIST_SHUFFLE_LIST_SIZE 1024
247 
w32g_shuffle_playlist_reset(int preserve)248 int w32g_shuffle_playlist_reset(int preserve )
249 {
250 	int i;
251 	int cur_old = -1;
252 	int max_old = 0;
253 	int max = playlist.nfiles;
254 	int allocate_min;
255 	if ( max < 0 ) max = 0;
256 	if ( playlist_shuffle_init == 0 ){
257 		playlist_shuffle.list = NULL;
258 		playlist_shuffle.allocated = 0;
259 		playlist_shuffle.cur = -1;
260 		playlist_shuffle.max = 0;
261 		playlist_shuffle_init = 1;
262 	}
263 	if ( preserve ) {
264 		cur_old = playlist_shuffle.cur;
265 		max_old = playlist_shuffle.max;
266 	}
267 	allocate_min = playlist_shuffle.allocated - PLAYLIST_SHUFFLE_LIST_SIZE;
268 	if ( allocate_min < 0 ) allocate_min = 0;
269 	if ( playlist_shuffle.list == NULL || max < allocate_min || playlist_shuffle.allocated < max ) {
270 		playlist_shuffle.allocated = (max/PLAYLIST_SHUFFLE_LIST_SIZE + 1) * PLAYLIST_SHUFFLE_LIST_SIZE;
271 		playlist_shuffle.list = (int *) realloc ( playlist_shuffle.list, (playlist_shuffle.allocated + 1) * sizeof(int) );
272 		if ( playlist_shuffle.list == NULL ) {
273 			playlist_shuffle_init = 0;
274 			playlist_shuffle.cur = -1;
275 			playlist_shuffle.max = 0;
276 			return 0;
277 		}
278 	}
279 	for ( i = max_old; i < max; i ++ ){
280 		playlist_shuffle.list[i] = i;
281 	}
282 	playlist_shuffle.list[max] = -1;
283 	playlist_shuffle.cur = cur_old;
284 	playlist_shuffle.max = max;
285 	return 1;
286 }
287 
w32g_shuffle_playlist_next(int skip_invalid_file)288 int w32g_shuffle_playlist_next(int skip_invalid_file)
289 {
290 	if ( !playlist_shuffle_init ) {
291 		if ( !w32g_shuffle_playlist_reset(0) )
292 			return 0;
293 	}
294 	for ( playlist_shuffle.cur ++ ; playlist_shuffle.cur < playlist_shuffle.max; playlist_shuffle.cur ++ ) {
295 		int n = int_rand(playlist_shuffle.max - playlist_shuffle.cur) + playlist_shuffle.cur;
296 		int temp = playlist_shuffle.list[playlist_shuffle.cur];
297 		if ( n > playlist_shuffle.max ) n = playlist_shuffle.max;
298 		playlist_shuffle.list[playlist_shuffle.cur] = playlist_shuffle.list[n];
299 		playlist_shuffle.list[n] = temp;
300 		if ( playlist_shuffle.list[playlist_shuffle.cur] < playlist.nfiles ) {
301 			playlist.selected = playlist_shuffle.list[playlist_shuffle.cur];
302 			if(!skip_invalid_file ||
303 				playlist.list[playlist.selected].info->file_type != IS_ERROR_FILE) {
304 				w32g_update_playlist();
305 				return 1;
306 			}
307 		}
308 	}
309     return 0;
310 }
311 
312 // void w32g_rotate_playlist(int dest) �p
w32g_shuffle_playlist_rotate(int dest,int i1,int i2)313 static int w32g_shuffle_playlist_rotate(int dest, int i1, int i2)
314 {
315     int i, save;
316 
317 	if ( i2 >= playlist_shuffle.max )
318 		i2 = playlist_shuffle.max - 1;
319     if(i1 >= i2)
320 		return 1;
321 
322     if(dest > 0) {
323 		save = playlist_shuffle.list[i2];
324 		for(i = i2; i > i1; i--) /* i: i2 -> i1 */
325 			playlist_shuffle.list[i] = playlist_shuffle.list[i - 1];
326 		playlist_shuffle.list[i] = save;
327 
328 	} else {
329 		save = playlist_shuffle.list[i1];
330 		for(i = i1; i < i2; i++) /* i: i1 -> i2 */
331 			playlist_shuffle.list[i] = playlist_shuffle.list[i + 1];
332 		playlist_shuffle.list[i] = save;
333     }
334 	return 0;
335 }
336 
337 // int w32g_delete_playlist(int pos) �p
w32g_shuffle_playlist_delete(int n)338 static int w32g_shuffle_playlist_delete(int n)
339 {
340 	int i;
341 	int delete_flag = 0;
342 	for ( i = 0; i < playlist_shuffle.max; i++ ) {
343 		if ( playlist_shuffle.list[i] == n ) {
344 			delete_flag = 1;
345 			break;
346 		}
347 	}
348 	for ( ; i < playlist_shuffle.max; i++ ) {
349 		playlist_shuffle.list[i-1] = playlist_shuffle.list[i];
350 	}
351 	for ( i = 0; i < playlist_shuffle.max; i++ ) {
352 		if ( playlist_shuffle.list[i] >= n )
353 			playlist_shuffle.list[i]--;
354 	}
355 	if ( delete_flag )
356 		playlist_shuffle.max--;
357 	return 0;
358 }
359 
w32g_first_playlist(int skip_invalid_file)360 void w32g_first_playlist(int skip_invalid_file)
361 {
362     playlist.selected = 0;
363     if(skip_invalid_file)
364     {
365 	while(playlist.selected < playlist.nfiles &&
366 	      playlist.list[playlist.selected].info->file_type == IS_ERROR_FILE)
367 	    playlist.selected++;
368 	if(playlist.selected == playlist.nfiles)
369 	    playlist.selected = 0;
370     }
371     w32g_update_playlist();
372 }
373 
w32g_goto_playlist(int num,int skip_invalid_file)374 int w32g_goto_playlist(int num, int skip_invalid_file)
375 {
376     if(0 <= num && num < playlist.nfiles)
377     {
378 	playlist.selected = num;
379 	if(skip_invalid_file)
380 	{
381 	    while(playlist.selected < playlist.nfiles &&
382 		  playlist.list[playlist.selected].info->file_type == IS_ERROR_FILE)
383 		playlist.selected++;
384 	    if(playlist.selected == playlist.nfiles)
385 		playlist.selected = num;
386 	}
387 	w32g_update_playlist();
388 	return 1;
389     }
390     return 0;
391 }
392 
w32g_isempty_playlist(void)393 int w32g_isempty_playlist(void)
394 {
395     return playlist.nfiles == 0;
396 }
397 
398 #if 0
399 char *w32g_curr_playlist(void)
400 {
401     if(!playlist.nfiles)
402 	return NULL;
403     return playlist.list[playlist.selected].filename;
404 }
405 #endif
406 
407 // Update an only list at the position.
w32g_update_playlist_pos(int pos)408 void w32g_update_playlist_pos(int pos)
409 {
410     int i, cur, modified;
411     HWND hListBox;
412 
413     if(!(hListBox = playlist_box()))
414 	return;
415 
416     cur = ListBox_GetCurSel(hListBox);
417     modified = 0;
418 	i = pos;
419 	if(i >= 0 && i < playlist.nfiles)
420     {
421 	char *filename, *title, *item1, *item2;
422 	int maxlen, item2_len;
423 	int notitle = 0;
424 
425 	filename = playlist.list[i].filename;
426 	title = playlist.list[i].title;
427 	if(title == NULL || title[0] == '\0')
428 	{
429 	    if(playlist.list[i].info->file_type == IS_ERROR_FILE)
430 		title = " --SKIP-- ";
431 		else
432 		{
433 //		title = " -------- ";
434 		title = playlist.list[i].filename;
435 		notitle = 1;
436 		}
437 	}
438 	maxlen = strlen(filename) + strlen(title) + 32 + 80;
439 	item1 = (char *)new_segment(&tmpbuffer, maxlen);
440 	if(!notitle)
441 	{
442 	if(i == playlist.selected)
443 	    snprintf(item1, maxlen, "==>%-80s   ==>(%s)", title, filename);
444 	else
445 	    snprintf(item1, maxlen, "   %-80s      (%s)", title, filename);
446 	} else
447 	{
448 	if(i == playlist.selected)
449 	    snprintf(item1, maxlen, "==>%-80s   ==>(%s)", title, filename);
450 	else
451 	    snprintf(item1, maxlen, "   %-80s      (%s)", title, filename);
452 	}
453 	item2_len = ListBox_GetTextLen(hListBox, i);
454 	item2 = (char *)new_segment(&tmpbuffer, item2_len + 1);
455 	ListBox_GetText(hListBox, i, item2);
456 	if(strcmp(item1, item2) != 0)
457 	{
458 	    ListBox_DeleteString(hListBox, i);
459 	    ListBox_InsertString(hListBox, i, item1);
460 	    modified = 1;
461 	}
462 	reuse_mblock(&tmpbuffer);
463     }
464 
465     if(modified && cur==pos)
466     {
467 	if(cur < 0)
468 	    cur = playlist.selected;
469 	else if(cur >= playlist.nfiles - 1)
470 	    cur = playlist.nfiles - 1;
471 	ListBox_SetCurSel(hListBox, cur);
472 	SetNumListWnd(cur,playlist.nfiles);
473     }
474 }
475 
w32g_update_playlist(void)476 void w32g_update_playlist(void)
477 {
478 #if 0
479     int i, cur, modified;
480     HWND hListBox;
481 
482     if(!(hListBox = playlist_box()))
483 	return;
484 
485     cur = ListBox_GetCurSel(hListBox);
486     modified = 0;
487     for(i = 0; i < playlist.nfiles; i++)
488     {
489 	char *filename, *title, *item1, *item2;
490 	int maxlen, item2_len;
491 
492 	filename = playlist.list[i].filename;
493 	title = playlist.list[i].title;
494 	if(title == NULL || title[0] == '\0')
495 	{
496 	    if(playlist.list[i].info->file_type == IS_ERROR_FILE)
497 		title = " --SKIP-- ";
498 	    else
499 		title = " -------- ";
500 	}
501 	maxlen = strlen(filename) + strlen(title) + 32;
502 	item1 = (char *)new_segment(&tmpbuffer, maxlen);
503 	if(i == playlist.selected)
504 	    snprintf(item1, maxlen, "==>%04d %s (%s)", i + 1, title, filename);
505 	else
506 	    snprintf(item1, maxlen, "   %04d %s (%s)", i + 1, title, filename);
507 	item2_len = ListBox_GetTextLen(hListBox, i);
508 	item2 = (char *)new_segment(&tmpbuffer, item2_len + 1);
509 	ListBox_GetText(hListBox, i, item2);
510 	if(strcmp(item1, item2) != 0)
511 	{
512 	    ListBox_DeleteString(hListBox, i);
513 	    ListBox_InsertString(hListBox, i, item1);
514 	    modified = 1;
515 	}
516 	reuse_mblock(&tmpbuffer);
517     }
518 
519     if(modified)
520     {
521 	if(cur < 0)
522 	    cur = playlist.selected;
523 	else if(cur >= playlist.nfiles - 1)
524 	    cur = playlist.nfiles - 1;
525 	ListBox_SetCurSel(hListBox, cur);
526 	SetNumListWnd(cur,playlist.nfiles);
527     }
528 #else
529     int i, cur, modified;
530     HWND hListBox;
531 
532     if(!(hListBox = playlist_box()))
533 	return;
534 
535     cur = ListBox_GetCurSel(hListBox);
536     modified = 0;
537     for(i = 0; i < playlist.nfiles; i++)
538     {
539 		w32g_update_playlist_pos(i);
540     }
541 
542     if(modified)
543     {
544 	if(cur < 0)
545 	    cur = playlist.selected;
546 	else if(cur >= playlist.nfiles - 1)
547 	    cur = playlist.nfiles - 1;
548 	ListBox_SetCurSel(hListBox, cur);
549 	SetNumListWnd(cur,playlist.nfiles);
550     }
551 #endif
552 }
553 
w32g_get_playlist_index(int * selected,int * nfiles,int * cursel)554 void w32g_get_playlist_index(int *selected, int *nfiles, int *cursel)
555 {
556     if(selected != NULL)
557 	*selected = playlist.selected;
558     if(nfiles != NULL)
559 	*nfiles = playlist.nfiles;
560     if(cursel != NULL)
561     {
562 	HWND hListBox;
563 	hListBox = playlist_box();
564 	if(hListBox)
565 	    *cursel = ListBox_GetCurSel(hListBox);
566 	else
567 	    *cursel = 0;
568     }
569 }
570 
w32g_delete_playlist(int pos)571 int w32g_delete_playlist(int pos)
572 {
573     int i;
574     HWND hListBox;
575 
576     if(!(hListBox = playlist_box()))
577 	return 0;
578 
579     if(pos >= playlist.nfiles)
580 	return 0;
581 
582 #ifdef W32G_RANDOM_IS_SHUFFLE
583 	w32g_shuffle_playlist_delete(pos);
584 #endif
585     ListBox_DeleteString(hListBox, pos);
586     free(playlist.list[pos].filename);
587     playlist.nfiles--;
588     for(i = pos; i < playlist.nfiles; i++)
589 		playlist.list[i] = playlist.list[i + 1];
590     if(pos < playlist.selected || pos == playlist.nfiles)
591     {
592 	playlist.selected--;
593 	if(playlist.selected < 0){
594 	    playlist.selected = 0;
595 		SetNumListWnd(playlist.selected,playlist.nfiles);
596 	} else
597 		w32g_update_playlist_pos(playlist.selected);
598     }
599     if(playlist.nfiles > 0)
600     {
601 	if(pos == playlist.nfiles)
602 	    pos--;
603 	ListBox_SetCurSel(hListBox, pos);
604 	SetNumListWnd(pos,playlist.nfiles);
605     }
606     return 1;
607 }
608 
w32g_ismidi_playlist(int n)609 int w32g_ismidi_playlist(int n)
610 {
611     if(n < 0 || n >= playlist.nfiles)
612 	return 0;
613     return playlist.list[n].info->format >= 0;
614 }
615 
w32g_nvalid_playlist(void)616 int w32g_nvalid_playlist(void)
617 {
618     int i, n;
619 
620     n = 0;
621     for(i = 0; i < playlist.nfiles; i++)
622 	if(w32g_ismidi_playlist(i))
623 	    n++;
624     return n;
625 }
626 
w32g_setcur_playlist(void)627 void w32g_setcur_playlist(void)
628 {
629     HWND hListBox;
630     if(!(hListBox = playlist_box()))
631 	return;
632     ListBox_SetCurSel(hListBox, playlist.selected);
633 	SetNumListWnd(playlist.selected,playlist.nfiles);
634 }
635 
w32g_uniq_playlist(int * is_selected_removed)636 int w32g_uniq_playlist(int *is_selected_removed)
637 {
638     int nremoved;
639     int i, n, j1, j2, cursel;
640     HWND hListBox;
641 
642     hListBox = playlist_box();
643     if(hListBox)
644 	cursel = ListBox_GetCurSel(hListBox);
645     else
646 	cursel = -1;
647 
648     if(is_selected_removed != NULL)
649 	*is_selected_removed = 0;
650     nremoved = 0;
651     n = playlist.nfiles;
652     for(i = 0; i < n - 1; i++)
653     {
654 	int save_n;
655 
656 	/* remove list[i] from list[i+1 .. n-1] */
657 	j1 = j2 = i + 1;
658 	save_n = n;
659 	while(j2 < save_n) /* j1 <= j2 */
660 	{
661 	    if(pathcmp(playlist.list[i].filename,
662 		       playlist.list[j2].filename, 0) == 0)
663 	    {
664 		nremoved++;
665 		n--;
666 		free(playlist.list[j2].filename);
667 		if(j2 == playlist.selected &&
668 		   is_selected_removed != NULL &&
669 		   !*is_selected_removed)
670 		{
671 		    *is_selected_removed = 1;
672 		    playlist.selected = j1;
673 		}
674 		if(j2 < playlist.selected)
675 		    playlist.selected--;
676 		if(j2 < cursel)
677 		    cursel--;
678 	    }
679 	    else
680 	    {
681 		playlist.list[j1] = playlist.list[j2];
682 		j1++;
683 	    }
684 	    j2++;
685 	}
686     }
687     if(nremoved)
688     {
689 	for(i = 0; i < nremoved; i++)
690 	    ListBox_DeleteString(hListBox, --playlist.nfiles);
691 	if(cursel >= 0){
692 	    ListBox_SetCurSel(hListBox, cursel);
693 		SetNumListWnd(cursel,playlist.nfiles);
694 	}
695 	w32g_update_playlist();
696     }
697     return nremoved;
698 }
699 
w32g_refine_playlist(int * is_selected_removed)700 int w32g_refine_playlist(int *is_selected_removed)
701 {
702     int nremoved;
703     int i, j1, j2, cursel;
704     HWND hListBox;
705 
706     hListBox = playlist_box();
707     if(hListBox)
708 	cursel = ListBox_GetCurSel(hListBox);
709     else
710 	cursel = -1;
711 
712     if(is_selected_removed != NULL)
713 	*is_selected_removed = 0;
714     nremoved = 0;
715     j1 = j2 = 0;
716     while(j2 < playlist.nfiles) /* j1 <= j2 */
717     {
718 	if(playlist.list[j2].info->format < 0)
719 	{
720 	    nremoved++;
721 	    free(playlist.list[j2].filename);
722 		if(j2 == playlist.selected &&
723 		   is_selected_removed != NULL &&
724 		   !*is_selected_removed)
725 		{
726 		    *is_selected_removed = 1;
727 		    playlist.selected = j1;
728 		}
729 		if(j2 < playlist.selected)
730 		    playlist.selected--;
731 		if(j2 < cursel)
732 		    cursel--;
733 	}
734 	else
735 	{
736 	    playlist.list[j1] = playlist.list[j2];
737 	    j1++;
738 	}
739 	j2++;
740     }
741     if(nremoved)
742     {
743 	for(i = 0; i < nremoved; i++)
744 	    ListBox_DeleteString(hListBox, --playlist.nfiles);
745 	if(cursel >= playlist.nfiles)
746 	    cursel = playlist.nfiles - 1;
747 	if(cursel >= 0){
748 	    ListBox_SetCurSel(hListBox, cursel);
749 		SetNumListWnd(cursel,playlist.nfiles);
750 	}
751 	w32g_update_playlist();
752     }
753     return nremoved;
754 }
755 
w32g_clear_playlist(void)756 void w32g_clear_playlist(void)
757 {
758     HWND hListBox;
759 
760     hListBox = playlist_box();
761     while(playlist.nfiles > 0)
762     {
763 	playlist.nfiles--;
764 	free(playlist.list[playlist.nfiles].filename);
765 #if 0
766 	if(hListBox)
767 	    ListBox_DeleteString(hListBox, playlist.nfiles);
768 #endif
769     }
770 //	LB_RESETCONTENT
771 	if(hListBox)
772 	    ListBox_ResetContent(hListBox);
773 	playlist.selected = 0;
774 	SetNumListWnd(0,0);
775 }
776 
w32g_rotate_playlist(int dest)777 void w32g_rotate_playlist(int dest)
778 {
779     int i, i1, i2;
780     HWND hListBox;
781     PlayListEntry save;
782 	char temp[1024];
783 
784     if(playlist.nfiles == 0)
785 	return;
786     if(!(hListBox = playlist_box()))
787 	return;
788 
789     i1 = ListBox_GetCurSel(hListBox);
790     i2 = playlist.nfiles - 1;
791     if(i1 >= i2)
792 	return;
793 
794 #ifdef W32G_RANDOM_IS_SHUFFLE
795 	w32g_shuffle_playlist_rotate(dest,i1,i2);
796 #endif
797     if(dest > 0)
798     {
799 	save = playlist.list[i2];
800 	for(i = i2; i > i1; i--) /* i: i2 -> i1 */
801 	    playlist.list[i] = playlist.list[i - 1];
802 	playlist.list[i] = save;
803 	ListBox_GetText(hListBox,i2,temp);
804     ListBox_DeleteString(hListBox,i2);
805     ListBox_InsertString(hListBox,i1,temp);
806 	ListBox_SetCurSel(hListBox,i1);
807 	if(playlist.selected == i2){
808 	    playlist.selected = i1;
809 		w32g_update_playlist_pos(playlist.selected);
810 	} else if(i1 <= playlist.selected && playlist.selected < i2){
811 	    playlist.selected++;
812 		w32g_update_playlist_pos(playlist.selected);
813 	}
814     }
815     else
816     {
817 	save = playlist.list[i1];
818 	for(i = i1; i < i2; i++) /* i: i1 -> i2 */
819 	    playlist.list[i] = playlist.list[i + 1];
820 	playlist.list[i] = save;
821 	ListBox_GetText(hListBox,i1,temp);
822     ListBox_DeleteString(hListBox,i1);
823     ListBox_InsertString(hListBox,-1,temp);
824 	ListBox_SetCurSel(hListBox,i1);
825 	if(playlist.selected == i1){
826 	    playlist.selected = i2;
827 		w32g_update_playlist_pos(playlist.selected);
828 	} else if(i1 < playlist.selected && playlist.selected <= i2){
829 	    playlist.selected--;
830 		w32g_update_playlist_pos(playlist.selected);
831 	}
832     }
833 }
834 
w32g_get_playlist(int idx)835 char *w32g_get_playlist(int idx)
836 {
837     if(idx < 0 || idx >= playlist.nfiles)
838 	return NULL;
839     return playlist.list[idx].filename;
840 }
841 
w32g_free_playlist(void)842 void w32g_free_playlist(void)
843 
844 
845 
846 {
847 	PlayListEntry *entry;
848 	int i;
849 
850 	for(i=0; i < playlist.nfiles; i++){
851 		entry = &playlist.list[i];
852 		if(entry->filename != NULL) free(entry->filename);
853 	}
854 	if(playlist.list != NULL) free(playlist.list);
855 	if(playlist_shuffle.list != NULL) free(playlist_shuffle.list);
856 }
857