;------------------------------------------------------------------------------
;
;    Fichier :	mpega_decode_asm.a
;
;    Auteur  :	Stéphane TAVENARD
;
;    $VER:   mpega_decode_asm.a  1.0  (23/06/1995)
;
;    (C) Copyright 1995 Stéphane TAVENARD
;	All Rights Reserved
;
;    #Rev|   Date   |			   Comment
;    ----|----------|--------------------------------------------------------
;    0	 |11/04/1995| Initial revision					   ST
;    1	 |18/06/1995| Use of fast cosine transform for synthesis filter    ST
;    2	 |23/06/1995| Aminet release					   ST
;
;    ------------------------------------------------------------------------
;
;    Routines pour le decodage MPEG audio (optimisées)
;
;------------------------------------------------------------------------------*/
;
; OPTIMIZE: to do:
; - put read2_bits where possible (!d2 is affected)
; - ? move.l d0,(a4) .. move.l d0,4*2*SBLIMIT(a4) .. addq.l #4,a4
;     -> move.l d0,(a4)+ .. move.l d0,(4*2*SBLIMIT)-4(a4)
; - reduce some arrays from LONG to BYTE (bit_alloc, alloc, ...)
;
		  IFND	   INCLUDE_SOURCE
		  incdir   "include:"
		  include  "exec/funcdef.i"
		  include  "exec/exec.i"
		  include  "exec/exec_lib.i"
		  ENDC
		  include  "mpega_decode_asm.i"
		  include  "mpega_decode_asm_tables.i"
		  include  "BitStream.i"
		  include  "AudioPort.i"


SKIP_UPPER_BAND   equ	1     ; if skip upper part of sub band (half & quart freq)
			      ; this flag is used for read & deqnor
			      ; !!! incompatible with FILTER_?_SUM because
			      ; if set filter use all of the sub band even in
			      ; half or quart frequency mode

READ3_BITS	  equ	1     ; if @BSTR_read3_bits func used



		  XREF	   @BSTR_open
		  XREF	   @BSTR_close
		  XREF	   @BSTR_rewind
		  XREF	   @BSTR_end
		  XREF	   @BSTR_read_bits
		  XREF	   @BSTR_skip_bits
		  XREF	   @BSTR_read3_bits
		  XREF	   @BSTR_read2_bits
		  XREF	   @BSTR_seek_sync
		  XREF	   @BSTR_seek_tell

		  XREF	   @AU_open
		  XREF	   @AU_write
		  XREF	   @AU_close

		  XDEF	   @ASM_init_decode
		  XDEF	   @ASM_read_header
		  XDEF	   @ASM_decode_header

		  XDEF	   @ASM_I_decode_bitalloc
		  XDEF	   @ASM_I_decode_scale
		  XDEF	   @ASM_I_buffer_sample
		  XDEF	   @ASM_I_deqnorm

		  XDEF	   @ASM_II_decode_bitalloc
		  XDEF	   @ASM_II_decode_scale
		  XDEF	   @ASM_II_buffer_sample
		  XDEF	   @ASM_II_deqnorm

		  XDEF	   @ASM_sub_band_synthesis

		  XDEF	   @ASM_I_decode_frame
		  XDEF	   @ASM_II_decode_frame


		  section  ASMCODE,code

;	       d0: int sub_band_size
;	       d1: int output_8bits
;	       d2: int quality (0..2)
;		   0 : 1/4 windowing
;		   1 : 1/2 windowing
;		   2 : full quality
;
@ASM_init_decode
	       movem.l	d2-d4,-(sp)
	       move.w	d1,output_8bits
	       move.w	d0,sub_band_size
	       moveq.l	#1,d3	       ; skip value for full freq output
	       clr.w	half_freq
	       clr.w	quar_freq
	       cmp.w	#SBLIMIT/2,d0
	       beq	init_decode_1
	       cmp.w	#SBLIMIT/4,d0
	       beq	init_decode_2
	       bra	init_decode_5
init_decode_1  move.w	#-1,half_freq
	       moveq.l	#2,d3	       ; skip value for half freq output
	       bra	init_decode_5
init_decode_2  move.w	#-1,quar_freq
	       moveq.l	#4,d3	       ; skip value for quarter freq output
init_decode_5  move.w	d3,window_skip
	       moveq.l	#0,d3	       ; start offset for windowing
	       moveq.l	#8-1,d4        ; #coeff (#-1)/2 used for windowing
	       move.w	d2,quality
	       cmp.b	#2,d2	       ; best quality
	       beq.s	init_decode_6
	       move.w	#2*128,d3
	       moveq.l	#4-1,d4
	       cmp.b	#1,d2
	       beq.s	init_decode_6
	       move.w	#3*128,d3
	       moveq.l	#2-1,d4
init_decode_6  move.w	d3,window_start
	       move.w	d4,window_coeff
init_decode_9  moveq.w	#64,d0
	       lea	band_offset,a0
	       move.w	d0,(a0)+
	       move.w	d0,(a0)+
	       lea	filter_buffer,a0
	       move.w	#2*2*HAN_SIZE-1,d0
init_decode_91 clr.w	(a0)+
	       dbra	d0,init_decode_91
	       movem.l	(sp)+,d2-d4
	       rts

;	       Read header information
;
;	       a0: frame_params *fr_ps
;	       -> d0 = 0 if end of bitstream
;
@ASM_read_header
	       movem.l	a2-a3/d2,-(sp)
	       move.l	a0,a3
	       move.l	fp_header(a3),a2     ; a2 = header
	       move.l	fp_bs(a3),a0         ; a0 = bitstream
	       moveq.l	#8,d1
	       move.b	#$FF,d2
ASM_read_hdr1  bsr	@BSTR_read_bits
	       cmp.b	d0,d2
	       beq	ASM_read_hdr1	  ; skip extra $FF sync
	       bfextu	d0{24:1},d1	  ; Version
	       move.l	d1,hdr_version(a2)
	       bfextu	d0{25:2},d2	  ; 4 - Layer
	       subq.l	#4,d2
	       neg.l	d2		  ; Layer
	       move.l	d2,hdr_lay(a2)
	       bfextu	d0{27:1},d1	  ; !Error protection
	       bchg	#0,d1
	       move.l	d1,hdr_error_protection(a2)
	       bfextu	d0{28:4},d1	  ; Bit rate index
	       move.l	d1,hdr_bitrate_index(a2)

	       subq.l	#1,d2
	       lsl.l	#4,d2		     ; (lay-1)*16
	       add.l	d1,d2
	       lea	BITRATE_table,a1
	       move.w	(a1,d2.w*2),d1       ; d1 = bitrate
	       ext.l	d1
	       move.l	d1,fp_bitstream_rate(a3)

	       moveq.l	#12,d1
	       bsr	@BSTR_read_bits   ; Read end of header
	       bfextu	d0{20:2},d1	  ; Sampling frequency
	       move.l	d1,hdr_sampling_frequency(a2)

	       lea	FREQ_table,a1
	       move.l	(a1,d1.w*4),d1
	       move.l	d1,fp_bitstream_freq(a3)

	       bfextu	d0{22:1},d1	  ; Padding
	       move.l	d1,hdr_padding(a2)
	       bfextu	d0{23:1},d1	  ; Extension
	       move.l	d1,hdr_extension(a2)
	       bfextu	d0{24:2},d1	  ; Mode
	       move.l	d1,hdr_mode(a2)
	       bfextu	d0{26:2},d1	  ; Mode ext
	       move.l	d1,hdr_mode_ext(a2)
	       bfextu	d0{28:1},d1	  ; Copyright
	       move.l	d1,hdr_copyright(a2)
	       bfextu	d0{29:1},d1	  ; Original
	       move.l	d1,hdr_original(a2)
	       bfextu	d0{30:2},d1	  ; Emphasis
	       move.l	d1,hdr_emphasis(a2)
	       bsr	@BSTR_end
	       not.l	d0
ASM_read_hdr9  movem.l	(sp)+,a2-a3/d2
	       rts

;	       Get the right alloc table for layer II
;
;	       a0: frame_params *fr_ps
;	       -> d0.l = sub band limit
;	       a0 is preserved
;
ASM_II_get_alloc_table
	       movem.l	a2,-(sp)
	       move.l	fp_header(a0),a1     ; a1 = header
	       move.l	hdr_lay(a1),d0
	       subq.l	#1,d0
	       lsl.l	#4,d0		     ; (lay-1)*16
	       move.l	hdr_bitrate_index(a1),d1
	       add.l	d1,d0
	       lea	BITRATE_table,a2
	       move.w	(a2,d0.w*2),d1       ; d1 = bitrate
	       move.l	fp_stereo(a0),d0
	       cmp.b	#1,d0
	       beq	ASM_II_get_a00
	       lsr.w	#1,d1		     ; d1 = bitrate per channel
ASM_II_get_a00 move.l	hdr_sampling_frequency(a1),d0
	       cmp.w	#56,d1
	       blt	ASM_II_get_a01
	       cmp.w	#1,d0		     ; 48kHz
	       beq	ASM_II_get_a0
	       cmp.w	#80,d1
	       bgt	ASM_II_get_a01
ASM_II_get_a0  moveq.l	#0,d0		     ; -> alloc table 0
	       lea	ALLOC_table0,a1
	       bra	ASM_II_get_a4
ASM_II_get_a01 cmp.w	#1,d0		     ; 48kHz
	       beq	ASM_II_get_a02
	       cmp.w	#96,d1
	       blt	ASM_II_get_a02
ASM_II_get_a1  moveq.l	#1,d0		     ; -> alloc table 1
	       lea	ALLOC_table1,a1
	       bra	ASM_II_get_a4
ASM_II_get_a02 cmp.w	#2,d0		     ; 32kHz
	       beq	ASM_II_get_a3
	       cmp.w	#48,d1
	       bgt	ASM_II_get_a3
ASM_II_get_a2  moveq.l	#2,d0		     ; -> alloc table 2
	       lea	ALLOC_table2,a1
	       bra	ASM_II_get_a4
ASM_II_get_a3  moveq.l	#3,d0		     ; -> alloc table 3
	       lea	ALLOC_table3,a1
ASM_II_get_a4  move.l	d0,fp_tab_num(a0)
	       move.l	a1,fp_alloc(a0)
	       lea	ALLOC_sub_band_limit,a1
	       move.l	(a1,d0.l*4),d0
;		move.l	 d0,fp_sblimit(a0)
	       movem.l	(sp)+,a2
	       rts

;	       Get the joint sub band
;
;	       a0: frame_params *fr_ps
;	       -> d0.l = join sub band
;	       a0 is preserved
;
ASM_joint_sub_band
	       move.l	fp_header(a0),a1     ; a1 = header
	       move.l	hdr_lay(a1),d0
	       subq.l	#1,d0
	       lsl.l	#2,d0		     ; (lay-1)*4
	       move.l	hdr_mode_ext(a1),d1
	       add.l	d1,d0
	       lea	JSB_table,a1
	       move.l	(a1,d0.l*4),d0
	       rts

;	       Decode header
;
;	       a0: frame_params *fr_ps
;
@ASM_decode_header
	       movem.l	a2,-(sp)
	       move.l	fp_header(a0),a2     ; a2 = header

	       move.l	hdr_mode(a2),d1
	       move.l	d1,fp_actual_mode(a0)
	       moveq.l	#1,d0
	       cmp.w	#MPG_MD_MONO,d1
	       beq	ASM_decode_he1
	       addq.l	#1,d0
ASM_decode_he1 move.l	d0,fp_stereo(a0)
	       move.l	d0,fp_channels(a0)
	       moveq.l	#SBLIMIT,d0
	       move.l	hdr_lay(a2),d1
	       cmp.w	#2,d1
	       bne	ASM_decode_he2
	       bsr	ASM_II_get_alloc_table
ASM_decode_he2 move.l	d0,fp_sblimit(a0)
	       move.l	hdr_mode(a2),d1
	       cmp.w	#MPG_MD_JOINT_STEREO,d1
	       bne	ASM_decode_he3
	       bsr	ASM_joint_sub_band
