******************************************************************************* * Example scope for HippoPlayer * By K-P Koljonen ******************************************************************************* * Can be assembled with Asm-One v1.25, at least. * Works on all Amiga configurations! * Version 1.1: Considered sample length to be bytes when it actually was in * words. * V1.2: Little fix. *** Includes: incdir include: include exec/exec_lib.i include exec/ports.i include exec/types.i include graphics/graphics_lib.i include graphics/rastport.i include intuition/intuition_lib.i include intuition/intuition.i incdir *** Some useful macros lob macro jsr _LVO\1(a6) endm lore macro ifc "\1","Exec" ifd _ExecBase ifeq _ExecBase move.l (a5),a6 else move.l _ExecBase(a5),a6 endc else move.l 4.w,a6 endc else move.l _\1Base(a5),a6 endc jsr _LVO\2(a6) endm pushm macro ifc "\1","all" movem.l d0-a6,-(sp) else movem.l \1,-(sp) endc endm popm macro ifc "\1","all" movem.l (sp)+,d0-a6 else movem.l (sp)+,\1 endc endm push macro move.l \1,-(sp) endm pop macro move.l (sp)+,\1 endm *** HippoPlayer's port: STRUCTURE HippoPort,MP_SIZE LONG hip_private1 * Private.. APTR hip_kplbase * kplbase address WORD hip_reserved0 * Private.. BYTE hip_reserved1 * Private.. BYTE hip_opencount * Open count BYTE hip_mainvolume * Main volume, 0-64 BYTE hip_play * If non-zero, HiP is playing BYTE hip_playertype * 33 = Protracker, 49 = PS3M. *** Protracker *** BYTE hip_reserved2 APTR hip_PTch1 * Protracker channel data for ch1 APTR hip_PTch2 * ch2 APTR hip_PTch3 * ch3 APTR hip_PTch4 * ch4 *** PS3M *** APTR hip_ps3mleft * Buffer for the left side APTR hip_ps3mright * Buffer for the right side LONG hip_ps3moffs * Playing position LONG hip_ps3mmaxoffs * Max value for hip_ps3moffs BYTE hip_PTtrigger1 BYTE hip_PTtrigger2 BYTE hip_PTtrigger3 BYTE hip_PTtrigger4 LABEL HippoPort_SIZEOF *** PT channel data block STRUCTURE PTch,0 LONG PTch_start * Start address of sample WORD PTch_length * Length of sample in words LONG PTch_loopstart * Start address of loop WORD PTch_replen * Loop length in words WORD PTch_volume * Channel volume WORD PTch_period * Channel period WORD PTch_private1 * Private... *** Dimensions: WIDTH = 320 HEIGHT = 64 *** Variables: rsreset _ExecBase rs.l 1 _GFXBase rs.l 1 _IntuiBase rs.l 1 port rs.l 1 owntask rs.l 1 screenlock rs.l 1 oldpri rs.l 1 windowbase rs.l 1 rastport rs.l 1 userport rs.l 1 windowtop rs 1 windowright rs 1 windowleft rs 1 windowbottom rs 1 draw1 rs.l 1 draw2 rs.l 1 omabitmap rs.b bm_SIZEOF size_var rs.b 0 *** Main program main lea var_b,a5 * Store execbase move.l 4.w,a6 move.l a6,(a5) sub.l a1,a1 * Find our process lob FindTask move.l d0,owntask(a5) lea intuiname(pc),a1 * Open libs lore Exec,OldOpenLibrary move.l d0,_IntuiBase(a5) lea gfxname(pc),a1 lob OldOpenLibrary move.l d0,_GFXBase(a5) *** Try to find HippoPlayer's port. If succesful, add 1 to hip_opencount *** indicating we are using the information in the port. *** Protect this procedure with Forbid()-Permit()! lob Forbid lea portname(pc),a1 lob FindPort move.l d0,port(a5) beq.w exit move.l d0,a0 addq.b #1,hip_opencount(a0) * We are using the port now! lob Permit *** Get some info about the screen we're running on bsr.w getscreendata *** Open our window lea winstruc,a0 lore Intui,OpenWindow move.l d0,windowbase(a5) beq.w exit move.l d0,a0 move.l wd_RPort(a0),rastport(a5) * Store rastport and userport move.l wd_UserPort(a0),userport(a5) *** Draw a bevel box plx1 equr d4 plx2 equr d5 ply1 equr d6 ply2 equr d7 moveq #8,plx1 move #331,plx2 moveq #13,ply1 moveq #80,ply2 add windowleft(a5),plx1 add windowleft(a5),plx2 add windowtop(a5),ply1 add windowtop(a5),ply2 move.l rastport(a5),a2 bsr.w piirra_loota2 subq #1,plx1 addq #1,plx2 bsr.w piirra_loota2a *** Initialize the bitmap structure lea omabitmap(a5),a0 moveq #1,d0 * depth (1 bitplane) move #WIDTH,d1 * width move #HEIGHT,d2 * height lore GFX,InitBitMap move.l #buffer1,omabitmap+bm_Planes(a5) * Plane pointer move.l #buffer1,draw1(a5) * Buffer pointers for drawing move.l #buffer2,draw2(a5) *** Set task priority to -30 to prevent messing up with other programs move.l owntask(a5),a1 moveq #-30,d0 lore Exec,SetTaskPri move.l d0,oldpri(a5) * Store the old priority *** Main loop begins here loop move.l _GFXBase(a5),a6 * Wait a while.. lob WaitTOF move.l port(a5),a0 * Check if HiP is playing tst.b hip_play(a0) beq.b .oh bsr.w dung * Do the scope .oh move.l userport(a5),a0 * Get messages from IDCMP lore Exec,GetMsg tst.l d0 beq.b loop move.l d0,a1 move.l im_Class(a1),d2 lob ReplyMsg cmp.l #IDCMP_CLOSEWINDOW,d2 * Should we exit? bne.b loop * No. Keep loopin' move.l owntask(a5),a1 * Restore the old priority move.l oldpri(a5),d0 lore Exec,SetTaskPri exit *** Exit program move.l port(a5),d0 * IMPORTANT! Subtract 1 from beq.b .uh0 * hip_opencount when the port is not move.l d0,a0 * needed anymore! subq.b #1,hip_opencount(a0) .uh0 move.l windowbase(a5),d0 * Close the window beq.b .uh1 move.l d0,a0 lore Intui,CloseWindow .uh1 move.l _IntuiBase(a5),a1 * And the libs lore Exec,CloseLibrary move.l _GFXBase(a5),a1 lob CloseLibrary moveq #0,d0 * No error rts ***** Get some info about the screen we're running on getscreendata move.l (a5),a0 * Running kick2.0 or newer? cmp #37,LIB_VERSION(a0) bhs.b .new rts .new * Yes. sub.l a0,a0 * Default public screen lore Intui,LockPubScreen * Kick2.0+ function move.l d0,d7 beq.b exit move.l d0,a0 * Store the values move.b sc_BarHeight(a0),windowtop+1(a5) move.b sc_WBorLeft(a0),windowleft+1(a5) move.b sc_WBorRight(a0),windowright+1(a5) move.b sc_WBorBottom(a0),windowbottom+1(a5) subq #4,windowleft(a5) subq #4,windowright(a5) subq #2,windowbottom(a5) sub #10,windowtop(a5) bpl.b .olde clr windowtop(a5) .olde move windowtop(a5),d0 * Adjust the window size add d0,winstruc+nw_Height move windowleft(a5),d1 add d1,winstruc+nw_Width move windowbottom(a5),d3 add d3,winstruc+nw_Height move.l d7,a1 * Unlock it. Let's hope it doesn't sub.l a0,a0 * go anywhere before we open our lob UnlockPubScreen * window ;-) rts *** Draw a bevel box piirra_loota2a pushm all moveq #1,d3 bra.b prl piirra_loota2 pushm all moveq #0,d3 prl move.l rastport(a5),a2 move #1,a3 move #2,a4 move.l _GFXBase(a5),a6 move.l a3,d0 move.l a2,a1 lob SetAPen move.l plx1,d0 move.l ply2,d1 lob Move move.l a2,a1 move.l plx1,d0 move.l ply1,d1 lob Draw move.l a2,a1 move.l plx2,d0 move.l ply1,d1 lob Draw move.l a2,a1 move.l a4,d0 lob SetAPen move.l a2,a1 move.l plx2,d0 move.l ply1,d1 addq.l #1,d1 sub.l d3,d1 lob Move move.l a2,a1 move.l plx2,d0 move.l ply2,d1 lob Draw move.l a2,a1 move.l plx1,d0 addq.l #1,d0 move.l ply2,d1 lob Draw move.l a2,a1 moveq #1,d0 lob SetAPen popm all rts *** Display the scope * I have two buffers, one for drawing and one for clearing. * Clearing is done with blitter during which cpu draws into the other * buffer. The drawn buffer is then dumped into the window using * BltBitMapRastPort(). If someone knows a faster way for doing this please * tell me. dung move.l _GFXBase(a5),a6 * Grab the blitter lob OwnBlitter lob WaitBlit * Clear the drawing area using 'demo programmer code'.. :) move.l draw2(a5),$dff054 * Blitter destination D move #0,$dff066 * Modulo D move.l #$01000000,$dff040 * Enable D move #HEIGHT*64+WIDTH/16,$dff058 * Write size, start blitter lob DisownBlitter * Free the blitter pushm all move.l port(a5),a0 cmp.b #33,hip_playertype(a0) * Protracker? beq.b .1 cmp.b #49,hip_playertype(a0) * PS3M? beq.b .2 bra.b .3 .1 bsr.b quadrascope * Quadrascope for PT bra.b .3 .2 bsr.w multiscope * Stereoscope for PS3M .3 popm all movem.l draw1(a5),d0/d1 * Switch the buffers exg d0,d1 movem.l d0/d1,draw1(a5) lea omabitmap(a5),a0 * Set the bitplane pointer move.l d1,bm_Planes(a0) ; lea omabitmap(a5),a0 * Copy from bitmap to rastport move.l rastport(a5),a1 moveq #0,d0 * source x,y moveq #0,d1 moveq #10,d2 * dest x,y moveq #15,d3 add windowleft(a5),d2 add windowtop(a5),d3 move #$c0,d6 * minterm a->d move #WIDTH,d4 * x-size move #HEIGHT,d5 * y-size lore GFX,BltBitMapRastPort * Zwoosh! rts *** Quarascope routine for Protracker * This (and the stereoscope) are very unoptimized. The reason for this is * that unoptimized code is usually easier to understand than optimized code. * Also this leaves a certain challenge for coders to try to get the loop * as fast as possible. quadrascope move.l port(a5),a3 move.l hip_PTch1(a3),a3 * Channel 1 data move.l draw1(a5),a0 bsr.b .scope * WIDTH/8/4 = 10 move.l port(a5),a3 move.l hip_PTch2(a3),a3 move.l draw1(a5),a0 lea 10(a0),a0 * Position bsr.b .scope move.l port(a5),a3 move.l hip_PTch3(a3),a3 move.l draw1(a5),a0 lea 10+10(a0),a0 bsr.b .scope move.l port(a5),a3 move.l hip_PTch4(a3),a3 move.l draw1(a5),a0 lea 10+10+10(a0),a0 bsr.b .scope rts .scope tst.l PTch_loopstart(a3) * Always check these to avoid beq.b .halt * enforcer hits! move.l PTch_start(a3),d0 bne.b .jolt .halt rts .jolt move.l d0,a1 * Sample start moveq #0,d5 move PTch_length(a3),d5 * Sample length in words add.l d5,d5 * Convert to bytes move.l port(a5),a2 * Get mainvolume moveq #0,d1 move.b hip_mainvolume(a2),d1 * (Main volume * sample volume)/64 mulu PTch_volume(a3),d1 lsr #6,d1 * Value for scaling the data moveq #0,d0 * X coordinate moveq #80-1,d7 * Loop counter, do 80 pixels drlo move.b (a1)+,d2 * Read one byte sample data ext d2 * Sign extend to word muls d1,d2 * Scale according to volume asr #6,d2 * ... add #$80,d2 * Change the sign asr #2,d2 * Scale down to 0-63 mulu #WIDTH/8,d2 * Get Y coordinate in the bitplane move d0,d4 * X move d0,d3 lsr #3,d4 * X offset in bytes = x-coord/8 add d4,d2 * Add to Y not d3 * Plot pixel bset d3,(a0,d2) * ... subq.l #1,d5 * Subtract sample length bpl.b .l * sample end? moveq #0,d5 * Get values for loop move PTch_replen(a3),d5 add.l d5,d5 move.l PTch_loopstart(a3),a1 .l addq #1,d0 * Increase X dbf d7,drlo * Loop.. rts *** Stereoscope for PS3M multiscope move.l port(a5),a1 move.l hip_ps3mleft(a1),a1 move.l draw1(a5),a0 bsr.b .h move.l port(a5),a1 move.l hip_ps3mright(a1),a1 move.l draw1(a5),a0 lea WIDTH/8/2(a0),a0 bsr.b .h rts .h move.l port(a5),a2 move.l hip_ps3moffs(a2),d5 * Get offset in buffers move.l hip_ps3mmaxoffs(a2),d4 * Get max offset move #160-1,d7 * Draw 160 pixels moveq #0,d0 * X coord .drlo moveq #0,d2 move.b (a1,d5.l),d2 * Get data from mixing buffer add.b #$80,d2 lsr #2,d2 mulu #WIDTH/8,d2 * Y move d0,d6 move d0,d3 lsr #3,d6 * X offset in bytes = x-coord/8 add d6,d2 not d3 * Plot pixel bset d3,(a0,d2) * ... addq #1,d0 * Increase x coord addq.l #1,d5 * Increase buffer position and.l d4,d5 * make sure it stays in the buffer dbf d7,.drlo * Loop rts ******************************************************************************* * Window wflags = WFLG_SMART_REFRESH!WFLG_DRAGBAR!WFLG_CLOSEGADGET!WFLG_DEPTHGADGET idcmpflags = IDCMP_CLOSEWINDOW winstruc dc 110,85 * x,y position winsiz dc 340,85 * x,y size dc.b 2,1 dc.l idcmpflags dc.l wflags dc.l 0 dc.l 0 dc.l .t * title dc.l 0 dc.l 0 dc 0,640 * min/max x dc 0,256 * min/max y dc WBENCHSCREEN dc.l 0 .t dc.b "HiP - Example scope",0 intuiname dc.b "intuition.library",0 gfxname dc.b "graphics.library",0 portname dc.b "HiP-Port",0 even section udnm,bss_p * Variables var_b ds.b size_var section hihi,bss_c * GFX buffers buffer1 ds.b WIDTH/8*HEIGHT buffer2 ds.b WIDTH/8*HEIGHT end