Brandt-Daroff

Here you can link to screenshots and demos etc. of programs made using BBC BASIC
KenDown
Posts: 91
Joined: Wed 04 Apr 2018, 06:36

Brandt-Daroff

Post by KenDown » Sat 02 Nov 2019, 05:29

Older people may suffer from a form of dizziness known as benign paroxysmal positional vertigo (abbreviated to BPPV). The cure, according to the NHS, is a simple exercise called the Brandt-Daroff Manoeuvre. My wife recently developed this and after the first session when I went cross-eyed staring at the second hand on my watch and helping her up and down, I wrote the following program to do the timing for me.

If anyone needs to use it, I suggest you watch the video at https://www.healthline.com/health/fitne ... #technique to see how it is done and then follow the program for the sequence of movements and their timing. (I would love some feedback if others find this useful and, of course, improvements are welcome.)

PROCinit

PROCnextstep(0)
PROCdrawclock
ssec%=(sec%+30)MOD60
REPEAT
REPEAT
t$=RIGHT$(TIME$,8)
IFt$<>time$time$=t$:PROCdrawclock:sc%+=1:PROCtimer
IFsec%=ssec%ssec%=(sec%+30)MOD60:step%=(step%+1)MOD4:PROCnextstep(step%):sc%=0:IFstep%=0advance%=TRUE
UNTILadvance%
cycle%+=1
CASEcycle%OF
WHEN1:cycle$="first"
WHEN2:cycle$="second"
WHEN3:cycle$="third"
WHEN4:cycle$="fourth"
WHEN5:cycle$="fifth and final"
ENDCASE
PROCnextstep(4)
OSCLI("FONT Arial,24,B")
GCOL0,14:RECTANGLEFILL-20,-280,40,80:GCOL0,0
VDU5:MOVE-18,-200:PRINTSTR$cycle%:VDU4
step%=0
ssec%=(sec%+30)MOD60
advance%=FALSE
UNTILcycle%=5
REPEAT
t$=RIGHT$(TIME$,8)
IFt$<>time$time$=t$:PROCdrawclock:sc%+=1:PROCtimer
IFsec%=ssec%advance%=TRUE
UNTILadvance%
PROCspeak("Congratulations! You have finished the exercise.")
END
:
DEFPROCnextstep(stp%)
CASEstp%OF
WHEN0:PROCspeak("Sit up and look straight ahead for thirty seconds.")
WHEN1:PROCspeak("Now lie on your right side and look up at forty-five degrees for thirty seconds.")
WHEN2:PROCspeak("Sit up again and look straight ahead for thirty seconds.")
WHEN3:PROCspeak("Now lie on your left side and look up at forty-five degrees for thirty seconds.")
WHEN4:PROCspeak("That is the end of your "+cycle$+" cycle.")
ENDCASE
ENDPROC
:
REM Draws the clock face and hands. Called once a second to update the clock
DEFPROCdrawclock:VDU5
ORIGINcx%,cy%
GCOL0,15:CIRCLEFILL0,0,190
GCOL0,0:CIRCLE0,0,190
r%=176:s%=186
FORi%=1TO60
t1=i%*PI/30:k%=(i%MOD5>0)+2
VDU23,23,k%;0;0;0;
LINE(14*(i%MOD5=0)+r%)*SINt1,(14*(i%MOD5=0)+r%)*COSt1,s%*SINt1,s%*COSt1
NEXT
GCOL0,4
OSCLI("FONT Ariel,12,B")
FORi%=1TO12:PROCnum(STR$i%,i%*PI/6):NEXT
time$=RIGHT$(TIME$,8)
hour%=VALLEFT$(time$,2)
min%=VALMID$(time$,4,2)
sec%=VALMID$(time$,7,2)
h=hour%+min%/60
GCOL0,8
PROChand(120,h*PI/6,(h-.3)*PI/6,(h+.3)*PI/6)
PROChand(140,min%*PI/30,(min%-1)*PI/30,(min%+1)*PI/30)
GCOL0,1
PROChand(150,sec%*PI/30,(sec%-.5)*PI/30,(sec%+.5)*PI/30)
CIRCLEFILL0,0,16
ENDPROC
:
REM Draws the clock hands
DEFPROChand(l%,t1,t2,t3)
MOVE0,0:MOVE.6*l%*SINt2,.6*l%*COSt2:PLOT85,l%*SINt1,l%*COSt1
MOVE.6*l%*SINt3,.6*l%*COSt3:PLOT85,0,0
ENDPROC
:
DEFPROCtimer
GCOL0,2:RECTANGLEFILL-120,210,sc%*8,50
GCOL0,1:RECTANGLEFILL-120+sc%*8,210,240-sc%*8,50
CASEsc%OF
WHEN5:PROCspeak("Five")
WHEN10:PROCspeak("Ten")
WHEN15:PROCspeak("Fifteen")
WHEN20:PROCspeak("Twenty")
WHEN25:PROCspeak("Twenty-five")
ENDCASE
ENDPROC
:
REM ===== Speech routines =====
:
DEFPROCspeechinit
speak%=TRUE
PROC_cominit
pitch%=0
speed%=0
voice$=""
tts%=FN_createobject("Sapi.SpVoice")
IFtts%=0PROCwarn("Voice module 'Sapi.SpVoice' not available. Sound cancelled.","Warning"):speak%=FALSE:ENDPROC
IFtts%THEN
LOCALqual$
qual$="<PITCH ABSMIDDLE="""""+STR$pitch%+"""""/><RATE ABSSPEED="""""+STR$speed%+"""""/>"
ENDIF
ENDPROC
:
DEFPROCspeak(phrase$)
REPEAT
qt%=INSTR(phrase$,CHR$34)
IFqt%phrase$=LEFT$(phrase$,qt%-1)+MID$(phrase$,qt%+1)
UNTILqt%=0
PROC_callmethod(tts%,"Speak("""+phrase$+""", 1)")
ENDPROC
:
REM Draws the hour numbers on the clock
DEFPROCnum(n$,t1):r%=144
MOVEr%*SINt1-8+12*(n$="12"),r%*COSt1+16
PRINTn$
ENDPROC
:
REM ===== Initialisation =====
:
DEFPROCinit
INSTALL @lib$+"COMLIBA"

SYS"SetWindowText",@hwnd%,"Brandt-Daroff"
REM These two calls set up the SystemMetrics
SYS"GetWindowLong",@hwnd%,-16TOws%
SYS"SetWindowLong",@hwnd%,-16,ws%AND&FFFBFFFF AND&FFFEFFFF
REM These calls give you the screen dimensions in graphics units, not Windows units
SYS"GetSystemMetrics",0TOscreenx%
SYS"GetSystemMetrics",1TOscreeny%

winwide%=108*2+12:REM The width of your main dialog box*2+12 to allow for the window borders
winhigh%=150*2+58:REM The height of your main dialog box*2+58 to allow for borders and menu bar
sx%=(screenx%-winwide%)DIV2
sy%=(screeny%-winhigh%)DIV2-30
SYS"SetWindowPos",@hwnd%,0,sx%,sy%,winwide%,winhigh%,0
SYS"SetWindowPos",@hwnd%,-1,0,0,0,0,3
VDU26

COLOUR7,220,220,220
GCOL0,135:CLG
PROCspeechinit
cx%=220
cy%=320
step%=0
cycle%=0
sc%=0
advance%=FALSE
ORIGINcx%,cy%
VDU23,23,2;0;0;0;
GCOL0,0:RECTANGLE-122,208,244,54
VDU23,23,1;0;0;0;
OSCLI("FONT Arial,24,B")
GCOL0,14:RECTANGLEFILL-20,-280,40,80:GCOL0,0
VDU5:MOVE-18,-200:PRINTSTR$cycle%:VDU4
OSCLI("FONT Arial,18,B")
VDU5:GCOL0,9
MOVE-70,100:PRINT"Press"
MOVE-120,50:PRINT"any key to"
MOVE-70,0:PRINT"begin"
VDU4
g%=GET
ENDPROC

User avatar
hellomike
Posts: 55
Joined: Sat 09 Jun 2018, 09:47

Re: Brandt-Daroff

Post by hellomike » Sun 03 Nov 2019, 08:53

Nice combination of graphics, GUI and speech!

You might want to add a WAIT somewhere though as the program takes a huge chunk of the CPU!

Regards,

Mike

KenDown
Posts: 91
Joined: Wed 04 Apr 2018, 06:36

Re: Brandt-Daroff

Post by KenDown » Sat 09 Nov 2019, 01:19

Thanks for the suggestion. Do you mean that if I have WAIT 100 instead of repeatedly reading TIME$ the program will use fewer CPU cycles? Hmmm. An interesting thought; I thought that WAIT itself used the CPU to count down and as the program couldn't do anything else during that time, it was best avoided. For example, the speech would take variable amounts of time and if it was followed by a WAIT the program is, effectively, hung up and will get the timing wrong.

User avatar
hellomike
Posts: 55
Joined: Sat 09 Jun 2018, 09:47

Re: Brandt-Daroff

Post by hellomike » Sat 09 Nov 2019, 09:34

Hi,

No, no, WAIT 0 will be enough.
For example, the current program takes about 14% of the processor while running but when I add one line like this:

Code: Select all

        REPEAT
          .......
          WAIT 0
        UNTILadvance%
It only takes 0.1% processor time!

Hope this helps.

Mike

RichardRussell
Posts: 94
Joined: Tue 15 Oct 2019, 09:10

Re: Brandt-Daroff

Post by RichardRussell » Sat 09 Nov 2019, 14:09

KenDown wrote:
Sat 09 Nov 2019, 01:19
I thought that WAIT itself used the CPU to count down and as the program couldn't do anything else during that time, it was best avoided.
It's the absence of a WAIT that must be avoided. Every program should have a WAIT (or INPUT, or GET or an equivalent way of telling the OS that it hasn't anything urgent to do) otherwise it will use 100% CPU time (of the current core) and potentially result in excess heat generation, short battery life and other programs running more slowly than they could. If enough programs did that it would help destroy the planet! :cry:

It's a pity that the use of WAIT (etc.) isn't enforced. In some languages (Liberty BASIC is an example) WAIT is an essential pre-requisite for any events to be processed, and without it your program typically won't run properly, so omitting it 'by accident' is less likely. Because of BBC BASIC's origins, way back when computers weren't capable of multi-tasking, WAIT is 'optional' in the sense that a program may appear to work correctly without it. It is nevertheless very important.
My posts are moderated; if you are seeing this it has already been approved. If you have a comment about the style or tone of the message please report it to the moderators by clicking the exclamation mark icon rather than complaining on the public forum.

KenDown
Posts: 91
Joined: Wed 04 Apr 2018, 06:36

Re: Brandt-Daroff

Post by KenDown » Sat 09 Nov 2019, 18:19

Hmmmm. Very interesting! The trouble is that, as I am sure you are aware, GET or INKEY doesn't really work in the Windows environment. I have tried using GET when debugging a program and I can tap any key on the keyboard till kingdom come and the program simply doesn't recognise that a key has been pressed (and clicking on the window to try and ensure that it has the keyboard focus doesn't appear to help). A negative INKEY is the only reliable way of detecting a keypress in a Windows program and that, of course, wouldn't spare the CPU or the planet! WAIT, though doubtless useful, is no help if I don't know in advance how long it will be until a key is pressed.

As for other programs being affected by its absence, in the case of the program under discussion, nothing else is running on the computer as both it and I are fully occupied in helping my wife up and down as she carries out the exercise.

Revisiting the Help file, I notice that WAIT 0 is recommended to give other programs a chance at the CPU. I'll try and remember that.

KenDown
Posts: 91
Joined: Wed 04 Apr 2018, 06:36

Re: Brandt-Daroff

Post by KenDown » Sat 09 Nov 2019, 18:21

Thanks, Mike. Careless of me, but I wasn't aware of the WAIT 0 thing. I only just discovered it when I re-read the Help file while replying to Richard.

I'm particularly grateful for your figures for how much CPU time is taken. I shall have to incorporate that into my programming.

One lives and learns!

RichardRussell
Posts: 94
Joined: Tue 15 Oct 2019, 09:10

Re: Brandt-Daroff

Post by RichardRussell » Sat 09 Nov 2019, 20:18

KenDown wrote:
Sat 09 Nov 2019, 18:19
The trouble is that, as I am sure you are aware, GET or INKEY doesn't really work in the Windows environment.
On the contrary, I would say they work perfectly in the 'Windows environment' and huge numbers of BBC BASIC programs wouldn't run if they didn't. What I presume you mean is that they only work when the 'input focus' (i.e. the window to which keyboard and mouse input is sent) is BB4W's default output window. If you have created one or more other windows in your program, and one of those windows has the focus, then your keystrokes won't then be picked up by GET or INKEY.
I have tried using GET when debugging a program and I can tap any key on the keyboard till kingdom come and the program simply doesn't recognise that a key has been pressed (and clicking on the window to try and ensure that it has the keyboard focus doesn't appear to help).
Giving BB4W's output window the input focus definitely should work. You could of course devise a program which keeps forcing the focus to another window, or which blocks the output window from acquiring it (certain types of window won't allow their parent to have focus).
A negative INKEY is the only reliable way of detecting a keypress in a Windows program
That's only "reliable" if you hold down the key for a certain minimum time; a normal (quick) "keypress" could still be missed.
My posts are moderated; if you are seeing this it has already been approved. If you have a comment about the style or tone of the message please report it to the moderators by clicking the exclamation mark icon rather than complaining on the public forum.

KenDown
Posts: 91
Joined: Wed 04 Apr 2018, 06:36

Re: Brandt-Daroff

Post by KenDown » Sun 10 Nov 2019, 03:13

Would a dialog box come under the heading of "another window"? I am aware that if one of the text edit boxes has the cursor, GET or INKEY won't work and merely clicking on the surround of the dialog box will not remove the cursor from the text edit box. (That, I am sure, is the fault of Windows, not of BB4W.)

RichardRussell
Posts: 94
Joined: Tue 15 Oct 2019, 09:10

Re: Brandt-Daroff

Post by RichardRussell » Sun 10 Nov 2019, 10:45

KenDown wrote:
Sun 10 Nov 2019, 03:13
Would a dialog box come under the heading of "another window"?
Certainly. Dialogue boxes are windows, as are individual dialogue controls (even a simple pushbutton is a 'window'). You move the input focus from control to control using Tab and Shift+Tab, and there is usually a visual indication that a control has the focus. Indeed 'modal' dialogue boxes block their parent window from acquiring focus (you must have noticed that clicking on a dialogue box's parent often results in a 'you can't do that' warning sound and flashing title bar).
clicking on the surround of the dialog box will not remove the cursor from the text edit box. (That, I am sure, is the fault of Windows, not of BB4W.)
Whether BB4W (i.e. the relevant library) or Windows is responsible for that behaviour would require some investigation. If you are saying that the caret continues to flash, implying that keyboard input will be accepted - but in fact it isn't - that is arguably an unhelpful behaviour.
My posts are moderated; if you are seeing this it has already been approved. If you have a comment about the style or tone of the message please report it to the moderators by clicking the exclamation mark icon rather than complaining on the public forum.

Post Reply