ASM_decode_he3 move.l	d0,fp_jsbound(a0)
	       movem.l	(sp)+,a2
	       rts

;	       Decode bit allocation (MPEG I Lay I)
;
;	       a0: frame_params *fr_ps

@ASM_I_decode_bitalloc
	       movem.l	d2-d3/a2-a5,-(sp)

	       move.l	a0,a2		     ; a2 = frame_params
	       move.l	fp_bs(a2),a0         ; a0 = bitstream
	       move.l	fp_bit_alloc(a2),a4  ; a4 = &bitalloc[0][0]

	       moveq.l	#4,d1		  ; 4 bits per bitalloc
	       cmp.l	#1,fp_stereo(a2)
	       bgt.s	I_dec_bitall5

	       moveq.l	#SBLIMIT-1,d2
I_dec_bitall1
	       bsr	@BSTR_read_bits   ; read d1 bits from bitstream
	       move.l	d0,(a4)+
	       dbra	d2,I_dec_bitall1
	       bra.s	I_dec_bitall9

I_dec_bitall5
	       lea.l	4*SBLIMIT(a4),a5  ; a5 = &bit_alloc[1][0]
	       move.l	fp_jsbound(a2),d2
	       subq.l	#1,d2
	       bmi.s	I_dec_bitall7	  ; jsbound <= 0 ?
I_dec_bitall6
	       bsr	@BSTR_read_bits   ; read d1 bits from bitstream
	       move.l	d0,(a4)+
	       bsr	@BSTR_read_bits   ; read d1 bits from bitstream
	       move.l	d0,(a5)+
	       dbra	d2,I_dec_bitall6
I_dec_bitall7
	       moveq.l	#SBLIMIT,d2
	       sub.l	fp_jsbound(a2),d2
	       subq.l	#1,d2
	       bmi.s	I_dec_bitall9	  ; jsbound >= SBLIMIT
I_dec_bitall8
	       bsr	@BSTR_read_bits   ; read d1 bits from bitstream
	       move.l	d0,(a4)+
	       move.l	d0,(a5)+          ; same band for 2 channels
	       dbra	d2,I_dec_bitall8
I_dec_bitall9
	       movem.l	(sp)+,d2-d3/a2-a5
	       rts

;	       Decode scale (MPEG I Lay I)
;
;	       a0: frame_params *fr_ps
;
;  OPTIMIZATION: bitalloc, scale_index -> BYTE
;
@ASM_I_decode_scale
	       movem.l	d2-d7/a2-a6,-(sp)

	       move.l	a0,a2		     ; a2 = frame_params
	       move.l	fp_bs(a2),a0         ; a0 = bitstream
	       move.l	fp_scale_index(a2),a3
	       move.l	fp_bit_alloc(a2),a4  ; a4 = &bitalloc[0][0]

	       moveq.l	#6,d1		     ; 6 bits per scale_index
	       moveq.l	#SBLIMIT-1,d7

	       cmp.l	#1,fp_stereo(a2)
	       bgt	I_dec_scale5	 ; stereo

I_dec_scale1   moveq.l	#SCALE_RANGE-1,d0
	       tst.l	(a4)+
	       beq.s	I_dec_scale11
	       bsr	@BSTR_read_bits   ; read d1 bits from bitstream
I_dec_scale11  move.l	d0,(a3)+
	       dbra	d7,I_dec_scale1
	       bra.s	I_dec_scale9

I_dec_scale5   lea	4*SBLIMIT(a4),a5
I_dec_scale51  moveq.l	#SCALE_RANGE-1,d0
	       tst.l	(a4)+
	       beq.s	I_dec_scale52
	       bsr	@BSTR_read_bits   ; read d1 bits from bitstream
I_dec_scale52  move.l	d0,(a3)
	       moveq.l	#SCALE_RANGE-1,d0
	       tst.l	(a5)+
	       beq.s	I_dec_scale53
	       bsr	@BSTR_read_bits   ; read d1 bits from bitstream
I_dec_scale53  move.l	d0,4*3*SBLIMIT(a3)
	       addq.l	#4,a3
	       dbra	d7,I_dec_scale51

I_dec_scale9   movem.l	(sp)+,d2-d7/a2-a6
	       rts



;	       Decode bit allocation (MPEG I Lay II)
;
;	       a0: frame_params *fr_ps

@ASM_II_decode_bitalloc
	       movem.l	d2-d3/a2-a5,-(sp)

	       move.l	a0,a2		     ; a2 = frame_params
	       move.l	fp_bs(a2),a0         ; a0 = bitstream
	       move.l	fp_bit_alloc(a2),a1  ; a1 = &bitalloc[0][0]
	       move.l	fp_alloc(a2),a3      ; a3 = &alloc[0][0]
	       move.l	a1,a4		     ; a4 = &bitalloc[0][0]
	       moveq.l	#4*16,d3	     ; d3 = next alloc step
	       cmp.l	#1,fp_stereo(a2)
	       bgt.s	II_dec_bitall5

	       move.l	fp_sblimit(a2),d2
	       subq.l	#1,d2
	       bmi.s	II_dec_bitall2	  ; sblimit <= 0 ?
II_dec_bitall1
	       bfextu	(a3){ALLOC_O_BITS:ALLOC_W_BITS},d1    ; d1 = bits
	       bsr	@BSTR_read_bits   ; read d1 bits from bitstream
	       move.l	d0,(a4)+
	       add.l	d3,a3		  ; next -> &alloc[i++][0]
	       dbra	d2,II_dec_bitall1
	       bra.s	II_dec_bitall9
II_dec_bitall2
;		moveq.l  #SBLIMIT,d2
	       move.w	sub_band_size,d2
	       ext.l	d2
	       sub.l	fp_sblimit(a2),d2
	       subq.l	#1,d2
	       bmi.s	II_dec_bitall9	  ; sblimit >= sub_band_size
	       clr.l	d0		  ; 0 -> upper band
II_dec_bitall3
	       move.l	d0,(a4)+
	       dbra	d2,II_dec_bitall3
	       bra.s	II_dec_bitall9

II_dec_bitall5
	       move.l	a4,a5
	       add.l	#4*SBLIMIT,a5	  ; a5 = &bit_alloc[1][0]
	       move.l	fp_jsbound(a2),d2
	       subq.l	#1,d2
	       bmi.s	II_dec_bitall8	  ; jsbound <= 0 ?
II_dec_bitall6
	       bfextu	(a3){ALLOC_O_BITS:ALLOC_W_BITS},d1    ; d1 = bits
	       bsr	@BSTR_read_bits   ; read d1 bits from bitstream
	       move.l	d0,(a4)+
	       bsr	@BSTR_read_bits   ; read d1 bits from bitstream
	       move.l	d0,(a5)+
	       add.l	d3,a3		  ; next -> &alloc[i++][0]
	       dbra	d2,II_dec_bitall6

	       move.l	fp_sblimit(a2),d2
	       sub.l	fp_jsbound(a2),d2
	       subq.l	#1,d2
	       bmi.s	II_dec_bitall8	  ; jsbound >= sblimit
II_dec_bitall7
	       bfextu	(a3){ALLOC_O_BITS:ALLOC_W_BITS},d1    ; d1 = bits
	       bsr	@BSTR_read_bits   ; read d1 bits from bitstream
	       move.l	d0,(a4)+
	       move.l	d0,(a5)+          ; same band for 2 channels
	       add.l	d3,a3		  ; next -> &alloc[i++][0]
	       dbra	d2,II_dec_bitall7
II_dec_bitall8
;		moveq.l  #SBLIMIT,d2
	       move.w	sub_band_size,d2
	       ext.l	d2
	       sub.l	fp_sblimit(a2),d2
	       subq.l	#1,d2
	       bmi.s	II_dec_bitall9	  ; sblimit >= sub_band_size
	       clr.l	d0		  ; 0 -> upper band
II_dec_bitall81
	       move.l	d0,(a4)+
	       move.l	d0,(a5)+
	       dbra	d2,II_dec_bitall81
II_dec_bitall9
	       movem.l	(sp)+,d2-d3/a2-a5
	       rts

;	       Decode scale (MPEG I Lay II)
;
;	       a0: frame_params *fr_ps
;
;  OPTIMIZATION: bitalloc, scfsi, scale_index -> BYTE
;
@ASM_II_decode_scale
	       movem.l	d2-d7/a2-a6,-(sp)

	       move.l	a0,a2		     ; a2 = frame_params
	       move.l	fp_bs(a2),a0         ; a0 = bistream
	       move.l	fp_bit_alloc(a2),a1
	       move.l	fp_scfsi(a2),a3
	       move.l	fp_scale_index(a2),a4

	       move.l	a1,a5		  ; a5 = &bitalloc[0][0]
	       moveq.l	#2,d1		  ; 2 bits per scfsi

	       cmp.l	#1,fp_stereo(a2)
	       bgt	II_dec_scale5	  ; stereo

	       move.l	fp_sblimit(a2),d7
	       subq.l	#1,d7
	       bmi	II_dec_scale3	  ; sblimit <= 0 !

	       movem.l	a3/a5,-(sp)
II_dec_scale1  tst.l	(a5)+
	       beq.s	II_dec_scale11
	       bsr	@BSTR_read_bits   ; read d1 bits from bitstream
	       move.l	d0,(a3)
II_dec_scale11 addq.l	#4,a3
	       dbra	d7,II_dec_scale1
	       movem.l	(sp)+,a3/a5
II_dec_scale2
	       move.l	fp_sblimit(a2),d7
	       subq.l	#1,d7
	       moveq.l	#6,d1
II_dec_scale21 tst.l	(a5)+
	       beq.s	II_dec_scale26
	       move.l	(a3)+,d0
	       bne.s	II_dec_scale22	     ; scfsi[0][i] > 0
	       bsr	@BSTR_read3_bits     ; read 3*d1 bits from bitstream
	       move.l	d4,(a4)              ; scale_index[0][0][i]
	       move.l	d5,4*SBLIMIT(a4)     ; scale_index[0][1][i]
	       move.l	d6,8*SBLIMIT(a4)     ; scale_index[0][2][i]
	       bra.s	II_dec_scale27
II_dec_scale22 subq.b	#1,d0
	       bne.s	II_dec_scale23	     ; scfsi[0][i] > 1
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,(a4)              ; scale_index[0][0][i]
	       move.l	d0,4*SBLIMIT(a4)     ; = scale_index[0][1][i]
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,8*SBLIMIT(a4)     ; scale_index[0][2][i]
	       bra.s	II_dec_scale27
II_dec_scale23 subq.b	#1,d0
	       bne.s	II_dec_scale24	     ; scfsi[0][i] > 2
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,(a4)              ; scale_index[0][0][i]
	       move.l	d0,4*SBLIMIT(a4)     ; = scale_index[0][1][i]
	       move.l	d0,8*SBLIMIT(a4)     ; = scale_index[0][2][i]
	       bra.s	II_dec_scale27
II_dec_scale24				     ; scfsi[0][i] == 3
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,(a4)              ; scale_index[0][0][i]
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,4*SBLIMIT(a4)     ; scale_index[0][1][i]
	       move.l	d0,8*SBLIMIT(a4)     ; = scale_index[0][2][i]
	       bra.s	II_dec_scale27
II_dec_scale26
	       moveq.l	#SCALE_RANGE-1,d0
	       move.l	d0,(a4)              ; scale_index[0][0][i]
	       move.l	d0,4*SBLIMIT(a4)     ; = scale_index[0][1][i]
	       move.l	d0,8*SBLIMIT(a4)     ; = scale_index[0][2][i]
	       addq.l	#4,a3		     ; next scfsi
II_dec_scale27
	       addq.l	#4,a4		     ; next scale_index
	       dbra	d7,II_dec_scale21

II_dec_scale3
;		moveq.l  #SBLIMIT,d7
	       move.w	sub_band_size,d7
	       ext.l	d7
	       sub.l	fp_sblimit(a2),d7
	       subq.l	#1,d7
	       bmi	II_dec_scale9	    ; sblimit >= sub_band_size
	       moveq.l	#SCALE_RANGE-1,d0
