[comp.sys.atari.st.tech] How do you play Sound Samples? The answer :)

friedric@unipas.fmi.uni-passau.de (Carsten Friedrich) (05/08/91)

; Hi,
; as i got many, many requests about the source-code to play digitized
; music, i decided to post it instead of mailing to everyone.
; don't be confused by the letter like style, cos i just post the
; letter i've written to the first ones.

; I DIDN'T WRITE THE SOURCE, BUT TOOK IT FROM A ST-MAGAZINE ARTICLE AND 
; CHANGED IT TO FIT MY NEEDS !!! (just wanted to make this clear)

; here's the promised source-code. It is NO executable program, but to 
; be compiled as an object file and linked to a C-program.
; How to use it from a C-program:

; if you want to play a sample:

; set smp_anf_ to the begining of the sound-data.
; set smp_len_ to the length of the sound-data.
; set smp_frq_ to the playing frequenzy (0 to 30.000 in Hz)
; set smp_out_ to the scan-code of the character you want to abort playing
;    			 before the end has been reached
; set smp_way_ to 1 if you want to play forward, any other value, if want
;				 to play the sample reverse (really funny flag)
; set smp_mod_ to 2 for playing samples
; start with start1();

; you don't have to set 'em all, just look at the default values at the end
; of the listing.

; if you want to listen to a digitizer:

; set smp_mod_ to 0 for listening
; set smp_frq_ see above
; set smp_out_ escape character (SCAN-CODE!!!). IMPORTANT: no exit from this
;	 mode with an wrong scan-code !!!! only way then is reset-button
; then start1();

; if you want to record samples

; set smp_mod_ to 1
; set smp_frq_ to the frequenzy you want to sample with (0 to 20.000 in Hz)
; set smp_anf_ begining of sample-buffer
; set smp_end_ end of sample-buffer
; set smp_out_ see above. program terminates as well if reaching smp_end_
; then start1();
; in return smp_len_ is set by the program to the really sampled length

; If using a digitizer, it should be at the printer-port!

; I hope all this above is true, as wrote it more then 1 year ago, but
; you should be able to correct it by looking at the code.
; I'm not shure about copyrights, as I took a computer-magazine-article
; about a self-made sampler, and adapted their source to fit my needs.
; If they don't have the copyrights, then the rights are by me. You may
; copy it, adapt it, delete it, throw it a you're brothers head, or do what
; ever you want with it, but don't blame me for the results.
; It would be nice, if using it in a program, to insert the names Martin
; Backschat (the original author) or/and Carsten Friedrich (me :) .

; this program is written for the Devpack assembler, so you might have
; to change some lines for other assemblers. (e.g. dc.l to .dc.l)
; the program can play 8-bit samples (should be standart), but only uses
; 6-Bit, because i only have a 6-Bit sound-data-table :(. If you get hold
; of an 8-Bit table, i made a mark in the source, what you would have to
; change. (and please mail it to me .... :) )
; although working with interupts, this program always (no matter what 
; smp_frq_ ) uses 100 % CPU-time. This was made to improve speed and with
; that to improve sound-quality. I made a mark in the source, with some
; hints how to change that. but smp_frq_ should not exceed 20.000 Hz when
; doing this and if you want the computer to have the time, really to work
; while playing 10.000 Hz is a kind of limit. (Remember real sound-frequenzy
; is 0.5 * sample-frequenzy !, this means setting smp_frq to 10.000 Hz means
; a real sound of 5.000 Hz )
; The program uses Timer D for interupt. If you want to uses RS232, you
; should change this to Timer A. I used Timer D, as I needed Timer A for
; more important things.

; I hope that helps you. Lables might be a bit confusing for you, as i named
; them in german.

; if using Devpack, you should be able to assemble it just as it is. 
; sorry, just noticed, that it is executable, just remove the line XDEF.
; you should just add Pterm0 (gemdos(0)) if you don't like it to terminate
; with two bombs at the end, then assemble it as an executable program (*.tos)
; and you can listen to a sampler, if one is connected to the printer-port.
; to stop press space :)

; if you still have questions, or it just doesn't work, mail me and I'll try
; to help you. If you send me some money for stamps, I can send you the
; source listing of Martin Bachschat (it's a complete assemler program to deal 
; with samplers at the printer port ca. 900 lines). If you send me a disc, I
; can copy the source-code and executable-code of a C-program I wrote for
; sampling and playing samples with the MarkWilliams C-compiler. It uses
; this assembler program for handling the sampler and sound out-put. I don't
; e-mail it, as it includes a .rsc file. But PLEASE don't forget to add some
; money for stamps and a disc, if you want my program.

;			greetings,
;				Carsten !

; adress: 
; Carsten Friedrich
; Machthildstr. 42
; 8400 Regensburg
; W-Germany

; The source:


