Here is a routine that *SHOULD* sum two sample fragments together.  You
feed it the address of the beginning of each sample fragment, as well as
the address of the destination buffer.  The Playback Lengths are the
Playback Rate of the sample (I.e. how many bytes per second) times the
vertical blank length (1/60 or 1/50).  You should use a lookup table to
calculate the fragment length from the hardware playback period values
that most Trackers use.  Just load the registers, BSR to the routine, and 
when it returns, the address registers will point to the start of the NEXT
sample fragment.  That is, you can just save the registers, and drop them
back in when you call next time.

It should be fast enough to do this for four voices within 1/60 second at
maximum playback rate.  I hope.  Well, the worst-possible case is for two
samples at NoiseTracker's highest frequency over a 1/50 second length; the
sample fragment length is 314 bytes AT WORST for realtime.  If you don't 
care about realtime, then samples of length up to 65536 bytes can be summed
at arbitrary frequencies.

However, this routine does NOT handle independent hardware volume!!!  This
could be implemented by having a "shiftdown" value for each sample.  each
byte of the sample would then be shifted down by this much.  That's for
next time.  Theoretically, a similar routine could handle the multiplexing
of four voices (not just summing the summed output), but that could get
extremely ugly... ;^)

Well, if there's anything wrong with it please let me know and I'll fix it.
Remember, this is *UNTESTED*, so if somebody wants to test it, let me know.

-----

; ADDSAMPLES
; Copyright 1992 Kenneth D. Miller III
; inputs:	d0 Playback Length of first sample (for 1 VBlank cycle)
;		d1 Playback Length of second sample (for 1 VBlank cycle)
;		a0 Address of first sample
;		a1 Address of second sample
;		a2 Address of destination buffer (chip RAM!)

AddSamp:
	moveq	#0,	d5	;note: d5 is the Update register
	moveq	#0,	d6
	moveq	#0,	d7
	cmp	d0,	d1
	bpl.s	ASInit
	beq.s	ASFast		;if playback rates are the same, use fast
	exg	d0,	d1	;make sure Sample 1 is the fast one
	exg	a0,	a1
ASInit:	move	d0,	d4	;load counter
	move.b	(a1)+,	d7	;pre-load first byte of sample 2
ASLoop:	move.b	(a0)+,	d6	;load byte from sample 1
	add.w	d7,	d6	;add 'em, preserving byte from sample2
	asr.w	#1,	d6	;divide by 2
	move.b	d6,	(a2)+	;jam the summed byte to the output buffer
	add	d1,	d5	;increment Update register
	cmp	d5,	d0
	bmi	ASLp2		;if it's greater than playback length 1
	sub	d0,	d5	;   then drop the Update register back
	move.b	(a1)+,	d7	;   and load another byte from Sample 2
ASLp2:	dbra	d4,	ASLoop
	rts
ASFast:	move.l	#$FEFEFEFE,d5	;load mask into d5
	move.l	d0,	d4	;load loop counter
	btst	#1,	d0
	beq	ASFas2
	move.w	(a0)+,	d6	;if length mod 4 != 0, pick off first word
	move.w	(a1)+,	d7
	and.w	d5,	d6
	and.w	d5,	d7
	lsr.w	#1,	d6
	lsr.w	#1,	d7
	add.w	d6,	d7
	move.w	d7,	(a2)+
	subq	#2,	d4
ASFas2:	move.l	(a0)+,	d6	;sum 4 bytes worth of samples
	move.l	(a1)+,	d7
	and.l	d5,	d6
	and.l	d5,	d7
	lsr.l	#1,	d6
	lsr.l	#1,	d7
	add.l	d6,	d7
	move.l	d7,	(a2)+
	subq	#4,	d4
	bpl.s	ASFas2
	rts

--
kdmiller@athena.mit.edu | Kenny Miller, sole member of Digital Horizons USA
    ///                 | UPCOMING COOL STUFF: KMUS music format, BrotBusters
\\\///  Amiga Makes     | Demo, Scrolly Roller Demo, Columns, Psycho Ball,
 \XX/   It Possible!    | AmigAtaxx, etc. (don't hold your breath ;^)