II_dec_scale31 move.l	d0,(a4)              ; scale_index[0][0][i]
	       move.l	d0,4*SBLIMIT(a4)     ; = scale_index[0][1][i]
	       move.l	d0,8*SBLIMIT(a4)     ; = scale_index[0][2][i]
	       addq.l	#4,a4		     ; next scale_index
	       dbra	d7,II_dec_scale31
	       bra	II_dec_scale9

II_dec_scale5
	       move.l	fp_sblimit(a2),d7
	       subq.l	#1,d7
	       bmi	II_dec_scale8	    ; sblimit <= 0 !

	       movem.l	a3/a5,-(sp)
II_dec_scale51 tst.l	(a5)
	       beq.s	II_dec_scale52
	       bsr	@BSTR_read_bits   ; read d1 bits from bitstream
	       move.l	d0,(a3)
II_dec_scale52 tst.l	4*SBLIMIT(a5)
	       beq.s	II_dec_scale53
	       bsr	@BSTR_read_bits   ; read d1 bits from bitstream
	       move.l	d0,4*SBLIMIT(a3)
II_dec_scale53 addq.l	#4,a3
	       addq.l	#4,a5
	       dbra	d7,II_dec_scale51
	       movem.l	(sp)+,a3/a5

	       move.l	fp_sblimit(a2),d7
	       subq.l	#1,d7
	       moveq.l	#6,d1
II_dec_scale61 tst.l	(a5)
	       beq.s	II_dec_scale66
	       move.l	(a3),d0
	       bne.s	II_dec_scale62	     ; scfsi[0][i] > 0
	       bsr	@BSTR_read3_bits     ; read 3*d1 bits from bitstream
	       move.l	d4,(a4)              ; scale_index[0][0][i]
	       move.l	d5,4*SBLIMIT(a4)     ; scale_index[0][1][i]
	       move.l	d6,8*SBLIMIT(a4)     ; scale_index[0][2][i]
	       bra.s	II_dec_scale67
II_dec_scale62 subq.b	#1,d0
	       bne.s	II_dec_scale63	     ; scfsi[0][i] > 1
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,(a4)              ; scale_index[0][0][i]
	       move.l	d0,4*SBLIMIT(a4)     ; = scale_index[0][1][i]
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,8*SBLIMIT(a4)     ; scale_index[0][2][i]
	       bra.s	II_dec_scale67
II_dec_scale63 subq.b	#1,d0
	       bne.s	II_dec_scale64	     ; scfsi[0][i] > 2
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,(a4)              ; scale_index[0][0][i]
	       move.l	d0,4*SBLIMIT(a4)     ; = scale_index[0][1][i]
	       move.l	d0,8*SBLIMIT(a4)     ; = scale_index[0][2][i]
	       bra.s	II_dec_scale67
II_dec_scale64
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,(a4)              ; scale_index[0][0][i]
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,4*SBLIMIT(a4)     ; scale_index[0][1][i]
	       move.l	d0,8*SBLIMIT(a4)     ; = scale_index[0][2][i]
	       bra.s	II_dec_scale67
II_dec_scale66
	       moveq.l	#SCALE_RANGE-1,d0
	       move.l	d0,(a4)              ; scale_index[0][0][i]
	       move.l	d0,4*SBLIMIT(a4)     ; = scale_index[0][1][i]
	       move.l	d0,8*SBLIMIT(a4)     ; = scale_index[0][2][i]
II_dec_scale67
	       tst.l	4*SBLIMIT(a5)
	       beq.s	II_dec_scale76
	       move.l	4*SBLIMIT(a3),d0
	       bne.s	II_dec_scale72	     ; scfsi[0][i] > 0
	       bsr	@BSTR_read3_bits     ; read 3*d1 bits from bitstream
	       move.l	d4,4*3*SBLIMIT(a4)   ; scale_index[1][0][i]
	       move.l	d5,4*4*SBLIMIT(a4)   ; scale_index[1][1][i]
	       move.l	d6,4*5*SBLIMIT(a4)   ; scale_index[1][2][i]
	       bra.s	II_dec_scale77
II_dec_scale72 subq.b	#1,d0
	       bne.s	II_dec_scale73	     ; scfsi[0][i] > 1
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,4*3*SBLIMIT(a4)   ; scale_index[1][0][i]
	       move.l	d0,4*4*SBLIMIT(a4)   ; = scale_index[1][1][i]
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,4*5*SBLIMIT(a4)   ; scale_index[1][2][i]
	       bra.s	II_dec_scale77
II_dec_scale73 subq.b	#1,d0
	       bne.s	II_dec_scale74	     ; scfsi[0][i] > 2
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,4*3*SBLIMIT(a4)   ; scale_index[1][0][i]
	       move.l	d0,4*4*SBLIMIT(a4)   ; = scale_index[1][1][i]
	       move.l	d0,4*5*SBLIMIT(a4)   ; = scale_index[1][2][i]
	       bra.s	II_dec_scale77
II_dec_scale74
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,4*3*SBLIMIT(a4)   ; scale_index[1][0][i]
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,4*4*SBLIMIT(a4)   ; = scale_index[1][1][i]
	       move.l	d0,4*5*SBLIMIT(a4)   ; = scale_index[1][2][i]
	       bra.s	II_dec_scale77
II_dec_scale76
	       moveq.l	#SCALE_RANGE-1,d0
	       move.l	d0,4*3*SBLIMIT(a4)   ; scale_index[1][0][i]
	       move.l	d0,4*4*SBLIMIT(a4)   ; = scale_index[1][1][i]
	       move.l	d0,4*5*SBLIMIT(a4)   ; = scale_index[1][2][i]
II_dec_scale77
	       addq.l	#4,a3		     ; next scfsi
	       addq.l	#4,a4		     ; next scale_index
	       addq.l	#4,a5		     ; next bitalloc
	       dbra	d7,II_dec_scale61

II_dec_scale8
;	       moveq.l	#SBLIMIT,d7
	       move.w	sub_band_size,d7
	       ext.l	d7
	       sub.l	fp_sblimit(a2),d7
	       subq.l	#1,d7
	       bmi	II_dec_scale9	    ; sblimit >= sub_band_size
	       moveq.l	#SCALE_RANGE-1,d0
II_dec_scale81 move.l	d0,(a4)              ; scale_index[0][0][i]
	       move.l	d0,4*SBLIMIT(a4)     ; = scale_index[0][1][i]
	       move.l	d0,8*SBLIMIT(a4)     ; = scale_index[0][2][i]
	       move.l	d0,4*3*SBLIMIT(a4)   ; scale_index[1][0][i]
	       move.l	d0,4*4*SBLIMIT(a4)   ; = scale_index[1][1][i]
	       move.l	d0,4*5*SBLIMIT(a4)   ; = scale_index[1][2][i]
	       addq.l	#4,a4		     ; next scale_index
	       dbra	d7,II_dec_scale81
;		bra	 II_dec_scale9

II_dec_scale9  movem.l	(sp)+,d2-d7/a2-a6
	       rts


;	       Read a sub band sample (MPEG I Lay I) into a buffer
;
;	       a0: frame_params *fr_ps
;

@ASM_I_buffer_sample
	       movem.l	d2-d7/a0-a6,-(sp)

	       move.l	fp_sblimit(a0),d0
	       move.l	fp_channels(a0),d1
	       move.l	fp_jsbound(a0),d2
	       move.l	fp_alloc(a0),a3
	       move.l	fp_bit_alloc(a0),a2
	       move.l	fp_sample(a0),a1
	       move.l	fp_bs(a0),a0

	       move.w	d0,bsamp_sblimit
	       move.w	d1,bsamp_channels
	       move.w	d2,bsamp_jsbound
	       move.l	a1,a4		     ; a4 = &sample[0][0][0]

	       clr.l	d7		     ; d7=i:0..sblimit
ASM_I_bsamp_1
	       move.l	(0,a2,d7.w*4),d1     ; d1 = bit_alloc[0][d7]
	       beq	ASM_I_bsamp_3	     ; no bit allocated for this sample

	       addq.l	#1,d1		     ; d1 = bits to read
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,(a4)              ; sample[0][0][i]
	       bra.s	ASM_I_bsamp_4
ASM_I_bsamp_3
	       clr.l	(a4)                 ; sample[0][0][i] = 0
ASM_I_bsamp_4
	       cmp.w	#1,bsamp_channels
	       beq	ASM_I_bsamp_8	    ; only 1 channel
	       cmp.w	bsamp_jsbound,d7
	       bge	ASM_I_bsamp_7	    ; i>=jsbound & stereo -> L=R

	       move.l	(4*SBLIMIT,a2,d7.w*4),d1     ; d1 = bit_alloc[1][d7]
	       beq	ASM_I_bsamp_6	    ; no bit allocated for this sample

	       addq.l	#1,d1		     ; d1 = bits to read
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,4*3*SBLIMIT(a4)   ; sample[1][0][i]
	       bra	ASM_I_bsamp_8
ASM_I_bsamp_6
	       clr.l	4*3*SBLIMIT(a4)      ; sample[1][0][i] = 0
	       bra	ASM_I_bsamp_8
ASM_I_bsamp_7
	       move.l	(a4),4*3*SBLIMIT(a4)          ; sample[1][0][i] = sample[0][0][i]
ASM_I_bsamp_8
	       addq.l	#4,a4		     ; next sample ptr
	       addq.w	#1,d7		     ; i++
	       IFND	SKIP_UPPER_BAND
	       cmp.w	bsamp_sblimit,d7
	       blt	ASM_I_bsamp_1	    ; i<sblimit
	       ELSE
	       cmp.w	sub_band_size,d7
	       bge.s	ASM_I_bsamp_81	    ; i >= sub_band_size -> skip others
	       cmp.w	bsamp_sblimit,d7
	       blt	ASM_I_bsamp_1
	       bra	ASM_I_bsamp_9
ASM_I_bsamp_81
	       cmp.w	bsamp_sblimit,d7
	       bge	ASM_I_bsamp_9	    ; i >= sblimit -> end of read

	       move.l	(0,a2,d7.w*4),d1    ; d1 = bit_alloc[0][d7]
	       beq	ASM_I_bsamp_84	    ; no bit allocated for this sample

	       addq.l	#1,d1		     ; d1 = bits to read
	       bsr	@BSTR_skip_bits      ; skip d1 bits from bitstream
ASM_I_bsamp_84
	       cmp.w	#1,bsamp_channels
	       beq	ASM_I_bsamp_88	    ; only 1 channel
	       cmp.w	bsamp_jsbound,d7
	       bge	ASM_I_bsamp_88	    ; i>=jsbound & stereo -> L=R

	       move.l	(4*SBLIMIT,a2,d7.w*4),d1   ; d1 = bit_alloc[1][d7]
	       beq.s	 ASM_I_bsamp_88      ; no bit allocated for this sample

	       addq.l	#1,d1		     ; d1 = bits to read
	       bsr	@BSTR_skip_bits      ; skip d1 bits from bitstream
ASM_I_bsamp_88
	       addq.l	#4,a4		     ; next sample ptr
	       addq.w	#1,d7		     ; i++
	       bra	ASM_I_bsamp_81
	       ENDC
ASM_I_bsamp_9
	       IFND	SKIP_UPPER_BAND
	       cmp.w	#SBLIMIT,d7
	       ELSE
	       cmp.w	sub_band_size,d7
	       ENDC
	       bge	ASM_I_bsamp_end

	       addq.w	#1,d7
	       clr.l	(a4)                 ; sample[0][0][i] = 0
	       cmp.w	#1,bsamp_channels
	       beq	ASM_I_bsamp_91	     ; only 1 channel
	       clr.l	4*3*SBLIMIT(a4)      ; sample[1][0][i] = 0
ASM_I_bsamp_91
	       addq.l	#4,a4		     ; next sample ptr
	       bra	ASM_I_bsamp_9
ASM_I_bsamp_end
	       movem.l	(sp)+,d2-d7/a0-a6
	       rts