XDEF start1_,smp_anf_,smp_end_,smp_frq_,smp_mod_,smp_out_,smp_len_,smp_way_
 opt d+
start1_:
 ;
 movem.l d0-d7/a0-a7,jaja    save registers
 clr.l -(sp)
 move.w #$20,-(sp)
 trap #1
 addq.l #6,sp
 move.l d0,oldsp            enter supervisor-mode
 ;
 pea siditab
 move.w #$20,-(sp)
 trap #$e
 addq.l #6,sp
 ;
 move.l #1000000,d0
test1:
 nop
 nop
 nop
 dbf d0,test1                initialise sound-chip and wait some time
 ;                           waiting is important !
 moveq.l #0,d0
 move.w smp_mod_,d0
 cmp.w #2,d0
 beq.s weit
 ;
 moveq.l #0,d0
 moveq.l #0,d2
 move.b smp_out_,d0
 move.w smp_frq_,d1
 move.w smp_mod_,d2
 move.l smp_anf_,a1
 move.l smp_end_,a2
 bsr input                for background-interupt do sndinit now, use 
 bra weiter               inputloop for interupt at $110, remove inpsync, 
weit:                     ; change inputloop and inpend to rte at the end
 moveq.l #0,d0            and not to loop. AND: SAVE REGISTERS whenstaring
 moveq.l #0,d2            inputloop, and restore before rte, and change sndinit
 move.b smp_out_,d0      to allow interupts, always refresh your own registers,
 move.w smp_frq_,d1    and no other sound during this time, and don't use discs
 move.w smp_way_,d2       (may cause loss of data), and don't try to print
 move.l smp_anf_,a1       (might kill the sound-chip, no kidding !!!!)
 move.l smp_len_,a2       if just playing samples, printing should be save
 add.l a1,a2              NO WARRANTY !!!!
 bsr play
weiter:                     ;  decide wich mode, set registers and enter
 
 move.l oldsp,-(sp)
 move.w #$20,-(sp)
 trap #1
 addq.l #6,sp                exit supervisor-mode
 movem.l jaja,d0-d7/a0-a7    restore registers
 rts                         back !!!
 
input:
 bsr sndinit                 do some initialising work
 ;
 move.b #$e,(a5)
 move.b (a5),d7
 or.b #$20,d7
 move.b d7,2(a5)
 move.b #7,(a5)
 move.b (a5),d7
 and.b #$7f,d7
 move.b d7,2(a5)         awake sampler and tell him we're ready
 ;			 should work with all samplers for the st
inploop:
 moveq.l #0,d6
 move.b #$f,(a5)
 move.b (a5),d6          get sound-data to d6
 ;
 move.b #$e,(a5)
 and.b #$df,2(a5)
 or.b #$20,2(a5)         tell sampler: sample next please
 ;
 tst.w d2
 beq.s norec
 move.b d6,(a1)+
 cmp.l a1,a2
 beq.s inpend            if recording, store data
 ;
norec:
 and.b #%11111100,d6     mask off last 2 bits (we're only using 6-Bit)
 move.w d6,d7            
 add.w d6,d7
 add.w d6,d7             get adress of data in sound-table. for 8-Bit
 movem.l 0(a3,d7),d5-d7  don't mask and change the get-adress-algorithm
 movem.l d5-d7,(a5)      put data to sound-chip
 ;
 cmp.b 2(a4),d0          escape-character pressed ?
 beq.s inpend            yes, then end
inpsync:
 btst #4,$d(a6)
 beq.s inpsync           waiting for the interupt   
 bclr #4,$d(a6)          restart interupt 
 bra inploop             next round
 ;
inpend: 
 tst.w d2                did we record?
 beq.s inpend2
 sub.l smp_anf_,a1
 move.l a1,smp_len_      yes, then evaluate smp_len_ and store it
 ;
inpend2:
 bra sndinit2            restore things and return
 
sndinit:
 move.w #$2700,sr        disable all interupts
 lea voldat,a3        
 move.w #$fc00,a4
 move.w #$8800,a5
 move.w #$fa00,a6       load some registers
 ;
 move.l #2456700,d7
 divu d1,d7
 lsr.w #2,d7
 move.b d7,$25(a6)
 move.b $1d(a6),d7
 and.b #$f0,d7
 or.b #$01,d7
 move.b d7,$1d(a6)
 bset #4,9(a6)        evaluate frequenzy to timer data and start interupt
 rts
 
sndinit2:
 move.b $1d(a6),d7
 and.b #$f0,d7
 move.b d7,$1d(a6)
 bclr #4,9(a6)       stop interupt
 move.w #$2300,sr    allow interupts
 rts                 return
 
play:
 bsr sndinit         init-work
 moveq.l #0,d4
playloop:
 cmp.w #1,d2
 beq play_v          forward or backward?
 
 move.b -(a2),d4
 cmp.l a1,a2
 beq playend          look if reached the end
 bra play_n
 
