Dr.Godfried-Willem RAES
Kursus Experimentele Muziek: Boekdeel 1: Algoritmische Kompositie
Hogeschool Gent : Departement Muziek & Drama
Dit hoofdstuk mag vandaag achterhaald heten. Binnen de nu in de klas gebruikte programeeromgeving (PowerBasic en de Windows API) stelt gebruik van de muis geen problemen. Niettemin bewaarden we dit hoofstuk toch hier, omdat het een low-level aanpak omvat voor de besturing van hardware interfaces.
1140
Muizen, Muizevallen, Muizenissen...
De muis als input-device heeft pas laat haar intrede gedaan in de wereld van de Intel personal komputers. Dit verklaart waarom het ding niet wordt ondersteund door het gros van de DOS programmas, inklusief kompilers en interpreters. Op PC's kennen we vandaag 2 verschillende muistypes: seriele muizen en bus muizen. De eerste soort maakt gebruik van een van de standaard seriele poorten op de PC (RS232), de tweede van een eigen en specifiek interface via een afzonderlijke I/O poort. Konden we vroeger muizen in onze eigen Basic programmas eigenlijk slechts gebruiken door rechtstreekse adressering van de hardware -iets wat steeds voor kompatibiliteitsproblemen zorgde, dan kunnen we nu gebruik maken van een reeks specifieke DOS-funkties die sedert DOS 6.0 vast deel zijn gaan uitmaken van het operating system. Helaas werden de beschikbare DOS interpreters voor Basic niet aan deze nieuwe situatie aangepast zodat we geen intrinsieke Basic funkties ter beschikking hebben waardoor de muis kan worden geintegreerd in onze eigen programmas.
Dit betekent echter niet dat we aan muizenissen moeten verzaken! Basic beschikt immers over de mogelijkheid via een interrupt call routine rechtstreeks alle DOS-funkties te gebruiken. In QBX-PDS moeten daartoe de specifieke libraries met de interpreter opgeladen worden bij het opstarten. Dit gebeurt via het kommando QBX /L. Vervolgens moeten de funkties via een include bestand in het programma opgenomen worden.
We geven een voorbeeld van een programma waarmee 'slider'-controllers ook binnen DOS kunnen worden ontworpen:
' This demonstration program contains all procedures required for mouse
' support under QBX - PDS version 7.1
' For compilation start up with the /L command: QBS /L
' The slider controllers as implemented here have advantages over the
' windows-silder controls: you can instantaneously input changes (no need
' to drag a knob) and they perform very fast draws. The code is suitable
' for use in multitaskers. Make sure you do not exagarate in the rsi's for
' the controls. Humans are'nt all that fast...
'$DYNAMIC
TYPE RegType
ax AS INTEGER
bx AS INTEGER
cx AS INTEGER
dx AS INTEGER
bp AS INTEGER
si AS INTEGER
di AS INTEGER
flags AS INTEGER
END TYPE
TYPE RegTypeX
ax AS INTEGER
bx AS INTEGER
cx AS INTEGER
dx AS INTEGER
bp AS INTEGER
si AS INTEGER
di AS INTEGER
flags AS INTEGER
ds AS INTEGER
es AS INTEGER
END TYPE
TYPE ControllerBlok
x1 AS INTEGER ' linkeronderhoek koordinaten
y1 AS INTEGER
x2 AS INTEGER ' rechterbovenboek koordinaten
y2 AS INTEGER
label AS STRING * 8 ' opschrift boven het sliderblok
rangelow AS INTEGER ' lowest returnvalue
rangehigh AS INTEGER ' highest returnvalue
nr AS INTEGER
retval(0 TO 127) AS INTEGER ' return values, slider-positions
END TYPE
CONST False = 0
CONST True = NOT False
DECLARE SUB Interrupt (intnum AS INTEGER, inreg AS RegType, outreg AS RegType)
DECLARE SUB InterruptX (intnum AS INTEGER, inreg AS RegTypeX, outreg AS RegTypeX)
DECLARE SUB Absolute (address AS INTEGER)
DECLARE SUB InitMuis ()
DECLARE SUB Muis (h%, v%, b%)
DECLARE SUB Slider (funktienummer%, h%, v%, button%, ctrl%, bt%)
DIM SHARED regs AS RegType
DIM SHARED Colums AS INTEGER, Lines AS INTEGER
DECLARE FUNCTION GetVideoMode! ()
Colums = 80
Lines = 60
SCREEN 12
WIDTH Colums, Lines
InitMuis
' kreeer 16 sliders:
horpos% = 100
verpos% = 256
breedte% = 4
afstand% = 10
aantal% = 16
Slider 1, horpos%, verpos%, aantal%, breedte%, afstand%
' gebruik ze:
DO
Muis h%, v%, b%
Slider 0, h%, v%, b%, controllernr%, value%
' onderschrift voor sliderblok:
LOCATE 2 + (verpos% \ 8), 2 + (horpos% \ 8)
PRINT "Slider:"; controllernr%; " ="; value%
k$ = INKEY$
SELECT CASE k$
CASE CHR$(27), "*"
END
CASE "+"
' test for rescaling of sliders whilst preserving contents
Slider 2, (horpos%), (verpos%), 16, (breedte% * 2), (afstand% * 2)
CASE "-"
' reset original
' with the brackets we force a call by value!
Slider 2, (horpos%), (verpos%), 16, breedte%, afstand%
CASE " "
' delete sliders
Slider -1, 0, 0, 0, 0, 0
EXIT DO
END SELECT
LOOP
REM $STATIC
FUNCTION GetVideoMode
DIM register AS RegType
' test-kode:
FOR i% = 0 TO 12
SELECT CASE i%
CASE 0, 1, 2, 7, 8, 9, 10, 11, 12
SCREEN i%
' use dos irq call to get current video mode:
register.ax = &HF00
CALL Interrupt(&H10, register, register)
SELECT CASE register.ax MOD 256
CASE &H11, &H12: SCREEN i%: WIDTH 80, 60
END SELECT
PRINT "Basic SCREEN"; i%; "= BIOS video mode="; regs.ax MOD 256
'SLEEP 3
CASE ELSE
' illegal
END SELECT
NEXT i%
GetVideoMode = register.ax MOD 256
END FUNCTION
SUB InitMuis
regs.ax = &H1
CALL Interrupt(&H33, regs, regs)
END SUB
SUB Muis (h%, v%, b%)
regs.ax = &H1
CALL Interrupt(&H33, regs, regs): ' show mouse pointer
regs.ax = &H3
CALL Interrupt(&H33, regs, regs)
h% = regs.cx: ' 0->639
v% = regs.dx: ' 0->479
b% = regs.bx: ' 0= no button
' 1= left button d0
' 2= right button d1
' 3= both buttons
' 4= middle button d2
'Task(13).rsi = Lps% / 20: ' 20 x per sec.
END SUB
SUB MuisHandler (hor%, ver%)
Khor% = (hor% \ 8) + 1
Kver% = (ver% \ 8) + 1
' -> locate-compatible coordinates for 80x60 screen
END SUB
SUB Slider (FuncNumber%, h%, v%, but%, ctrl%, retval%)
STATIC Sliderareas() AS INTEGER, Slidervalues() AS INTEGER, Toggle%
CONST sliderlengte% = 127: ' in pixels (7-bit resolution) - this is a constant!!!
' this also limits retval% to this value
CONST SliderBackColor = 10: ' green
CONST SliderBorderColor = 13: ' purple
CONST SliderHotColor = 12: ' red
IF Toggle% = 0 THEN
Toggle% = True: ' reset by deleting sliders.
DIM Sliderareas(0 TO 3, 0 TO 7) AS INTEGER
DIM Slidervalues(0 TO 7) AS INTEGER: ' pro forma
END IF
' Users-guide:
' FuncNumber% -1: removes sliders
' FuncNumber% 1: creates sliders
' the parameters then are:
' h% = leftmost horizontal position for sliderblock
' v% = vertical coordinate for this same point of the sliderblock
' but% = number of sliders to create
' ctrl% = width of sliders
' retval% = distance (spacing) between sliders
' FuncNumber% 0 : pass mouse params en returns active slider and its newest position
' h% = horizontal mouse coordinate
' v% = vertical mouse coordinate
' but% = switches byte (left button activates sliders)
' ctrl% = returns the number of the moved slider
' If -1, no slider was moved
' retval% = returns the value of the moved slider
' This is a 7-bit number 0 to 127, (Midi compatible)
' FuncNumber% = 2:
' redraw the sliders but keep the positions intact
' FuncNumber% =3
' return the active area for the slider box in absolute coordinates
' x1% = hor%
' y1% = ver%
' but% = irrelevant
' x2% = ctrl%
' y2% = retval%
' FuncNumber = 4
' return the most recenty position of a given slider control
' hor%= irrelevant
' ver% = irrelevant
' but% = irrelevant
' ctr% = number of the requested controller
' retval% = the requested value
SELECT CASE FuncNumber%
CASE -1
' this removes all sliders from the screen
x1% = Sliderareas(0, 1)
y1% = Sliderareas(1, 1)
x2% = Sliderareas(2, UBOUND(Sliderareas, 2))
y2% = Sliderareas(3, UBOUND(Sliderareas, 2))
LINE (x1% - 1, y1% + 1)-(x2% + 1, y2% - 1), False, BF
' the +1/-1's are because without them, the border is not
' removed properly.
ERASE Sliderareas
' as now it keeps Slidervalues()
' we could also erase this one...
Toggle% = False
CASE 0
' here we make the sliders react on mouse movement
' first we check mouse horizontal position
Sliderhit% = False
FOR i% = 1 TO UBOUND(Sliderareas, 2)
IF h% >= Sliderareas(0, i%) AND h% <= Sliderareas(2, i%) THEN
' check vertical within range condition...
FOR j% = 1 TO UBOUND(Sliderareas, 2)
IF v% >= Sliderareas(3, i%) AND v% <= Sliderareas(1, i%) THEN
' now the mouse must be at slider i%
Sliderhit% = True
' for debug : LOCATE 50, 10: PRINT "Slider"; i%
IF but% = 1 THEN
' if left button is down...
' hide the mouse cursor...
regs.ax = 2
CALL Interrupt(&H33, regs, regs)
LINE (Sliderareas(0, i%) + 1, Sliderareas(1, i%) - 1)-(Sliderareas(2, i%) - 1, v%), SliderHotColor, BF
LINE -(Sliderareas(0, i%) + 1, Sliderareas(3, i%) - 1), SliderBackColor, BF
' show cursus again:
regs.ax = 1
CALL Interrupt(&H33, regs, regs)
ctrl% = i%
retval% = Sliderareas(1, i%) - v%
Slidervalues(i%) = retval%
END IF
EXIT FOR
END IF
NEXT j%
IF Sliderhit% = True THEN EXIT FOR
END IF
NEXT i%
CASE 1
' this case creates sliders
sliderhor% = h%: ' horizontaal vertrekpunt van de reeks sliders
sliderbottom% = v%: 'laagste punt op scherm in absolute koordinaten
sliderafstand% = retval%
sliderbreedte% = ctrl%:
Slideraantal% = but%
REDIM Sliderareas(0 TO 3, 1 TO Slideraantal%) AS INTEGER:
REDIM Slidervalues(1 TO Slideraantal%) AS INTEGER
' needed to remember the positions of the
' sliders for later calls...
FOR i% = 1 TO Slideraantal%
stap% = (i% - 1) * sliderafstand%
Sliderareas(0, i%) = sliderhor% + stap%
Sliderareas(1, i%) = sliderbottom%
Sliderareas(2, i%) = sliderhor% + sliderbreedte% + stap%
Sliderareas(3, i%) = sliderbottom% - sliderlengte%
' here we 'misuse' Basic VIEW to draw boxes...
VIEW (Sliderareas(0, i%), Sliderareas(1, i%))-(Sliderareas(2, i%), Sliderareas(3, i%)),SliderBackColor, SliderBorderColor
NEXT i%
' now we remember where the sliders are on the screen
' the values/setting are kept in Slidervalues()
VIEW: ' reset to full screen view
CASE 2
' redraw/rescale sliders but save slider positions!
' the number of sliders should of course be the same than
' at the time of their original creation
' First we delete the existing sliderbox:
x2% = Sliderareas(2, UBOUND(Sliderareas, 2))
y2% = Sliderareas(3, UBOUND(Sliderareas, 2))
LINE (Sliderareas(0, 1) - 1, Sliderareas(1, 1) + 1)-(x2% + 1, y2% - 1), False, BF
' the +1/-1's are because without them, the border is not
' removed properly.
' then we create the new resized one:
sliderhor% = h%: ' new horizontal starting point for sliderblock
sliderbottom% = v%: 'lowest point in screen in absolute coordinates
sliderafstand% = retval%
sliderbreedte% = ctrl%:
Slideraantal% = UBOUND(Sliderareas, 2)
FOR i% = 1 TO Slideraantal%
stap% = (i% - 1) * sliderafstand%
Sliderareas(0, i%) = sliderhor% + stap%
Sliderareas(1, i%) = sliderbottom%
Sliderareas(2, i%) = sliderhor% + sliderbreedte% + stap%
Sliderareas(3, i%) = sliderbottom% - sliderlengte%
' here we again 'misuse' Basic VIEW to draw boxes...
VIEW (Sliderareas(0, i%), Sliderareas(1, i%))-(Sliderareas(2, i%), Sliderareas(3, i%)),SliderBackColor, SliderBorderColor
VIEW
' replace the previous slider positions:
' recalculate the vertical position:
v% = Sliderareas(1, i%) - Slidervalues(i%)
LINE (Sliderareas(0, i%) + 1, Sliderareas(1, i%) - 1)-(Sliderareas(2, i%) - 1, v%), 12, BF
LINE -(Sliderareas(0, i%) + 1, Sliderareas(3, i%) - 1), 10, BF
NEXT i%
CASE 3
' returns the active area for the sliderbox
h% = Sliderareas(0, LBOUND(Sliderareas, 2))
v% = Sliderareas(1, LBOUND(Sliderareas, 2))
ctrl% = Sliderareas(2, UBOUND(Sliderareas, 2))
retval% = Sliderareas(3, UBOUND(Sliderareas, 2))
CASE 4
' returns the most recent position of a slider in the box.
' the slider must be passed in ctrl%
retval% = Slidervalues%(ctrl%)
END SELECT
END SUB
Deze kode moge dienen als een vertrekpunt voor eigen implementaties.
Filedate: 971104
Terug naar inhoudstafel kursus: <Index Kursus> |
Naar homepage dr.Godfried-Willem RAES |