;	       Read a sub band sample (MPEG I Lay II) into a buffer
;
;	       a0: frame_params *fr_ps
;

@ASM_II_buffer_sample
	       movem.l	d2-d7/a0-a6,-(sp)

	       move.l	fp_sblimit(a0),d0
	       move.l	fp_channels(a0),d1
	       move.l	fp_jsbound(a0),d2
	       move.l	fp_alloc(a0),a3
	       move.l	fp_bit_alloc(a0),a2
	       move.l	fp_sample(a0),a1
	       move.l	fp_bs(a0),a0

	       move.w	d0,bsamp_sblimit
	       move.w	d1,bsamp_channels
	       move.w	d2,bsamp_jsbound
	       move.l	a1,a4		     ; a4 = &sample[0][0][0]

	       clr.l	d7		     ; d7=i:0..sblimit
ASM_II_bsamp_1
	       move.l	(0,a2,d7.w*4),d3     ; d3 = bit_alloc[0][d7]
	       beq	ASM_II_bsamp_3	     ; no bit allocated for this sample
	       move.l	(a3,d3.w*4),d3       ; d3 = alloc_table[i][d3]
	       bfextu	d3{ALLOC_O_BITS:ALLOC_W_BITS},d1    ; d1 = bits
	       btst	#ALLOC_B_GROUP,d3
	       beq	ASM_II_bsamp_2	     ; group <> 3
	       ; read each sub band sample separately
	       IFND	READ3_BITS
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,(a4)              ; sample[0][0][i]
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,4*SBLIMIT(a4)     ; sample[0][1][i]
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,8*SBLIMIT(a4)     ; sample[0][2][i]
	       ELSE
	       bsr	@BSTR_read3_bits     ; read 3*d1 bits from bitstream
	       move.l	d4,(a4)              ; sample[0][0][i]
	       move.l	d5,4*SBLIMIT(a4)     ; sample[0][1][i]
	       move.l	d6,8*SBLIMIT(a4)     ; sample[0][2][i]
	       ENDC
	       bra	ASM_II_bsamp_4
ASM_II_bsamp_2				     ; bit_alloc.steps = 3, 5, 9
	       bfextu	d3{ALLOC_O_STEPS:ALLOC_W_STEPS},d4  ; d4 = steps
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.w	d0,d1
	       divs.w	d4,d1		     ; d1/d4 -> d1.h=r d1.l=q
	       move.l	d1,d0
	       swap	d0
	       ext.l	d0
	       move.l	d0,(a4)              ; r -> sample[0][0][i]
	       ext.l	d1
	       divs.w	d4,d1
	       move.l	d1,d0
	       swap	d0
	       ext.l	d0
	       move.l	d0,4*SBLIMIT(a4)     ; r -> sample[0][1][i]
	       ext.l	d1
	       move.l	d1,8*SBLIMIT(a4)     ; q -> sample[0][2][i]
	       bra	ASM_II_bsamp_4
ASM_II_bsamp_3
	       clr.l	(a4)                 ; sample[0][0][i] = 0
	       clr.l	4*SBLIMIT(a4)        ; sample[0][1][i] = 0
	       clr.l	8*SBLIMIT(a4)        ; sample[0][2][i] = 0
ASM_II_bsamp_4
	       cmp.w	#1,bsamp_channels
	       beq	ASM_II_bsamp_8	     ; only 1 channel
	       cmp.w	bsamp_jsbound,d7
	       bge	ASM_II_bsamp_7	     ; i>=jsbound & stereo -> L=R

	       move.l	(4*SBLIMIT,a2,d7.w*4),d3     ; d3 = bit_alloc[1][d7]
	       beq	ASM_II_bsamp_6	     ; no bit allocated for this sample
	       move.l	(a3,d3.w*4),d3       ; d3 = alloc_table[i][d3]
	       bfextu	d3{ALLOC_O_BITS:ALLOC_W_BITS},d1    ; d1 = bits
	       btst	#ALLOC_B_GROUP,d3
	       beq	ASM_II_bsamp_5	     ; group <> 3
	       IFND	READ3_BITS
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,4*3*SBLIMIT(a4)   ; sample[1][0][i]
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,4*4*SBLIMIT(a4)   ; sample[1][1][i]
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       move.l	d0,4*5*SBLIMIT(a4)   ; sample[1][2][i]
	       ELSE
	       bsr	@BSTR_read3_bits     ; read 3*d1 bits from bitstream
	       move.l	d4,4*3*SBLIMIT(a4)   ; sample[1][0][i]
	       move.l	d5,4*4*SBLIMIT(a4)   ; sample[1][1][i]
	       move.l	d6,4*5*SBLIMIT(a4)   ; sample[1][2][i]
	       ENDC
	       bra	ASM_II_bsamp_8
ASM_II_bsamp_5				     ; bit_alloc.steps = 3, 5, 9
	       bfextu	d3{ALLOC_O_STEPS:ALLOC_W_STEPS},d4  ; d4 = steps
	       bsr	@BSTR_read_bits      ; read d1 bits from bitstream
	       tst.w	d4
	       beq.s	ASM_II_bsamp_6	     ; if d4=0 (should not happend !)
	       move.w	d0,d1
	       divs.w	d4,d1		     ; d1/d4 -> d1.h=r d1.l=q
	       move.l	d1,d0
	       swap	d0
	       ext.l	d0
	       move.l	d0,4*3*SBLIMIT(a4)   ; r -> sample[1][0][i]
	       ext.l	d1
	       divs.w	d4,d1
	       move.l	d1,d0
	       swap	d0
	       ext.l	d0
	       move.l	d0,4*4*SBLIMIT(a4)   ; r -> sample[1][1][i]
	       ext.l	d1
	       move.l	d1,4*5*SBLIMIT(a4)   ; q -> sample[1][2][i]
	       bra	ASM_II_bsamp_8
ASM_II_bsamp_6
	       clr.l	4*3*SBLIMIT(a4)      ; sample[1][0][i] = 0
	       clr.l	4*4*SBLIMIT(a4)      ; sample[1][1][i] = 0
	       clr.l	4*5*SBLIMIT(a4)      ; sample[1][2][i] = 0
	       bra	ASM_II_bsamp_8
ASM_II_bsamp_7
	       move.l	(a4),4*3*SBLIMIT(a4)          ; sample[1][0][i] = sample[0][0][i]
	       move.l	4*SBLIMIT(a4),4*4*SBLIMIT(a4) ; sample[1][1][i] = sample[0][1][i]
	       move.l	8*SBLIMIT(a4),4*5*SBLIMIT(a4) ; sample[1][2][i] = sample[0][2][i]
ASM_II_bsamp_8
	       addq.l	#4,a4		     ; next sample ptr
	       add.l	#4*16,a3	     ; next alloc_table ptr
	       addq.w	#1,d7		     ; i++
	       IFND	SKIP_UPPER_BAND
	       cmp.w	bsamp_sblimit,d7
	       blt	ASM_II_bsamp_1	     ; i<sblimit
	       ELSE
	       cmp.w	sub_band_size,d7
	       bge.s	ASM_II_bsamp_81      ; i >= sub_band_size -> skip others
	       cmp.w	bsamp_sblimit,d7
	       blt	ASM_II_bsamp_1
	       bra	ASM_II_bsamp_9
ASM_II_bsamp_81
	       cmp.w	bsamp_sblimit,d7
	       bge	ASM_II_bsamp_9	     ; i >= sblimit -> end of read

	       move.l	(0,a2,d7.w*4),d3     ; d3 = bit_alloc[0][d7]
	       beq	ASM_II_bsamp_84      ; no bit allocated for this sample
	       move.l	(a3,d3.w*4),d3       ; d3 = alloc_table[i][d3]
	       bfextu	d3{ALLOC_O_BITS:ALLOC_W_BITS},d1    ; d1 = bits
	       btst	#ALLOC_B_GROUP,d3
	       beq	ASM_II_bsamp_82      ; group <> 3
	       ; read each sub band sample separately
	       move.l	d1,d2
	       add.l	d1,d1
	       add.l	d2,d1
	       bsr	@BSTR_skip_bits      ; skip 3*d1 bits from bitstream
	       bra	ASM_II_bsamp_84
ASM_II_bsamp_82
	       bsr	@BSTR_skip_bits      ; skip d1 bits from bitstream
ASM_II_bsamp_84
	       cmp.w	#1,bsamp_channels
	       beq	ASM_II_bsamp_88      ; only 1 channel
	       cmp.w	bsamp_jsbound,d7
	       bge	ASM_II_bsamp_88      ; i>=jsbound & stereo -> L=R

	       move.l	(4*SBLIMIT,a2,d7.w*4),d3     ; d3 = bit_alloc[1][d7]
	       beq.s	 ASM_II_bsamp_88      ; no bit allocated for this sample
	       move.l	(a3,d3.w*4),d3       ; d3 = alloc_table[i][d3]
	       bfextu	d3{ALLOC_O_BITS:ALLOC_W_BITS},d1    ; d1 = bits
	       btst	#ALLOC_B_GROUP,d3
	       beq	ASM_II_bsamp_85      ; group <> 3
	       ; read each sub band sample separately
	       move.l	d1,d2
	       add.l	d1,d1
	       add.l	d2,d1
	       bsr	@BSTR_skip_bits      ; skip 3*d1 bits from bitstream
	       bra	ASM_II_bsamp_88
ASM_II_bsamp_85
	       bsr	@BSTR_skip_bits      ; skip d1 bits from bitstream
ASM_II_bsamp_88
	       addq.l	#4,a4		     ; next sample ptr
	       add.l	#4*16,a3	     ; next alloc_table ptr
	       addq.w	#1,d7		     ; i++
	       bra	ASM_II_bsamp_81
	       ENDC
ASM_II_bsamp_9
	       IFND	SKIP_UPPER_BAND
	       cmp.w	#SBLIMIT,d7
	       ELSE
	       cmp.w	sub_band_size,d7
	       ENDC
	       bge	ASM_II_bsamp_end

	       addq.w	#1,d7
	       clr.l	(a4)                 ; sample[0][0][i] = 0
	       clr.l	4*SBLIMIT(a4)        ; sample[0][1][i] = 0
	       clr.l	8*SBLIMIT(a4)        ; sample[0][2][i] = 0
	       cmp.w	#1,bsamp_channels
	       beq	ASM_II_bsamp_91      ; only 1 channel
	       clr.l	4*3*SBLIMIT(a4)      ; sample[1][0][i] = 0
	       clr.l	4*4*SBLIMIT(a4)      ; sample[1][1][i] = 0
	       clr.l	4*5*SBLIMIT(a4)      ; sample[1][2][i] = 0
ASM_II_bsamp_91
	       addq.l	#4,a4
	       bra	ASM_II_bsamp_9
ASM_II_bsamp_end
	       movem.l	(sp)+,d2-d7/a0-a6
	       rts

;	       Dequantize & denormalize samples (layer I)
;
;	       a0:   frame_params *fr_ps

@ASM_I_deqnorm
	       movem.l	d2-d7/a2-a6,-(sp)

	       move.l	fp_sblimit(a0),d0
	       move.l	fp_stereo(a0),d1
	       move.l	fp_scale_index(a0),a3
	       move.l	fp_fraction(a0),a2
	       move.l	fp_bit_alloc(a0),a1
	       move.l	fp_sample(a0),a0

	       move.w	d0,sub_band_limit    ; sblimit
	       IFD	SKIP_UPPER_BAND
	       cmp.w	sub_band_size,d0
	       ble.s	ASM_I_deqnorm_0      ; sub_band_limit <= sub_band_size
	       move.w	sub_band_size,sub_band_limit
ASM_I_deqnorm_0
	       ENDC
	       move.w	d1,channels	     ; stereo ?
	       mulu.w	#SBLIMIT,d2	     ; x*SBLIMIT
	       moveq.l	#MULT_FACTOR,d7
	       moveq.l	#DEQUANT_FACTOR,d6
	       lea.l	mult_table,a5

ASM_I_deqnorm_1
	       movem.l	d2/a0-a4,-(sp)
	       move.l	a0,a6		     ; a6 = sample[k][0][0]
