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

  1.  
  2. ; Lezione14-5a.s    ** SUONA SAMPLE MOLTO LUNGHI **
  3.  
  4.  
  5.     SECTION    PlayLongSamples,CODE
  6.  
  7. Start:
  8.     bset    #1,$bfe001        ; spegne il filtro passa-basso
  9.  
  10.                     ; >>>> PARAMETRI <<<<
  11.     lea    sample,a0        ; indirizzo sample
  12.     move.l    #sample_end-sample,d0    ; lunghezza sample in byte
  13.     move.w    #17897,d1        ; frequenza di lettura
  14.     moveq    #64,d2            ; volume
  15.     bsr.s    playlongsample_init    ; INIT routine (comincia)....
  16.                     ; ....CPU libera....
  17. WLMB:
  18.     btst    #6,$bfe001        ; testa LMB+RMB...provate, dunque,
  19.     bne.s    wlmb            ; a girare per il Wb e noterete
  20.     btst    #10,$dff016        ; come non avvenga NESSUN rallentamento
  21.     bne.s    wlmb            ; ....magie del DMA !
  22.  
  23.     bsr.w    playlongsample_restore    ; RESTORE routine (spegne tutto)
  24.     rts
  25.  
  26.  
  27. ***************************************
  28. *****  Play Long Sample Routines  *****
  29. ***************************************
  30. ;
  31. ; a0    = sample adr
  32. ; d0.l  = lunghezza.b sample, d1.w=frequenza, d2.w=volume
  33. ;
  34. ; L'AutoVector Lv4 IRQ deve essere disponibile
  35.  
  36.  
  37. _LVOSupervisor    equ    -30
  38. Clock        equ    3546895
  39. AFB_68010    equ    0
  40. AttnFlags    equ    296
  41.  
  42. PlayLongSample_init:
  43.     movem.l    d2/a0/a6,-(sp)
  44.     movem.l    d0/a0,plsregs        ; registri fissi di riferimento
  45.     movem.l    d0/a0,plsregs+4*2    ; registri di lavoro
  46.     sub.l    a0,a0            ; FAST CLEAR An
  47.     move.l    4.w,a6
  48.     btst    #afb_68010,attnflags+1(a6)    ; 68010+ ?
  49.     beq.s    .no010
  50.     lea    getvbr(pc),a5
  51.     jsr    _LVOSupervisor(a6)
  52. .No010:
  53.     lea    $dff000,a6
  54.     move.w    #$0780,$9c(a6)        ; azzera eventuali richieste di IRQ
  55.     move.w    $1c(a6),oldint        ; salva INTENA dell'OS
  56.     move.w    #$0780,$9a(a6)        ; maschera INT AUD0-AUD3
  57.     move.l    $70(a0),oldlv4        ; salva l'autovettore del livello 4
  58.     move.l    #lv4irq,$70(a0)        ; imposta il nuovo autovettore
  59.     move.w    d2,$a8(a6)        ; imposta AUD0VOL
  60.     move.w    d2,$b8(a6)        ; imposta AUD1VOL
  61.     move.w    d2,$c8(a6)        ; imposta AUD2VOL
  62.     move.w    d2,$d8(a6)        ; imposta AUD3VOL
  63.     move.l    #clock,d2
  64.     divu.w    d1,d2            ; d2.w=clock/freq = periodo di camp.
  65.     move.w    d2,$a6(a6)        ; imposta AUD0PER
  66.     move.w    d2,$b6(a6)        ; imposta AUD1PER
  67.     move.w    d2,$c6(a6)        ; imposta AUD2PER
  68.     move.w    d2,$d6(a6)        ; imposta AUD3PER
  69.     move.w    $2(a6),olddma        ; salva DMACON dell'OS
  70.     move.w    #$8400,$9a(a6)        ; accende AUD3 IRQ - basta lui...
  71.     move.w    #$8400,$9c(a6)        ; forza l'IRQ per comiciare...
  72.     movem.l    (sp)+,d2/a0/a6
  73.     rts
  74.  
  75. ;--------------------------------------
  76. GetVBR:
  77.     dc.l    $4e7a8801    ;movec    vbr,a0    ;base dei vettori di eccezione
  78.     rte
  79. ;--------------------------------------
  80.  
  81. PlayLongSample_restore:
  82.     movem.l    d0/a0/a6,-(sp)
  83.     sub.l    a0,a0
  84.     move.l    4.w,a6
  85.     btst    #afb_68010,attnflags+1(a6)
  86.     beq.s    .no010
  87.     lea    getvbr(pc),a5
  88.     jsr    _LVOSupervisor(a6)
  89. .No010:
  90.     lea    $dff000,a6
  91.     move.w    #$0780,$9c(a6)        ; azzera le richieste di tutti i canali
  92.     move.w    #$0400,$9a(a6)        ; maschera l'INT AUD3
  93.     move.l    oldlv4(pc),$70(a0)    ; reimposta l'autovettore 4 dell'OS
  94.     move.w    #$000f,$96(a6)        ; spegne tutti i DMA audio
  95.     move.w    oldint(pc),d0
  96.     or.w    #$8000,d0        ; imposta SET/CLR che e' a 0 in INTENAR 
  97.     move.w    d0,$9a(a6)        ; reimposta l'INTENA dell'OS
  98.     move.w    olddma(pc),d0
  99.     or.w    #$8000,d0        ; imposta SET/CLR che e' a 0 in DMACONR
  100.     move.w    d0,$96(a6)        ; reimposta il DMACON dell'OS
  101.     movem.l    (sp)+,d0/a0/a6
  102.     rts
  103.  
  104. ;--------------------------------------
  105.  
  106. PlayLongSample_IRQ:
  107.     movem.l    d0-d1/a0-a1/a6,-(sp)
  108.     lea    $dff000,a6
  109.     movem.l    plsregs+4*2(pc),d0/a0    ; grabba i registri di lavoro
  110.     move.l    a0,$a0(a6)        ; imposta AUD0LC
  111.     move.l    a0,$b0(a6)        ; imposta AUD1LC
  112.     move.l    a0,$c0(a6)        ; imposta AUD2LC
  113.     move.l    a0,$d0(a6)        ; imposta AUD3LC
  114.     move.l    d0,d1            ; d1.l=lunghezza mancante
  115.     and.l    #~(128*1024-1),d1    ; mancano ancora piu' di 128 kB
  116.     bne.s    .long            ; se SI: vai a .long
  117.     move.l    d0,d1            ; se NO: usa lungh. mancante (< 128 kB)
  118. .Long:    lsr.l    #1,d1            ; trasforma la lungh. da suonare in .W
  119.     move.w    d1,$a4(a6)        ; imposta AUD0LEN
  120.     move.w    d1,$b4(a6)        ; imposta AUD1LEN
  121.     move.w    d1,$c4(a6)        ; imposta AUD2LEN
  122.     move.w    d1,$d4(a6)        ; imposta AUD3LEN
  123.     add.l    #128*1024,a0        ; punta a0 al prossimo blocco
  124.     sub.l    #128*1024,d0        ; lunghezza MENO 128 kB
  125.     bhi.s    .noloop            ; d0 => 1 ? (manca ALMENO 1 byte)
  126.     movem.l    plsregs(pc),d0/a0    ; se NO: reimposta registri originali
  127. .NoLoop:movem.l    d0/a0,plsregs+4*2    ; salva comunque d0 e a0 nelle copie
  128.     move.w    #$820f,$96(a6)        ; accende tutti i DMA audio, e viene
  129.                     ; generato subito l'IRQ, nel caso
  130.                     ; della prima accensione dell'audio
  131.     movem.l    (sp)+,d0-d1/a0-a1/a6
  132.     rts
  133.  
  134. ;--------------------------------------
  135.  
  136. OldINT:    dc.w    0
  137. OldDMA:    dc.w    0
  138. OldLv4:    dc.l    0
  139. PLSRegs: dc.l    0,0    ; lunghezza,puntatore - fissi
  140.     dc.l    0,0    ; lunghezza,puntatore - variabili
  141.  
  142.  
  143. ***************************************
  144. *****  Level 4 Interrupt Handler  *****
  145. ***************************************
  146.  
  147.     cnop    0,8
  148. Lv4IRQ:    
  149.     btst    #10-8,$dff01e        ;IRQ AUD3 ?
  150.     beq.s    .exit            ;se NO: esci
  151.     move.w    #$0400,$dff09c        ;spegni subito la richiesta, poiche'
  152.                     ;nella routine vengono accesi i DMA
  153.                     ;ed il nuovo IRQ viene subito generato:
  154.                     ;spegnendo la richiesta dopo la routine
  155.                     ;si corre il rischio di annullare la
  156.                     ;richiesta di IRQ al primo ciclo
  157.                     ;dell'interrupt (appena avviata la
  158.                     ;routine).
  159.     bsr.w    playlongsample_irq
  160. .Exit:
  161.     rte
  162.  
  163.  
  164.  
  165.     SECTION    Sample,DATA_C
  166.  
  167.     ; MammaGamma by Alan Parsons Project (©1981)
  168. Sample:
  169.     incbin    "assembler2:sorgenti8/Mammagamma.17897"
  170. Sample_end:
  171.  
  172.     END
  173.  
  174.  
  175. Ora le cosa ricominciano a complicarsi... Abbiamo iniziato ad usare interrupt
  176. e routine non piu' - diciamo - banali.
  177. Come e' stato gia' scritto nella LEZIONE, i canali audio sono associati a 4
  178. diversi interrupt assegnati al livello 4 del 680x0; tali interrupt vengono
  179. generati dall'harware ogni qual volta un canale viene forzato a leggere i dati
  180. in memoria a partire dall'indirizzo contenuto nel suo AUDLC: avvegono, dunque,
  181. appena acceso il DMA ed ogni volta all'inizio di un nuovo loop del sample.
  182. * Appena un canale comincia a suonare dall'inizio un sample, oltre a venir
  183. "sparato" l'IRQ, il suo AUDLC rimane immutato e, pertanto, ALTERABILE:
  184. in questo modo funziona la routine "PlayLongSample": ogni volta che il DMA
  185. comincia a leggere un pezzo (da 128 kB o meno, a seconda che la parte di
  186. sample mancante da suonare sia piu' lunga della massima AUDLEN loopabile) viene
  187. generato l'interrupt, ed i registri di locazione AUDxLC (tutti e 4, in questo
  188. caso, poiche' vengono utilizzati tutti per suonare i medesimi dati) vengono
  189. ricalcolati e fatti avanzare o retrocedere in base al "pezzetto" di sample
  190. a cui PRECEDENTEMENTE putavano e che ORA il DMA sta' leggendo *.
  191. *** In sostanza, con questa tecnica, e' possibile far suonare all'Amiga tanti
  192. pezzi di 128 kB - o meno, per quanto riguarda l'ultimo pezzo - di dati audio
  193. adiacenti in memoria, senza far sentire lo "stacco" tra uno e l'altro ***. 
  194.  
  195. N.B.:    una volta avviata la routine, essa continua a far loopare il sample
  196.     all'infinito solo dal codice in interrupt, per cui ** e' COMPLETAMENTE
  197.     INDIPENDENTE: in altre parole, dopo l'"_init", tornate in main
  198.     ed avete normale controllo di tutto l'hardware (escluso quello sonoro,
  199.     ovviamente) e della CPU (escluso l'interrupt di livello 4, che e'
  200.     quello utilizzato dalla "PlayLongSample") **.
  201.     Quando volete spegnere il sample, chiamate la "_restore" e tutto
  202.     tornera' come prima di aver chiamato la "_init" (eventuali routine
  203.     su interrupt audio comprese !).
  204.  
  205. P.S.:    un'ultima precisazione: qui e' stato utilizzato solo un IRQ per
  206.     tutte le voci, visto che tutte suonavano contemporaneamente la
  207.     medesima cosa, e precisamente quello della voce 3, ovvero il piu'
  208.     alto di priorita' hardware.
  209.     In teoria non dovrebbe cambiare nulla nell'usare quello di quelche
  210.     altra voce, * a patto che si mascherino gli altri - o che comunque
  211.     vengano ignorati dall'handler -, altrimenti al termine di ogni blocco
  212.     letto verrebbero generati 4 interrupt.
  213.