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