;		lea.l	 (a3,d2.w*4),a3       ; a3 = &scale_index[k][x][0]
	       move.w	sub_band_limit,d0
	       move.w	d0,sub_band_index

	       lea.l	dequantize_I_table,a0
ASM_I_deqnorm_2
	       subq.w	#1,sub_band_index
	       bmi	ASM_I_deqnorm_7

	       move.l	(a3)+,d0             ; d0 = *scale++
	       move.l	(a1)+,d1             ; d1 = *bit_alloc++;
	       beq	ASM_I_deqnorm_5      ; no bit allocated

	       move.w	(a5,d0.w*2),d5       ; m = d5;
	       move.w	(a0,d1.w*4),d3       ; d
	       move.w	(2,a0,d1.w*4),d4     ; c
	       muls.w	d5,d4		     ; c*m
	       asr.l	d7,d4		     ; >>MULT_FACTOR

	       move.l	(a6)+,d0             ; sample[k][0][i]
	       moveq.w	#31-16,d2
	       sub.w	d1,d2
	       asl.l	d2,d0		     ; left justify sample (normalize)
	       bchg	#15,d0		     ; Invert Msb of sample
	       asr.w	#15-INT_FACTOR,d0
	       add.w	d3,d0		     ; d0 + d
	       muls.w	d4,d0		     ; * c*m
	       asr.l	d6,d0		     ; >>DEQUANT_FACTOR
	       move.w	d0,(a2)+             ; -> fraction[k][0][i]

	       bra	ASM_I_deqnorm_2     ; next sub_band
ASM_I_deqnorm_5
	       addq.l	#4,a6		     ; -> sample ptr ++ (skipped)
	       clr.w	(a2)+                ; fraction[k][0][i] = 0
ASM_I_deqnorm_6
	       bra	ASM_I_deqnorm_2     ; next sub_band

ASM_I_deqnorm_7
	       move.w	sub_band_limit,d0
ASM_I_deqnorm_8
	       IFND	SKIP_UPPER_BAND      ; 27/05/1995
	       cmp.w	#SBLIMIT,d0
	       ELSE			     ; !!! incompatible with FILTER_?_SUM
	       cmp.w	sub_band_size,d0
	       ENDC
	       bge	ASM_I_deqnorm_9
	       clr.w	(a2)+                ; fraction[k][0][i] = 0
	       addq.w	#1,d0
	       bra	ASM_I_deqnorm_8
ASM_I_deqnorm_9
	       movem.l	(sp)+,d2/a0-a4
	       subq.w	#1,channels
	       ble	ASM_I_deqnorm_end
	       add.l	#4*3*SBLIMIT,a0      ; next -> &sample[k][0][0]
	       add.l	#4*SBLIMIT,a1	     ; next -> &bit_alloc[k][0]
	       add.l	#2*3*SBLIMIT,a2      ; next -> &fraction[k][0][0]
	       add.l	#4*3*SBLIMIT,a3      ; next -> &scale_index[k][0][0]
	       bra	ASM_I_deqnorm_1

ASM_I_deqnorm_end
	       movem.l	(sp)+,d2-d7/a2-a6
	       rts


;	       Dequantize & denormalize samples (layer II)
;
;	       a0:   frame_params *fr_ps
;	       d0.l: int x	  (0..2)

@ASM_II_deqnorm
	       movem.l	d2-d7/a2-a6,-(sp)

	       move.l	d0,d2
	       move.l	fp_sblimit(a0),d0
	       move.l	fp_stereo(a0),d1
	       move.l	fp_alloc(a0),a4
	       move.l	fp_scale_index(a0),a3
	       move.l	fp_fraction(a0),a2
	       move.l	fp_bit_alloc(a0),a1
	       move.l	fp_sample(a0),a0

	       move.w	d0,sub_band_limit    ; sblimit
	       IFD	SKIP_UPPER_BAND
	       cmp.w	sub_band_size,d0
	       ble.s	ASM_II_deqnorm_0     ; sub_band_limit <= sub_band_size
	       move.w	sub_band_size,sub_band_limit
ASM_II_deqnorm_0
	       ENDC
	       move.w	d1,channels	     ; stereo ?
	       mulu.w	#SBLIMIT,d2	     ; x*SBLIMIT
	       moveq.l	#MULT_FACTOR,d7
	       moveq.l	#DEQUANT_FACTOR,d6
	       lea.l	mult_table,a5

ASM_II_deqnorm_1
	       movem.l	d2/a0-a4,-(sp)
	       move.l	a0,a6		     ; a6 = sample[k][0][0]
	       lea.l	(a3,d2.w*4),a3       ; a3 = &scale_index[k][x][0]
	       move.w	sub_band_limit,d0
	       move.w	d0,sub_band_index

	       lea.l	dequantize_II_table,a0
ASM_II_deqnorm_2
	       subq.w	#1,sub_band_index
	       bmi	ASM_II_deqnorm_7

	       move.l	(a3)+,d0             ; d0 = *scale++
	       move.l	(a1)+,d1             ; d1 = *bit_alloc++;
	       beq	ASM_II_deqnorm_5     ; no bit allocated

	       move.w	(a5,d0.w*2),d5       ; m = d5;
	       move.l	(a4,d1.w*4),d0       ; d0 = alloc_table[i][d3]
	       bfextu	d0{ALLOC_O_SHIFT:ALLOC_W_SHIFT},d2  ; d2 = shift
	       bfextu	d0{ALLOC_O_QUANT:ALLOC_W_QUANT},d1  ; d1 = quant

	       move.w	(a0,d1.w*4),d3       ; d
	       move.w	(2,a0,d1.w*4),d4     ; c
	       muls.w	d5,d4		     ; c*m
	       asr.l	d7,d4		     ; >>MULT_FACTOR

	       move.l	(a6),d0              ; sample[k][0][i]
	       asl.l	d2,d0		     ; left justify sample (normalize)
	       bchg	#15,d0		     ; Invert Msb of sample
	       asr.w	#15-INT_FACTOR,d0
	       add.w	d3,d0		     ; d0 + d
	       muls.w	d4,d0		     ; * c*m
	       asr.l	d6,d0		     ; >>DEQUANT_FACTOR
	       move.w	d0,(a2)              ; -> fraction[k][0][i]

	       move.l	SBLIMIT*4(a6),d0     ; sample[k][1][i]
	       asl.l	d2,d0		     ; left justify sample (normalize)
	       bchg	#15,d0		     ; Invert Msb of sample
	       asr.w	#15-INT_FACTOR,d0
	       add.w	d3,d0		     ; d0 + d
	       muls.w	d4,d0		     ; * c*m
	       asr.l	d6,d0		     ; >>DEQUANT_FACTOR
	       move.w	d0,SBLIMIT*2(a2)     ; -> fraction[k][1][i]

	       move.l	SBLIMIT*8(a6),d0     ; sample[k][2][i]
	       asl.l	d2,d0		     ; left justify sample (normalize)
	       bchg	#15,d0		     ; Invert Msb of sample
	       asr.w	#15-INT_FACTOR,d0
	       add.w	d3,d0		     ; d0 + d
	       muls.w	d4,d0		     ; * c*m
	       asr.l	d6,d0		     ; >>DEQUANT_FACTOR
	       move.w	d0,SBLIMIT*4(a2)     ; -> fraction[k][2][i]

	       bra	ASM_II_deqnorm_6
ASM_II_deqnorm_5
	       clr.w	(a2)                 ; fraction[k][0][i] = 0
	       clr.w	SBLIMIT*2(a2)        ; fraction[k][1][i] = 0
	       clr.w	SBLIMIT*4(a2)        ; fraction[k][2][i] = 0
ASM_II_deqnorm_6
	       addq.l	#4,a6		     ; -> sample ptr ++
	       addq.l	#2,a2		     ; -> fraction ptr ++
	       add.l	#4*16,a4	     ; next alloc_table ptr

	       bra	ASM_II_deqnorm_2     ; next sub_band

ASM_II_deqnorm_7
	       move.w	sub_band_limit,d0
ASM_II_deqnorm_8
	       IFND	SKIP_UPPER_BAND      ; 08/05/1995
	       cmp.w	#SBLIMIT,d0
	       ELSE			     ; !!! incompatible with FILTER_?_SUM
	       cmp.w	sub_band_size,d0
	       ENDC
	       bge	ASM_II_deqnorm_9
	       clr.w	(a2)                 ; fraction[k][0][i] = 0
	       clr.w	SBLIMIT*2(a2)        ; fraction[k][1][i] = 0
	       clr.w	SBLIMIT*4(a2)        ; fraction[k][2][i] = 0
	       addq.l	#2,a2		     ; -> fraction ptr ++
	       addq.w	#1,d0
	       bra	ASM_II_deqnorm_8
ASM_II_deqnorm_9
	       movem.l	(sp)+,d2/a0-a4
	       subq.w	#1,channels
	       ble	ASM_II_deqnorm_end
	       add.l	#4*3*SBLIMIT,a0      ; next -> &sample[k][0][0]
	       add.l	#4*SBLIMIT,a1	     ; next -> &bit_alloc[k][0]
	       add.l	#2*3*SBLIMIT,a2      ; next -> &fraction[k][0][0]
	       add.l	#4*3*SBLIMIT,a3      ; next -> &scale_index[k][0][0]
	       bra	ASM_II_deqnorm_1

ASM_II_deqnorm_end
	       movem.l	(sp)+,d2-d7/a2-a6
	       rts

;	       Apply the synthesis filter to a sub band
;
;	       a0: bandPtr (=fraction)
;	       a1: out_filter_buffer
;
@ASM_filter_band
	       tst.w	quar_freq
	       bne	fast_filter_quart
	       tst.w	half_freq
	       bne	fast_filter_half
	       bra	fast_filter_full
;
;	       Filter COS values for fast cosine transform
;
COS1_64        equ	$8028
COS3_64        equ	$8167
COS5_64        equ	$83F4
COS7_64        equ	$87F2
COS9_64        equ	$8D98
COS11_64       equ	$953B
COS13_64       equ	$9F5C
COS15_64       equ	$ACC0
COS17_64       equ	$BE9A
COS19_64       equ	$D6E0
COS21_64       equ	$F8FA
COS23_64       equ	$12B60
COS25_64       equ	$17BF2
COS27_64       equ	$20ECB
COS29_64       equ	$36859
COS31_64       equ	$A30A4
COS1_32        equ	$809F
COS3_32        equ	$85C2
COS5_32        equ	$9123
COS7_32        equ	$A596
COS9_32        equ	$C9C5
COS11_32       equ	$10F89
COS13_32       equ	$1B8F2
COS15_32       equ	$519E5
COS1_16        equ	$8282
COS3_16        equ	$99F2
COS5_16        equ	$E665
COS7_16        equ	$2901B
COS1_8	       equ	$8A8C
COS3_8	       equ	$14E7B
COS1_4	       equ	$B505


FF_MUL	       MACRO
	       move.l	(a2)+,d0
	       sub.l	-(a3),d0
	       muls.l	#\1,d1:d0
	       move.w	d1,d0
	       swap	d0
	       move.l	d0,(a4)+
	       ENDM

FF_ADD	       MACRO
	       move.l	\1*4(a2),d0
	       add.l	\2*4(a2),d0
	       move.l	d0,(a4)+
	       ENDM

FF_SUB_MUL     MACRO
	       move.l	\1*4(a2),d0
	       sub.l	\2*4(a2),d0
	       muls.l	\3,d4:d0
	       move.w	d4,d0
	       swap	d0
	       move.l	d0,(a4)+
	       ENDM

FFF_MUL        MACRO
	       move.l	(a2)+,d0
	       move.l	d0,d1
	       move.l	-(a3),d2
	       add.l	d2,d1
	       move.l	d1,(a4)+
	       sub.l	d2,d0
	       muls.l	#\1,d1:d0
	       move.w	d1,d0
	       swap	d0
	       move.l	d0,\2*4-4(a4)
	       ENDM

