1
2	incdir	"Amiga:Includes/"
3	include "misc/DeliPlayer.i"
4
5;
6;
7	SECTION Player,Code
8;
9;
10
11	PLAYERHEADER PlayerTagArray
12
13	dc.b '$VER: Ultimate Soundtracker player 1.1 (Jan 2003)',0
14	even
15
16PlayerTagArray
17	dc.l	DTP_PlayerVersion,1
18	dc.l	DTP_PlayerName,PName
19	dc.l	DTP_Creator,CName
20	dc.l	DTP_Check2,Chk
21*	dc.l	DTP_StartInt,START_MUZAK
22*	dc.l	DTP_StopInt,STOP_MUZAK
23	dc.l	DTP_Interrupt,REPLAY_MUZAK
24	dc.l	DTP_Config,Config
25	dc.l	DTP_InitPlayer,InitPlay
26	dc.l	DTP_EndPlayer,EndPlay
27	dc.l	DTP_InitSound,InitSnd
28	dc.l	DTP_EndSound,RemSnd
29	dc.l	DTP_Flags,PLYF_SONGEND
30	dc.l	TAG_DONE
31
32*-----------------------------------------------------------------------*
33;
34; Player/Creatorname und lokale Daten
35
36PName	dc.b 'The Ultimate Soundtracker',0
37CName	dc.b "87/88 by Karsten Obarski",10
38	dc.b 'adapted for UADE by mld',0
39songendflag	dc.b 0
40
41mod15flag		dc.b 0		; is it a mod15
42bpmflag			dc.b 0		; mod uses bpm
43samplelenflag		dc.b 0		; samplelen <= 9999
44repeatoffsetflag	dc.b 0		; smp start + repeat *2 > sample end
45samplenameflag		dc.b 0		; no st-xy: ?
46effectsflag		dc.b 0		; 1xy and 2xy && xy >1f
47
48	even
49delibase	dc.l	0
50
51
52*-----------------------------------------------------------------------*
53;
54; Testet auf Ultimate Soundtracker-Modul
55
56Chk						; UST ?
57	move.w	#-1,d0
58	move.l	dtg_ChkData(a5),a0
59	;move.l	dtg_chksize(a5),d2		; File len
60	move.l	a0,ustsong
61
62	bsr	mod15_check			; lame 15 inst checks?
63	cmp.b	#1,mod15flag
64	bne	chk_rts
65
66	bsr	do_ust_checks
67	cmp.b	#1,samplelenflag
68	bne 	chk_rts
69
70	cmp.b	#1,repeatoffsetflag
71	bne 	chk_rts
72
73	cmp.b	#1,bpmflag
74	beq 	chk_ok
75
76	cmp.b	#1,samplenameflag
77	bne 	chk_rts
78
79chk_ok
80	moveq	#0,d0
81chk_rts
82	rts
83
84mod15_check:					; check if mod15
85	moveq	#0,d1
86
87	move.b	$1d6(a0),d1			; max pos
88	tst.b	d1				; 0 ?
89	beq.s	mod15_rts			; no mod15
90
91	cmp.w	#$78,d1				; max pos > 78
92	bge	mod15_rts			; no mod15
93
94	cmp.b	#1,$1f3(a0)			; smpl repeat = 1?
95	beq.s	mod15_rts			; nomod
96is_mod15
97	move.b	#1,mod15flag
98mod15_rts
99	rts
100
101do_ust_checks:
102	moveq	#0,d1
103	move.b	$1d7(a0),d1			; zero bpm?
104	tst.b	d1
105	beq	duc_end				; can't be ust
106
107	cmp.w	#$78,d1				; BPM value != 78
108	beq	duc1
109	move.b	#1,bpmflag
110duc1:
111	moveq	#$0e,d1				; smpl check
112	move.l	a0,a1
113duc1loop:
114	clr.l	d1
115	clr.l	d2
116	clr.l	d3
117	cmp.l	#0,20(a1)			; empty smpl name?
118	beq	duc1next			; yup, next Instr.
119
120	move.w	42(a1),d1			; smpl len < 9999
121	add.l	d1,d1				; *2
122	cmp.l	#9999,d1
123	bgt	duc_end				; nope no UST
124
125	move.w	46(a1),d2			; repeat offset
126	move.w	48(a1),d3			; repeat size
127	add.l	d3,d3				; *2
128	add.l	d3,d2
129
130	cmp.l	#$ffff,d2			; it's only words...
131	bgt	duc_end
132
133	cmp.l	d2,d1				; repeat offset+ size > smpl len
134	blt	duc_end				; yup
135duc1next:
136	add.l	#30,a1
137	dbra	d1,duc1loop
138	move.b	#1,samplelenflag
139	move.b	#1,repeatoffsetflag
140
141	moveq	#$0e,d1				; smpl check
142	move.l	a0,a1
143duc2loop:					; chk sample name
144	clr.l	d1
145	clr.l	d2
146	clr.l	d3
147	cmp.l	#0,20(a1)			; empty smpl name?
148	beq	duc2next			; yup, next Instr.
149
150	move.b	25(a1),d1			; ":"?
151	cmp.b	#":",d1
152	bne	duc2next
153
154	move.b	22(a1),d1			; "-"?
155	cmp.b	#"-",d1
156	bne	duc2next
157
158	move.w	20(a1),d1			; "st" ?
159	cmp.w	#"st",d1
160	beq	duc_end
161	cmp.w	#"ST",d1			; ST
162	beq	duc_end
163
164duc2next:
165	add.l	#30,a1
166	dbra	d1,duc2loop
167	move.b	#1,samplenameflag
168duc_end
169	rts
170
171*-----------------------------------------------------------------------*
172;
173; Einmalige Initialisierung des Players
174
175Config
176
177	moveq	#0,d0				; no Error
178	rts
179
180*-----------------------------------------------------------------------*
181;
182; Init Player
183
184InitPlay
185	move.l	a5,delibase
186	moveq	#0,d0
187	move.l	dtg_GetListData(a5),a0		; Function
188	jsr	(a0)
189	move.l	a0,ustsong
190
191	move.l	dtg_AudioAlloc(a5),a0		; Function
192	jsr	(a0)				; returncode is already set !
193	sf songendflag
194	rts
195
196*-----------------------------------------------------------------------*
197;
198; End Player
199
200EndPlay
201	move.l	dtg_AudioFree(a5),a0		; Function
202	jsr	(a0)
203	rts
204
205*-----------------------------------------------------------------------*
206;
207; Init Sound
208
209InitSnd
210	bsr	START_MUZAK
211	rts
212
213
214*-----------------------------------------------------------------------*
215;
216; Remove Sound
217
218RemSnd
219	lea	$dff000,a0
220	moveq	#0,d0
221	move.w	d0,$a8(a0)
222	move.w	d0,$b8(a0)
223	move.w	d0,$c8(a0)
224	move.w	d0,$d8(a0)
225	move.w	#$000F,$96(a0)			; End Sound
226	rts
227
228SetCIASpeed:
229	movem.l	d0-d2/a0-a6,-(sp)
230	move.l	delibase(pc),a5
231	move.w	d0,dtg_Timer(a5)
232	move.l	dtg_SetTimer(a5),a1
233	jsr	(a1)
234	movem.l	(sp)+,d0-d2/a0-a6
235	rts
236Songend
237	movem.l	d0-d7/a0-a6,-(a7)
238	move.l  delibase(pc),a5
239	move.l	dtg_SongEnd(a5),a1
240	jsr (a1)
241	movem.l	(a7)+,d0-d7/a0-a6
242	rts
243
244*-----------------------------------------------------------------------*
245
246	even
247ustsong	dc.l	0
248
249
250;������������������������������������������������
251;�                                              �
252;�   The Ultimate Soundtracker Replay-Routine   �
253;�         Version 27  All bugs removed         �
254;�              Update  29.03.1988              �
255;�      Written 1987/88 by Karsten Obarski      �
256;�                                              �
257;������������������������������������������������
258
259START_MUZAK:
260	move.l	ustsong,muzakoffset	;** get offset
261
262init0:	move.l	muzakoffset,a0		;** get highest used pattern
263	add.l	#472,a0
264	move.l	#128,d0
265	clr.l	d1
266init1:	move.l	d1,d2
267	subq.w	#1,d0
268init2:	move.b	(a0)+,d1
269	cmp.b	d2,d1
270	bgt	init1
271	dbra	d0,init2
272	addq.b	#1,d2
273
274init3:	move.l	muzakoffset,a0		;** calc samplepointers
275	lea.l	pointers,a1
276	mulu	#1024,d2
277	add.l	#600,d2
278	add.l	a0,d2
279	move.l	#15-1,d0
280init4:	move.l	d2,(a1)+
281	move.l	d2,a2
282	clr.l	(a2)			; clear first four bytes
283	clr.l	d1
284	move.w	42(a0),d1
285	lsl.l	#1,d1
286	add.l	d1,d2
287	add.l	#30,a0
288	dbra	d0,init4
289
290init5:	move.w	#$0,$dff0a8		;** clear used values
291	move.w	#$0,$dff0b8
292	move.w	#$0,$dff0c8
293	move.w	#$0,$dff0d8
294	clr.w	timpos
295	clr.l	trkpos
296	clr.l	patpos
297
298init6:	move.l	muzakoffset,a0		;** initialize timer irq
299	move.b	470(a0),numpat+1	;number of patterns
300	move.l	#240,d0
301	sub.b	471(a0),d0
302	mulu	#122,d0
303
304	bsr	SetCIASpeed
305
306*	move.b	#$0,$bfde00		; CIAA
307*	move.b	d0,$bfd400
308*	lsr.w	#8,d0
309*	move.b	d0,$bfd500
310*	move.b	#$81,$bfdd00
311*	move.b	#$11,$bfde00
312*	move.l	$78,lev6save		; Argh! bad, bad irq alloc!
313*	move.l	#lev6interrupt,$78
314NOPLAY:	rts
315
316*STOP_MUZAK:
317*	move.b	#$1,$bfdd00		;** restore timer & dma
318*	move.l	lev6save,$78
319*	move.w	#$0,$dff0a8
320*	move.w	#$0,$dff0b8
321*	move.w	#$0,$dff0c8
322*	move.w	#$0,$dff0d8
323*	move.w	#$f,$dff096
324*	rts
325
326*lev6interrupt:
327*	movem.l	d0/d1,-(sp)		;** jump
328*	bsr	REPLAY_MUZAK
329*	move.b	$bfdd00,d0
330*	move.w	#$2000,$dff09c
331*	movem.l	(sp)+,d0/d1
332*	rte
333
334;------------------------------------------------
335; replay-routine
336;------------------------------------------------
337
338REPLAY_MUZAK:
339	movem.l	d0-d7/a0-a6,-(a7)
340	addq.w	#1,timpos
341	cmp.w	#6,timpos
342	beq	replaystep
343
344;------------------------------------------------
345; time left to handle effects between steps
346;------------------------------------------------
347
348chaneleffects:				;** seek effects
349	lea.l	datach0,a6
350	cmp.b	#0,3(a6)
351	beq.s	ceff1
352	lea.l	$dff0a0,a5
353	bsr.s	ceff5
354ceff1:	lea.l	datach1,a6
355	cmp.b	#0,3(a6)
356	beq.s	ceff2
357	lea.l	$dff0b0,a5
358	bsr.s	ceff5
359ceff2:	lea.l	datach2,a6
360	cmp.b	#0,3(a6)
361	beq.s	ceff3
362	lea.l	$dff0c0,a5
363	bsr.s	ceff5
364ceff3:	lea.l	datach3,a6
365	cmp.b	#0,3(a6)
366	beq.s	ceff4
367	lea.l	$dff0d0,a5
368	bsr.s	ceff5
369ceff4:	movem.l	(a7)+,d0-d7/a0-a6
370	rts
371ceff5:	move.b	2(a6),d0
372	and.b	#$0f,d0
373	cmp.b	#1,d0
374	beq	arpreggiato
375	cmp.b	#2,d0
376	beq	pitchbend
377	rts
378
379;------------------------------------------------
380; effect 1 arpreggiato
381;------------------------------------------------
382
383arpreggiato:				;** spread by time
384	cmp.w	#1,timpos
385	beq.s	arp1
386	cmp.w	#2,timpos
387	beq.s	arp2
388	cmp.w	#3,timpos
389	beq.s	arp3
390	cmp.w	#4,timpos
391	beq.s	arp1
392	cmp.w	#5,timpos
393	beq.s	arp2
394	rts
395arp1:	clr.l	d0			;** get higher note-values
396	move.b	3(a6),d0		;   or play original
397	lsr.b	#4,d0
398	bra.s	arp4
399arp2:	clr.l	d0
400	move.b	3(a6),d0
401	and.b	#$0f,d0
402	bra.s	arp4
403arp3:	move.w	16(a6),d2
404	bra.s	arp6
405arp4:	lsl.w	#1,d0
406	clr.l	d1
407	move.w	16(a6),d1
408	lea.l	notetable,a0
409arp5:	move.w	(a0,d0.w),d2
410	cmp.w	(a0),d1
411	beq.s	arp6
412	addq.l	#2,a0
413	bra.s	arp5
414arp6:	move.w	d2,6(a5)
415	rts
416
417;------------------------------------------------
418; effect 2 pitchbend
419;------------------------------------------------
420
421pitchbend:				;** increase or decrease
422	clr.l	d0			;   period every time
423	move.b	3(a6),d0
424	lsr.b	#4,d0
425	beq.s	pit2
426	add.w	d0,(a6)
427	move.w	(a6),6(a5)
428	rts
429pit2:	clr.l	d0
430	move.b	3(a6),d0
431	and.b	#$0f,d0
432	beq.s	pit3
433	sub.w	d0,(a6)
434	move.w	(a6),6(a5)
435pit3:	rts
436
437;------------------------------------------------
438; handle a further step of 16tel data
439;------------------------------------------------
440
441replaystep:				;** work next pattern-step
442	clr.w	timpos
443	move.l	muzakoffset,a0
444	move.l	a0,a3
445	add.l	#12,a3			;ptr to soundprefs
446	move.l	a0,a2
447	add.l	#472,a2			;ptr to pattern-table
448	add.l	#600,a0			;ptr to first pattern
449	clr.l	d1
450	move.l	trkpos,d0		;get ptr to current pattern
451	move.b	(a2,d0),d1
452	mulu	#1024,d1
453	add.l	patpos,d1		;get ptr to current step
454	clr.w	enbits
455	lea.l	$dff0a0,a5		;chanel 0
456	lea.l	datach0,a6
457	bsr	chanelhandler
458	lea.l	$dff0b0,a5		;chanel 1
459	lea.l	datach1,a6
460	bsr	chanelhandler
461	lea.l	$dff0c0,a5		;chanel 2
462	lea.l	datach2,a6
463	bsr	chanelhandler
464	lea.l	$dff0d0,a5		;chanel 3
465	lea.l	datach3,a6
466	bsr	chanelhandler
467	move.l	#400,d0			;** wait a while and set len
468rep1:	dbra	d0,rep1			;   of oneshot to 1 word
469	move.l	#$8000,d0
470	or.w	enbits,d0
471	move.w	d0,$dff096
472	cmp.w	#1,datach0+14
473	bne.s	rep2
474	clr.w	datach0+14
475	move.w	#1,$dff0a4
476rep2:	cmp.w	#1,datach1+14
477	bne.s	rep3
478	clr.w	datach1+14
479	move.w	#1,$dff0b4
480rep3:	cmp.w	#1,datach2+14
481	bne.s	rep4
482	clr.w	datach2+14
483	move.w	#1,$dff0c4
484rep4:	cmp.w	#1,datach3+14
485	bne.s	rep5
486	clr.w	datach3+14
487	move.w	#1,$dff0d4
488
489rep5:	add.l	#16,patpos		;next step
490	cmp.l	#64*16,patpos		;pattern finished ?
491	bne	rep6
492	clr.l	patpos
493	addq.l	#1,trkpos		;next pattern in table
494	clr.l	d0
495	move.w	numpat,d0
496	cmp.l	trkpos,d0		;song finished ?
497	bne	rep6
498	clr.l	trkpos
499	st	songendflag
500rep6:	movem.l	(a7)+,d0-d7/a0-a6
501
502	tst.b	songendflag
503	beq	rep7
504	bsr	Songend
505rep7
506	rts
507
508;------------------------------------------------
509; proof chanel for actions
510;------------------------------------------------
511
512chanelhandler:
513	move.l	(a0,d1.l),(a6)		;get period & action-word
514	addq.l	#4,d1			;point to next chanel
515	clr.l	d2
516	move.b	2(a6),d2		;get nibble for soundnumber
517	lsr.b	#4,d2
518	beq	chan2			;no soundchange !
519	move.l	d2,d4			;** calc ptr to sample
520	lsl.l	#2,d2
521	mulu	#30,d4
522	lea.l	pointers-4,a1
523	move.l	0(a1,d2.l),04(a6)	;store sample-address
524	move.w	0(a3,d4.l),08(a6)	;store sample-len in words
525	move.w	2(a3,d4.l),18(a6)	;store sample-volume
526	move.w	2(a3,d4.l),08(a5)	;change chanel-volume
527	clr.l	d3
528	move.w	4(a3,d4),d3		;** calc repeatstart
529	add.l	4(a6),d3
530	move.l	d3,10(a6)		;store repeatstart
531	move.w	6(a3,d4),14(a6)		;store repeatlength
532	cmp.w	#1,14(a6)
533	beq	chan2			;no sustainsound !
534	move.l	10(a6),4(a6)		;repstart  = sndstart
535	move.w	6(a3,d4),8(a6)		;replength = sndlength
536chan2:	cmp.w	#0,(a6)
537	beq	chan4			;no new note set !
538	move.w	22(a6),$dff096		;clear dma
539	cmp.w	#0,14(a6)
540	bne	chan3			;no oneshot-sample
541	move.w	#1,14(a6)		;allow resume (later)
542chan3:	move.w	(a6),16(a6)		;save note for effect
543	move.l	4(a6),0(a5)		;set samplestart
544	move.w	8(a6),4(a5)		;set samplelength
545	move.w	0(a6),6(a5)		;set period
546	move.w	22(a6),d0
547	or.w	d0,enbits		;store dma-bit
548	move.w	18(a6),20(a6)		;volume trigger
549chan4:	rts
550
551;------------------------------------------------
552; used varibles
553;------------------------------------------------
554;	datachx - structure	(22 bytes)
555;
556;	00.w	current note
557;	02.b	sound-number
558;	03.b	effect-number
559;	04.l	soundstart
560;	08.w	soundlenght in words
561;	10.l	repeatstart
562;	14.w	repeatlength
563;	16.w	last saved note
564;	18.w	volume
565;	20.w	volume trigger (note on dynamic)
566;	22.w	dma-bit
567;------------------------------------------------
568
569datach0:	dc.w	0,0,0,0,0,0,0,0,0,0,0,1
570datach1:	dc.w	0,0,0,0,0,0,0,0,0,0,0,2
571datach2:	dc.w	0,0,0,0,0,0,0,0,0,0,0,4
572datach3:	dc.w	0,0,0,0,0,0,0,0,0,0,0,8
573pointers:	dc.l	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
574notetable:	dc.w	856,808,762,720,678,640,604,570
575		dc.w	538,508,480,453,428,404,381,360
576		dc.w	339,320,302,285,269,254,240,226
577		dc.w	214,202,190,180,170,160,151,143
578		dc.w	135,127,120,113,000
579muzakoffset:	dc.l	0
580lev6save:	dc.l	0
581trkpos:		dc.l	0
582patpos:		dc.l	0
583numpat:		dc.w	0
584enbits:		dc.w	0
585timpos:		dc.w	0
586data:		blk.b	0,0
587
588
589