File: SAMPLE.M65 - Tab length: 1 2 4 8 - Lines: on off - No wrap: on off

* sample.m65
* started : 97-09-24 (only 3mths till Xmas !!)
*
* Warning : Just experimental. This code _WILL_ change !
*           Also parameters etc.

* functions: void SmpInit(char channel,char timer);
*            void SmpStart(char * sample,char speed);
*            void SmpStop();
*            int  SmpActive();

                global _SmpInit
                global _SmpStart
                global _SmpStop
                global _SmpActive

* extern labels
                xref popax,pushax
                xref _InstallIRQ

 bss

SmpCount        ds 2
SmpSema         ds 1
SmpTemp         ds 1
SmpChannel      ds 1
SmpChannel8     ds 1
SmpTimer        ds 1
                bsszp
smp_ptr         ds 2

                text
mask            dc.b $11,$22,$44,$88

; void SmpInit(char channel,char timer)
; channel is the channel-number : 0..3
; timer is the timer-number     : 0..7 (where 0,2,4 makes no sense !)

_SmpInit::
                jsr popax       ; get timer
                and #7
                asl A
                asl A
                pha
                sta SmpTimer
               
                jsr popax       ; get channel
                and #3
                sta SmpChannel
                plx
                stz $fd01,x     ; stop Timer
               
                tay
                asl A
                asl A
                asl A
                sta SmpChannel8
                pha
               
                lda mask,y
                tsb $fd44       ; voice A balance controled
                tsb $fd50       ; but curr. quite
               
                lda #$ff
                sta $fd40,y     ; and full volume left and right
               
                plx
                stz $fd25,x     ; stop channel counter
                stz $fd22,x     ; channel  quiet please
                rts

****************
* play mono sample
****************
SmpIRQ::        lda (smp_ptr)
                ldx SmpChannel8
                sta $fd22,x
                inc smp_ptr
                bne SmpIRQ2
                  inc smp_ptr+1
SmpIRQ2:        inc SmpCount
                bne SmpExit
                inc SmpCount+1
                bne SmpExit
_SmpStop::
                ldy SmpChannel
                lda mask,y
                tsb $fd50
                ldx SmpTimer
                stz $fd01,x
SmpExit:
                rts
****************
* play packed mono-samples
*****************
SmpIRQp::
                dec SmpSema
                bmi no_read

                lda (smp_ptr)
                inc smp_ptr
                bne SmpIRQp0
                  inc smp_ptr+1

SmpIRQp0        inc SmpCount
                bne SmpIRQp1
                inc SmpCount+1
                beq _SmpStop

SmpIRQp1        sta SmpIRQp2+1  ; self mod
                               
                lsr A
                lsr A
                lsr A
                lsr A
*
* if there's enough space, could do it with a table
*
                bra SmpIRQp3

no_read:        lda #1
                sta SmpSema

SmpIRQp2:       lda #0
                and #$f

SmpIRQp3:       tax
                clc
                lda tabelle,x
                adc SmpTemp
                sta SmpTemp
                ldx SmpChannel8
                bcc __1
                dec $fda0
*
* Note : with stx $fd22+8 it sounds better but you'll use another channel
*
__1
                asl
                bcc __2
                lda #255
__2
                sta $fd22,x
                rts

tabelle:         DC.B 128,-64,-32,-16,-8,-4,-2,-1,0,1,2,4,8,16,32,64

       
; SmpStart(char * sample,char speed)
;
; sample is a pointer to a structure :
; stereo        ds 1
; length        ds 2 ; big-endian (har,har)
; divider       ds 1 ; 1MHz/sample-freq.
; unpacked      ds 1 : == 0 sample packed
;
; divider may be overridden by speed (!= 0)
;
_SmpStart::
                ldx SmpTimer
                stz $fd01,x     ; stop current sample
                ldx SmpChannel8
                stz $fd22,x      ; silence

                stz SmpTemp
                lda #1
                sta SmpSema
                jsr popax
                pha             ; save speed for later use
                jsr popax       ; get data
                sta ptr1
                stx ptr1+1
                clc
                adc #5
                sta smp_ptr
                txa
                adc #0
                sta smp_ptr+1
               
; no stereo yet, so go to offset 1          
               
                ldy #1  
                lda (ptr1),y
                eor #$ff
                sta SmpCount+1
                iny
                lda (ptr1),y
                eor #$ff
                sta SmpCount
                iny
                lda (ptr1),y
                ldx SmpTimer
                sta $fd00,x
                iny
                lda (ptr1),y
                pha             ; save packed-flag

                txa
                ldx #0
                lsr A
                lsr A           ; we want the number not offset
                jsr pushax      ; pushax destroys y and maybe ptr1 !!

                ldax #SmpIRQ
                ply             ; check packed-flag
                bne _SmpStart0
                  ldax #SmpIRQp
_SmpStart0:
                jsr pushax
;>                ldy #2
                jsr _InstallIRQ
               
                ldx SmpTimer
                pla
                beq _SmpStart2
                  sta $fd00,x
_SmpStart2:     php
                sei
                lda #%10011000
                sta $fd01,x
                ldy SmpChannel
                lda mask,y
                trb $fd50
                plp
                rts
****************
* int SmpActive()
****************
_SmpActive::    ldx SmpTimer
                lda $fd01,x
                ldx #0
                cmp #0
                rts