fast_filter_sub
	       move.l	a5,a2	       ; @p(0)
	       lea	16*4(a2),a3    ; @p(16)
	       move.l	a6,a4	       ; @pp(0)

	       FFF_MUL	COS1_32,8      ; pp(i=0..7)  = p(i) + p(15-i)
	       FFF_MUL	COS3_32,8      ; pp(i=8..15) = COSx*[p(i) - p(15-i)]
	       FFF_MUL	COS5_32,8
	       FFF_MUL	COS7_32,8
	       FFF_MUL	COS9_32,8
	       FFF_MUL	COS11_32,8
	       FFF_MUL	COS13_32,8
	       FFF_MUL	COS15_32,8

	       move.l	a6,a2	       ; @pp(0)
	       lea	8*4(a2),a3     ; @pp(8)
	       move.l	a5,a4	       ; @p(0)

	       FFF_MUL	COS1_16,4      ; p(i=0..3) = pp(i) + pp(7-i)
	       FFF_MUL	COS3_16,4      ; p(i=4..7) = COSx*[pp(i) - pp(7-i)]
	       FFF_MUL	COS5_16,4
	       FFF_MUL	COS7_16,4
	       lea	8*4(a6),a2     ; @pp(8)
	       lea	8*4(a2),a3     ; @pp(16)
	       lea	4*4(a4),a4     ; skip p(4)..p(7)
	       FFF_MUL	COS1_16,4
	       FFF_MUL	COS3_16,4
	       FFF_MUL	COS5_16,4
	       FFF_MUL	COS7_16,4

	       move.l	a5,a2	       ; @p(0)
	       move.l	a6,a4	       ; @pp(0)

	       move.l	#COS1_8,d1
	       move.l	#COS3_8,d2
	       FF_ADD	0,3
	       FF_ADD	1,2
	       FF_SUB_MUL  0,3,d1
	       FF_SUB_MUL  1,2,d2
	       FF_ADD	4,7
	       FF_ADD	5,6
	       FF_SUB_MUL  4,7,d1
	       FF_SUB_MUL  5,6,d2
	       FF_ADD	8,11
	       FF_ADD	9,10
	       FF_SUB_MUL  8,11,d1
	       FF_SUB_MUL  9,10,d2
	       FF_ADD	12,15
	       FF_ADD	13,14
	       FF_SUB_MUL  12,15,d1
	       FF_SUB_MUL  13,14,d2

	       lea	filter_pp,a2	  ; @pp(0)
	       lea	filter_p,a4	  ; @p(0)
	       move.l	#COS1_4,d3
	       moveq.w	#8-1,d7
fast_filter_s5
	       move.l	(a2)+,d0
	       move.l	d0,d2
	       move.l	(a2)+,d1
	       add.l	d1,d0
	       move.l	d0,(a4)+
	       sub.l	d1,d2
	       muls.l	d3,d4:d2
	       move.w	d4,d2
	       swap	d2
	       move.l	d2,(a4)+
	       dbra	d7,fast_filter_s5

	       rts

;	       Apply the FAST synthesis filter to a sub band
;	       Generate full frequency sample
;
;	       a0: bandPtr (=fraction)
;	       a1: out_filter_buffer
;
fast_filter_full
	       movem.l	d2-d7/a2-a6,-(sp)

	       lea	filter_p,a5
	       lea	filter_pp,a6

	       move.l	a0,a2	       ; fraction(0)
	       lea	32*2(a2),a3    ; fraction(32)
	       move.l	a5,a4	       ; @p(0)

	       moveq.w	#16-1,d7
fast_filter_f1			       ; p(i=0..15) = f(i) + f(31-i)
	       move.w	(a2)+,d0
	       ext.l	d0
	       move.w	-(a3),d1
	       ext.l	d1
	       add.l	d0,d1
	       move.l	d1,(a4)+
	       dbra	d7,fast_filter_f1

	       bsr	fast_filter_sub

	       move.l	a5,a2	       ; @p(0)

	       move.l	6*4(a2),d1
	       add.l	7*4(a2),d1
	       move.l	5*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,36*2(a1)       ; [36-17] => b(36)
	       move.w	d0,60*2(a1)       ; [36-17] => b(60)
	       move.l	4*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,44*2(a1)       ; [44-17] => b(44)
	       move.w	d0,52*2(a1)       ; [44-17] => b(52)
	       move.l	11*4(a2),d1
	       add.l	15*4(a2),d1
	       move.l	d1,d0
	       move.w	d0,10*2(a1)       ; [10] => b(10)
	       neg.l	d0
	       move.w	d0,22*2(a1)       ; [10] => -b(22)
	       move.l	13*4(a2),d0
	       add.l	d1,d0
	       move.w	d0,6*2(a1)        ; [6] => b(6)
	       neg.l	d0
	       move.w	d0,26*2(a1)       ; [6] => -b(26)
	       move.l	14*4(a2),d1
	       add.l	15*4(a2),d1
	       move.l	8*4(a2),d0
	       add.l	12*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,46*2(a1)       ; [46-17] => b(46)
	       move.w	d0,50*2(a1)       ; [46-17] => b(50)
	       move.l	9*4(a2),d0
	       add.l	13*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,34*2(a1)       ; [34-17] => b(34)
	       move.w	d0,62*2(a1)       ; [34-17] => b(62)
	       add.l	10*4(a2),d1
	       add.l	11*4(a2),d1
	       move.l	13*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,38*2(a1)       ; [38-17] => b(38)
	       move.w	d0,58*2(a1)       ; [38-17] => b(58)
	       move.l	12*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,42*2(a1)       ; [42-17] => b(42)
	       move.w	d0,54*2(a1)       ; [54-17] => b(54)
	       move.l	9*4(a2),d0
	       add.l	13*4(a2),d0
	       add.l	15*4(a2),d0
	       move.w	d0,2*2(a1)        ; [2] => b(2)
	       neg.l	d0
	       move.w	d0,30*2(a1)       ; [2] => -b(30)
	       move.l	5*4(a2),d0
	       add.l	7*4(a2),d0
	       move.w	d0,4*2(a1)        ; [4] => b(4)
	       neg.l	d0
	       move.w	d0,28*2(a1)       ; [4] => -b(28)
	       move.l	0*4(a2),d0
	       neg.l	d0
	       move.w	d0,48*2(a1)       ; [48-17] => b(48)
	       move.l	1*4(a2),d0
	       move.w	d0,0*2(a1)        ; [0] => b(0)
	       neg.l	d0
	       move.w	d0,32*2(a1)       ; [0] => -b(32)
	       move.l	3*4(a2),d0
	       move.w	d0,8*2(a1)        ; [8] => b(8)
	       neg.l	d0
	       move.w	d0,24*2(a1)       ; [8] => -b(24)
	       move.l	7*4(a2),d0
	       move.w	d0,12*2(a1)       ; [12] => b(12)
	       neg.l	d0
	       move.w	d0,20*2(a1)       ; [12] => -b(20)
	       move.l	15*4(a2),d0
	       move.w	d0,14*2(a1)       ; [14] => b(14)
	       neg.l	d0
	       move.w	d0,18*2(a1)       ; [14] => -b(18)
	       move.l	2*4(a2),d0
	       add.l	3*4(a2),d0
	       neg.l	d0
	       move.w	d0,40*2(a1)       ; [40-17] => b(40)
	       move.w	d0,56*2(a1)       ; [40-17] => b(56)

	       clr.w	16*2(a1)          ; 0 => b(16)

	       move.l	a0,a2	       ; fraction(0)
	       lea	32*2(a2),a3    ; fraction(32)
	       move.l	a5,a4	       ; @p(0)

	       lea	filter_cos64,a0
	       moveq.w	#16-1,d7
fast_filter_f2			       ; p(i=0..15) = COSx*[f(i) - f(31-i)]
	       move.w	(a2)+,d0
	       ext.l	d0
	       move.w	-(a3),d1
	       ext.l	d1
	       sub.l	d1,d0
	       muls.l	(a0)+,d1:d0
	       move.w	d1,d0
	       swap	d0
	       move.l	d0,(a4)+
	       dbra	d7,fast_filter_f2

	       bsr	fast_filter_sub

	       move.l	a5,a2	       ; @p(0)

	       move.l	13*4(a2),d1
	       add.l	15*4(a2),d1
	       move.l	1*4(a2),d0
	       add.l	9*4(a2),d0
	       add.l	d1,d0
	       move.w	d0,1*2(a1)        ; [1] => b(1)
	       neg.l	d0
	       move.w	d0,31*2(a1)       ; [1] => -b(31)
	       move.l	5*4(a2),d0
	       add.l	7*4(a2),d0
	       add.l	11*4(a2),d0
	       add.l	d1,d0
	       move.w	d0,5*2(a1)        ; [5] => b(5)
	       neg.l	d0
	       move.w	d0,27*2(a1)       ; [5] => -b(27)
	       add.l	9*4(a2),d1
	       move.l	1*4(a2),d0
	       add.l	14*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,33*2(a1)       ; [33-17] => b(33)
	       move.w	d0,63*2(a1)       ; [33-17] => b(63)
	       add.l	5*4(a2),d1
	       add.l	7*4(a2),d1
	       move.l	d1,d0
	       move.w	d0,3*2(a1)        ; [3] => b(3)
	       neg.l	d0
	       move.w	d0,29*2(a1)       ; [3] => -b(29)
	       move.l	6*4(a2),d0
	       add.l	14*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,35*2(a1)       ; [35-17] => b(35)
	       move.w	d0,61*2(a1)       ; [35-17] => b(61)
	       move.l	10*4(a2),d1
	       add.l	11*4(a2),d1
	       add.l	14*4(a2),d1
	       add.l	15*4(a2),d1
	       move.l	2*4(a2),d0
	       add.l	3*4(a2),d0
	       add.l	13*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,39*2(a1)       ; [39-17] => b(39)
	       move.w	d0,57*2(a1)       ; [39-17] => b(57)
	       move.l	4*4(a2),d0
	       add.l	6*4(a2),d0
	       add.l	7*4(a2),d0
	       add.l	12*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,43*2(a1)       ; [43-17] => b(43)
	       move.w	d0,53*2(a1)       ; [43-17] => b(53)
	       move.l	5*4(a2),d0
	       add.l	6*4(a2),d0
	       add.l	7*4(a2),d0
	       add.l	13*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,37*2(a1)       ; [37-17] => b(37)
	       move.w	d0,59*2(a1)       ; [37-17] => b(59)
	       move.l	2*4(a2),d0
	       add.l	3*4(a2),d0
	       add.l	12*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,41*2(a1)       ; [41-17] => b(41)
	       move.w	d0,55*2(a1)       ; [55-17] => b(55)
	       move.l	8*4(a2),d1
	       add.l	12*4(a2),d1
	       add.l	14*4(a2),d1
	       add.l	15*4(a2),d1
	       move.l	0*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,47*2(a1)       ; [47-17] => b(47)
	       move.w	d0,49*2(a1)       ; [47-17] => b(49)
	       move.l	4*4(a2),d0
	       add.l	6*4(a2),d0
	       add.l	7*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,45*2(a1)       ; [45-17] => b(45)
	       move.w	d0,51*2(a1)       ; [45-17] => b(51)
	       move.l	11*4(a2),d1
	       add.l	15*4(a2),d1
	       move.l	7*4(a2),d0
	       add.l	d1,d0
	       move.w	d0,11*2(a1)       ; [11] => b(11)
	       neg.l	d0
	       move.w	d0,21*2(a1)       ; [11] => -b(21)
	       add.l	3*4(a2),d1
	       move.l	d1,d0
	       move.w	d0,9*2(a1)        ; [9] => b(9)
	       neg.l	d0
	       move.w	d0,23*2(a1)       ; [9] => -b(23)
	       move.l	13*4(a2),d0
	       add.l	d1,d0
	       move.w	d0,7*2(a1)        ; [7] => b(7)
	       neg.l	d0
	       move.w	d0,25*2(a1)       ; [7] => -b(25)
	       move.l	7*4(a2),d0
	       add.l	15*4(a2),d0
	       move.w	d0,13*2(a1)       ; [13] => b(13)
	       neg.l	d0
	       move.w	d0,19*2(a1)       ; [13] => -b(19)
	       move.l	15*4(a2),d0
	       move.w	d0,15*2(a1)       ; [15] => b(15)
	       neg.l	d0
	       move.w	d0,17*2(a1)       ; [15] => -b(17)

	       movem.l	(sp)+,d2-d7/a2-a6
	       rts



