1 /*
2     TiMidity++ -- MIDI to WAVE converter and player
3     Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4     Copyright (C) 1995 Tuukka Toivonen <tt@cgs.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 	Macintosh interface for TiMidity
21 	by T.Nogami	<t-nogami@happy.email.ne.jp>
22 
23     mac_main.c
24 */
25 
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif /* HAVE_CONFIG_H */
29 #include	<Sound.h>
30 #include	<stdio.h>
31 #include	<stdlib.h>
32 #include	<string.h>
33 #include	<Threads.h>
34 
35 #include	"timidity.h"
36 #include	"common.h"
37 #include	"instrum.h"
38 #include	"playmidi.h"
39 #include	"readmidi.h"
40 #include	"output.h"
41 #include	"controls.h"
42 #include	"tables.h"
43 #include	"wrd.h"
44 #ifdef SUPPORT_SOUNDSPEC
45 #include "soundspec.h"
46 #endif /* SUPPORT_SOUNDSPEC */
47 #include "recache.h"
48 #include "miditrace.h"
49 #include "aq.h"
50 
51 #include	"mac_main.h"
52 #include	"mac_c.h"
53 #include	"mac_util.h"
54 
55 #ifdef MAC_USE_OMS
56 #include	"OMS.h"
57 #include	"mac_oms.h"
58 #endif
59 
60 #define MAIN_INTERFACE  /* non-static */
61 MAIN_INTERFACE void	timidity_start_initialize(void);
62 MAIN_INTERFACE int	timidity_pre_load_configuration(void);
63 MAIN_INTERFACE int	timidity_post_load_configuration(void);
64 MAIN_INTERFACE void	timidity_init_player(void);
65 MAIN_INTERFACE int	timidity_play_main(int nfiles, char **files);
66 MAIN_INTERFACE void	timidity_init_aq_buff(void);
67 
68 extern char *wrdt_open_opts;
69 
70 Boolean	skin_f_repeat, gQuit, gBusy, gShuffle;
71 int		mac_rc, skin_state=WAITING, mac_n_files, nPlaying;
72 long	gStartTick;
73 double	gSilentSec;
74 MidiFile	fileList[LISTSIZE];
75 int		evil_level;
76 int		do_initial_filling;
77 
78 #ifdef __MRC__
79 QDGlobals	qd;
80 #endif
81 
82 /*****************************************/
83 
84 /* ************************************************** */
85 
myHandleOAPP(AppleEvent *,AppleEvent *,long)86 static pascal OSErr myHandleOAPP(AppleEvent* /*theAppleEvent*/, AppleEvent* /*reply*/, long /*handlerRefCon*/)
87 {
88 	return noErr;
89 }
90 
myHandleODOC(AppleEvent * theAppleEvent,AppleEvent *,long)91 static pascal OSErr myHandleODOC(AppleEvent *theAppleEvent, AppleEvent* /*reply*/, long /*handlerRefCon*/)
92 {
93 	int				oldListEnd;
94 	AEDescList		docList;
95 	AEKeyword		keyword;
96 	DescType		returnedType;
97 	FSSpec			theFSSpec;
98 	Size			actualSize;
99 	long			itemsInList;
100 	short			index;
101 	OSErr			err;
102 	KeyMap			keys;
103 
104 	GetKeys(keys);
105 	if( keys[1] & 0x00000004 )
106 		if( mac_SetPlayOption()!=noErr ) return noErr; /* user cancel*/
107 
108 	if ( (err=AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, &docList))!=0 )
109 		return(err);
110 
111 	if ( (err=AECountItems(&docList, &itemsInList))!=0 )
112 		return(err);
113 
114 	oldListEnd=mac_n_files;
115 	for (index = 1; index <= itemsInList; index++) {
116 		if ( (err=AEGetNthPtr(&docList, index, typeFSS, &keyword,
117 								 &returnedType, (Ptr) &theFSSpec, sizeof(FSSpec), &actualSize))!=0 )
118 			return(err);
119 		mac_add_fsspec(&theFSSpec);
120 		//if( isArchiveFile(&theFSSpec) ){
121 		//	mac_add_archive_file(&theFSSpec);
122 		//}else  {
123 		//	mac_add_midi_file(&theFSSpec);
124 		//}
125 	}
126 
127 	if( gShuffle ) ShuffleList( oldListEnd, mac_n_files);
128 	return noErr;
129 }
130 
myHandleQUIT(AppleEvent *,AppleEvent *,long)131 static pascal OSErr myHandleQUIT(AppleEvent* /*theEvent*/, AppleEvent* /*reply*/, long /*refCon*/)
132 {
133 	gQuit=true;
134 	return noErr;	/* don't ExitToShell() here, must return noErr */
135 }
136 /*******************************************************/
137 
InitMenuBar()138 static void InitMenuBar()
139 {
140 	MenuHandle	synth;
141 
142 	SetMenuBar(GetNewMBar(128));
143 	AppendResMenu(GetMenu(128),'DRVR');
144 
145 	synth= GetMenu(mSynth);
146 	InsertMenu(synth, -1); //setup submenu
147 	CheckItem(synth, iTiMidity & 0x0000FFFF, 1);
148 
149 	DrawMenuBar();
150 }
151 
mac_init()152 static void mac_init()
153 {
154 	long	gestaltResponse;
155 
156 	InitGraf( &qd.thePort );
157 	InitFonts();
158 	FlushEvents( everyEvent,0 );
159 	InitWindows();
160 	InitMenus();
161 	TEInit();
162 	InitDialogs( 0 );
163 	InitCursor();
164 	MaxApplZone();
165 	ReadDateTime( (unsigned long*)&qd.randSeed );
166 
167 	if( !((Gestalt(gestaltSystemVersion, &gestaltResponse)==noErr )
168 			&& gestaltResponse>=0x0750))
169 				mac_ErrorExit("\pThis program can run on System 7.5 or later!");
170 
171 	if ((Gestalt(gestaltDragMgrAttr, &gestaltResponse) == noErr)
172 		&& (gestaltResponse & (1 << gestaltDragMgrPresent)))
173 			gHasDragMgr=true;
174 	else gHasDragMgr=false;
175 
176 #if (__MC68K__ && __MC68881__)
177 	if (!((Gestalt(gestaltFPUType, &gestaltResponse) == noErr)
178 		&& (gestaltResponse!=gestaltNoFPU )))
179 			mac_ErrorExit("\pSorry, No FPU.");
180 #endif
181 
182 	AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
183 					NewAEEventHandlerProc(myHandleOAPP), 0, false);
184 	AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
185 					NewAEEventHandlerProc(myHandleODOC), 0, false);
186 	AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
187 					NewAEEventHandlerProc(myHandleQUIT), 0, false);
188 	InitMenuBar();
189 }
190 
191 extern char *opt_aq_max_buff,*opt_aq_fill_buff;
main()192 int  main()
193 {
194 	int32	output_rate=DEFAULT_RATE;
195 	int		err;
196 
197 	mac_init();
198 
199 	nPlaying=mac_n_files=0; skin_state=WAITING;
200 
201 	mac_DefaultOption();
202 	mac_GetPreference();
203 
204 #ifdef MAC_INITIAL_FILLING
205 	if(!opt_aq_max_buff)
206 		opt_aq_max_buff = safe_strdup("0.0");
207 	if(!opt_aq_fill_buff)
208 		opt_aq_fill_buff = safe_strdup("100%");
209 #endif
210 
211 	timidity_start_initialize();
212 	if((err = timidity_pre_load_configuration()) != 0)
213 		return err;
214 	err += timidity_post_load_configuration();
215 	if( err )
216 	{
217 		//ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
218 		//	  "Try %s -h for help", program_name);
219 		return 1; /* problems with command line */
220 	}
221 
222 	timidity_init_player();
223 	wrdt=wrdt_list[0];  //dirty!!
224 	wrdt_open_opts= "m";
225 	timidity_play_main(0, NULL);
226 	 	//CPU won't return from timidity_play_main
227 	return 0;
228 }
229 
StartPlay(void * threadParam)230 static pascal void *StartPlay(void *threadParam)
231 {
232 	int		rc;
233 
234 	//for( i=0; i<nfiles; i++)
235 	{
236 		skin_state=PLAYING; gBusy=true; DrawButton();
237 		gCursorIsWatch=true; SetCursor(*GetCursor(watchCursor));
238 		DisableItem(GetMenu(mFile), iSaveAs & 0x0000FFFF);
239 		DisableItem(GetMenu(mFile), iPref & 0x0000FFFF);
240 			rc=play_midi_file( fileList[nPlaying].filename );
241 			gStartTick=0;
242 			gBusy=true;
243 			//theCmd.cmd=waitCmd;
244 			//theCmd.param1=2000*gSilentSec;
245 			//SndDoCommand(gSndCannel, &theCmd, 1);
246 		EnableItem(GetMenu(mFile), iSaveAs & 0x0000FFFF);
247 		EnableItem(GetMenu(mFile), iPref & 0x0000FFFF);
248 		skin_state=(rc==RC_QUIT? STOP:WAITING);
249 
250 		if( rc==RC_REALLY_PREVIOUS && nPlaying>0)
251 				nPlaying--;
252 		else if(rc==RC_RESTART)	/*noting*/;
253 		else if(rc==RC_QUIT) /*noting*/;
254 		else if(rc==RC_LOAD_FILE) /*noting*/;
255 		else if(rc==RC_NEXT) nPlaying++;
256 		else if(!skin_f_repeat) nPlaying++;
257 	}
258 	DrawButton();
259 	if( gCursorIsWatch ){
260 		InitCursor();	gCursorIsWatch=false;
261 	}
262 	return 0;
263 }
264 
HandleNullEvent()265 static void HandleNullEvent()
266 {
267 	YieldToAnyThread();
268 	if( Button() ){DoVolume();}
269 	if( skin_state==WAITING && mac_rc==RC_PREVIOUS && nPlaying>0)
270 		{nPlaying--; mac_rc=0; }
271 	if( skin_state==WAITING && nPlaying<mac_n_files )
272 	{
273 		NewThread(kCooperativeThread, StartPlay,
274 		         0, 0, kCreateIfNeeded, 0, 0);
275 	}
276 
277 #ifdef MAC_USE_OMS
278 	mac_oms_doevent();
279 #endif
280 }
281 
mac_HandleEvent(EventRecord * event)282 void mac_HandleEvent(EventRecord *event)
283 {
284 	switch(event->what)
285 	{
286 	case nullEvent:
287 		HandleNullEvent();
288 		break;
289 	case mouseDown:
290 		HandleMouseDown(event);
291 		break;
292 	case keyDown:
293 		if( event->modifiers&cmdKey )
294 		{
295 			mac_HandleMenuSelect(MenuKey(event->message&charCodeMask), event->modifiers);
296 			HiliteMenu(0);
297 			break;
298 		}else{ //no command key
299 			HandleSpecKeydownEvent( event->message, event->modifiers);
300 		}
301 		break;
302 	case updateEvt:
303 		BeginUpdate((WindowRef)event->message);
304 		DoUpdate((WindowRef)event->message);
305 		EndUpdate((WindowRef)event->message);
306 		break;
307 	case kHighLevelEvent:
308 		AEProcessAppleEvent(event);
309 		break;
310 	default:
311 		break;
312 	}
313 
314 }
315 
mac_HandleControl()316 void mac_HandleControl()
317 {
318 	SndCommand		theCmd;
319 
320 	switch(mac_rc)
321 	{
322 	case RC_QUIT:
323 			if( skin_state==PAUSE )
324 			{
325 				play_mode->acntl(PM_REQ_DISCARD,0);
326 				theCmd.cmd=resumeCmd; SndDoImmediate(gSndCannel, &theCmd);
327 				skin_state=PLAYING;
328 			}
329 		break;/*and wait ctl_read*/
330 	case RC_NEXT:
331 		if( skin_state==STOP )
332 			{ skin_state=WAITING; mac_rc=0; if( nPlaying<mac_n_files ) nPlaying++; }
333 		else if( skin_state==WAITING )
334 			{ skin_state=WAITING; mac_rc=0; if( nPlaying<mac_n_files ) nPlaying++; }
335 		else if( skin_state==PAUSE )
336 			{ mac_rc=RC_CONTINUE; mac_HandleControl(); mac_rc=RC_NEXT;}
337 		break;
338 	case RC_PREVIOUS:
339 		if( skin_state==PAUSE ){ mac_rc=RC_CONTINUE; mac_HandleControl(); mac_rc=RC_PREVIOUS;}
340 		else if( skin_state==STOP ) {skin_state=WAITING; if( nPlaying>0 ) nPlaying--; mac_rc=0; }
341 		else if( skin_state==WAITING  && nPlaying>0)
342 			{nPlaying--; mac_rc=0; }
343 		break;			/*and wait ctl_read*/
344 	case RC_FORWARD:
345 		if( skin_state==STOP ){ skin_state=WAITING; mac_rc=0; }
346 		else if( skin_state==PAUSE ){ mac_rc=RC_CONTINUE; mac_HandleControl(); }
347 		break;			/*and wait ctl_read*/
348 	case RC_TOGGLE_PAUSE:
349 		if( skin_state==PAUSE ){ theCmd.cmd=resumeCmd; SndDoImmediate(gSndCannel, &theCmd); skin_state=PLAYING;}
350 		else if( skin_state==PLAYING ){theCmd.cmd=pauseCmd; SndDoImmediate(gSndCannel, &theCmd); skin_state=PAUSE;}
351 		break;
352 	case RC_RESTART:
353 		break;			/*and wait ctl_read*/
354 	case RC_LOAD_FILE:
355 		if( skin_state==PAUSE )
356 			{ mac_rc=RC_CONTINUE; mac_HandleControl(); mac_rc=RC_LOAD_FILE;}
357 		skin_state=WAITING;
358 		break;
359 	/*case RC_PAUSE:
360 		if( skin_state==PLAYING ){theCmd.cmd=pauseCmd; SndDoImmediate(gSndCannel, &theCmd); skin_state=PAUSE;}
361 		break;*/
362 	/*case RC_CONTINUE:
363 		if( skin_state==PAUSE ){ theCmd.cmd=resumeCmd; SndDoImmediate(gSndCannel, &theCmd); skin_state=PLAYING;}
364 		else if( skin_state==STOP ){ skin_state=WAITING; mac_rc=0; }
365 		break;*/
366 	case RC_REALLY_PREVIOUS:
367 		break;			/*and wait ctl_read*/
368 	}
369 	DrawButton();
370 }
371 
372 
373 /*******************************************/
374 #pragma mark -
375 
376 extern PlayMode wave_play_mode;
377 extern PlayMode aiff_play_mode;
378 extern PlayMode mac_play_mode;
379 extern PlayMode mac_quicktime_play_mode;
380 extern PlayMode mac_oms_play_mode;
381 
ConvertToAiffFile(void * threadParam)382 static pascal void *ConvertToAiffFile(void *threadParam)
383 {
384 	OSErr	err;
385 	int		tmp;
386 	char	newfile[256];
387 	StandardFileReply	stdReply;
388 	Str255	fullPath;
389 
390 #ifdef __MWERKS__
391 	_fcreator='TVOD';     //Movie Player
392 	_ftype='AIFF';
393 #endif
394 	StandardGetFile(0, 0, 0, &stdReply);
395 	if (stdReply.sfGood)
396 	{
397 		play_mode=&aiff_play_mode;
398 			if( play_mode->open_output()==-1 ) return 0;
399 			aq_setup();
400 			tmp=skin_state;
401 			skin_state=PLAYING;
402 			err=GetFullPath( &stdReply.sfFile, fullPath);
403 			if( err==noErr )
404 				play_midi_file( p2cstr(fullPath) );
405 			skin_state=tmp;
406 			play_mode->close_output();
407 		play_mode=&mac_play_mode;
408 		aq_setup();
409 		timidity_init_aq_buff();
410 		p2cstrcpy(newfile, stdReply.sfFile.name); strcat(newfile,".aiff");
411 		rename("output.aiff", newfile);
412 	}
413 	DrawButton();
414 	return 0;
415 }
416 
mac_AboutBox()417 static void mac_AboutBox()
418 {
419 	short		item;
420 	DialogRef	dialog, theDialog;
421 	EventRecord	event;
422 
423 	dialog=GetNewDialog(200,0,(WindowRef)-1);
424 	if( dialog==0 ) return;
425 	SetDialogDefaultItem(dialog, 1);
426 
427 #ifdef __POWERPC__
428  #define TIMID_CPU "PPC"
429 #elif __MC68K__
430  #if  __MC68881__
431   #define TIMID_CPU "68k+FPU"
432  #else
433   #define TIMID_CPU "68k"
434  #endif
435 #endif
436 
437 	ParamText("\p" TIMID_VERSION TIMID_CPU, "\p", "\p", "\p");
438 
439 	ShowWindow(dialog);
440 	for(;;){
441 		WaitNextEvent(everyEvent, &event, 10, 0);
442 		if( ! IsDialogEvent(&event) )	continue;
443 		if( StdFilterProc(dialog, &event, &item) ) /**/;
444 			else DialogSelect(&event, &theDialog, &item);
445 		if( theDialog!=dialog ) continue;
446 		if( item==1 ) break;
447 		YieldToAnyThread();
448 	}
449 	DisposeDialog(dialog);
450 }
451 
CloseFrontWindow()452 static void CloseFrontWindow()
453 {
454 	WindowRef window;
455 	MacWindow   *macwin;
456 
457 	window=FrontWindow();
458 	if( ! window ) return;
459 	macwin= (MacWindow*)GetWRefCon(window);
460 	if( ! macwin ) return;
461 	macwin->goaway(macwin);
462 }
463 
mac_HandleMenuSelect(long select,short modifiers)464 void mac_HandleMenuSelect(long select, short modifiers)
465 {
466 	StandardFileReply	stdReply;
467 	Str255	str;
468 
469 	switch(select)
470 	{
471 	case iAbout:
472 		mac_AboutBox();
473 		return;
474 	case iOpen:
475 		StandardGetFile(0, -1, 0, &stdReply);
476 		if (stdReply.sfGood)
477 		{
478 			mac_add_fsspec(&stdReply.sfFile);
479 		}
480 		return;
481 	case iClose:
482 		CloseFrontWindow();
483 		return;
484 
485 	case iLogWindow:	SHOW_WINDOW(mac_LogWindow);		return;
486 	case iListWindow:	SHOW_WINDOW(mac_ListWindow);	return;
487 	case iWrdWindow:	SHOW_WINDOW(mac_WrdWindow);		return;
488 	case iDocWindow:	SHOW_WINDOW(mac_DocWindow);		return;
489 	case iSpecWindow:
490 #ifdef SUPPORT_SOUNDSPEC
491 		if(!mac_SpecWindow.show)
492 		{
493 			mac_SpecWindow.show=true;
494 		    open_soundspec();
495   			soundspec_update_wave(NULL, 0);
496 		}
497 		SelectWindow(mac_SpecWindow.ref);
498 #endif /* SUPPORT_SOUNDSPEC */
499 		return;
500 	case iTraceWindow:	SHOW_WINDOW(mac_TraceWindow);	return;
501 	case iSkinWindow: SHOW_WINDOW(mac_SkinWindow); return;
502 	case iSaveAs:
503 		NewThread(kCooperativeThread, ConvertToAiffFile,
504 	         0, 0, kCreateIfNeeded, 0, 0);
505 		return;
506 
507 	case iPref:	mac_SetPlayOption(); return;
508 	case iQuit:	Do_Quit();			 return;
509 
510 	//Play menu
511 	case iPlay:	SKIN_ACTION_PLAY(); break;
512 	case iStop:	SKIN_ACTION_STOP();	break;
513 	case iPause:	SKIN_ACTION_PAUSE(); break;
514 	case iPrev:	SKIN_ACTION_PREV(); break;
515 	case iNext:	SKIN_ACTION_NEXT(); break;
516 
517 		//Synth menu
518 	case iTiMidity:{
519 		MenuHandle menu=GetMenu(mSynth);
520 		CheckItem(menu, iTiMidity & 0x0000FFFF, 1);
521 		CheckItem(menu, iQuickTime & 0x0000FFFF, 0);
522 		CheckItem(menu, iOMS & 0x0000FFFF, 0);
523 		play_mode=&mac_play_mode;
524 		}
525 		return;
526 	case iQuickTime:{
527 		MenuHandle menu=GetMenu(mSynth);
528 
529 		if( mac_quicktime_play_mode.fd==-1 ){ //not opened yet
530 			if( mac_quicktime_play_mode.open_output()!=0 ){
531 				SysBeep(0);
532 				return;	//can't open device
533 			}
534 		}
535 		CheckItem(menu, iTiMidity & 0x0000FFFF, 0);
536 		CheckItem(menu, iQuickTime & 0x0000FFFF, 1);
537 		CheckItem(menu, iOMS & 0x0000FFFF, 0);
538 		play_mode=&mac_quicktime_play_mode;
539 		}
540 		return;
541 #ifdef MAC_USE_OMS
542 	case iOMS:{
543 		MenuHandle menu=GetMenu(mSynth);
544 
545 		if( mac_oms_play_mode.fd==-1 || (modifiers & optionKey) ){
546 			if( mac_oms_play_mode.open_output()!=0 ){
547 				SysBeep(0);
548 				return;	//can't open device
549 			}
550 		}
551 		CheckItem(menu, iTiMidity & 0x0000FFFF, 0);
552 		CheckItem(menu, iQuickTime & 0x0000FFFF, 0);
553 		CheckItem(menu, iOMS & 0x0000FFFF, 1);
554 		play_mode=&mac_oms_play_mode;
555 		}
556 		return;
557 #endif
558 	}
559 
560 	if( (select>>16)==mApple )
561 	{
562 		GetMenuItemText(GetMenu(mApple), select&0x0000FFFF, str);
563 		OpenDeskAcc(str);
564 	}
565 }
566 
Do_Quit()567 void Do_Quit()
568 {
569 	if( mac_play_mode.fd!=-1 )
570 		mac_play_mode.close_output();
571 	if( mac_quicktime_play_mode.fd!=-1 )
572 		mac_quicktime_play_mode.close_output();
573 #ifdef MAC_USE_OMS
574 	if( mac_oms_play_mode.fd!=-1 )
575 		mac_oms_play_mode.close_output();
576 #endif
577 	if( ctl )
578 		ctl->close();
579 
580 	mac_SetPreference();
581 
582 #ifdef MAC_USE_OMS
583 	mac_oms_quit();
584 #endif
585 
586 	ExitToShell();
587 }
588 
mac_ErrorExit(Str255 s)589 void mac_ErrorExit(Str255 s)
590 {
591 	StopAlertMessage(s);
592 	SndDisposeChannel(gSndCannel, 1); gSndCannel=0;
593 	ExitToShell();
594 }
595 
596 /* ****************************** */
597 #pragma mark -
598 
ShuffleList(int start,int end)599 void	ShuffleList(int start, int end)
600 {
601 	int 	i, newFile;
602 	MidiFile	tmpItem;
603 
604 	for( i=start; i<end; i++){ /*Shuffle target is start..end-1*/
605 		newFile= i+(end-i-1)*((32767+Random())/65535.0);
606 					/*Random() returns between -32767 to 32767*/
607 		tmpItem=fileList[newFile];	/*Swapping*/
608 		fileList[newFile]=fileList[i];
609 		fileList[i]=tmpItem;
610 			//update list window
611 		change_ListRow( i, &fileList[i]);
612 	}
613 }
614 
isMidiFilename(const char * fn)615 static int isMidiFilename(const char *fn)
616 {
617 	char	*p;
618 
619 	p= strrchr(fn, '.'); if( p==0 ) return 0;
620 	if( strcasecmp(p, ".mid")==0 ||
621 		strcasecmp(p, ".rcp")==0 ||
622 		strcasecmp(p, ".r36")==0 ||
623 		strcasecmp(p, ".g18")==0 ||
624 		strcasecmp(p, ".g36")==0 ||
625 		strcasecmp(p, ".kar")==0 ||
626 		strcasecmp(p, ".mod")==0 ||
627 		strcasecmp(p, ".gz")==0
628 		){
629 		return 1;
630 	}else{
631 		return 0;
632 	}
633 }
634 
isArchiveFilename(const char * fn)635 static int isArchiveFilename(const char *fn)
636 {
637 	char	*p;
638 
639 	p= strrchr(fn, '.'); if( p==0 ) return 0;
640 	if(	strcasecmp(p, ".lzh")==0 ||
641 		strcasecmp(p, ".zip")==0 ||
642 		strcasecmp(p, ".tar")==0 ||
643 		strcasecmp(p, ".gz")==0
644 		){
645 		return 1;
646 	}else{
647 		return 0;
648 	}
649 }
650 
isBMPFilename(const char * fn)651 static int isBMPFilename(const char *fn)
652 {
653 	char	*p;
654 
655 	p= strrchr(fn, '.'); if( p==0 ) return 0;
656 	if( strcasecmp(p, ".BMP")==0 ){
657 		return 1;
658 	}else{
659 		return 0;
660 	}
661 }
662 
AddFolderFSSpec2PlayList(const FSSpec * spec)663 static void AddFolderFSSpec2PlayList(const FSSpec *spec)
664 {
665 	CInfoPBRec	cipb;
666 	Str32		theString;
667 	OSErr		err = noErr;
668 
669 	BlockMoveData(spec->name, theString, spec->name[0]+1);
670 
671 	cipb.hFileInfo.ioCompletion 	= nil;
672 	cipb.hFileInfo.ioFDirIndex  	= 0;	/* this mean 'use ioNamePtr' */
673 	cipb.hFileInfo.ioDirID			= spec->parID;
674 	cipb.hFileInfo.ioVRefNum 		= spec->vRefNum;
675 	cipb.hFileInfo.ioNamePtr 		= (StringPtr)theString;
676 
677 	if( noErr==PBGetCatInfoSync(&cipb) )
678 		AddFolder2PlayList(spec->vRefNum, cipb.hFileInfo.ioDirID);
679 }
680 
mac_add_midi_file(const char * fullpath)681 static void mac_add_midi_file(const char *fullpath)
682 {
683 	if( mac_n_files<LISTSIZE )	//not full
684 	{
685 		fileList[mac_n_files].filename= (char*)safe_malloc(strlen(fullpath)+1);
686 		strcpy(fileList[mac_n_files].filename, fullpath);
687 		if( skin_state==STOP ){ skin_state=WAITING; nPlaying=mac_n_files; }
688 		add_ListWin(&fileList[mac_n_files]);
689 		mac_n_files++;
690 	}
691 }
692 
mac_add_bmp_file(const char * fullpath)693 static void mac_add_bmp_file(const char *fullpath)
694 {
695 	mac_SkinWindow.message(MW_SKIN_LOAD_BMP, (long)fullpath);
696 }
697 
mac_add_nonarchive_file(const char * fullpath)698 static void mac_add_nonarchive_file(const char *fullpath)
699 {
700 	if(isMidiFilename(fullpath)){
701 		mac_add_midi_file(fullpath);
702 	}else if(isBMPFilename(fullpath)){
703 		mac_add_bmp_file(fullpath);
704 	}else if( strtailcasecmp(fullpath, "viscolor.txt")==0 ){
705 		read_viscolor(fullpath);
706 	}
707 }
708 
mac_add_archive_file(const char * fullpath)709 static void mac_add_archive_file(const char *fullpath)
710 {
711 	if( mac_n_files<LISTSIZE )	/*not full*/
712 	{
713 		const char  *arc_files[1];
714 		char		**new_files;
715 		int			nfiles=1,i;
716 
717 		//fileList[mac_n_files].filename= (char*)safe_malloc(fullpath[0]+1);
718 		arc_files[0]= fullpath;
719 
720 		new_files = expand_file_archives((char **)arc_files, &nfiles);
721 
722 		for( i=0; i<nfiles; i++ ){
723 			mac_add_nonarchive_file(new_files[i]);
724 		}
725 		if( arc_files!=new_files ) free(new_files);
726 	}
727 }
728 
mac_add_file(const char * fullpath)729 static void mac_add_file(const char *fullpath)
730 {
731 	if( isArchiveFilename(fullpath) ){
732 		mac_add_archive_file(fullpath);
733 	}else{
734 		mac_add_nonarchive_file(fullpath);
735 	}
736 }
737 
mac_add_fsspec(FSSpec * spec)738 void mac_add_fsspec( FSSpec *spec )
739 {
740 	OSErr	err;
741 	FInfo	fndrInfo;
742 	Boolean	targetIsFolder,wasAliased;
743 
744 	ResolveAliasFile(spec, true, &targetIsFolder, &wasAliased);
745 
746 	err= FSpGetFInfo(spec, &fndrInfo);
747 
748 	if( err ){
749 		if( err==fnfErr ){
750 			AddFolderFSSpec2PlayList(spec); // spec may be directory
751 			return;
752 		}else return;
753 	}
754 
755 	//no error
756 	{ //spec is file, not folder or disk
757 		Str255	fullpath;
758 
759 		GetFullPath(spec, fullpath);
760 		p2cstr(fullpath);
761 
762 		if( fndrInfo.fdType=='Midi' ){
763 			mac_add_midi_file((char*)fullpath);
764 		}else{
765 			mac_add_file((char*)fullpath);
766 		}
767 	}
768 }
769 
AddHFS2PlayList(HFSFlavor * item)770 void	AddHFS2PlayList(HFSFlavor* item)
771 {
772 	if( item->fileType=='fold' || item->fileType=='disk')
773 		AddFolderFSSpec2PlayList(&item->fileSpec);
774 	//else if(item->fileType=='Midi'){}
775 	else mac_add_fsspec(&item->fileSpec);
776 }
777 
778 #define kDirFlag (1<<4)
779 
AddFolder2PlayList(short vRefNum,long dirID)780 OSErr AddFolder2PlayList( short vRefNum, long dirID)
781 {
782 	CInfoPBRec	cipb;
783 	Str32		theString;
784 	StringPtr	saveString;
785 	short		saveIndex;
786 	OSErr		err = noErr;
787 
788 	// initialize ourselves
789 	cipb.hFileInfo.ioCompletion 	= nil;
790 	cipb.hFileInfo.ioFDirIndex  	= 1;
791 	cipb.hFileInfo.ioVRefNum 		= vRefNum;
792 	cipb.hFileInfo.ioNamePtr 		= (StringPtr)theString;
793 
794 	while (err == noErr) {
795 
796 		// always reset directory id
797 		cipb.hFileInfo.ioDirID = dirID;
798 
799 		// get the info for the next catalog item
800 		err = PBGetCatInfoSync(&cipb);
801 		if (err) goto exit;
802 
803 		// increment the count
804 		cipb.hFileInfo.ioFDirIndex++;
805 
806 		// if we are a directory, recurse
807 		if (cipb.hFileInfo.ioFlAttrib & kDirFlag) {
808 
809 			// save before recursing
810 			saveIndex = cipb.hFileInfo.ioFDirIndex;
811 			saveString = cipb.hFileInfo.ioNamePtr;
812 
813 			// recurse within the directory
814 			err = AddFolder2PlayList( vRefNum, cipb.hFileInfo.ioDirID );
815 
816 			// restore after recursion
817 			cipb.hFileInfo.ioFDirIndex = saveIndex;
818 			cipb.hFileInfo.ioNamePtr = saveString;
819 
820 		} else {	// we are a file
821 
822 			// call our scanProc if there is one specified
823 			/*if (sp != nil)
824 				err = (*sp)(cipbp, refCon);*/
825 			FSSpec	spec;
826 			if(noErr==FSMakeFSSpec(vRefNum, dirID,
827 						cipb.hFileInfo.ioNamePtr, &spec))
828 				mac_add_fsspec(&spec);
829 
830 		}
831 	}
832 
833 exit:
834 
835 	// ignore fnfErr and afpAccessDenied errors since fnfErr is what we
836 	// get when there are no more files left to scan, and afpAccessDenied
837 	// can just ��happen�� depending on what we are scanning (ie: network
838 	// volumes)
839 	if ((err == fnfErr) || (err == afpAccessDenied)) return noErr;
840 	else return err;
841 }
842 
843 /*******************************************/
844 #pragma mark -
845 
846 
847