play_v:
 move.b (a1)+,d4
 cmp.l a1,a2
 beq playend          look if reached the end
play_n:              ; load next sound to play to d4

 and.b #%11111100,d4
 move.w d4,d7
 add.w d4,d7
 add.w d4,d7
 movem.l 0(a3,d7),d5-d7
 movem.l d5-d7,(a5)         
 ;
 cmp.b 2(a4),d0
 beq.s playend
playsync2:
 btst #4,$d(a6)
 beq.s playsync2
 bclr #4,$d(a6)
 bra playloop 
 
playend: 
 bra sndinit2                 see input loop, it's nearly the same
 
 
 SECTION DATA  
voldat:
 dc.l $08000000,$09000000,$0a000000
 dc.l $08000000,$09000000,$0a000200
 dc.l $08000000,$09000000,$0a000300
 dc.l $08000200,$09000200,$0a000200
 dc.l $08000500,$09000000,$0a000000
 dc.l $08000500,$09000200,$0a000000
 dc.l $08000600,$09000100,$0a000000
 dc.l $08000600,$09000200,$0a000100
 dc.l $08000700,$09000100,$0a000000
 dc.l $08000700,$09000200,$0a000000
 dc.l $08000700,$09000300,$0a000100
 dc.l $08000800,$09000000,$0a000000
 dc.l $08000800,$09000200,$0a000000
 dc.l $08000800,$09000300,$0a000100
 dc.l $08000800,$09000400,$0a000100
 dc.l $08000900,$09000000,$0a000000
 dc.l $08000900,$09000200,$0a000000
 dc.l $08000900,$09000300,$0a000100
 dc.l $08000900,$09000400,$0a000100
 dc.l $08000900,$09000500,$0a000000
 dc.l $08000900,$09000500,$0a000200
 dc.l $08000900,$09000600,$0a000000
 dc.l $08000900,$09000600,$0a000200
 dc.l $08000a00,$09000200,$0a000000
 dc.l $08000a00,$09000200,$0a000200
 dc.l $08000a00,$09000400,$0a000100
 dc.l $08000a00,$09000500,$0a000000
 dc.l $08000a00,$09000500,$0a000200
 dc.l $08000a00,$09000600,$0a000100
 dc.l $08000a00,$09000600,$0a000300
 dc.l $08000b00,$09000100,$0a000000
 dc.l $08000b00,$09000200,$0a000100
 dc.l $08000b00,$09000300,$0a000100
 dc.l $08000b00,$09000400,$0a000100
 dc.l $08000b00,$09000500,$0a000100
 dc.l $08000b00,$09000600,$0a000000
 dc.l $08000b00,$09000600,$0a000200
 dc.l $08000b00,$09000700,$0a000000
 dc.l $08000b00,$09000700,$0a000100
 dc.l $08000b00,$09000700,$0a000300
 dc.l $08000b00,$09000700,$0a000400
 dc.l $08000b00,$09000800,$0a000100
 dc.l $08000b00,$09000800,$0a000300
 dc.l $08000b00,$09000800,$0a000400
 dc.l $08000b00,$09000800,$0a000500
 dc.l $08000b00,$09000800,$0a000500
 dc.l $08000c00,$09000200,$0a000000
 dc.l $08000c00,$09000200,$0a000200
 dc.l $08000c00,$09000400,$0a000100
 dc.l $08000c00,$09000500,$0a000000
 dc.l $08000c00,$09000500,$0a000300
 dc.l $08000c00,$09000600,$0a000000
 dc.l $08000c00,$09000600,$0a000200
 dc.l $08000c00,$09000700,$0a000000
 dc.l $08000c00,$09000700,$0a000300
 dc.l $08000c00,$09000700,$0a000400
 dc.l $08000c00,$09000800,$0a000000
 dc.l $08000c00,$09000800,$0a000300
 dc.l $08000c00,$09000800,$0a000400
 dc.l $08000c00,$09000800,$0a000500
 dc.l $08000c00,$09000900,$0a000000
 dc.l $08000c00,$09000900,$0a000300
 dc.l $08000c00,$09000900,$0a000400
 dc.l $08000c00,$09000900,$0a000500
 
siditab:
 dc.b 0,$ff,1,$ff,2,$ff,3,$ff,4,$ff,5,$ff,6,0,7,$3f
 dc.b 8,0,9,0,10,0,$ff,0
 even
smp_anf_:
 dc.l 1000000
smp_end_:
 dc.l 1000000
smp_frq_:
 dc.w 20000
smp_mod_:
 dc.w 0
smp_way_:
 dc.w 1
smp_out_:
 dc.b $39
 even
smp_len_:
 dc.l 5
oldsp:
 dc.l 1
jaja:
 dc.l 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,9,0