FFH_MUL        MACRO
	       move.w	(a2)+,d0
	       ext.l	d0
	       move.l	d0,d1
	       move.w	-(a3),d2
	       ext.l	d2
	       add.l	d2,d1
	       move.l	d1,(a4)+
	       sub.l	d2,d0
	       muls.l	#\1,d1:d0
	       move.w	d1,d0
	       swap	d0
	       move.l	d0,7*4(a4)
	       ENDM

fast_filter_half
	       movem.l	d2-d7/a2-a6,-(sp)

	       move.l	a0,a2	       ; fraction(0)
	       lea	16*2(a2),a3    ; fraction(16)

	       lea	filter_pp,a4   ; @pp(0)

	       FFH_MUL	COS1_32        ; pp(i=0..7)  = f(i) + f(15-i)
	       FFH_MUL	COS3_32        ; pp(i=8..15) = COSx*[f(i) - f(15-i)]
	       FFH_MUL	COS5_32
	       FFH_MUL	COS7_32
	       FFH_MUL	COS9_32
	       FFH_MUL	COS11_32
	       FFH_MUL	COS13_32
	       FFH_MUL	COS15_32

	       lea	filter_pp,a2  ; @pp(0)
	       lea	8*4(a2),a3    ; @pp(8)
	       lea	filter_p,a4   ; @p(0)
	       moveq.w	#4-1,d7
fast_filter_h3			      ; p(i=0..3) = pp(i) + p(7-i)
	       move.l	(a2)+,d0
	       add.l	-(a3),d0
	       move.l	d0,(a4)+
	       dbra	d7,fast_filter_h3

	       lea	filter_pp,a2  ; @pp(0)
	       lea	8*4(a2),a3    ; @pp(8)

	       FF_MUL	COS1_16 ; p(i=4..7) = COSx*[p(i) - p(7-i)]
	       FF_MUL	COS3_16
	       FF_MUL	COS5_16
	       FF_MUL	COS7_16

	       lea	filter_pp+8*4,a2  ; @pp(8)
	       lea	8*4(a2),a3        ; @pp(16)
	       moveq.w	#4-1,d7
fast_filter_h4			 ; p(i=8..11) = pp(i) + p(15-i+8)
	       move.l	(a2)+,d0
	       add.l	-(a3),d0
	       move.l	d0,(a4)+
	       dbra	d7,fast_filter_h4

	       lea	filter_pp+8*4,a2  ; @pp(8)
	       lea	8*4(a2),a3        ; @pp(16)

	       FF_MUL	COS1_16 ; p(i=12..15) = COSx*[p(i) - p(15-i+8)]
	       FF_MUL	COS3_16
	       FF_MUL	COS5_16
	       FF_MUL	COS7_16

	       lea	filter_p,a2	  ; @p(0)
	       lea	filter_pp,a4	  ; @pp(0)

	       move.l	#COS1_8,d1
	       move.l	#COS3_8,d2
	       FF_ADD	0,3
	       FF_ADD	1,2
	       FF_SUB_MUL  0,3,d1
	       FF_SUB_MUL  1,2,d2
	       FF_ADD	4,7
	       FF_ADD	5,6
	       FF_SUB_MUL  4,7,d1
	       FF_SUB_MUL  5,6,d2
	       FF_ADD	8,11
	       FF_ADD	9,10
	       FF_SUB_MUL  8,11,d1
	       FF_SUB_MUL  9,10,d2
	       FF_ADD	12,15
	       FF_ADD	13,14
	       FF_SUB_MUL  12,15,d1
	       FF_SUB_MUL  13,14,d2

	       lea	filter_pp,a2	  ; @pp(0)
	       lea	filter_p,a4	  ; @p(0)
	       move.l	#COS1_4,d3
	       moveq.w	#8-1,d7
fast_filter_h5
	       move.l	(a2)+,d0
	       move.l	d0,d2
	       move.l	(a2)+,d1
	       add.l	d1,d0
	       move.l	d0,(a4)+
	       sub.l	d1,d2
	       muls.l	d3,d4:d2
	       move.w	d4,d2
	       swap	d2
	       move.l	d2,(a4)+
	       dbra	d7,fast_filter_h5

	       lea	filter_p,a2	  ; @p(0)

	       move.l	6*4(a2),d1
	       add.l	7*4(a2),d1
	       move.l	5*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,36*2(a1)       ; [36-17] => b(36)
	       move.w	d0,60*2(a1)       ; [36-17] => b(60)
	       move.l	4*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,44*2(a1)       ; [44-17] => b(44)
	       move.w	d0,52*2(a1)       ; [44-17] => b(52)
	       move.l	11*4(a2),d1
	       add.l	15*4(a2),d1
	       move.l	d1,d0
	       move.w	d0,10*2(a1)       ; [10] => b(10)
	       neg.l	d0
	       move.w	d0,22*2(a1)       ; [10] => -b(22)
	       move.l	13*4(a2),d0
	       add.l	d1,d0
	       move.w	d0,6*2(a1)        ; [6] => b(6)
	       neg.l	d0
	       move.w	d0,26*2(a1)       ; [6] => -b(26)
	       move.l	14*4(a2),d1
	       add.l	15*4(a2),d1
	       move.l	8*4(a2),d0
	       add.l	12*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,46*2(a1)       ; [46-17] => b(46)
	       move.w	d0,50*2(a1)       ; [46-17] => b(50)
	       move.l	9*4(a2),d0
	       add.l	13*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,34*2(a1)       ; [34-17] => b(34)
	       move.w	d0,62*2(a1)       ; [34-17] => b(62)
	       add.l	10*4(a2),d1
	       add.l	11*4(a2),d1
	       move.l	13*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,38*2(a1)       ; [38-17] => b(38)
	       move.w	d0,58*2(a1)       ; [38-17] => b(58)
	       move.l	12*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,42*2(a1)       ; [42-17] => b(42)
	       move.w	d0,54*2(a1)       ; [54-17] => b(54)
	       move.l	9*4(a2),d0
	       add.l	13*4(a2),d0
	       add.l	15*4(a2),d0
	       move.w	d0,2*2(a1)        ; [2] => b(2)
	       neg.l	d0
	       move.w	d0,30*2(a1)       ; [2] => -b(30)
	       move.l	5*4(a2),d0
	       add.l	7*4(a2),d0
	       move.w	d0,4*2(a1)        ; [4] => b(4)
	       neg.l	d0
	       move.w	d0,28*2(a1)       ; [4] => -b(28)
	       move.l	0*4(a2),d0
	       neg.l	d0
	       move.w	d0,48*2(a1)       ; [48-17] => b(48)
	       move.l	1*4(a2),d0
	       move.w	d0,0*2(a1)        ; [0] => b(0)
	       neg.l	d0
	       move.w	d0,32*2(a1)       ; [0] => -b(32)
	       move.l	3*4(a2),d0
	       move.w	d0,8*2(a1)        ; [8] => b(8)
	       neg.l	d0
	       move.w	d0,24*2(a1)       ; [8] => -b(24)
	       move.l	7*4(a2),d0
	       move.w	d0,12*2(a1)       ; [12] => b(12)
	       neg.l	d0
	       move.w	d0,20*2(a1)       ; [12] => -b(20)
	       move.l	15*4(a2),d0
	       move.w	d0,14*2(a1)       ; [14] => b(14)
	       neg.l	d0
	       move.w	d0,18*2(a1)       ; [14] => -b(18)
	       move.l	2*4(a2),d0
	       add.l	3*4(a2),d0
	       neg.l	d0
	       move.w	d0,40*2(a1)       ; [40-17] => b(40)
	       move.w	d0,56*2(a1)       ; [40-17] => b(56)

	       clr.w	16*2(a1)          ; 0 => b(16)

	       movem.l	(sp)+,d2-d7/a2-a6
	       rts


FFQ_MUL        MACRO
	       move.w	(a2)+,d0
	       ext.l	d0
	       move.l	d0,d1
	       move.w	-(a3),d2
	       ext.l	d2
	       add.l	d2,d1
	       move.l	d1,(a4)+
	       sub.l	d2,d0
	       muls.l	#\1,d1:d0
	       move.w	d1,d0
	       swap	d0
	       move.l	d0,3*4(a4)
	       ENDM

FFQ_MUL2       MACRO
	       movem.l	(a2)+,d0-d3
	       move.l	d0,d4
	       add.l	d3,d4
	       move.l	d4,(a4)+
	       move.l	d0,d4
	       sub.l	d3,d4
	       muls.l	\1,d5:d4
	       move.w	d5,d4
	       swap	d4
	       move.l	d4,4(a4)
	       move.l	d1,d4
	       add.l	d2,d4
	       move.l	d4,(a4)+
	       move.l	d1,d4
	       sub.l	d2,d4
	       muls.l	\2,d5:d4
	       move.w	d5,d4
	       swap	d4
	       move.l	d4,4(a4)
	       ENDM


;	       Apply the FAST synthesis filter to a sub band
;	       Generate 1/4 frequency sample
;
;	       a0: bandPtr (=fraction)
;	       a1: out_filter_buffer
;
fast_filter_quart
	       movem.l	d2-d7/a2-a6,-(sp)

	       lea	filter_p,a5
	       lea	filter_pp,a6

	       move.l	a0,a2	       ; fraction(0)
	       lea	8*2(a2),a3     ; fraction(8)
	       move.l	a5,a4	       ; @p(0)

				       ; p(i=0..3) = x(i) + x(7-i)
	       FFQ_MUL	COS1_16        ; p(i=4..7) = COSx*[x(i) - x(7-i)]
	       FFQ_MUL	COS3_16
	       FFQ_MUL	COS5_16
	       FFQ_MUL	COS7_16

	       move.l	a5,a2	       ; @p(0)
	       move.l	a6,a4	       ; @pp(0)

	       IFD	FF_ADD
	       move.l	#COS1_8,d1
	       move.l	#COS3_8,d2
	       FF_ADD	0,3
	       FF_ADD	1,2
	       FF_SUB_MUL  0,3,d1
	       FF_SUB_MUL  1,2,d2
	       FF_ADD	4,7
	       FF_ADD	5,6
	       FF_SUB_MUL  4,7,d1
	       FF_SUB_MUL  5,6,d2
	       ELSE
	       move.l	#COS1_8,d6
	       move.l	#COS3_8,d7
	       FFQ_MUL2 d6,d7
	       addq.l	#4*2,a4
	       FFQ_MUL2 d6,d7
	       ENDC

	       move.l	a6,a2	      ; @pp(0)
	       move.l	a5,a4	      ; @p(0)
	       move.l	#COS1_4,d3
	       moveq.w	#4-1,d7
