home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 109 / EnigmaAmiga109CD.iso / software / testi / corsoasm / sorgenti8 / lezione14-6a.s < prev    next >
Text File  |  1995-09-29  |  9KB  |  249 lines

  1.  
  2. ; Corso Asm - LEZIONE xx:  ** SUONA SAMPLE MOLTO LUNGHI ANCHE IN FAST **
  3.  
  4.  
  5.     SECTION    PlayLongSamples,CODE
  6.  
  7. Start:
  8.     bset    #1,$bfe001        ;spegne il filtro passa-basso
  9.                     ;>>>> PARAMETRI <<<<
  10.     lea    sample,a0        ;indirizzo sample
  11.     move.l    #sample_end-sample,d0    ;lunghezza sample in byte
  12.     move.w    #17897,d1        ;frequenza di lettura
  13.     moveq    #64,d2            ;volume
  14.     bsr.s    playlongsample_init    ;INIT routine (comincia)....
  15.                     ;....CPU libera....
  16. WLMB:    btst    #6,$bfe001        ;testa LMB+RMB...provate, dunque,
  17.     bne.s    wlmb            ;a girare per il Wb e noterete
  18.     btst    #10,$dff016        ;come non avvenga NESSUN rallentamento
  19.     bne.s    wlmb            ;....magie del DMA !
  20.  
  21.     bsr.w    playlongsample_restore    ;RESTORE routine (spegne tutto)
  22.     rts
  23.  
  24.  
  25. ***************************************
  26. *****  Play Long Sample Routines  *****
  27. ***************************************
  28.  
  29. PlayLongSample_init:
  30.         ;[a0=sample adr]
  31.         ;[d0.l=lunghezza.b sample, d1.w=frequenza, d2.w=volume]
  32.         ;* L'AutoVector Lv4 IRQ deve essere disponibile *
  33.  
  34. _LVOSupervisor    equ    -30
  35. _LVOAllocMem    EQU    -198
  36. _LVOFreeMem    EQU    -210
  37. _LVOAvailMem    EQU    -216
  38. MEMF_CHIP    equ    1<<1
  39. MEMF_LARGEST    equ    1<<17
  40. MEMF_CLEAR    equ    1<<16
  41. Clock        equ    3546895
  42. AFB_68010    equ    0
  43. AttnFlags    equ    296
  44.  
  45.     movem.l    d0-d2/a0-a1/a5-a6,-(sp)    ;salva molti registri perche' le
  46.                     ;library sporcano d0-d2/a0-a1
  47.     lea    plsregs(pc),a5
  48.     movem.l    d0/a0,(a5)        ;registri fissi di riferimento
  49.     movem.l    d0/a0,4*2(a5)        ;registri di lavoro
  50.     move.l    4.w,a6
  51.     move.l    #MEMF_CHIP!MEMF_LARGEST,d1
  52.     jsr    _LVOAvailMem(a6)    ;-> d0.l=blocco di chip di grande
  53.     cmp.l    #2*128*1024,d0        ;d0.l > 256 kB ?
  54.     bls.s    .okmem            ;se NO: prendi la lungh. del blocco
  55.     move.l    #2*128*1024,d0        ;se SI: bastano 256 kB
  56. .OkMem:    and.w    #~%111,d0        ;d0.l=lungh.totale allineata a 64 bit
  57.     move.l    d0,4*4(a5)
  58.     move.l    #MEMF_CHIP!MEMF_CLEAR,d1;MEMF_CLEAR: a 0 la RAM alloccata
  59.     jsr    _LVOAllocMem(a6)    ;allocca 2 banchi da 128 kB adiacenti
  60.     tst.l    d0            ;d0.l=0 ?
  61.     beq.w    .bye            ;se SI: RAM non sufficiente -> esci
  62.     move.l    d0,4*5(a5)        ;salva base del PRIMO banco in chip
  63.     move.l    4*4(a5),d1
  64.     lsr.l    #1,d1
  65.     add.l    d1,d0
  66.     move.l    d0,4*6(a5)        ;salve base del SECONDO banco in chip
  67.     movem.l    4(sp),d1-d2        ;ripristina d1-d2 dallo stack
  68.     sub.l    a0,a0
  69.     move.l    4.w,a6
  70.     btst    #afb_68010,attnflags+1(a6)    ;68010+ ?
  71.     beq.s    .no010
  72.     lea    getvbr(pc),a5        ;va a routine con comandi privilegiati
  73.     jsr    _LVOSupervisor(a6)    ;in modo supervisore con l'exec
  74. .No010:    lea    $dff000,a6
  75.     move.w    #$0780,$9c(a6)        ;azzera eventuali richieste di IRQ
  76.     move.w    $1c(a6),oldint        ;salva INTENA dell'OS
  77.     move.w    #$0780,$9a(a6)        ;maschera INT AUD0-AUD3
  78.     move.l    $70(a0),oldlv4        ;salva l'autovettore del livello 4
  79.     move.l    #lv4irq,$70(a0)        ;imposta il nuovo autovettore
  80.     move.w    d2,$a8(a6)        ;imposta AUD0VOL
  81.     move.w    d2,$b8(a6)        ;imposta AUD1VOL
  82.     move.w    d2,$c8(a6)        ;imposta AUD2VOL
  83.     move.w    d2,$d8(a6)        ;imposta AUD3VOL
  84.     move.l    #clock,d2
  85.     divu.w    d1,d2            ;d2.w=clock/freq = periodo di camp.
  86.     move.w    d2,$a6(a6)        ;imposta AUD0PER
  87.     move.w    d2,$b6(a6)        ;imposta AUD1PER
  88.     move.w    d2,$c6(a6)        ;imposta AUD2PER
  89.     move.w    d2,$d6(a6)        ;imposta AUD3PER
  90.     move.w    $2(a6),olddma        ;salva DMACON dell'OS
  91.     move.w    #$c400,$9a(a6)        ;accende AUD3 IRQ - basta lui...
  92.     move.w    #$8400,$9c(a6)        ;forza l'IRQ per comiciare...
  93.     movem.l    (sp)+,d0-d2/a0-a1/a5-a6
  94. .Bye:    rts
  95. ;--------------------------------------
  96. GetVBR:
  97.     dc.l    $4e7a8801    ;movec    vbr,a0    ;base dei vettori di eccezione
  98.     rte
  99. ;--------------------------------------
  100. PlayLongSample_restore:
  101.     movem.l    d0-d2/a0-a1/a5-a6,-(sp)
  102.     sub.l    a0,a0
  103.     move.l    4.w,a6
  104.     btst    #afb_68010,attnflags+1(a6)
  105.     beq.s    .no010
  106.     lea    getvbr(pc),a5
  107.     jsr    _LVOSupervisor(a6)
  108. .No010:    lea    $dff000,a6
  109.     move.w    #$0780,$9c(a6)        ;azzera le richieste di tutti i canali
  110.     move.w    #$0400,$9a(a6)        ;maschera l'INT AUD3
  111.     move.l    oldlv4(pc),$70(a0)    ;reimposta l'autovettore 4 dell'OS
  112.     move.w    #$000f,$96(a6)        ;spegne tutti i DMA audio
  113.     move.w    oldint(pc),d0
  114.     or.w    #$8000,d0        ;imposta SET/CLR che e' a 0 in INTENAR 
  115.     move.w    d0,$9a(a6)        ;reimposta l'INTENA dell'OS
  116.     move.w    olddma(pc),d0
  117.     or.w    #$8000,d0        ;imposta SET/CLR che e' a 0 in DMACONR
  118.     move.w    d0,$96(a6)        ;reimposta il DMACON dell'OS
  119.     move.l    4.w,a6
  120.     movem.l    plsregs+4*4(pc),d0/a0-a1
  121.     cmp.l    a0,a1            ;a1 < a0 ? (a1 punta al banco con
  122.     blo.s    .min            ;indirizzo minore da cui comincia
  123.     move.l    a0,a1            ;la memoria alloccata ?)
  124. .Min:    jsr    _LVOFreeMem(a6)        ;restituisci la RAM al sistema
  125.     movem.l    (sp)+,d0-d2/a0-a1/a5-a6
  126.     rts
  127. ;--------------------------------------
  128. PlayLongSample_IRQ:
  129.     movem.l    d0-d2/a0-a1/a5-a6,-(sp)
  130.     lea    $dff000,a6
  131.     lea    plsregs+4*4(pc),a5
  132.     movem.l    -4*2(a5),d0/a0        ;d0.l=lungh.mancante/a0=base sample
  133.     movem.l    (a5),d1/a1        ;d1.l=lungh.banco/a1=base banco
  134.     move.l    a1,$a0(a6)        ;imposta gli AUDLC
  135.     move.l    a1,$b0(a6)
  136.     move.l    a1,$c0(a6)
  137.     move.l    a1,$d0(a6)
  138.     lsr.l    #1,d1            ;meta' banco
  139.     cmp.l    d0,d1            ;meta' banco <= lungh.mancante ?
  140.     bls.s    .longc
  141.     move.l    d0,d1            ;se NO: copia e suona lungh.mancante
  142. .LongC:    move.l    d1,d2
  143.     lsr.l    #1,d1            ;devidi per 2 per AUDLEN in word
  144.     move.w    d1,$a4(a6)        ;imposta gli AUDLEN
  145.     move.w    d1,$b4(a6)
  146.     move.w    d1,$c4(a6)
  147.     move.w    d1,$d4(a6)
  148.     lsr.l    #1,d1            ;dividi per 2 per copiare longword
  149.     subq.w    #1,d1
  150.     move.w    #$007,$180(a6)    ;blu quando comicia a copiare
  151. .CopyLp:move.l    (a0)+,(a1)+
  152.     dbra    d1,.copylp
  153.     move.w    #$000,$180(a6)    ;nero quando finisce
  154.     move.l    -4*1(a5),a0
  155.     add.l    d2,a0            ;punta a0 al prossimo blocco
  156.     sub.l    d2,d0            ;lunghezza MENO lungh.suonata
  157.     bhi.s    .noloop            ;d0 => 1 ? (manca ancora ALMENO 1 byte)
  158.     movem.l    plsregs(pc),d0/a0    ;se NO: reimposta registri originali
  159. .NoLoop:movem.l    d0/a0,-4*2(a5)        ;salva comunque d0 e a0 nelle copie
  160.     movem.l    4*1(a5),a0/a1        ;scambia puntatori ai 2 banchi
  161.     exg    a0,a1        ;commendola viene usato un solo buffer
  162.     movem.l    a0/a1,4*1(a5)
  163.     move.w    #$820f,$96(a6)
  164.     movem.l    (sp)+,d0-d2/a0-a1/a5-a6
  165.     rts
  166. ;--------------------------------------
  167. OldINT:    dc.w    0
  168. OldDMA:    dc.w    0
  169. OldLv4:    dc.l    0
  170. PLSRegs:dc.l    0,0    ;lunghezza,puntatore del sample - fissi
  171.     dc.l    0,0    ;lunghezza,puntatore del sample- variabili
  172.     dc.l    0,0,0    ;lunghezza,puntatore banco 1,puntatore banco 2 - fissi
  173.  
  174.  
  175. ***************************************
  176. *****  Level 4 Interrupt Handler  *****
  177. ***************************************
  178.  
  179.     cnop    0,8
  180. Lv4IRQ:    
  181.     btst    #10-8,$dff01e        ;IRQ AUD3 ?
  182.     beq.s    .exit
  183.     move.w    #$0780,$dff09c
  184.     bsr.w    playlongsample_irq
  185. .Exit:    rte
  186.  
  187.  
  188.  
  189.     SECTION    Sample,DATA_F
  190.  
  191.     ; MammaGamma by Alan Parsons Project (©1981)
  192. Sample:
  193.     incbin    "assembler2:sorgenti8/Mammagamma.17897"
  194. Sample_end:
  195.  
  196.     END
  197.  
  198. Con queta sezione 6 di sorgenti sull'audio dell'Amiga siamo passati al
  199. sofisticato: con questo sorgente (o, se preferite affidare gli handler di
  200. interrupt all'exec, modificatelo VOI come nel sorgente 5b in modo da usare
  201. il SetIntVector - non e' necessario, in linea di massima: l'OS non usa
  202. gli interrupt audio, infatti non ha server chain di livello 4) potete
  203. praticamente suoanare qualsiasi cosa che abbiate in memoria ovunque si trovi
  204. (a patto che occupi un solo blocco continuo di RAM; fare un player di sample
  205. "spezzettati" in vari chunk in giro per le RAM non sarebbe troppo difficile:
  206. sarebbe sufficiente usare questo stesso sorgente in modo che legga sample
  207. diversi in vari punti; l'unico problema sarebbe includere un file spezzandolo
  208. - cosa che l'assemblatore NON fa - con le routine della DOS library che
  209. leggono porzioni di file: a questo punto, fatta la routine di LOAD, avete
  210. anche fatto un ottimo player da CLI !) siete finalmente in grado di suonare
  211. un sample situato ovunque in memoria, nel chunk più grande che l'AllocMem
  212. riesce a trovare (MEMF_ANY).
  213.  
  214. Il funzionamento della routine è estremamente semplice: dato un sample di
  215. lunghezza indeterminata in un blocco di RAM QUALSIASI (chip o fast), viene
  216. alloccato un blocco di chip RAM (MEMF_CHIP) di 256 kB - se possibile - o meno,
  217. che viene suddiviso in due buffer da 128 kB - o meno - l'uno in cui copiare
  218. con un loop di CPU i dati del sample di 128 kB - o meno - in 128 kB - o meno -,
  219. al fine di riuscire a far leggere il DMA.
  220. Il motivo dell'uso dei 2 buffer è molto semplice: mentre l'audio ne suona uno,
  221. la CPU ne riempie un'altro con i dati successivi a quello in fase di lettura.
  222.  
  223. N.B.:    per la verità, certe CPU come il 68040 od il 68030 sono talmente veloci
  224.     da riuscire a copiare tutto il blocco di 128 kB - o meno - in poco più
  225.     di un raster; per cui, anche se non usate due buffer, soprattutto,
  226.     quando il buffer è molto piccolo, è onestamente impossibile sentire
  227.     il DMA suonare gli stessi dati 2 volte nello stesso buffer che loopa,
  228.     perchè la CPU li ha già copiati quando stanno ancora venendo lette
  229.     le prime word.
  230.     I motivi per cui sono stati utilizzati due buffer separati sono
  231.     i seguenti: innanzitutto, per eleganza di coding: IN TEORIA i due
  232.     buffer sono necessari; inoltre, su CPU lente come il 68000 a 16 bit
  233.     di accesso alla RAM dell'Amiga 500, la copia non è poi così istantanea;
  234.     infine, così com'è, la routine avrebbe un bug: l'ultimo blocco del
  235.     sample verrebbe suonato 2 volte, prima di loopare (per allenamento,
  236.     cercate di capire perchè ed aggiustate la ruotine...).
  237.  
  238.     La lunghezza minima per i buffer è di 4 byte ciascuno; provate
  239.     ad allocare solo 8 byte in tutto e suonare un sample alla frequenza
  240.     di lettura massima (28000 Hz ca., periodo=123): ebbene si, lo 040
  241.     - non si sa bene come - riesce a tener testa al DMA anche con
  242.     2 buffer di un longword !!! Provare per credere...
  243.  
  244. P.S.:    sulla _IRQ trovate 2 linee commentate: servono a cambiare il colore
  245.     di sfondo ogni volta che, chiamato l'interrupt, la CPU comincia
  246.     a copiare i dati dalla RAM sorgente ai buffer: togliete i commenti
  247.     per renedervi conto di cosa stà combinando il processore mentre
  248.     il DMA suona ignaro del cambiamento di dati...
  249.