fast_filter_q5
	       move.l	(a2)+,d0
	       move.l	d0,d2
	       move.l	(a2)+,d1
	       add.l	d1,d0
	       move.l	d0,(a4)+
	       sub.l	d1,d2
	       muls.l	d3,d4:d2
	       move.w	d4,d2
	       swap	d2
	       move.l	d2,(a4)+
	       dbra	d7,fast_filter_q5

	       move.l	a5,a2	      ; @p(0)

	       move.l	6*4(a2),d1
	       add.l	7*4(a2),d1
	       move.l	5*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,36*2(a1)       ; [36-17] => b(36)
	       move.w	d0,60*2(a1)       ; [36-17] => b(60)
	       move.l	4*4(a2),d0
	       add.l	d1,d0
	       neg.l	d0
	       move.w	d0,44*2(a1)       ; [44-17] => b(44)
	       move.w	d0,52*2(a1)       ; [44-17] => b(52)
	       move.l	5*4(a2),d0
	       add.l	7*4(a2),d0
	       move.w	d0,4*2(a1)        ; [4] => b(4)
	       neg.l	d0
	       move.w	d0,28*2(a1)       ; [4] => -b(28)
	       move.l	0*4(a2),d0
	       neg.l	d0
	       move.w	d0,48*2(a1)       ; [48-17] => b(48)
	       move.l	1*4(a2),d0
	       move.w	d0,0*2(a1)        ; [0] => b(0)
	       neg.l	d0
	       move.w	d0,32*2(a1)       ; [0] => -b(32)
	       move.l	3*4(a2),d0
	       move.w	d0,8*2(a1)        ; [8] => b(8)
	       neg.l	d0
	       move.w	d0,24*2(a1)       ; [8] => -b(24)
	       move.l	7*4(a2),d0
	       move.w	d0,12*2(a1)       ; [12] => b(12)
	       neg.l	d0
	       move.w	d0,20*2(a1)       ; [12] => -b(20)
	       move.l	2*4(a2),d0
	       add.l	3*4(a2),d0
	       neg.l	d0
	       move.w	d0,40*2(a1)       ; [40-17] => b(40)
	       move.w	d0,56*2(a1)       ; [40-17] => b(56)

	       clr.w	16*2(a1)          ; 0 => b(16)

	       movem.l	(sp)+,d2-d7/a2-a6
	       rts


	       section	ASMDATA,data
	       CNOP	0,4

filter_cos64   dc.l	COS1_64, COS3_64, COS5_64, COS7_64
	       dc.l	COS9_64, COS11_64, COS13_64, COS15_64
	       dc.l	COS17_64, COS19_64, COS21_64, COS23_64
	       dc.l	COS25_64, COS27_64, COS29_64, COS31_64

	       section	ASMVARS,bss
	       CNOP	0,4

filter_p       ds.l	16
filter_pp      ds.l	16

	       section	ASMCODE,code


;WINDOW_CLIP	equ	 1
;WINDOW_HARD	equ	 1

;
;	       Window a sub band filtered sample
;
;	       a0: out_filter_buffer
;	       a1: out_sample_buffer
;	       d0: buffer offset
;	       -> a1 = out_sample_buffer + out_sample_length
@ASM_window_band

	       movem.l	d2-d7/a2-a6,-(sp)

	       move.l	a1,a2
	       moveq.l	#4,d7		     ; Band skip for quarter
	       tst.w	quar_freq
	       beq.s	ASM_window_band0
	       moveq.l	#2,d7		     ; Band skip for half
	       tst.w	half_freq
	       beq.s	ASM_window_band0
	       moveq.l	#1,d7		     ; Band skip for normal
ASM_window_band0
	       moveq.l	#WINDOW_FACTOR+INT_FACTOR-15,d7
	       add.w	output_8bits,d7      ; add right shift value
	       move.w	#$3FF,d2
	       lea.l	window_table,a1
	       lea.l	32*2*2,a4
	       lea.l	32,a5
	       lea.l	96,a6
	       move.w	window_start,d6
	       ext.l	d6
	       add.w	d6,d0		     ; add window offset to d0 (buffer offset)
	       add.l	d6,a1		     ; add window offset to window ptr

	       moveq.l	#0,d6		     ; d6 = j
	       tst.w	output_8bits
	       bne	window_band_5	     ; 8 bit output selected
window_band_1
	       clr.l	d1		     ; d1 = sum
	       lea.l	(a1,d6.w*2),a3       ; a3 = window[ k(=j) ]
	       move.w	d6,d3
	       add.w	d0,d3		     ; d3 = l = j + buf_offset
	       move.w	window_coeff,d5      ; d5 = (#-1)/2 coeffs
window_band_2
	       and.w	d2,d3		     ; l &= 0x3FF
	       move.w	(a0,d3.w*2),d4       ; bufPtr[ l ] -> d4
	       muls.w	(a3),d4              ; window[ k ] * bufPtr[ l ] -> d4
	       add.l	d4,d1		     ; sum += d4
	       add.w	a6,d3		     ; l += 96
	       and.w	d2,d3		     ; l &= 0x3FF
	       move.w	(a0,d3.w*2),d4       ; bufPtr[ l ] -> d4
	       muls.w	64(a3),d4            ; window[ k ] * bufPtr[ l ] -> d4
	       add.l	a4,a3		     ; a3 += 64
	       add.l	d4,d1		     ; sum += d4
	       add.w	a5,d3		     ; l += 32
	       dbra	d5,window_band_2
	       asr.l	d7,d1		     ; sum >>= (WINDOW_FACTOR+INT_FACTOR-15)

	       cmp.l	#-32768,d1
	       blt	window_band_4l
	       cmp.l	#32767,d1
	       bgt	window_band_4h
window_band_4n
	       move.w	d1,(a2)+
	       add.w	window_skip,d6		   ; next band
	       cmp.w	a5,d6			   ; equiv cmp.w #32,d6
	       blt	window_band_1
	       bra	window_band_9
window_band_4l move.l	#-32768,d1
	       bra.s	window_band_4n
window_band_4h move.l	#32767,d1
	       bra.s	window_band_4n

window_band_5
	       clr.l	d1		     ; d1 = sum
	       lea.l	(a1,d6.w*2),a3       ; a3 = window[ k(=j) ]
	       move.w	d6,d3
	       add.w	d0,d3		     ; d3 = l = j + buf_offset
	       move.w	window_coeff,d5      ; d5 = (#-1)/2 coeffs
window_band_6
	       and.w	d2,d3		     ; l &= 0x3FF
	       move.w	(a0,d3.w*2),d4       ; bufPtr[ l ] -> d4
	       muls.w	(a3),d4              ; window[ k ] * bufPtr[ l ] -> d4
	       add.l	d4,d1		     ; sum += d4
	       add.w	a6,d3		     ; l += 96
	       and.w	d2,d3		     ; l &= 0x3FF
	       move.w	(a0,d3.w*2),d4       ; bufPtr[ l ] -> d4
	       muls.w	64(a3),d4            ; window[ k ] * bufPtr[ l ] -> d4
	       add.l	a4,a3		     ; a3 += 64
	       add.l	d4,d1		     ; sum += d4
	       add.w	a5,d3		     ; l += 32
	       dbra	d5,window_band_6
	       asr.l	d7,d1		     ; sum >>= (WINDOW_FACTOR+INT_FACTOR-15)

	       cmp.w	#-128,d1
	       bge.s	window_band_71
	       moveq.b	#-128,d1
	       bra.s	window_band_72
window_band_71
	       cmp.w	#127,d1
	       ble.s	window_band_72
	       moveq.b	#127,d1
window_band_72
	       move.b	d1,(a2)+
	       add.w	window_skip,d6		   ; next band
	       cmp.w	a5,d6			   ; equiv cmp.w #32,d6
	       blt	window_band_5
window_band_9
	       move.l	a2,a1
	       movem.l	(sp)+,d2-d7/a2-a6
	       rts


;	       Sub band synthesis
;
;	       a0:   frame_params *fr_ps
;	       d0:   int band_count
;
@ASM_sub_band_synthesis
	       movem.l	d2-d6/a2-a6,-(sp)

	       move.l	a0,a2		  ; a2 = frame_params
	       move.l	d0,d4
	       subq.l	#1,d4		  ; d4 = band_count-1
	       move.l	fp_stereo(a2),d5
	       subq.l	#1,d5		  ; d5 = #channels-1
	       clr.l	d6		  ; d6 = channel
	       lea	fp_out_buffer(a2),a6 ; a6 = &sample[ 0 ]
sub_band_synthesis_0
	       move.l	(a6),a5           ; a5 = sample[channel]
	       move.l	fp_fraction(a2),a3
	       move.l	d6,d1
	       mulu.w	#2*3*SBLIMIT,d1
	       add.l	d1,a3		  ; a3 = fraction[channel]
	       lea.l	filter_buffer,a4
	       move.w	d6,d2
	       mulu.w	#2*2*HAN_SIZE,d2
	       add.l	d2,a4		  ; -> a4 = &filter_buffer[channel][0]
	       move.w	d4,d3
sub_band_synthesis_1
	       lea.l	band_offset,a1
	       move.w	(a1,d6.w*2),d2
	       sub.w	#64,d2
	       and.w	#$3FF,d2	  ; d2 = (band_offset[k] - 64) & 0x3ff;
	       move.w	d2,(a1,d6.w*2)
	       lea.l	(a4,d2.w*2),a1    ; a1 = &filter_buffer[k][d2]
	       move.l	a3,a0		  ; a0 = &bandPtr[k][j][0]
	       bsr	@ASM_filter_band

	       move.l	a5,a1		  ; a1 = &samples[k][j][0]
	       move.l	a4,a0		  ; a0 = &filter_buffer[k][0]
	       move.l	d2,d0		  ; d0 = band_offset[k]
	       bsr	@ASM_window_band

	       add.l	#2*SBLIMIT,a3	  ; -> a3 = &bandPtr[k][j+1][0]
	       move.l	a1,a5		  ; a5 = next sample ptr

	       dbra	d3,sub_band_synthesis_1 ; j++

	       move.l	a5,(a6)           ; a5 = sample[channel]
	       addq.l	#1,d6
	       addq.l	#4,a6

	       dbra	d5,sub_band_synthesis_0 ; next channel

	       movem.l	(sp)+,d2-d6/a2-a6
	       rts


;
;	       Decode an audio MPEG I Layer I frame
;
;	       a0:   frame_params *fr_ps
;
@ASM_I_decode_frame
	       movem.l	d2/a2,-(sp)
	       move.l	a0,a2
	       clr.l	d2
ASM_I_decode_frame_1
	       move.l	a2,a0
	       bsr	@ASM_I_buffer_sample
	       move.l	a2,a0
	       bsr	@ASM_I_deqnorm
	       move.l	a2,a0
	       moveq.l	#1,d0
	       bsr	@ASM_sub_band_synthesis
	       addq.l	#1,d2
	       cmp.w	#SCALE_BLOCK,d2
	       blt	ASM_I_decode_frame_1

	       movem.l	(sp)+,d2/a2
	       rts

;
;	       Decode an audio MPEG I Layer II frame
;
;	       a0:   frame_params *fr_ps
;
@ASM_II_decode_frame
	       movem.l	d2/a2,-(sp)
	       move.l	a0,a2
	       clr.l	d2
ASM_II_decode_frame_1
	       move.l	a2,a0
	       bsr	@ASM_II_buffer_sample
	       move.l	a2,a0
	       move.l	d2,d0
	       lsr.l	#2,d0
	       bsr	@ASM_II_deqnorm
	       move.l	a2,a0
	       moveq.l	#3,d0
	       bsr	@ASM_sub_band_synthesis
	       addq.l	#1,d2
	       cmp.w	#SCALE_BLOCK,d2
	       blt	ASM_II_decode_frame_1

	       movem.l	(sp)+,d2/a2
	       rts

	       section	ASMDATA,data
	       even

band_offset    dc.w	64,64

	       section	ASMVARS,bss
	       even

bsamp_sblimit  ds.w	1
bsamp_jsbound  ds.w	1
bsamp_channels ds.w	1

channels       ds.w	1
sub_band_limit ds.w	1
sub_band_index ds.w	1

sub_band_size  ds.w	1
output_8bits   ds.w	1		  ; 0 if 16 bits output
					  ; > 0 if 8 bits output = right shift
half_freq      ds.w	1		  ; = 0 if full freq output
quar_freq      ds.w	1		  ; != 0 if quarter freq output

window_start   ds.w	1		  ; start offset for windowing
window_coeff   ds.w	1		  ; #coeff used for windowing
window_skip    ds.w	1		  ; #values skipped (1=full,2=half,4=quart)

quality        ds.w	1

	       even

band_buffer    ds.w	32

h_band_input   ds.w	16
h_band_buffer  ds.w	16
h_band_buffer2 ds.w	4+8+4+8

q_band_input   ds.w	8
q_band_buffer  ds.w	8
q_band_buffer2 ds.w	2+4+2+4


filter_buffer  ds.w	2*2*HAN_SIZE


