Home » Personal collection » Acorn ADFS disks » Archimedes » RiscOs_Apps_2.ADF » !Maestro/!RunImage
!Maestro/!RunImage
This website contains an archive of files for the Acorn Electron, BBC Micro, Acorn Archimedes, Commodore 16 and Commodore 64 computers, which Dominic Ford has rescued from his private collection of floppy disks and cassettes.
Some of these files were originally commercial releases in the 1980s and 1990s, but they are now widely available online. I assume that copyright over them is no longer being asserted. If you own the copyright and would like files to be removed, please contact me.
Tape/disk: | Home » Personal collection » Acorn ADFS disks » Archimedes » RiscOs_Apps_2.ADF |
Filename: | !Maestro/!RunImage |
Read OK: | ✔ |
File size: | 173C0 bytes |
Load address: | FFFFFB41 |
Exec address: | 666169DF |
Duplicates
There are 8 duplicate copies of this file in the archive:
- Personal collection » Acorn ADFS disks » Archimedes » Dominic_1.ADF » !Maestro/!RunImage
- Personal collection » Acorn ADFS disks » Archimedes » Dominic_1B.ADF » !Maestro/!RunImage
- Personal collection » Acorn ADFS disks » Archimedes » RiscOs_Apps_2.ADF » !Maestro/!RunImage
- Personal collection » Acorn ADFS disks » Greaseweazled » adfs_1.6M_Apps1.adf » Apps/!Maestro/!RunImage
- Personal collection » Acorn ADFS disks » Greaseweazled » adfs_Dominic_1.adf » !Maestro/!RunImage
- Personal collection » Acorn ADFS disks » Greaseweazled » adfs_Dominic_1B.adf » !Maestro/!RunImage
- Personal collection » Acorn ADFS disks » Greaseweazled » adfs_RiscOs_Apps_2.adf » !Maestro/!RunImage
- Personal collection » Acorn hard disk » apps » !Maestro » !RunImage
- Personal collection » Acorn hard disk » zipped_disks » 2000_apps_1 » apps1/Apps/!Maestro/!RunImage
File contents
10REM > Music.Maestxt 20REM (c) Acorn Computers 1988 30 40VersionStr$="1.65 (4-Jan-89)" 50 60Task_h%=0 70MusicFileType%=&AF1 80INITIALISED%=FALSE 90DIM ERRBLOCK% 200 100REM space for an error window 110SPACE%=HIMEM-END :REM check enough space available 120IF SPACE%<100000 STOP 130REMdebug=OPENOUT "debugfile" 140ON ERROR PROCerror:END 150REM get name of file to load 160SYS "OS_GetEnv" TO EnvStr$ 170IF INSTR(EnvStr$," -quit ") THEN 180 I%=INSTR(EnvStr$,"""") 190 I%=INSTR(EnvStr$,"""",I%+1) 200 REPEATI%+=1:UNTILMID$(EnvStr$,I%,1)<>" " 210 f$=MID$(EnvStr$,I%) 220 ENDIF 230INITIALISED%=FNinitialise 240mask%=0 : REM mask out unwanted reason codes 250ON ERROR PROCerror 260REPEAT 270 IF PLAYING% PROCCheckQ 280 SYS Poll%,mask%,Window%+handle% TO R% 290 IF PLAYING% PROCCheckQ: REM recheck since poll might have stayed away for a while 300 CASE R% OF 310 WHEN 0 320 IF AwaitingAck% IFFNCheckOK("Bad Data Transfer, Receiver Dead",3) :AwaitingAck%=FALSE : CHANGED%=wasCHANGED% 330 IF SCORING% PROCsymbol_pointer 340 IF f$<>"" PROCload_music(f$) : f$="" 350 IF SCROLLING% PROCCheckScroll :REM auto-scrolling 360 WHEN 1:PROCredraw_window_request 370 WHEN 2:PROCopen_window_request 380 WHEN 3:PROCclose_window_request 390 WHEN 4 :REM pointer leaving window 400 IF Window%!handle%=ScoreWind_h% THEN 410 PROCrelease 420 wasSCORING%=SCORING% 430 SCORING%=FALSE 440 ELSE 450 IF Window%!handle%=AbortQuery_h% PROCCloseWindow(AbortQuery_h%) 460 ENDIF 470 WHEN 5: IF Window%!handle%=ScoreWind_h% SCORING% = (wasSCORING% AND NOT stopSCORING%)=TRUE 480 WHEN 6:PROCmouse_button_click 490 WHEN 7:PROCUserDragBox 500 WHEN 8:PROCKeyPressed 510 WHEN 9:PROCMenuSelect 520 WHEN 10: PROCScrollReq(Window%!(handle%+32), Window%!(handle%+36)) 530 WHEN 17,18:PROCreceive 540 ENDCASE 550 UNTIL FALSE 560END 570 580DEF PROCCheckQ 590B1%=B2%: B2%=BEAT 600IFB2%<B1% PROCplay_bar 610ENDPROC 620 630DEF PROCreceive 640LOCAL task%, ref%, block,F$ 650block=Window% :REM temporary buffer 660ref%=!(Window%+handle%+8) 670task%=!(Window%+handle%+4) 680IF task%=Task_h% ENDPROC : REM ignore messages from this task 690CASE Window%!(handle%+16) OF 700 WHEN 0 710 IF NOT CHANGED% THEN 720 PROCterminate 730 ELSE 740 !block=20 750 block!12=ref% 760 block!16=0 :REM quit block 770 SYS SendMessage,19,block :REM acknowledge, and refuse quit request 780 IF FNCheckOK("Unsaved music. Do you really want to quit?",3) THEN 790 PROCterminate 800 ELSE 810 SYS GetPointerInfo%,,Mouse% 820 PROCOpenWindow(Save_h%, Mouse%!x0%, Mouse%!y0%) 830 ENDIF 840 ENDIF 850 WHEN 2 : REM save file 860 IF SAVING% THEN 870 wasCHANGED%=CHANGED% 880 PROCsave_music(FNGetStr(Window%+handle%+44)) 890 SAVING%=FALSE 900 SYS GetPointerInfo%, ,block 910 block!20=block!12 920 block!24=block!16 930 block!28=block!0 940 block!32=block!4 950 block!0=44 960 block!12=ref% 970 block!16=3 :REM DataLoad application to filer 980 block!40=MusicFileType% 990 SYS SendMessage,17,block 1000 AwaitingAck%=TRUE 1010 PROCCloseMenu 1020 ENDIF 1030 WHEN 3 : REM load file 1040 PROCload_music(FNGetStr(Window%+handle%+44)) 1050 PROCDataLoadAck(ref%) 1060 WHEN 4 :AwaitingAck%=FALSE : REM DataLoadAck. End of DataSave protocol 1070 WHEN 5 : REM open double-clicked file 1080 IF !(Window%+handle%+40) = MusicFileType% THEN 1090 PROCload_music(FNGetStr(Window%+handle%+44)) 1100 PROCDataLoadAck(ref%) 1110 ENDIF 1120 WHEN &502:PROCHelp(ref%) 1130 WHEN &400C1:PROCgetmodeinfo(FALSE) 1140 ENDCASE 1150ENDPROC 1160 1170DEF PROCHelp(ref%) 1180LOCAL block%,text$ 1190block%=Window%+handle% 1200block%!12 = ref% 1210block%!16 = &503 :REM Send help message 1220text$="" 1230CASE block%!32 OF 1240 WHEN -2 : text$="This is the Maestro icon.|MClick SELECT to open score." 1250 WHEN ScoreWind_h% 1260 IFSCORING%ANDSCRIBE%(drawn%) THEN 1270 text$="Click SELECT to place item in score" 1280 ELSE 1290 text$="Select an item in a pane to place on the score" 1300 ENDIF 1310 WHEN NotesPane_h% 1320 text$="Click SELECT to select a " 1330 CASE block%!36 OF 1340 WHEN 0 : text$=text$+"breve." 1350 WHEN 1 : text$=text$+"semibreve." 1360 WHEN 2 : text$=text$+"minim." 1370 WHEN 3 : text$=text$+"crochet." 1380 WHEN 4 : text$=text$+"quaver." 1390 WHEN 5 : text$=text$+"semiquaver." 1400 WHEN 6 : text$=text$+"demisemiquaver." 1410 WHEN 7 : text$=text$+"hemidemisemiquaver." 1420 OTHERWISE text$="" 1430 ENDCASE 1440 WHEN SharpsPane_h% 1450 text$="Click SELECT to select a " 1460 CASE block%!36 OF 1470 WHEN 0 : text$=text$+"natural." 1480 WHEN 1 : text$=text$+"sharp." 1490 WHEN 2 : text$=text$+"flat." 1500 WHEN 3 : text$=text$+"double-sharp." 1510 WHEN 4 : text$=text$+"double-flat." 1520 WHEN 5 : text$=text$+"naturalised sharp." 1530 WHEN 6 : text$=text$+"naturalised flat." 1540 WHEN 7 : text$=text$+"dot." 1550 WHEN 8 : text$=text$+"double-dot." 1560 WHEN 9 : text$=text$+"triple-dot." 1570 WHEN 10 : text$=text$+"tie." 1580 WHEN 11 : text$=text$+"bar line." 1590 WHEN 12 : text$=text$+"treble clef." 1600 WHEN 13 : text$=text$+"bass clef." 1610 WHEN 14 : text$=text$+"key signature." 1620 WHEN 15 : text$=text$+"time signature." 1630 OTHERWISE text$="" 1640 ENDCASE 1650 WHEN RestsPane_h% 1660 text$="Click SELECT to select a " 1670 CASE block%!36 OF 1680 WHEN 0 : text$=text$+"breve rest." 1690 WHEN 1 : text$=text$+"semibreve rest." 1700 WHEN 2 : text$=text$+"minim rest." 1710 WHEN 3 : text$=text$+"crochet rest." 1720 WHEN 4 : text$=text$+"quaver rest." 1730 WHEN 5 : text$=text$+"semiquaver rest." 1740 WHEN 6 : text$=text$+"demisemiquaver rest." 1750 WHEN 7 : text$=text$+"hemidemisemiquaver rest." 1760 OTHERWISE text$="" 1770 ENDCASE 1780 WHEN InstrWind_h% 1790 IF (block%!36>7) THEN 1800 IF (block%!36<16) THEN 1810 text$="Click SELECT or ADJUST to select an instrument for this stave" 1820 ELSE 1830 IF (block%!36<24) THEN 1840 text$="Click SELECT or ADJUST to set the volume of this channel" 1850 ELSE IF (block%!36<32) text$="Click SELECT or ADJUST to set the stereo position of this channel" 1860 ENDIF 1870 ENDIF 1880 ENDIF 1890 WHEN Save_h% 1900 IF block%!36=2 text$="Drag this icon into a directory window to save it in that directory" ELSE text$="Fill in the file name and then drag the icon into a filer directory window to save it" 1910 WHEN TimeSig_h% 1920 text$="use SELECT and ADJUST on each field to set a time signature" 1930 WHEN AbortQuery_h% 1940 text$="click YES to terminate Maestro" 1950 ENDCASE 1960$(block%+20)=text$ 1970block%!0 = (((20+LEN(text$)+1)DIV4)*4)+4 1980$(block%+21+LEN(text$)) = CHR$(0) :REM null-terminate 1990SYS SendMessage,17,block% :REM acknowledge message 2000ENDPROC 2010 2020DEF PROCDataLoadAck(ref%) 2030LOCAL block 2040block=Window% 2050block!0 = 20 2060block!12 = ref% 2070block!16 = 4 :REM DataLoadAck 2080SYS SendMessage,17,block :REM acknowledge message 2090ENDPROC 2100 2110DEF PROCredraw_window_request 2120LOCAL R% 2130SYS RedrawWindow%,,Window%+handle% TO R% 2140WHILE R% 2150 IF Window%!handle% = ScoreWind_h% PROCdraw_staves:IF PLAYING% PROCCheckQ 2160REM try to avoid interruptions in the music 2170 SYS GetRectangle%,,Window%+handle% TO R% 2180 ENDWHILE 2190ENDPROC 2200 2210DEF PROCplace_top_panes(behind) 2220LOCAL xsize% 2230xsize%=Window%!x1%-Window%!x0% 2240RestPBlk%!x1%=Window%!x1% 2250RestPBlk%!x0%=Window%!x0%+xsize%/2 2260RestPBlk%!y1%=Window%!y1% 2270RestPBlk%!y0%=RestPBlk%!y1%-PaneHeight% 2280RestPBlk%!under%=behind 2290SYS OpenWindow%, RestsPane_h%, RestPBlk%+handle% 2300NotePBlk%!x0%=Window%!x0% 2310NotePBlk%!x1%=RestPBlk%!x0% 2320NotePBlk%!y1%=Window%!y1% 2330NotePBlk%!y0%=NotePBlk%!y1%-PaneHeight% 2340NotePBlk%!under%=RestsPane_h% 2350SYS OpenWindow%, NotesPane_h%, NotePBlk%+handle% 2360ENDPROC 2370 2380DEF PROCplace_bottom_panes(behind) 2390LOCAL xsize% 2400xsize%=Window%!x0%+Window%!x1% 2410SharpPBlk%!x0%=Window%!x0% 2420SharpPBlk%!x1%=SharpPBlk%!x0%+xsize% 2430SharpPBlk%!x1%=Window%!x1% 2440SharpPBlk%!y0%=Window%!y0% 2450SharpPBlk%!y1%=SharpPBlk%!y0%+PaneHeight% 2460SharpPBlk%!under%=behind 2470SYS OpenWindow%, SharpsPane_h%, SharpPBlk%+handle% 2480ENDPROC 2490 2500DEF PROCremove_panes 2510PROCCloseWindow(NotesPane_h%) 2520PROCCloseWindow(SharpsPane_h%) 2530PROCCloseWindow(RestsPane_h%) 2540ENDPROC 2550 2560DEF PROCopen_window_request 2570LOCAL bhandle% 2580bhandle%=Window%!under% 2590PROCrelease 2600IF Window%!handle%=ScoreWind_h% THEN 2610 IF TRANSCRIBE% THEN 2620REM define window stack as top->bottom sharpspane->restspane->notespane->score 2630REM open top or bottom panes before score depending on direction of drag 2640 SYS GetWindowState%,,SharpPBlk%+handle% 2650 IF SharpPBlk%!under%=bhandle% Window%!under%=NotesPane_h% 2660 SYS GetWindowState%,,ScoreWBlk%+handle% 2670 IF Window%!y1%>ScoreWBlk%!y1% THEN 2680 PROCplace_top_panes(bhandle%) 2690 ELSE 2700 PROCplace_bottom_panes(bhandle%) 2710 ENDIF 2720 ENDIF 2730 IF PLAYING% AND Window%!scx%<>ScoreWBlk%!scx% ENDPROC:REM no user-scrolling while playing 2740 SYS OpenWindow%,,Window%+handle% 2750 ScoreClosed%=FALSE 2760 IF TRANSCRIBE% THEN 2770 IF bhandle%=-2 THEN 2780 REM find behind handle% if pushed to the back 2790 SYS GetWindowState%,,ScoreWBlk%+handle% 2800 bhandle% = ScoreWBlk%!under% 2810 ENDIF 2820 REM re-open all panes 2830 PROCplace_bottom_panes(bhandle%) 2840 PROCplace_top_panes(SharpsPane_h%) 2850 IF bhandle%=ScoreWind_h% SYS OpenWindow%,,Window%+handle% :REM ensure window is behind panes in unusual case 2860 ENDIF 2870 LHBAR%=FNFindBar(ScoreWBlk%!scx%) :REM the bar number at the left of the window 2880 ELSE 2890 SYS OpenWindow%,,Window%+handle% 2900 ENDIF 2910ENDPROC 2920 2930DEF PROCclose_window_request 2940SYS CloseWindow%,,Window%+handle% 2950IF Window%!handle%=ScoreWind_h% PROCremove_panes : ScoreClosed%=TRUE 2960ENDPROC 2970 2980DEF PROCmouse_button_click 2990LOCALB%,C%,W%,I%,inc% 3000W%=Mouse%!window:I%=Mouse%!icon 3010B%=%111ANDMouse%!buttons 3020Mouse_X%=Mouse%!x0%:Mouse_Y%=Mouse%!y0% 3030IF B%=%010 THEN 3040 PROCCheckInstalledVoices 3050 PROCStopScoring 3060 IF W%=-2 PROCOpenMenu(IconMenu%) ELSE PROCOpenMainMenu 3070ELSE 3080IF B%=%100 inc%=-1 ELSE IF B%=%001 inc%=1 ELSE inc%=0 3090CASE W% OF 3100WHEN -2 : IF ScoreClosed% OR NOT PLAYING% PROCsetup_staves:ENDPROC :REM iconbar 3110WHEN AbortQuery_h% 3120 IF I%=2 THEN 3130 PROCterminate 3140 ELSE 3150 PROCCloseMenu 3160 PROCCloseWindow(AbortQuery_h%) 3170 ENDIF 3180WHEN NotesPane_h% 3190 IF I%>=0 THEN 3200 PROCrelease 3210 wasSCORING%=TRUE 3220 stopSCORING%=FALSE 3230 PROCUpdateIcon(SelW%, SelI%, 0, 1<<2) 3240 PROCUpdateIcon(W%, I%, 1<<2, 0) 3250 SelW%=W% 3260 SelI%=I% 3270 PROCattach(note%+I%,%111000) 3280 ENDIF 3290WHEN RestsPane_h% 3300 IF I%>=0 THEN 3310 PROCrelease 3320 wasSCORING%=TRUE 3330 stopSCORING%=FALSE 3340 PROCUpdateIcon(SelW%, SelI%, 0, 1<<2) 3350 PROCUpdateIcon(W%, I%, 1<<2, 0) 3360 SelW%=W% 3370 SelI%=I% 3380 PROCattach(rest%+I%,%11000) 3390 ENDIF 3400WHEN SharpsPane_h% 3410 IF I%>=0 THEN 3420 PROCrelease 3430 wasSCORING%=TRUE 3440 stopSCORING%=FALSE 3450 PROCUpdateIcon(SelW%, SelI%, 0, 1<<2) 3460 PROCUpdateIcon(W%, I%, 1<<2, 0) 3470 SelW%=W% 3480 SelI%=I% 3490 IF I%<7 PROCattach(accidental%+I%+1,%1100000) ELSEIF I%<11 PROCattach(dot%+I%-6,%1101000) 3500 IF I%=10 PROCattach(tie%,%1101000) 3510 IF I%=11 PROCattach(bar%,%10010000) 3520 IF I%=12 PROCattach(clef%,%100) :REM Treble clef 3530 IF I%=13 PROCattach(clef%+3,%100):REM Bass clef 3540 IF I%=14 PROCattach(key%,%10) :REM key signature 3550 IF I%=15 PROCattach(time%,%1) :REM time signature 3560 ENDIF 3570WHEN ScoreWind_h% 3580 IF B%=%100 IFSCORING%ANDSCRIBE%(drawn%) PROCput_down 3590WHEN InstrWind_h% 3600 LOCAL chan%, v% 3610 PROCCheckInstalledVoices 3620 PROCStopScoring 3630 IF I%>=8 THEN 3640 chan%=I%-8 3650 IF chan%<8 THEN 3660 v%=FNAttachVoice(chan%, inc%) 3670 SYS Sound_AttachVoice, chan%+1, v% 3680 $(VoiceStr%(chan%))=LEFT$(Voice$(v%), VoiceSize%) 3690 Instrument%(chan%,1) = v% 3700 PROCUpdateIcon(W%, I%, 0,0) 3710 ELSE 3720 chan%-=8 3730 IF chan%<8 THEN 3740 v%=Volumes%(chan%) 3750 v%+=inc% : IF v%>NVolumes% v%=NVolumes% ELSEIF v%<0 v%=0 3760 Volumes%(chan%)=v% 3770 $(VolumeStr%(chan%))=LEFT$(Volume$(Volumes%(chan%)), VolSize%) 3780 PROCUpdateIcon(W%, I%, 0,0) 3790 ELSE 3800 chan%-=8 3810 IF chan%<8 THEN 3820 v%=Stereo_Position%(chan%) 3830 v%+=inc% : IF v%>NStereos% v%=NStereos% ELSEIF v%<0 v%=0: REM no wrap 3840 Stereo_Position%(chan%)=v% 3850 SYS Sound_Stereo,chan%+1,Stereo%(Stereo_Position%(chan%)) 3860 $(StereoStr%(chan%)) = LEFT$(Stereo$(Stereo_Position%(chan%), 0), SterSize%) 3870 PROCUpdateIcon(W%, I%, 0,0) 3880 ELSE 3890 IF MIDIpresent% THEN 3900 chan%-=8 3910 IF chan%<8 THEN 3920 v%=MIDIChannel%(chan%) 3930 v%+=inc% : IF v%>NMIDIChannels% v%=1 ELSEIF v%<1 v%=NMIDIChannels% 3940 MIDIChannel%(chan%)=v% 3950 $(MIDIChStr%(chan%)) = STR$(MIDIChannel%(chan%)) 3960 PROCUpdateIcon(W%, I%, 0,0) 3970 ENDIF 3980 ENDIF 3990 ENDIF 4000 ENDIF 4010 ENDIF 4020 ENDIF 4030WHEN Save_h% 4040 PROCStopScoring 4050 IF I%=0 PROCsave_music(FNGetStr(SaveText)) : REM 0 is OK. 4060 IF I%=2 THEN 4070 LOCAL x%, y% : REM dragging icon 4080 Window%!handle%=W% 4090 SYS GetWindowState%,,Window%+handle% 4100 ysize%=Window%!y1%-Window%!y0% 4110 x%=Window%!x0% 4120 y%=Window%!y0% 4130 !Window% = W% 4140 Window%!4 = I% 4150 SYS GetIconInfo%, ,Window% : REM returns icon box in right place for drag box 4160 Window%!8 += x% 4170 Window%!12 += y% + ysize% 4180 Window%!16 += x% 4190 Window%!20 += y% + ysize% 4200REM get size in appropriate part of block: parent box=screen boundary 4210 Window%!24 = 0 4220 Window%!28 = 0 4230 Window%!32 = S_Width% 4240 Window%!36 = S_Height% 4250 !Window%=0 4260 Window%!4=5: REM fixed size drag box 4270 SAVING%=TRUE 4280 DRAGGING%=TRUE 4290 SYS DragBox, ,Window% 4300 ELSE 4310 PROCCloseWindow(Save_h%) 4320 PROCCloseMenu 4330 ENDIF 4340WHEN Load_h% 4350 PROCStopScoring 4360 IF I%=0 PROCload_music(FNGetStr(LoadText)) : REM 0 is OK. 4370 PROCCloseWindow(Load_h%) 4380 PROCCloseMenu 4390WHEN TimeSig_h% 4400 CASE I% OF 4410 WHEN 0 4420 TIME_SIG%(0)=1+(TIME_SIG%(0)+inc%+14)MOD15 4430 $BarLength%=STR$(TIME_SIG%(0)+1) 4440 WHEN 1 4450 TIME_SIG%(1)=(TIME_SIG%(1)-inc%)MOD4+2 4460 $NoteValue%=STR$(1<<(TIME_SIG%(1)-1)) 4470 ENDCASE 4480 IF I%=0 OR I%=1 PROCUpdateIcon(W%,I%,0,0) 4490ENDCASE 4500ENDIF 4510ENDPROC 4520 4530DEF PROCCheckInstalledVoices 4540LOCAL NewVoice$, NewNVoices%, changedVoices% 4550changedVoices%=FALSE 4560SYS Sound_InstallVoice TO I$,NewNVoices%:NewNVoices%-=1 4570IF FNassert(NVoices%>0,"No sound voices are installed.") STOP 4580IF MIDIpresent% NewNVoices%+=1:Voice$(NewNVoices%)="":REM allow a NULL voice to permit just MIDI on this channel 4590IF NewNVoices%<>NVoices% THEN 4600 changedVoices%=TRUE 4610 NVoices%=NewNVoices% 4620 ENDIF 4630IF NVoices%>MAX_Voices% NVoices%=MAX_Voices% 4640FORR%=1TONVoices% 4650IF (MIDIpresent% AND R%=NVoices%) THEN 4660 Voice$(R%)="" 4670ELSE 4680 SYS Sound_InstallVoice,0,R% TO NewVoice$ 4690 IF NewVoice$<>Voice$(R%) THEN 4700 changedVoices%=TRUE 4710 Voice$(R%)=NewVoice$ 4720 ENDIF 4730 ENDIF 4740NEXT:REM find if instruments have changed 4750IF NOT changedVoices% ENDPROC 4760FORR%=0TO7 4770SYS Sound_AttachVoice,R%+1,0 TO L%,S% 4780IFS%<1ORS%>NVoices% S%=1:REM Make sure a voice is attached to all channels 4790SYS Sound_AttachVoice,L%,S% 4800Instrument%(R%,0)=S_C%(R%)+1:REM Instrument stave 4810Instrument%(R%,1)=S%:REM Instrument voice 4820$(VoiceStr%(R%)) = LEFT$(Voice$(S%), VoiceSize%) 4830PROCUpdateIcon(InstrWind_h%, R%+8, 0,0) 4840NEXT:REM Get details of each channel 4850PROCSetDefaultChannels 4860ENDPROC 4870 4880DEF FNAttachVoice(chan%,inc%) :REM inc% is +1 or -1 or 0 to find nearest 4890LOCAL stop%,v%,perc% 4900PROCCheckInstalledVoices 4910IF NVoices%<2 SYS Sound_AttachVoice, chan%+1, 1 : =1 4920REM attach next voice to channel. Attach percussion voice only on perc line, and not on stave lines 4930perc%=(INSTR($StaveStr%(chan%),"perc")>0) :REM is it a percussion channel? 4940SYS Sound_AttachVoice, chan%+1 TO , v% 4950IF v%=0 v%=1 4960SYS Sound_AttachVoice, chan%+1, v% :REM restore it 4970REM check if current voice is valid for this channel 4980IF inc%=0 THEN IF (perc% = (INSTR(Voice$(v%),"Perc")>0)) THEN =v% 4990REM inc or dec until found 5000IF ABS(inc%)<>1 THEN inc%=1 5010stop%=v% 5020REPEAT 5030 v%+=inc% : IF v%>NVoices% v%=1 ELSEIF v%<1 v%=NVoices% 5040 IF MIDIpresent% AND Voice$(v%)="" stop%=v% :REM permit NULL voice on any channel if MIDI installed 5050 UNTIL (perc% = (INSTR(Voice$(v%),"Perc")>0)) OR stop%=v% 5060=v% 5070 5080DEF PROCUpdateIcon(W%, I%, st%, msk%) 5090Window%!handle%=W%:!Icon%=I% 5100Icon%!state=st%:Icon%!mask=msk% 5110SYS SetIconState%,,Window%+handle% : REM update icon text 5120ENDPROC 5130 5140DEF PROCUserDragBox 5150LOCAL block 5160DRAGGING%=FALSE 5170block=Window% :REM temporary buffer 5180IF SAVING% THEN 5190 SYS GetPointerInfo%, ,block 5200 block!32=block!4 5210 block!28=!block 5220 block!24=block!16 5230 block!20=block!12 : REM this is the destination window handle% 5240 block!16=1 : REM DataSave 5250 block!12=0 5260 block!36=0 :REM don't know file size 5270 block!40=MusicFileType% 5280 $(block+44)=FNGetLeafName(SaveText) 5290 !block = 60 5300 SYS SendMessage, 17, block, block!20 5310 ENDIF 5320ENDPROC 5330 5340DEF FNSetBit(test, word, bitnum) : REM set or clear bit depending on test 5350IF test THEN 5360 = word OR (1<<bitnum) 5370ELSE 5380 = word AND NOT (1<<bitnum) 5390ENDIF 5400 5410DEF PROCMenuSelect 5420LOCAL item%, n, selection, SoundEnable%,F$ 5430selection=Window%+handle% 5440SYS DecodeMenu, ,CurrentMenu%, selection, MenuString 5450CASE LEFT$($MenuString,INSTR($MenuString, ".")-1) OF 5460 WHEN "Save" 5470 F$=FNGetStr(SaveText) 5480 IF ( INSTR(F$,".")=0 AND INSTR(F$,":")=0 ) THEN 5490 PROCOpenWindow(Save_h%, Mouse_X%, Mouse_Y%) 5500 ELSE 5510 PROCsave_music(F$) 5520 ENDIF 5530 WHEN "Staves" 5540 SYS "Hourglass_On" 5550 IF LEFT$($StaveNum%,1)="" $StaveNum%="1" 5560 STAVE%=VAL(LEFT$($StaveNum%,1))-1 5570 IF INSTR($MenuString,"+perc",6) THEN 5580 IF PERC%=1 PERC%=0 ELSE PERC%=1 5590 ENDIF 5600 item% = FNFindMenuItem("+percussion", StaveMenu%) 5610 IF (item%>=0) !item% = FNSetBit(PERC%=1, !item%, 0):REM set or clear tick 5620 PROCsetup_score 5630 PROCstart_music 5640 PROCrescore(0) 5650 SYS "Hourglass_Off" 5660 WHEN "Instruments" : PROCOpenWindow(InstrWind_h%,Mouse_X%,Mouse_Y%) 5670 WHEN "Volume" 5680 IF selection!4>=0 THEN 5690 PROCSetVolume(selection!4) 5700 PROCSetMenuTick(VolumeMenu%, selection!4) 5710 ENDIF 5720 WHEN "Tempo" 5730 IF selection!4>=0 THEN 5740 PROCSetTempo(selection!4) 5750 PROCSetMenuTick(TempoMenu%, selection!4) 5760 ENDIF 5770 WHEN "Time sig" : TIME_SIG%(0)=VAL($BarLength%)-1 5780 WHEN "Key sig" 5790 IF selection!4>=0 THEN 5800 KEY_SIG%(0) = ((selection!8)>=7)+1 5810 KEY_SIG%(1) = ABS((selection!8)-7) 5820 PROCSetMenuTick(MajorMenu%, selection!8) 5830 PROCSetMenuTick(MinorMenu%, selection!8) 5840 IF KEY_SIG%(1) n=accidental%+2+KEY_SIG%(0) : X%(key%)=(x%(n)+X%(n))*KEY_SIG%(1) ELSE X%(key%)=x%(accidental%+2)+X%(accidental%+2) 5850 ENDIF 5860 WHEN "Play" 5870 SYS Sound_Enable,0 TO SoundEnable%:REM dont pretend to be able to play if the sound system is disabled 5880 IF SoundEnable%=2 THEN 5890 SCORING%=FALSE 5900 PLAYING%=NOT PLAYING% 5910 SCROLLING%=PLAYING% 5920 IF PLAYING% PROCplay_start ELSE PROCplay_stop 5930 ELSE n=FNCheckOK("Sound is not enabled. You cannot play", 1) 5940 ENDIF 5950 WHEN "Clear" 5960 IF CHANGED% IF NOT FNCheckOK("Are you sure? Current music is unsaved",3) ENDPROC 5970 PROCClearAllMusic 5980 Window%!handle%=ScoreWind_h% 5990 SYS GetWindowState%,,Window%+handle% 6000 Window%!scx%=0 6010 LHBAR%=0 6020 SYS OpenWindow%,,Window%+handle% 6030 SYS GetWindowState%,,ScoreWBlk%+handle% 6040 WHEN "Info" : PROCOpenWindow(ProgInfo_h%, Mouse_X%, Mouse_Y%) 6050 WHEN "Quit" : IF CHANGED% PROCOpenAbortQuery(Mouse_X%, Mouse_Y%) ELSE PROCterminate 6060 WHEN "Goto" 6070 Window%!handle%=ScoreWind_h% 6080 SYS GetWindowState%,,Window%+handle% 6090 Window%!scx%=0 6100 SYS OpenWindow%,,Window%+handle% : REM set scroll to 0 6110 SYS GetWindowState%,,ScoreWBlk%+handle% 6120 LHBAR%=0 :REM the bar number at the left of the window 6130 ENDCASE 6140 IF (CurrentMenu%=MenuStart) THEN 6150 SYS GetPointerInfo%,,Mouse% 6160 IF %001 AND Mouse%!buttons PROCOpenMainMenu :REM persistent menu 6170 ENDIF 6180ENDPROC 6190 6200DEF PROCSetMenuTick(menu%, this%) 6210REM set 1 tick in menu and clear all others 6220LOCAL n, item% 6230n = 0 6240item%=menu%+28 6250!item% = FNSetBit(n=this%, !item%, 0) :REM set or clear tick 6260REPEAT 6270 item% += 24 6280 n += 1 6290 !item% = FNSetBit(n=this%, !item%, 0) :REM set or clear tick 6300 UNTIL (!item% AND &80) 6310ENDPROC 6320 6330DEF PROCKeyPressed 6340LOCAL ThisWindow% 6350IF !(Window%+handle%+24)=13 THEN 6360 ThisWindow%=Window%!handle% 6370 CASE (ThisWindow%) OF 6380 WHEN Save_h% : PROCsave_music(FNGetStr(SaveText)) : REM c/r in save window 6390 WHEN Load_h% : PROCload_music(FNGetStr(LoadText)) : REM c/r in load window 6400 WHEN Bar_h% 6410 BAR%=VAL($BarNum%) 6420 IF BAR%>NBars% BAR%=NBars% ELSEIF BAR%<0 BAR%=0 6430 Window%!handle%=ScoreWind_h% 6440 SYS GetWindowState%,,Window%+handle% 6450 Window%!scx%=PX%(PXn%(BAR%)) 6460 SYS OpenWindow%,,Window%+handle% : REM set scroll to requested bar number 6470 SYS GetWindowState%,,ScoreWBlk%+handle% 6480 LHBAR%=FNFindBar(ScoreWBlk%!scx%) :REM the bar number at the left of the window 6490 OTHERWISE : SYS "Wimp_ProcessKey",!(Window%+handle%+24) : REM ie. pass on key code in R0 6500 ENDCASE 6510 PROCCloseWindow(ThisWindow%) 6520 PROCCloseMenu 6530 ELSE 6540 SYS "Wimp_ProcessKey",!(Window%+handle%+24) : REM ie. pass on key code in R0 6550 ENDIF 6560ENDPROC 6570 6580DEF PROCScrollReq(x_scroll%, y_scroll%) 6590REM if bad mode disallow scroll to prevent mode warning being garbled 6600IF BADMODE% ENDPROC 6610IF Window%!handle%=ScoreWind_h% THEN 6620 IF PLAYING%AND(x_scroll%<>0) ENDPROC 6630 CASE ABS(x_scroll%) OF 6640 WHEN 1:Window%!scx%+=x_scroll%*4*Pgap% 6650 WHEN 2:Window%!scx%+=(x_scroll%/2)*(Window%!x1%-Window%!x0%) 6660 ENDCASE 6670 CASE ABS(y_scroll%) OF 6680 WHEN 1:Window%!scy%+=y_scroll%*C_Height% 6690 WHEN 2:Window%!scy%+=(y_scroll%/2)*(Window%!y1%-Window%!y0%) 6700 ENDCASE 6710 SYS OpenWindow%, ,Window%+handle% 6720 SYS GetWindowState%,,ScoreWBlk%+handle% 6730 ScoreClosed%=FALSE 6740 LHBAR%=FNFindBar(ScoreWBlk%!scx%) :REM the bar number at the left of the window 6750 ENDIF 6760ENDPROC 6770 6780DEF PROCOpenMainMenu 6790LOCAL item% 6800item% = FNFindMenuItem("Play", MenuStart) 6810IF (item%>=0) !item% = FNSetBit(PLAYING%, !item%, 0) 6820REM set or clear tick 6830item% = FNFindMenuItem("Goto", MenuStart) 6840IF (item%>=0) item%!8 = FNSetBit(PLAYING%, item%!8, 22) 6850REM shaded bit. disable Goto when playing 6860SYS CreateMenu, ,MenuStart, Mouse_X%-C_Width%*4, Mouse_Y%+C_Height%*4 6870CurrentMenu%=MenuStart 6880PROCCloseWindow(Save_h%) 6890PROCCloseWindow(Load_h%) 6900ENDPROC 6910 6920DEF PROCOpenMenu(Menu%) 6930IF (Menu%=IconMenu%) THEN 6940 SYS CreateMenu, ,IconMenu%, Mouse_X%-C_Width%*4, 112+C_Height%*2:REM y adjusted to line up 6950ELSE 6960 SYS CreateMenu, ,Menu%, Mouse_X%-C_Width%*4, Mouse_Y%+C_Height% 6970ENDIF 6980CurrentMenu%=Menu% 6990PROCCloseWindow(Save_h%) 7000PROCCloseWindow(Load_h%) 7010ENDPROC 7020 7030DEF PROCCloseMenu 7040SYS CreateMenu, ,-1 7050PROCCloseWindow(Save_h%) 7060PROCCloseWindow(Load_h%) 7070ENDPROC 7080 7090DEF PROCsymbol_pointer 7100SYS GetPointerInfo%,,Mouse% 7110IF (Mouse%!window=ScoreWind_h%) PROCscribe(Mouse%!x0%,Mouse%!y0%) 7120ENDPROC 7130 7140DEF PROCStopScoring 7150stopSCORING%=TRUE 7160PROCrelease 7170PROCUpdateIcon(SelW%, SelI%, 0, 1<<2) :REM remove highlight on icon in pane 7180ENDPROC 7190 7200DEF PROCUpdateTitle(T$) 7210LOCAL a,b,c,d 7220$ScoreTitle%=T$+CHR$(0) 7230Window%!handle%=ScoreWind_h% 7240SYS GetWindowState%,,Window%+handle% 7250a=Window%!x0% : b=Window%!y1% : c=Window%!x1% :REM get title area and force redraw 7260SYS GetWindowOutline,,Window%+handle% 7270d=Window%!y1% 7280SYS ForceRedraw,-1,a+Hi%,b+Vi%,c-Hi%,d+Vi% 7290ENDPROC 7300 7310DEF PROCOpenWindow(h%, x%, y%) 7320LOCAL xsize%, ysize% 7330Window%!handle% = h% 7340SYS GetWindowState%, ,Window%+handle% 7350xsize%=Window%!x1%-Window%!x0% 7360ysize%=Window%!y1%-Window%!y0% 7370Window%!under%=-1 7380Window%!x0%=x% 7390Window%!x1%=Window%!x0%+xsize% 7400Window%!y0%=y% 7410Window%!y1%=Window%!y0%+ysize% 7420SYS OpenWindow%, ,Window%+handle% 7430ENDPROC 7440 7450DEF PROCCloseWindow(h%) 7460Window%!handle%=h% 7470SYS CloseWindow%, ,Window%+handle% 7480ENDPROC 7490 7500DEF PROCSetExtent(W%) 7510Score_Width%=W% 7520Window%!x0%=0 7530Window%!y0%=-Score_Height%-PaneHeight% 7540Window%!x1%=Score_Width% 7550Window%!y1%=PaneHeight% 7560SYS SetExtent,ScoreWind_h%,Window% 7570ENDPROC 7580 7590DEF FNGetLeafName(name%) :REM returns leaf name 7600LOCAL ch$,n%,name$ 7610name$=FNGetStr(name%) 7620IF ( (INSTR(name$,".")=0) AND (INSTR(name$,":")=0) ) THEN=name$ 7630n%=LEN(name$) 7640REM scan string to find leaf name of file 7650REPEAT 7660 ch$= MID$(name$, n%, 1) 7670 n%-=1 7680 UNTIL (n%<=0 OR ch$="." OR ch$=":") 7690IF n%>0 THEN =RIGHT$(name$, LEN(name$)-n%-1) 7700 7710DEF FNGetStr(s%) : REM get string 7720LOCAL n$ 7730WHILE?s%:n$+=CHR$?s%:s%+=1:ENDWHILE 7740=n$ 7750 7760DEF PROCSetVolume(R%) 7770SYS Sound_Volume,Volume%(R%) 7780ENDPROC 7790 7800DEF PROCSetDefaultChannels 7810LOCALS%,P% 7820REM only 1 percussion channel permitted now 7830FORS%=0TO7:S_C%(S%)=Stave_Channels%(STAVE%,S%):NEXT:REM Channel assignment changes if staves change 7840IF PERC% S_C%(7)=STAVE%+1:REM Steal channel for percussion lines 7850FORS%=0TO7 7860Instrument%(S%,0)=S_C%(S%)+1 7870$StaveStr%(S%)=Nth$(Instrument%(S%,0)+(STAVE%-3)*((Instrument%(S%,0)-1)>STAVE%))+";" :REM set up stave names in instrument wimdow 7880PROCUpdateIcon(InstrWind_h%,S%,0,0) :REM update text in icons 7890v%=FNAttachVoice(S%,0) 7900SYS Sound_AttachVoice,S%+1,v% 7910$(VoiceStr%(S%))=LEFT$(Voice$(v%), VoiceSize%) 7920Instrument%(S%,1) = v% 7930PROCUpdateIcon(InstrWind_h%,S%+8, 0,0) 7940NEXT:REM Instrument allocation 7950IF PERC% $StaveStr%(7)=Nth$(5)+";" :REM steal 1 channel for percussion 7960ENDPROC 7970 7980DEF PROCsetup_score 7990LOCALS%,P% 8000REM only 1 percussion channel permitted now 8010PROCsetup_staves:REM Calculate new stave positions 8020PROCSetDefaultChannels 8030ENDPROC 8040 8050DEF FNGetFileInfo(F$) 8060LOCALT%,L%,A%,M$,time%,FileType$,r2,r3 8070IF F$<>"" SYSOS_File,5,F$ TO T%,,laddr%,eaddr%,L%,A% 8080IF (F$="") OR ((T%=1) AND (A% AND 1) AND (L%>8)) = 0 THEN 8090$ThisFile%="<untitled>"+CHR$(0) 8100$FileSize%="" 8110$FileType%="" 8120$FileDate%="" 8130=FALSE 8140ELSE 8150$ThisFile%=F$ 8160$FileSize%=STR$(L%) 8170IF ((laddr%>>20)AND&FFF)=&FFF THEN 8180 IF (laddr%>>8 AND &FFF) = MusicFileType% THEN 8190 FileType$= "Music " 8200 ELSE 8210 SYS "OS_FSControl",18,,laddr%>>8 AND &FFF TO ,,r2,r3 8220 FileType$=CHR$(r2 AND &FF) + CHR$((r2>>8) AND &FF) + CHR$((r2>>16) AND &FF) + CHR$((r2>>24) AND &FF) 8230 FileType$ += CHR$(r3 AND &FF) + CHR$((r3>>8) AND &FF) + CHR$((r3>>16) AND &FF) + CHR$((r3>>24) AND &FF) 8240 ENDIF 8250 $FileType%=FileType$+STR$~(laddr%>>8 AND &FFF) 8260 time%=Window% :REM a convenient buffer 8270REM load and execution addresses are, in fact, time stamp 8280 time%?4=laddr% AND &FF 8290 time%?3=eaddr%>>24 AND &FF 8300 time%?2=eaddr%>>16 AND &FF 8310 time%?1=eaddr%>>8 AND &FF 8320 time%?0=eaddr% AND &FF 8330 SYS "OS_ConvertStandardDateAndTime", time%, FileDate%, 28 8340 REM put timestamp of file into file info window 8350 ENDIF 8360ENDIF 8370=TRUE 8380 8390DEF PROCload_music(F$) 8400LOCAL F%,M$ 8410LOCAL ERROR 8420IF CHANGED% IF NOT FNCheckOK("Are you sure? Current music is unsaved",3) ENDPROC 8430SCORING%=FALSE 8440IF PLAYING% PROCplay_stop 8450SCROLLING%=FALSE 8460IF LENF$=0 THEN VDU7 : T%=FNCheckOK("Invalid filename",1) : ENDPROC 8470SYS "Hourglass_On" 8480ON ERROR LOCAL VDU7: OSCLI("FX 229,1") : PROCClearAllMusic : SYS "Hourglass_Off" : T%=FNCheckOK(REPORT$,1) : ENDPROC 8490OSCLI("FX 229,0") :REM enable escape key 8500FILE%=OPENINF$ 8510M$="":FORR%=1TO7:M$+=CHR$BGET#FILE%:NEXT 8520B%=BGET#FILE% 8530IFM$="Maestro" THEN 8540$LoadText=F$+CHR$(0) 8550$SaveText=F$+CHR$(0) 8560IF NOT FNGetFileInfo(F$) THEN VDU7 :OSCLI("FX 229,1") : SYS "Hourglass_Off" :T%=FNCheckOK("Invalid or locked file",1) : ENDPROC 8570T%=TRUE 8580NBars%=0 8590CASE BGET#FILE% OF 8600WHEN 0:T%=FALSE 8610WHEN 1 8620PROClTempo:PROClInstruments:PROClStaves:PROClMusic 8630OTHERWISEREM File id version 2 and above 8640A%=FALSE 8650REPEAT 8660ON BGET#FILE% PROClMusic,PROClStaves,PROClInstruments,PROClVolumes,PROClStereos,PROClTempo ELSEA%=TRUE 8670UNTILEOF#FILE%ORA% 8680ENDCASE 8690CLOSE#FILE%:FILE%=FALSE 8700OSCLI("FX 229,1") 8710$Updated%="NO" 8720PROCUpdateTitle(F$) 8730SYS "Hourglass_Off" 8740SYS "Hourglass_On" 8750IFT% THEN 8760 PROCposition_staves 8770 PROCstart_music 8780 PROCset_score(0) 8790 PROCSetupBarStarts(0) 8800 PROCsetup_score 8810 PROCupdate_score(0,-Score_Height%,Score_Width%,0) 8820 PROCStopScoring 8830 CHANGED%=FALSE 8840 ENDIF 8850ELSE 8860OSCLI("FX 229,1") 8870T%=FALSE 8880ENDIF 8890IF NOT T% THEN VDU7 : T%=FNCheckOK("Invalid music file",1) 8900SYS "Hourglass_Off" 8910ENDPROC 8920 8930DEF PROClMusic 8940LOCALC%,B% 8950INPUT#FILE%,GATE%:GATE%+=MUSIC% 8960FORC%=0TO7 8970INPUT#FILE%,FINE%(C%):FINE%(C%)+=MUSIC%(C%) 8980NEXT 8990B%=MUSIC%:WHILEB%<GATE%:?B%=BGET#FILE%:B%+=1:ENDWHILE 9000FORC%=0TO7 9010B%=MUSIC%(C%):WHILEB%<FINE%(C%):?B%=BGET#FILE%:B%+=1:ENDWHILE 9020NEXT 9030PP%=MUSIC%:P%()=MUSIC%() 9040ENDPROC 9050 9060DEF PROClStaves 9070LOCAL item% 9080STAVE%=BGET#FILE% 9090$StaveNum%=LEFT$(STR$(STAVE%+1),1) 9100PERC%=BGET#FILE% 9110item% = FNFindMenuItem("+percussion", StaveMenu%) 9120IF item%>0 !item%=FNSetBit(PERC%=1, !item%, 0) :REM set or clear tick 9130ENDPROC 9140 9150DEF PROClInstruments 9160LOCALC%, chan%,v% 9170FORC%=0TO7 9180chan%=BGET#FILE%:REM Channel 9190v%=BGET#FILE%MOD(NVoices%+1):REM Write voice numbers allocated to each channel 9200IF v%=0 v%=1 9210SYS Sound_AttachVoice, chan%+1, v% 9220v%=FNAttachVoice(chan%, 0) :REM check if it is a valid voice 9230SYS Sound_AttachVoice, chan%+1, v% 9240Instrument%(chan%,1) = v% 9250$(VoiceStr%(chan%))=LEFT$(Voice$(v%), VoiceSize%) 9260PROCUpdateIcon(InstrWind_h%, chan%+8, 0,0) 9270NEXT 9280ENDPROC 9290 9300DEF PROClVolumes 9310LOCALC% 9320FORC%=0TO7 9330Volumes%(C%)=BGET#FILE% 9340IFVolumes%(C%)>7 Volumes%(C%)=7 9350IFVolumes%(C%)<0 Volumes%(C%)=0 9360$(VolumeStr%(C%))=LEFT$(Volume$(Volumes%(C%)), VolSize%) 9370PROCUpdateIcon(InstrWind_h%, C%+16, 0,0) :REM update icon in instrument window 9380NEXT 9390ENDPROC 9400 9410DEF PROClStereos 9420LOCALC% 9430FORC%=0TO7 9440Stereo_Position%(C%)=BGET#FILE% 9450SYS Sound_Stereo,C%+1,Stereo%(Stereo_Position%(C%)) 9460$(StereoStr%(C%)) = LEFT$(Stereo$(Stereo_Position%(C%), 0), SterSize%) 9470PROCUpdateIcon(InstrWind_h%, C%+24, 0,0) 9480NEXT 9490ENDPROC 9500 9510DEF PROClTempo 9520LOCAL t 9530t=BGET#FILE% 9540PROCSetTempo(t) 9550PROCSetMenuTick(TempoMenu%, t) 9560ENDPROC 9570 9580DEF PROCsave_music(F$) 9590LOCAL block,n 9600LOCAL ERROR 9610block=Window% 9620$SaveText=F$+CHR$(0) 9630$LoadText=F$+CHR$(0) 9640REM simple check for pathname rather than local name 9650IF ( INSTR(F$,".")=0 AND INSTR(F$,":")=0 ) THEN 9660 n=FNCheckOK("To save, drag the icon to a directory viewer.",1) 9670 ENDPROC 9680 ENDIF 9690SYS "Hourglass_On" 9700ON ERROR LOCAL OSCLI("FX 229,1") : SYS "Hourglass_Off" : T%=FNCheckOK(REPORT$,1) : ENDPROC 9710OSCLI("FX 229,0") :REM enable escape key 9720IF CHANGED% OR (((laddr%>>20)AND&FFF) <> &FFF) THEN 9730 REM file changed or wasn't timestamped 9740 REM get current time 9750 block?0=3:SYS "OS_Word",&0E,block 9760 laddr%=block?4 9770 eaddr%=block!0 9780 ENDIF 9790REM force music file type, and preserve timestamp 9800laddr%=(laddr% AND &FF) OR (&FFF<<20) OR (MusicFileType%<<8) 9810REM I don't know what the length will be, so use zero 9820SYS "OS_File", &07, F$, laddr%, eaddr%, 0, 0 9830REM OPENUP, error if directory or not found 9840SYS "OS_Find", &CC, F$ TO FILE% 9850REM timestamp is automatically updated on 1st byte write 9860BPUT#FILE%,"Maestro" 9870BPUT#FILE%,2 9880PROCsMusic 9890PROCsStaves 9900PROCsInstruments 9910PROCsVolumes 9920PROCsStereos 9930PROCsTempo 9940CLOSE#FILE%:FILE%=FALSE 9950IF (NOT CHANGED%) AND (((laddr%>>20) AND &FFF) = &FFF) THEN 9960 REM file not changed and was timestamped 9970 REM preserve original timestamp 9980 SYS OS_File,2,F$,laddr% :REM re-stamp with old stamp 9990 SYS OS_File,3,F$,,eaddr% :REM nb eaddr% in r3 10000 ENDIF 10010OSCLI("FX 229,1") 10020F%=FNGetFileInfo(F$) 10030CHANGED%=FALSE 10040$Updated%="NO" 10050PROCUpdateTitle(F$) 10060IF NOT T% THEN VDU7 : T%=FNCheckOK("Invalid music file",1) 10070SYS "Hourglass_Off" 10080ENDPROC 10090 10100DEF PROCsMusic 10110LOCALC%,B% 10120BPUT#FILE%,1 10130PRINT#FILE%,GATE%-MUSIC% 10140FORC%=0TO7 10150PRINT#FILE%,FINE%(C%)-MUSIC%(C%) 10160NEXT 10170B%=MUSIC%:WHILEB%<GATE%:BPUT#FILE%,?B%:B%+=1:ENDWHILE 10180FORC%=0TO7 10190B%=MUSIC%(C%):WHILEB%<FINE%(C%):BPUT#FILE%,?B%:B%+=1:ENDWHILE 10200NEXT 10210ENDPROC 10220 10230DEF PROCsStaves 10240BPUT#FILE%,2 10250BPUT#FILE%,STAVE% 10260BPUT#FILE%,PERC% 10270ENDPROC 10280 10290DEF PROCsInstruments 10300LOCALC% 10310BPUT#FILE%,3 10320FORC%=0TO7 10330BPUT#FILE%,C% 10340BPUT#FILE%,Instrument%(C%,1) 10350NEXT 10360ENDPROC 10370 10380DEF PROCsVolumes 10390LOCALC% 10400BPUT#FILE%,4 10410FORC%=0TO7 10420BPUT#FILE%,Volumes%(C%) 10430NEXT 10440ENDPROC 10450 10460DEF PROCsStereos 10470LOCALC% 10480BPUT#FILE%,5 10490FORC%=0TO7 10500BPUT#FILE%,Stereo_Position%(C%) 10510NEXT 10520ENDPROC 10530 10540DEF PROCsTempo 10550BPUT#FILE%,6 10560BPUT#FILE%,Tempo% 10570ENDPROC 10580 10590DEF PROCsprite(s%,X%,Y%) : REM plot sprite S%(s%) at X%,Y% 10600SYS SpriteOp%, SprPlot%, SprBlk%, S%(s%), X%-x%(s%),Y%-y%(s%), 8, factors%, pixtrans% 10610REM overwrite screen colour, but using sprite mask 10620ENDPROC 10630 10640DEF PROCfloat(s%,X%,Y%) 10650LOCALR% 10660Window%!handle%=ScoreWind_h% 10670Window%!x1%=X%+X%(s%) 10680X%-=x%(s%) 10690Window%!x0%=X% 10700Window%!y1%=Y%+Y%(s%) 10710Y%-=y%(s%) 10720Window%!y0%=Y% 10730SYS UpdateWindow%,,Window%+handle% TO R% 10740X%+=Window%!x0%-Window%!scx% 10750Y%+=Window%!y1%-Window%!scy% 10760ChSprite%=S%(s%) 10770WHILE R% 10780 CASE s% OF 10790 WHEN key% : PROCfloat_key_sig(X%,Y%+y%(s%)) 10800 WHEN time% : PROCfloat_time_sig(X%,Y%) 10810 OTHERWISE : pixtrans%?1 = pixtrans%?0 EOR pixtrans%?1 10820 SYS SpriteOp%, SprPlot%, SprBlk%, ChSprite%, X%,Y%, 11, factors%, pixtrans% 10830 pixtrans%?1 = pixtrans%?0 EOR pixtrans%?1 10840 ENDCASE 10850 SYS GetRectangle%,,Window%+handle% TO R% 10860 ENDWHILE 10870ENDPROC 10880 10890DEF PROCfloat_key_sig(X%,Y%) 10900LOCALI%,A%,C%,W% 10910IFKEY_SIG%(1) THEN 10920C%=SCRIBE%(sclef%) 10930A%=KEY_SIG%(0) 10940I%=accidental%+2+A% 10950W%=x%(I%)+X%(I%):Y%-=y%(I%) 10960ChSprite%=S%(I%) 10970FOR I%=0 TO KEY_SIG%(1)-1 10980SYS SpriteOp%, SprPlot%, SprBlk%, ChSprite%, X%, Y%+Li%*Key_Y%(C%,A%,I%), 3, factors%, pixtrans% 10990X%+=W% 11000NEXT 11010ELSE 11020SYS SpriteOp%, SprPlot%, SprBlk%, ChSprite%, X%, Y%-y%(s%), 3, factors%, pixtrans% 11030ENDIF 11040ENDPROC 11050 11060DEF PROCfloat_time_sig(X%,Y%) 11070SYS SetColour, 7 OR 3<<4 11080IF LEN($NoteValue%)>1 MOVE X%+C_Width%DIV2, Y%+C_Height% ELSE MOVE X%+C_Width%, Y%+C_Height% 11090PRINT $NoteValue% 11100IF LEN($BarLength%)>1 MOVE X%+C_Width%DIV2, Y%+2*C_Height% ELSE MOVE X%+C_Width%, Y%+2*C_Height% 11110PRINT $BarLength% 11120ENDPROC 11130 11140REM *********************************************************************** REM 11150REM REM 11160REM M U S I C T R A N S C R I P T I O N R O U T I N E S REM 11170REM REM 11180REM *********************************************************************** REM 11190:: 11200REM PROCEDURE: start_music 11210REM 11220REM DESCRIPTION: Initialise to start of music 11230: 11240DEF PROCstart_music 11250LOCAL n% 11260BAR%=0 :REM current bar 11270GP%=MUSIC%:REM Set current gate pointer to start of displayed music 11280N%()=MUSIC%() 11290CLEF%()=0:REM Start with base clefs (NOT BASS!) 11300SIG%(0)=%01100111:REM (Default time sig of 4/4 time) 11310SIG%(1)=%00000010:REM (Default of C Major) First displayed signatures attribute byte 11320PX%=0 11330PROCPutBarInfo(0) 11340ENDPROC 11350 11360REM PROCEDURE: note_type(Channel C%, Type T%) 11370 11380DEF PROCnote_type(C%,T%) 11390N%(C%)?1=N%(C%)?1AND&1F ORT%<<5 11400ENDPROC 11410 11420DEF PROCnote_dots(C%,D%) 11430N%(C%)?1=N%(C%)?1AND&E7 ORD%<<3 11440ENDPROC 11450 11460DEF PROCnote_accidental(C%,A%) 11470N%(C%)?1=N%(C%)?1AND&F8 ORA% 11480ENDPROC 11490 11500REM PROCEDURE: note_line(Channel C%, Stave line L%) 11510REM 11520REM NOTE: If a note's position is not defined or specified as -16, it is treated as a rest 11530 11540DEF PROCnote_line(C%,L%) 11550?N%(C%)=?N%(C%)AND7 OR(16+L%)<<3 11560ENDPROC 11570 11580DEF PROCnote_tie(C%,T%) 11590?N%(C%)=?N%(C%)AND&FB OR(T%<>0)AND4 11600ENDPROC 11610 11620DEF PROCnote_join(C%,J%) 11630?N%(C%)=?N%(C%)AND&FD OR(J%<>0)AND2 11640ENDPROC 11650 11660DEF PROCnote_stem(C%,D%) 11670?N%(C%)=?N%(C%)AND&FE OR(D%<>0)AND%1 11680ENDPROC 11690 11700DEF PROCnote_clear(C%) 11710?N%(C%)=0:N%(C%)?1=0 11720ENDPROC 11730 11740REM PROCEDURE: time_sig(Number of beats-1 N%,Beat type B%) 11750 11760DEF PROCtime_sig(N%,B%) 11770?GP%=0:GP%?1=Time%ORN%<<1ORB%<<5 11780ENDPROC 11790 11800REM PROCEDURE: key_sig(Key K%) 11810 11820DEF PROCkey_sig(A%,N%) 11830?GP%=0:GP%?1=Key%ORA%<<2ORN%<<3 11840ENDPROC 11850 11860REM PROCEDURE: clef(Stave S%, Clef C%) 11870 11880DEF PROCclef(S%,C%) 11890?GP%=0:GP%?1=Clef%ORC%<<3ORS%<<6 11900ENDPROC 11910 11920DEF PROCbar 11930?GP%=0:GP%?1=Bar% 11940ENDPROC 11950 11960DEF PROCinsert_gate(W%) 11970LOCALG% 11980IFGP%<GATE% THEN 11990FORG%=GATE%-W%TOGP%STEP-4:G%!W%=!G%:NEXT:REM Shift up by W% from insertion 12000G%+=3:REM Byte before last copied 12010WHILEG%>=GP%:G%?W%=?G%:G%+=TRUE:ENDWHILE:REM Clear up in odd word 12020ENDIF 12030GATE%+=W%:REM Insert gate of size W% into gate queue 12040EP%+=W%:REM This assumes gates will only be inserted below EP% 12050?GP%=0:GP%?(W%-1)=0:REM Zeroise inserted gate 12060ENDPROC 12070 12080DEF PROCinsert_note(C%) 12090LOCALN% 12100IFN%(C%)<FINE%(C%) THEN 12110FORN%=FINE%(C%)-2TON%(C%)STEP-4:N%!2=!N%:NEXT:REM Shift up from insertion 12120N%+=3:REM Last copied word 12130WHILEN%>=N%(C%):N%?2=?N%:N%+=TRUE:ENDWHILE:REM Clear up in odd word 12140ENDIF 12150FINE%(C%)+=2:REM Insert a note word into this queue 12160?GP%=?GP%OR%1<<C%:REM Mark in gate 12170PROCnote_clear(C%) 12180ENDPROC 12190:: 12200DEF PROCdelete_gate(W%) 12210LOCALG% 12220GATE%-=W% 12230IFGP%<GATE% FORG%=GP%TOGATE%STEP4:!G%=G%!W%:NEXT 12240EP%-=W%:REM This assumes gates will only be deleted below EP% 12250ENDPROC 12260:: 12270DEF PROCdelete_note(C%) 12280LOCALN% 12290FINE%(C%)-=2 12300IFN%(C%)<FINE%(C%) FORN%=N%(C%)TOFINE%(C%)STEP4:!N%=N%!2:NEXT 12310?GP%=?GP%ANDNOT(%1<<C%) 12320ENDPROC 12330 12340DEF FNallocate_channel(S%) 12350LOCALC%,c%,G% 12360G%=?GP% 12370C%=-1:c%=7 12380REPEAT 12390WHILEc%>=0ANDG%AND%1<<c%:c%+=TRUE:ENDWHILE 12400IFc%>=0 IFS_C%(c%)=S% C%=c% 12410c%+=TRUE 12420UNTILc%<0 12430=C% 12440 12450DEF PROCarrange_stave(S%) 12460LOCALC%,B% 12470B%=TRUE:C%=TRUE 12480IF?GP% ELSEREPEATGP%+=2:UNTIL?GP%ORGP%>=GATE% 12490WHILEB%ANDGP%<GATE% 12500C%=C%ORFNsort_gate 12510PROCskip_notes(?GP%):GP%+=1 12520IF?GP% ELSEB%=C%:C%=FALSE:REPEATGP%+=2:UNTIL?GP%ORGP%>=GATE% 12530ENDWHILE 12540ENDPROC 12550 12560DEF FNsort_gate 12570LOCALC%,NC%,NN%,G%,g%,pg%,d%,shortest%,Gchanged% 12580shortest%=255 12590G%=?GP% 12600g%=FNprevious_gate(GP%) 12610pg%=FNpreceding_gate(GP%) 12620NC%=-1 12630NN%=-1 12640FORC%=0TO7 12650IFS_C%(C%)=S% THEN 12660NC%+=1:n%(NC%)=C%:IFG%AND%1<<C% NN%+=1:C%(NN%)=C% 12670IFpg%AND%1<<C% d%=N%(C%)?-1>>3EOR%11100:IFd%<shortest% shortest%=d% 12680ENDIF 12690NEXT 12700shortest%=shortest%EOR%11100 12710IFg%ANDNC%>0ANDNN%>=0 PROCsort 12720=Gchanged% 12730 12740DEF PROCsort 12750LOCALN%,M% 12760c%()=-1 12770FORM%=0TONC% 12780FORN%=0TONN% 12790IFFNsame_pitch(n%(M%),C%(N%)) c%(N%)=n%(M%) 12800NEXT 12810NEXT 12820FORN%=0TONN% 12830IFc%(N%)<0 c%(N%)=FNbest 12840NEXT 12850FORN%=0TONN% 12860IFC%(N%)=c%(N%) ELSEGchanged%=TRUE:M%=FNin(c%(N%),C%()):IFM%>N% PROCswap_notes(N%,M%) ELSEPROCmove_note(N%) 12870NEXT 12880ENDPROC 12890 12900DEF PROCswap_notes(N%,M%) 12910LOCALs%,d% 12920s%=C%(N%):d%=c%(N%) 12930SWAPC%(N%),C%(M%) 12940SWAP?N%(s%),?N%(d%) 12950SWAPN%(s%)?1,N%(d%)?1 12960ENDPROC 12970 12980DEF PROCmove_note(N%) 12990LOCALs%,d% 13000s%=C%(N%):d%=c%(N%) 13010PROCinsert_note(d%) 13020?N%(d%)=?N%(s%) 13030N%(d%)?1=N%(s%)?1 13040PROCdelete_note(s%) 13050ENDPROC 13060 13070DEF FNbest 13080LOCALN%,C% 13090LOCAL short%,free%,rest%,any%,tied% 13100FOR N%=NC%TO0STEP-1 13110C%=n%(N%) 13120IFFNin(C%,c%())<0 THEN 13130IFN%(C%)?-2AND4 THEN 13140tied%=C%+1 13150ELSE 13160IFpg%AND%1<<C% THEN 13170IF(N%(C%)?-1>>3)=shortest% short%=C%+1 13180IFN%(C%)?-2AND&F8 ELSErest%=C%+1 13190ELSE 13200free%=C%+1 13210ENDIF 13220any%=C%+1 13230ENDIF 13240ENDIF 13250NEXT 13260IFshort% C%=short% ELSEIFfree% C%=free% ELSEIFrest% C%=rest% ELSEIFany% C%=any% ELSEC%=tied% 13270=C%-1 13280 13290DEF FNin(U%,U%()) 13300LOCALI%:I%=NN% 13310WHILEI%ANDU%<>U%(I%):I%-=1:ENDWHILE 13320=I%+(U%<>U%(I%)) 13330 13340DEF FNsame_pitch(c%,C%):LOCALR%,r%:R%=?N%(C%)AND&F8:r%=N%(c%)?-2AND&F8:=N%(c%)-2>=MUSIC%(c%)AND(g%OR(N%(c%)?-2AND4)=4)AND%1<<c%AND(R%EORr%)=FALSE AND(FALSE<>R%EORr%=FALSE) 13350 13360DEF FNpreceding_gate(gp%) 13370LOCALC%,gm% 13380FORC%=0TO7:IFS_C%(C%)=S% gm%=gm%OR%1<<C% 13390NEXT 13400REPEAT 13410gp%-=1 13420UNTILgm%AND?gp%ORgp%<MUSIC%+2ORgp%?-1=FALSE 13430=?gp%ANDgp%>MUSIC%+1ANDgp%?-1<>FALSE 13440 13450DEF FNprevious_gate(gp%) 13460LOCALC%,gm% 13470FORC%=0TO7:IFS_C%(C%)=S% gm%=gm%OR%1<<C% 13480NEXT 13490REPEAT 13500gp%-=1 13510WHILEgp%>MUSIC%ANDgp%?-1=FALSE:gp%-=2:ENDWHILE 13520UNTILgm%AND?gp%ORgp%<MUSIC%+2 13530=?gp%ANDgp%>MUSIC%+1 13540 13550DEF FNconflict(T%,S%,L%) 13560LOCALC%,co% 13570L%+=16 13580C%=7 13590REPEAT 13600co%=?GP%AND%1<<C%ANDS_C%(C%)=S%AND(?N%(C%)>>3)=L% 13610C%+=TRUE 13620UNTILco%ORC%<FALSE 13630=C%-(co%<>0) 13640 13650REM *********************************************************************** REM 13660REM REM 13670REM M U S I C T Y P E S E T T I N G R O U T I N E S REM 13680REM REM 13690REM *********************************************************************** REM 13700:: 13710REM PROCEDURE: set_score(Starting position PX%) 13720REM 13730REM DESCRIPTION: Typeset music score from current bar to end of music/screen 13740REM No drawing is done as only the positions are calculated. 13750REM 13760REM EFFECTS: Stores gate X positions & types in PX%() & PTYPE%() 13770: 13780DEF PROCset_score(PX%) 13790WHILE GP%<GATE% 13800IF?GP% PROCset_notes(?GP%):GP%+=1 ELSEPROCset_attribute(GP%?1):GP%+=2 13810ENDWHILE:REM Until edge of screen or end of music 13820EP%=GP%:REM Last GP%, pointer to first undrawn gate 13830EX%=PX%:REM Last PX%, index to last position 13840PX%(PX%+1)=PX%(PX%)+PW%(PX%)+Pgap%:REM Appendation position after last symbol 13850IF PX%(PX%+1)>S_Width% PROCSetExtent(PX%(PX%+1)+100*Hi%) ELSE PROCSetExtent(S_Width%) 13860PXn%(NBars%)=PX% 13870PTYPE%(PX%+1)=Note%:REM Note type by default 13880ENDPROC 13890:: 13900REM NOTE: The key signature is the only attribute that must be kept track of in order to ensure correct setting. 13910REM This is because a naturalising signature consists of the same number of naturals as accidentals in the previous key signature 13920: 13930DEF PROCset_attribute(A%) 13940IFA%ANDPTYPE%(PX%)+TRUE ELSEIFA%ANDPTYPE%(PX%) ENDPROC 13950LOCALT%:T%=%1:IFA%AND%1 ELSEREPEATT%=T%<<1:UNTILA%ANDT% 13960PX%(PX%+1)=PX%(PX%)+PW%(PX%)+Pgap% 13970PX%+=1 13980PTYPE%(PX%)=T% 13990CASE T% OF 14000WHENTime%:PW%(PX%)=20*Hi% 14010WHENKey% 14020IFA%AND56 T%=accidental%+(A%>>2AND%1)+2:SIG%(1)=A% ELSET%=accidental%+1:SWAPA%,SIG%(1):IFA%AND56 ELSEA%=8:T%+=1 14030PW%(PX%)=(A%>>3AND7)*(x%(T%)+X%(T%)) 14040WHENClef%:PW%(PX%)=x%(clef%+3)+X%(clef%+3) 14050WHENBar%:PW%(PX%)=Hi%*4 14060ENDCASE 14070ENDPROC 14080 14090DEF PROCset_notes(G%) 14100LOCALlx0%,lx1%,ly0%,ly1% 14110LOCALC%,P%,R%,s%:REM Channel, Note prefix & remainder widths, Sprite 14120C%=-1 14130REPEAT 14140REPEATC%-=TRUE:UNTILG%AND%1<<C% 14150PROCbound_note(!N%(C%)) 14160IFlx0%>P% P%=lx0%:REM Maximum prefix 14170IFlx1%>R% R%=lx1%:REM Maximum remainder 14180N%(C%)+=2:REM Pull from note queue 14190UNTIL(2<<C%)>G%:REM Until no more notes (1 bits) 14200PX%(PX%+1)=PX%(PX%)+PW%(PX%)+Pgap%+P%:REM Next position is previous position + width+gap+prefix of next note 14210PX%+=1:REM next note position index 14220PW%(PX%)=R%:REM Width of new note 14230PTYPE%(PX%)=Note%:REM Note type 14240ENDPROC 14250 14260DEF PROCbound_note(L%) 14270LOCALH%,S%,s% 14280H%=L%>>8AND&FF 14290IFL%AND&F8 S%=H%>>5ORL%<<3AND8 ELSES%=rest%ORH%>>5:REM Note/rest sprite 14300lx0%=x%(S%):REM Prefix width 14310lx1%=X%(S%):REM Suffix width 14320ly0%=y%(S%):REM Decender height 14330ly1%=Y%(S%):REM Ascender height 14340IFH%AND7 THEN 14350s%=accidental%ORH%AND7 14360lx0%+=x%(s%):REM Add accidental width 14370IFy%(s%)>ly0% ly0%=y%(s%):REM Lower ? 14380IFY%(s%)>ly1% ly1%=Y%(s%):REM Higher ? 14390ENDIF 14400IFH%AND24 s%=dot%+(H%>>3AND3):lx1%=x%(S%)+X%(s%):IFy%(s%)>ly0% ly0%=y%(s%):REM Dot adds suffix and may be lower 14410ENDPROC 14420:: 14430DEF PROCposition_staves 14440LOCAL Y%,S% 14450Score_Height%=(PERC%+1+3*(STAVE%+1)+1)*Stave_Height% 14460Y%=-Score_Height%-Stave_Height%DIV2 14470IFPERC% FORS%=PERC%TO1STEP-1:Y%+=Stave_Height%:Y_STAVE%(STAVE%+S%)=Y%:NEXT 14480FOR S%=STAVE%TO0STEP-1:Y%+=3*Stave_Height%:Y_STAVE%(S%)=Y%:NEXT 14490ENDPROC 14500 14510DEF PROCsetup_staves 14520LOCAL O% 14530PROCposition_staves 14540ScoreWBlk%!handle%=ScoreWind_h% 14550SYS GetWindowState%,,ScoreWBlk%+handle% 14560ScoreWBlk%!y0%=ScoreWBlk%!y1%-Score_Height%-PaneHeight% 14570ScoreWBlk%!scx%=0:ScoreWBlk%!scy%=PaneHeight%/2 14580ScoreWBlk%!under%=-1 14590SYS OpenWindow%,,ScoreWBlk%+handle% 14600LHBAR%=0 14610ScoreClosed%=FALSE 14620Window%!handle%=ScoreWind_h% 14630SYS GetWindowState%,,Window%+handle% 14640IF TRANSCRIBE% PROCplace_top_panes(-1): PROCplace_bottom_panes(-1) 14650IF PLAYING% PROCCheckScroll 14660ENDPROC 14670 14680DEF PROCupdate_score(Window%!x0%,Window%!y0%,Window%!x1%,Window%!y1%) 14690Window%!handle%=ScoreWind_h% 14700SYS UpdateWindow%,,Window%+handle% TO R% 14710WHILE R% 14720CLG:PROCdraw_staves 14730SYS GetRectangle%,,Window%+handle% TO R% 14740ENDWHILE 14750ENDPROC 14760 14770REM PROCEDURE: draw_staves 14780REM 14790REM DESCRIPTION: Draw current stave structure 14800REM 1 stave for 1 voice 14810REM 2 staves for keyboard 14820REM 3 staves for 1 voice and keyboard 14830REM 4 staves for 4 voice chorus 14840: 14850DEF PROCdraw_staves 14860LOCAL Y%,T%,B%,S%,L%:REM Y%,T%,B%=Position & Y bounds of each stave, S%=Stave index, L%=Line position 14870LOCAL x%,y%,lx1%:REM Virtual coordinates of bottom left & top right of score window 14880LOCAL c%,t%,b%:REM Left edge of clip window and Y bounds 14890y%=Window%!y1%-Window%!scy% 14900x%=Window%!x0%-Window%!scx% 14910lx1%=x%+Score_Width%:IF lx1%>Clip%!x1% lx1%=Clip%!x1% 14920c%=Clip%!x0%:IFc%<x%+Hi% c%=x%+Hi% 14930b%=Clip%!y0%:t%=Clip%!y1% 14940IFPERC% THEN 14950FOR S%=STAVE%+1TOSTAVE%+PERC% 14960Y%=y%+Y_STAVE%(S%) 14970IFb%<=Y%ANDt%>=Y% LINEc%,Y%,lx1%,Y% 14980NEXT 14990ENDIF 15000FOR S%=0 TO STAVE% 15010Y%=y%+Y_STAVE%(S%):T%=Y%+Stave_Height%DIV2:B%=T%-Stave_Height% 15020IFb%<=T%ANDt%>=B% THEN 15030LINEc%,Y%,lx1%,Y%:REM Plot centre bar line 15040FORL%=Li%*2TOL%*2STEPL% 15050LINEc%,Y%+L%,lx1%,Y%+L%:REM Plot upper line 15060LINEc%,Y%-L%,lx1%,Y%-L%:REM Plot lower line 15070NEXT 15080ENDIF 15090NEXT 15100B%=Score_Width% 15110T%=Clip%!x1%-x%:IFT%<B% B%=T%:REM Right bound 15120T%=Clip%!x0%-x%:IFT%<0 T%=0:REM Left bound 15130IF NOT BADMODE% THEN 15140 PROCdraw_score(x%,y%,T%,B%):REM Draw symbols on stave 15150ELSE 15160 MOVE Window%!x0%, Window%!y1%-100 15170 PRINT "Cannot display score in this (256-colour) mode" 15180 ENDIF 15190ENDPROC 15200:: 15210REM PROCEDURE: draw_score(Based X%,Y%, PX bounds A%,B%) 15220REM 15230REM DESCRIPTION: Write current section of music score that appears between A% 15240REM and B% 15250: 15260DEF PROCdraw_score(X%,Y%,A%,B%) 15270LOCALPX% 15280BAR%=0 15290REM must be subtle about redrawing last note (or other item) of score to prevent picking up rubbish data after end 15300IF A%>PX%(PXn%(NBars%)) THEN 15310 IF A%>PX%(PXn%(NBars%))+2*Pgap% ENDPROC ELSE A%=PX%(PXn%(NBars%)) 15320 ENDIF 15330REM ensure bar numbers are always completely updated; but don't lose 1st-note draw 15340IF NBars%>2 THEN 15350WHILE PX%(PXn%(BAR%+2))<A% AND BAR%<=NBars%-1 15360 BAR%+=1 15370 ENDWHILE :REM get to drawstart quickly 15380 IF BAR%>NBars% ENDPROC 15390 PROCGetBarInfo(BAR%) 15400 IF GP%>=GATE% ENDPROC 15410 WHILEPX%(PX%+3)<A%ANDPX%<EX% 15420 PROCskip_gate 15430 ENDWHILE:REM Skip music until A% 15440ELSE 15450 PROCstart_music 15460ENDIF 15470WHILEPX%(PX%)<=B%ANDGP%<GATE% 15480IF?GP% PROCdraw_notes(?GP%):GP%+=1 ELSEPROCdraw_attribute(GP%?1):GP%+=2:IF PLAYING% PROCCheckQ 15490ENDWHILE 15500ENDPROC 15510 15520REM PROCEDURE: draw_notes(Gate G%) 15530REM 15540REM DESCRIPTION: Get notes from the indicated channel queues and draw the 15550REM particular types of note in the correct places on the stave. 15560REM One may be a rest, may have accidentals preceding it, may have 15570REM dots following it, may be tied 15580REM 15590REM ASSUMPTIONS: Gate is non-zero 15600REM 15610REM Join=?N%(C%)AND2 15620: 15630DEF PROCdraw_notes(G%) 15640LOCAL C%,x%,y%,s%,l%,NC0%,NC1%,lasty%,checkstagger% 15650PX%+=1:REM Move on to next position 15660x%=X%+PX%(PX%):REM Calculate gate column X (convert from work- to screen-coord) 15670checkstagger%=FALSE 15680C%=-1 15690REPEAT 15700REPEATC%-=TRUE:UNTILG%AND%1<<C% 15710NC0%=?N%(C%) : NC1%=N%(C%)?1 :REM fast local vars 15720y%=Y%+Y_STAVE%(S_C%(C%)) 15730IFNC0%AND&F8 THEN 15740l%=(NC0%>>3)-16 15750IFABSl%>5 PROCsprite(ledger%+l%DIV2,x%,y%):REM Ledger lines 15760y%+=Li%*l% 15770s%=NC1%>>5ORNC0%<<3AND8 15780IF checkstagger% THEN 15790REM stagger next note if too close to one below 15800REM stagger fails sometimes if channels of 2 adjacent notes are not in draw order? 15810 IF ABS(lasty%-y%)<2*Li% PROCsprite(s%,x%+Pgap%,y%):checkstagger%=FALSE ELSE PROCsprite(s%,x%,y%) 15820ELSE 15830 PROCsprite(s%,x%,y%):checkstagger%=TRUE 15840 ENDIF 15850lasty%=y% 15860IFNC1%AND7 PROCsprite(accidental%ORNC1%AND7,x%-x%(s%),y%) 15870ELSE 15880s%=rest%ORNC1%>>5 15890PROCsprite(s%,x%,y%) 15900ENDIF 15910IFNC1%AND24 PROCsprite(dot%+(NC1%>>3AND3),x%+x%(s%),y%) 15920IFNC0%AND4 PROCsprite(tie%,x%,y%) 15930N%(C%)+=2:REM Pull from note queue 15940UNTIL(2<<C%)>G%:REM Until no more notes (1 bits) 15950ENDPROC 15960:: 15970DEF PROCdraw_attribute(A%) 15980LOCALx%,N% 15990N%=TRUE:REPEATN%-=TRUE:UNTILA%AND%1<<N% 16000IFPTYPE%(PX%)EOR%1<<N% PX%+=1 16010x%=X%+PX%(PX%) 16020ONN%+1 PROCdraw_time_sig(A%),PROCdraw_key_sig(A%),PROCdraw_clef(A%),PROCdraw_slur(A%),PROCdraw_octave(A%),PROCdraw_bar_line(A%) 16030ENDPROC 16040 16050DEF PROCPutBarInfo(bar%) 16060REM setup the various pointers to arrays at the start of this bar 16070FOR n%=0 TO 7 16080 BPn%(n%,bar%)=N%(n%) 16090 NEXT 16100PXn%(bar%)=PX% 16110GPn%(bar%)=GP% 16120FOR n%=0 TO Max_Stave% 16130 CLEFn%(n%,bar%)=CLEF%(n%) 16140 NEXT 16150SIGn%(0,bar%)=SIG%(0) 16160SIGn%(1,bar%)=SIG%(1) 16170ENDPROC 16180 16190DEF PROCGetBarInfo(bar%) 16200REM get the values of the data at the start of this bar 16210FOR n%=0 TO 7 16220 N%(n%)=BPn%(n%,bar%) 16230 NEXT 16240PX%=PXn%(bar%) 16250GP%=GPn%(bar%) 16260FOR n%=0 TO Max_Stave% 16270 CLEF%(n%)=CLEFn%(n%,bar%) 16280 NEXT 16290SIG%(0)=SIGn%(0,bar%) 16300SIG%(1)=SIGn%(1,bar%) 16310ENDPROC 16320 16330DEF PROCSetupBarStarts(bar%) 16340REM find pointers to various bits at the starts of all bars through 16350REM the music. Start at bar% 16360REM this is just to speed up redraw, avoiding all the note-skipping 16370LOCAL last% 16380BAR%=bar% 16390IF bar%>0 PROCGetBarInfo(bar%) ELSE PROCstart_music 16400last%=BAR% 16410PROCPutBarInfo(BAR%) 16420WHILE GP%<GATE% 16430 IF?GP% THEN 16440 PROCskip_notes(?GP%):GP%+=1 16450 ELSE 16460 PROCskip_attribute(GP%?1):GP%+=2 16470 IF BAR%<>last% last%=BAR% : PROCPutBarInfo(BAR%) 16480 ENDIF 16490 ENDWHILE 16500BAR%+=1 16510PROCPutBarInfo(BAR%) 16520NBars%=BAR% 16530ENDPROC 16540 16550DEF PROCskip_gate 16560IF?GP% PROCskip_notes(?GP%):GP%+=1 ELSEPROCskip_attribute(GP%?1):GP%+=2 16570ENDPROC 16580 16590DEF PROCskip_notes(G%) 16600PX%+=1 16610LOCALC%:C%=-1 16620REPEATREPEATC%+=1:UNTILG%AND%1<<C%:N%(C%)+=2:UNTIL(2<<C%)>G% 16630ENDPROC 16640 16650DEF PROCskip_attribute(A%) 16660LOCALT% 16670T%=%1:IFA%AND%1 ELSEREPEATT%=T%<<%1:UNTILA%ANDT% 16680CASET%OF 16690WHENTime%,Key%:SIG%(T%-1)=A% 16700WHENClef%:CLEF%(A%>>6)=A%>>3AND3 16710WHENBar%:BAR%+=1 16720ENDCASE 16730IFT%EORPTYPE%(PX%) PX%+=1 16740ENDPROC 16750 16760DEF PROCback_gate 16770IFGP%?-2 GP%-=1:PROCback_notes(?GP%) ELSEGP%-=2:PROCback_attribute(GP%?1) 16780ENDPROC 16790 16800DEF PROCback_notes(G%) 16810PX%-=1 16820LOCALC%:C%=TRUE 16830REPEATREPEATC%-=TRUE:UNTILG%AND%1<<C%:N%(C%)-=2:UNTIL(2<<C%)>G% 16840ENDPROC 16850 16860DEF PROCback_attribute(A%) 16870IFA%=Bar% BAR%-=1 16880IFA%ANDPTYPE%(PX%+1)+TRUE ELSEIFA%ANDPTYPE%(PX%+1) ENDPROC 16890PX%-=1 16900ENDPROC 16910 16920DEF PROCdraw_time_sig(A%) 16930SIG%(0)=A% 16940LOCALS%,B$,D$,w% 16950B$=STR$((A%>>1AND15)+1) 16960D$=STR$(%1<<(A%>>5)-1) 16970w%=x% 16980IFLENB$<2 w%+=PW%(PX%)>>2 16990IFLEND$<2 x%+=PW%(PX%)>>2 17000FORS%=0TOSTAVE%+PERC% 17010MOVEw%,Y%+Y_STAVE%(S%)+Li%*4-Vi%:PRINTB$ 17020MOVEx%,Y%+Y_STAVE%(S%)-Vi%:PRINTD$ 17030NEXT 17040ENDIF 17050ENDPROC 17060 17070DEF PROCdraw_key_sig(A%) 17080LOCALS%,C%,N%,a%,W% 17090IFA%AND56 SIG%(1)=A% ELSESWAPA%,SIG%(1):a%=accidental%+1:REM Change to C Major uses naturals in old key sig positions 17100N%=(A%>>3AND7)-1 17110IFN%>=0 THEN 17120A%=A%>>2AND%1:REM 0-Sharp or 1-flat signature 17130IFa% ELSEa%=accidental%+2+A% 17140W%=x%(a%)+X%(a%) 17150x%+=x%(a%) 17160FOR C%=0 TO N% 17170FOR S%=0TOSTAVE% 17180PROCsprite(a%,x%,Y%+Y_STAVE%(S%)+Li%*Key_Y%(CLEF%(S%),A%,C%)) 17190NEXT 17200x%+=W% 17210NEXT 17220ENDIF 17230ENDPROC 17240 17250DEF PROCdraw_clef(A%) 17260LOCALS% 17270S%=A%>>6 17280CLEF%(S%)=A%>>3AND3 17290IFS%<=STAVE% PROCsprite(clef%+CLEF%(S%),x%,Y%+Y_STAVE%(S%)) 17300ENDPROC 17310 17320DEF PROCdraw_slur(A%) 17330ENDPROC 17340 17350DEF PROCdraw_octave(A%) 17360ENDPROC 17370 17380DEF PROCdraw_bar_line(A%) 17390BAR%+=1 17400FORS%=0TOSTAVE%+PERC% 17410PROCsprite(bar%,x%,Y%+Y_STAVE%(S%)) 17420NEXT 17430IF BAR%MOD5=0 THEN 17440 MOVE x%+Hi%,Y%+Y_STAVE%(0)+Stave_Height%+2*Vi% 17450 PRINT STR$(BAR%) 17460 ENDIF 17470IF(STAVE%+1)AND2 THEN 17480LOCAL y% 17490MOVEx%+Hi%,Y%+Y_STAVE%(STAVE%)+Stave_Height%DIV2 17500y%=Y_STAVE%(STAVE%-1)-Y_STAVE%(STAVE%)-Stave_Height% 17510DRAW BY 0,y% : MOVE BY Hi%,0 : DRAW BY 0,-y% : REM Connect keyboard staves 17520ENDIF 17530ENDPROC 17540 17550DEF PROCput_down 17560LOCALC%,PX%,X%,Y%,S%,s% 17570SYS "Hourglass_On" 17580GP%=SCRIBE%(sgp%) 17590FORC%=0TO7:N%(C%)=SCRIBE%(C%):NEXT 17600PX%=SCRIBE%(posx%) 17610X%=SCRIBE%(sx%) 17620Y%=SCRIBE%(sy%) 17630s%=SCRIBE%(sprite%) 17640S%=SCRIBE%(stave%) 17650C%=SCRIBE%(sc%) 17660PROCrelease:REM undraw sprite being dragged 17670IFs%<accidental% PROCput_note ELSEIFs%<clef% PROCput_accidental ELSEIFs%<dot% PROCput_clef ELSEIFs%<bar% PROCput_dot ELSEIFs%<time% PROCput_bar ELSEIFs%<key% PROCput_time ELSEIFs%<tie% PROCput_key ELSEPROCput_tie 17680GP%=SCRIBE%(sgp%) 17690FORC%=0TO7:N%(C%)=SCRIBE%(C%):NEXT 17700PROCarrange_stave(SCRIBE%(stave%)) 17710IF PX%(EX%)+200*Hi%>S_Width% PROCSetExtent(PX%(EX%)+200*Hi%) 17720IF NOT CHANGED% THEN 17730 CHANGED%=TRUE 17740 $Updated%="YES" 17750 PROCUpdateTitle(FNGetStr(ScoreTitle%)+" *") 17760 ENDIF 17770SYS "Hourglass_Off" 17780ENDPROC 17790 17800DEF PROCput_note 17810LOCALL%,E% 17820L%=SCRIBE%(line%) 17830IFX%=PX%(PX%+1) THEN 17840IFs%>=rest% L%=-16 17850E%=GP%=EP% 17860IFE% PROCinsert_gate(1) ELSEC%=FNconflict(Note%,S%,L%) 17870IFE%ORC%=TRUE THEN 17880C%=FNallocate_channel(S%) 17890IFC%>=0 THEN 17900PROCinsert_note(C%) 17910PROCnote_type(C%,s%AND7) 17920IFs%<rest% PROCnote_line(C%,L%):PROCnote_stem(C%,s%AND8) 17930s%=!N%(C%) 17940IFE% PROCset_score(PX%):X%=PX%(PX%+1) 17950PROCupdate_note(S%,s%,X%,Y%) 17960ENDIF 17970ELSE 17980s%=!N%(C%) 17990PROCdelete_note(C%) 18000IF?GP% THEN 18010PROCupdate_note(S%,s%,X%,Y%) 18020ELSE 18030PROCdelete_gate(1) 18040IFGP%?-2=0 WHILE?GP%=0ANDGP%<EP%:PROCdelete_gate(2):ENDWHILE 18050PROCrescore(PX%) 18060ENDIF 18070ENDIF 18080ELSE 18090IFX%>PX%(PX%+1) PROCskip_gate 18100PROCinsert_gate(1) 18110C%=FNallocate_channel(S%) 18120PROCinsert_note(C%) 18130PROCnote_type(C%,s%AND7) 18140IFs%<rest% PROCnote_line(C%,L%):PROCnote_stem(C%,s%AND8) 18150PROCrescore(PX%) 18160ENDIF 18170ENDPROC 18180 18190DEF PROCput_tie 18200IF?N%(C%)AND4 THEN 18210PROCnote_tie(C%,FALSE) 18220PROCupdate_score(X%+24,Y%+12,X%+70,Y%+24) 18230ELSE 18240LOCALI% 18250PROCnote_tie(C%,TRUE) 18260PROCskip_notes(?GP%):GP%+=1 18270PROCarrange_stave(S%) 18280GP%=SCRIBE%(sgp%) 18290FORI%=0TO7:N%(I%)=SCRIBE%(I%):NEXT 18300IFN%(C%)+2>=FINE%(C%)OR(?N%(C%)EORN%(C%)?2)AND&F8 PROCnote_tie(C%,FALSE) ELSEPROCupdate_score(X%+24,Y%+12,X%+70,Y%+24) 18310ENDIF 18320ENDPROC 18330 18340DEF PROCput_accidental 18350LOCALA%,a% 18360a%=N%(C%)?1AND7 18370A%=s%AND7 18380IFA%=a% A%=0 18390PROCnote_accidental(C%,A%) 18400IFA%*a% PROCupdate_score(X%-34,Y%-24,X%+16,Y%+52) ELSEPROCrescore(PX%) 18410ENDPROC 18420 18430DEF PROCput_dot 18440LOCALD%,d% 18450d%=N%(C%)?1>>3AND3 18460D%=s%AND3 18470IFD%=d% D%=0 18480PROCnote_dots(C%,D%) 18490IFD%*d% THEN 18500s%=N%(C%)?1>>5OR?N%(C%)<<3AND8:IF?N%(C%)AND&F8 ELSEs%=s%ORrest% 18510X%+=x%(s%) 18520PROCupdate_score(X%+24,Y%-8,X%+50,Y%) 18530ELSE 18540PROCrescore(PX%) 18550ENDIF 18560ENDPROC 18570 18580DEF PROCput_clef 18590LOCALc% 18600c%=s%AND3 18610IFGP%=EP%OR?GP%OR(GP%?1AND%111)<>Clef% THEN 18620PROCinsert_gate(2) 18630PROCclef(S%,c%) 18640ELSE 18650WHILE ?GP%=0AND(GP%?1AND%111)=Clef%AND(GP%?1>>6)<>S%ANDGP%<EP% 18660PROCskip_gate 18670ENDWHILE 18680IFGP%<EP%AND?GP%=0AND(GP%?1AND%111)=Clef%AND(GP%?1>>6)=S% THEN 18690IF(GP%?1>>3AND3)<>c% PROCclef(S%,c%) ELSEPROCdelete_gate(2) 18700ELSE 18710PROCinsert_gate(2) 18720PROCclef(S%,c%) 18730ENDIF 18740ENDIF 18750PROCrescore(PX%) 18760ENDPROC 18770 18780DEF PROCput_key 18790IFGP%=EP%OR?GP%OR(GP%?1AND%11)<>Key% THEN 18800PROCinsert_gate(2) 18810PROCkey_sig(KEY_SIG%(0),KEY_SIG%(1)) 18820ELSE 18830IFKEY_SIG%(1)>0AND(GP%?1>>2AND%1)<>KEY_SIG%(0)OR(GP%?1>>3)<>KEY_SIG%(1) PROCkey_sig(KEY_SIG%(0),KEY_SIG%(1)) ELSEPROCdelete_gate(2) 18840ENDIF 18850PROCrescore(PX%) 18860ENDPROC 18870 18880DEF PROCput_time 18890IFGP%=EP%OR?GP%OR(GP%?1AND%1)<>Time% THEN 18900PROCinsert_gate(2) 18910PROCtime_sig(TIME_SIG%(0),TIME_SIG%(1)) 18920PROCrescore(PX%) 18930ELSE 18940IF(GP%?1>>1AND15)<>TIME_SIG%(0)OR(GP%?1>>5)<>TIME_SIG%(1) THEN 18950PROCtime_sig(TIME_SIG%(0),TIME_SIG%(1)) 18960PROCupdate_score(X%,-Score_Height%,X%+48,0) 18970ELSE 18980PROCdelete_gate(2) 18990PROCrescore(PX%) 19000ENDIF 19010ENDIF 19020ENDPROC 19030 19040DEF PROCput_bar 19050IF(?GP%ORGP%?1<>Bar%)ANDX%>PX%(PX%+1)ANDGP%<EP% PROCskip_gate ELSEIFGP%?-2=0ANDGP%?-1=Bar% PROCback_gate 19060IFGP%>MUSIC% THEN 19070IFGP%<EP%AND?GP%=0ANDGP%?1=Bar% THEN 19080PROCdelete_gate(2) 19090NBars%-=1 19100WHILE?GP%=0ANDGP%<EP% 19110PROCdelete_gate(2) 19120ENDWHILE 19130PROCrescore(PX%) 19140ELSE 19150IFGP%?-2 PROCinsert_gate(2):PROCbar:NBars%+=1:PROCrescore(PX%) 19160ENDIF 19170ENDIF 19180ENDPROC 19190 19200DEF PROCrescore(px%) 19210IFpx% ELSEPROCstart_music:REM Bar position assumed set, but reset if px%=0 19220PROCset_score(px%) 19230IF px%=0 PROCSetupBarStarts(0) ELSE PROCSetupBarStarts(FNFindBar(px%)) 19240PROCupdate_score(PX%(px%),-Score_Height%,Score_Width%,0) 19250ENDPROC 19260 19270DEF PROCupdate_note(S%,N%,X%,Y%) 19280LOCALlx0%,lx1%,ly0%,ly1% 19290PROCbound_note(N%):REM Get minimum bounding rectangle of note 19300IFN%AND4 lx1%=X%(tie%):IFY%(tie%)>ly1% ly1%=Y%(tie%):REM Tie sets suffix and may be higher (Tie bounds only apply to updating) 19310IFABS(Y%-Y_STAVE%(S%))>Li%*5 THEN 19320IFx%(dot%)>lx0% lx0%=x%(dot%) 19330IFX%(dot%)>lx1% lx1%=X%(dot%):REM Extend to ledger extent 19340ENDIF 19350ly1%+=Y%:Y%-=ly0%:ly0%=Y_STAVE%(S%):REM Stave position 19360IFly1%<ly0%-Li%*5 ly1%=ly0%-Li%*5 ELSEIFY%>ly0%+Li%*5 Y%=ly0%+Li%*5:REM If ledger lines will be drawn increase vertical update space 19370PROCupdate_score(X%-lx0%,Y%,X%+lx1%+Pgap%,ly1%):REM Update symbol space 19380ENDPROC 19390 19400DEF PROCattach(s%,V%) 19410SCRIBE%(sx%)=TRUE:REM New position (Maintain Y for orientation maintainance) 19420SCRIBE%(drawn%)=FALSE 19430IFs%<rest%ANDSCRIBE%(sprite%)<rest% s%=s%AND7ORSCRIBE%(sprite%)AND8:REM Maintain note orientation 19440SCRIBE%(sprite%)=s% 19450SCRIBE%(valid%)=V% 19460SCORING%=TRUE 19470ENDPROC 19480:: 19490DEF PROCrelease 19500IFSCORING%ANDSCRIBE%(drawn%) THEN 19510LOCALWindow%:Window%=Icon%+100:REM Don't corrupt window workspace 19520PROCfloat(SCRIBE%(sprite%),SCRIBE%(sx%),SCRIBE%(sy%)):REM Undraw sprite 19530IFSCRIBE%(sprite%)<rest% IFABSSCRIBE%(line%)>5 PROCfloat(ledger%+SCRIBE%(line%)DIV2,SCRIBE%(sx%),Y_STAVE%(SCRIBE%(stave%))):REM Undraw ledger lines 19540SCRIBE%(sx%)=TRUE:REM Continue drawing of symbol 19550SCRIBE%(drawn%)=FALSE 19560ENDIF 19570ENDPROC 19580:: 19590REM PROCEDURE: scribe(At X%,Y%) 19600REM 19610REM DESCRIPTION: Draw current music symbol at position over score window 19620: 19630DEF PROCscribe(X%,Y%) 19640LOCALS%,L%,C% 19650Window%!handle%=ScoreWind_h% 19660SYS GetWindowState%,,Window%+handle% 19670X%-=Window%!x0%-Window%!scx% 19680Y%-=Window%!y1%-Window%!scy% 19690PROCproximate(SCRIBE%(valid%)) 19700IFX%<>SCRIBE%(sx%)ORY%<>SCRIBE%(sy%) THEN 19710LOCALA% 19720A%=TRUE 19730IF(SCRIBE%(valid%)AND112)=96 A%=FALSE:IFC%>=0 A%=SCRIBE%(valid%)AND8ORS%<=STAVE%AND?N%(C%)AND&F8 19740IFA% THEN 19750IFSCRIBE%(drawn%) THEN 19760PROCfloat(SCRIBE%(sprite%),SCRIBE%(sx%),SCRIBE%(sy%)) 19770IFSCRIBE%(sprite%)<rest% IFABSSCRIBE%(line%)>5 PROCfloat(ledger%+SCRIBE%(line%)DIV2,SCRIBE%(sx%),Y_STAVE%(SCRIBE%(stave%))) 19780ELSE 19790SCRIBE%(drawn%)=TRUE 19800ENDIF 19810IFSCRIBE%(sprite%)<rest% THEN 19820IFABSL%>5 PROCfloat(ledger%+L%DIV2,X%,Y_STAVE%(S%)) 19830IFY%<>SCRIBE%(sy%) SCRIBE%(sprite%)=SCRIBE%(sprite%)AND7OR8ANDY%>SCRIBE%(sy%) 19840ENDIF 19850SCRIBE%(sx%)=X% 19860SCRIBE%(sy%)=Y% 19870SCRIBE%(stave%)=S% 19880IFS%<=Max_Stave% SCRIBE%(sclef%)=CLEF%(S%) ELSESCRIBE%(sclef%)=CLEF%(Max_Stave%) 19890SCRIBE%(line%)=L% 19900SCRIBE%(posx%)=PX% 19910SCRIBE%(sgp%)=GP% 19920SCRIBE%(sc%)=C% 19930FORC%=0TO7:SCRIBE%(C%)=N%(C%):NEXT 19940PROCfloat(SCRIBE%(sprite%),X%,Y%) 19950ENDIF 19960ENDIF 19970ENDPROC 19980:: 19990REM PROCEDURE: proximate(Positions valid mask V%) 20000REM 20010REM DESCRIPTION: Will set X%,Y% to be the nearest valid position to the point 20020REM X%,Y% supplied (all in stave coordinates) and return the 20030REM associated position index PX%. 20040REM 20050REM A mask is supplied to indicate the valid positions: 20060REM V% bit 0 -> Valid Time signature positions 20070REM 1 -> Valid Key signature positions 20080REM 2 -> Valid Clef positions 20090REM 3 -> At note positions 20100REM 4 -> In between notes 20110REM 5 -> To nearest stave line (else nearest stave) 20120REM 6 -> To nearest symbol present 20130REM 7 -> On bar line if near 20140REM 20150REM EFFECTS: Sets S%=Stave, L%=Line(-15..15), C%=Channel of note, GP%,N%()=Gate & note pointers, PX%=PX%() index, X%,Y% position 20160: 20170DEF PROCproximate(V%):REM (V%, var X%,Y%) = (S%,L%,PX%) 20180LOCALd%,D%:REM Distance previous¤t 20190LOCALpx%,x%:REM Previous PX%, Between note X position 20200LOCALgp%:REM Previous gate pointer, key sig 20210IF NBars%>4 THEN BAR%=LHBAR% ELSE BAR%=0 20220PROCGetBarInfo(BAR%) : REM Start from start of page 20230D%=4*S_Width%:REM A suitably excessive distance 20240IF V%AND7 THEN 20250LOCALT%:REM Type mask 20260X%-=X%(clef%)>>1:REM Pointer points to centre of Clef/Key/Time 20270T%=-V%<<1AND6:REM Valid Clef/Key/Time: Work out types to ignore after bars 20280REPEAT 20290PROCsavp:REM Save previous distance, pointers etc 20300REPEATPROCskip_gate:UNTILPTYPE%(PX%)ANDBar%ORGP%=EP%:REM Move to next bar PX% 20310IFPTYPE%(PX%)ANDBar% THEN 20320WHILEPTYPE%(PX%+1)ANDT%ANDGP%<EP% 20330REPEATPROCskip_gate:UNTILGP%=EP%ORGP%?1AND%111EOR%100:REM Skip ALL clefs 20340ENDWHILE:REM Skipping any T% types 20350D%=ABS(X%-PX%(PX%+1)):REM Calculate distance to this position 20360ELSE 20370D%=2*S_Width%:REM No more bars 20380ENDIF 20390UNTILD%>d%ORGP%=EP%:REM Until distance increases or no more positions 20400IFd%<D% PROCrstp:REM Previous position may be closer 20410X%=PX%(PX%+1):REM Set as position 20420ELSE 20430X%-=X%(2)>>1:REM Pointer points to centre of note 20440REPEAT 20450PROCsavp:REM Save previous distance, pointers etc 20460PROCskip_gate:REM Next symbol 20470WHILEPTYPE%(PX%+1)ANDGP%<EP%:PROCskip_gate:ENDWHILE:REM Skip any attribute types 20480D%=ABS(X%-PX%(PX%+1)):REM Calculate distance to this note position 20490UNTILD%>d%ORGP%=EP%:REM Until distance increases or no more notes 20500IFd%<D%ORGP%=EP%ANDV%AND64 PROCrstp:REM Previous position may be closer (or the last valid note position for an accidental/dot to appear) 20510IFV%AND16ANDGP%<EP% THEN 20520REM Valid between notes (if before last position) 20530IFX%<PX%(PX%+1)ORX%>PX%(EX%) THEN 20540IFPTYPE%(PX%) x%=PX%(PX%)+PW%(PX%)-X%(2) ELSEx%=PX%(PX%):REM Before current: between previous. (also if after last note) 20550x%=x%+PX%(PX%+1)>>1 20560IFV%AND128 x%+=Hi%*4:IFPTYPE%(PX%)=Bar% x%=PX%(PX%) 20570ELSE 20580x%=PX%(PX%+1)+PX%(PX%+2)>>1:REM After current: between next. 20590IFV%AND128 x%+=Hi%*4:IFPTYPE%(PX%+2)=Bar% x%=PX%(PX%+2) 20600ENDIF 20610IFV%AND8ANDABS(PX%(PX%+1)-X%)<ABS(x%-X%) X%=PX%(PX%+1) ELSEX%=x%:REM If on notes also valid then find closest position 20620ELSE 20630X%=PX%(PX%+1):REM Only at notes valid: closest position 20640ENDIF 20650ENDIF 20660C%=-1:REM Initially no channel 20670L%=0:REM Initially centre line 20680IFV%AND64AND?GP%>0 THEN 20690REM To nearest symbol at gate (just note at the moment !!) 20700LOCALG%,c%:REM Gate mask copy, Previous channel counter 20710c%=C% 20720d%=2*S_Height%:REM A suitably excessive distance 20730G%=?GP% 20740REPEAT 20750REPEATC%-=TRUE:UNTILG%AND%1<<C% 20760D%=Y%-Y_STAVE%(S_C%(C%)) 20770IF?N%(C%)AND&F8 D%=ABS(D%-Li%*((?N%(C%)>>3)-16)) ELSED%=ABSD%:REM Distance to note/rest 20780IFD%<d% d%=D%:c%=C% 20790UNTIL(2<<C%)>G% 20800C%=c%:REM Nearest note 20810S%=S_C%(C%) 20820IF?N%(C%)AND&F8 L%=(?N%(C%)>>3)-16 20830ELSE 20840LOCALMS%:REM Highest stave number 20850MS%=STAVE%:IFV%AND6 ELSEMS%+=PERC%:REM Clef & Key not on percussion. 20860S%=-1:REM Before first stave 20870D%=2*S_Height%:REM A suitably excessive distance 20880REPEAT 20890d%=D%:REM Copy previous distance 20900S%+=1:REM Next stave 20910D%=ABS(Y%-Y_STAVE%(S%)):REM Distance between point and current stave 20920UNTILD%>d%ORS%=MS%:REM Until distance increases or no more staves 20930S%+=d%<D%:REM Previous stave was closest unless last¤t stave is nearer 20940IFV%AND32THEN 20950IFS%=STAVE%+1 S%+=Y%>=Y_STAVE%(STAVE%)-Li%*16:REM Ledger lines take priority over percussion lines 20960IFS%<=STAVE% THEN 20970L%=(Y%-Y_STAVE%(S%))/Li%+16.75:L%-=16:REM Y% is L% Lines away from centre stave 20980IFABSL%>15 L%=15*SGNL%:REM No further than 15 lines away 20990ENDIF 21000ENDIF 21010ENDIF 21020Y%=Y_STAVE%(S%)+L%*Li%:REM Centre line + offset 21030ENDPROC 21040:: 21050 21060DEF PROCsavp:n%()=N%():d%=D%:px%=PX%:gp%=GP%:clef%()=CLEF%():sig%()=SIG%():ENDPROC 21070 21080DEF PROCrstp:N%()=n%():PX%=px%:GP%=gp%:CLEF%()=clef%():SIG%()=sig%():ENDPROC 21090 21100DEF PROCSetTempo(T%) 21110Tempo%=T% 21120SYS Sound_QTempo,Tempo%(T%)*128*4096DIV6000 21130ENDPROC 21140 21150REM given x position, return number of bar 21160DEF FNFindBar(xpos%) 21170LOCAL bar% 21180bar%=0 21190WHILE PX%(PXn%(bar%))<xpos% AND bar%<=NBars%:bar%+=1:ENDWHILE 21200IF bar%>0 bar%-=1 21210=bar% 21220 21230DEF PROCplay_start 21240LOCALC%,n% 21250SYS Sound_Configure,8 21260REM set play start bar PBAR% to start of currently displayed window (scx%) 21270Window%!handle%=ScoreWind_h% 21280SYS GetWindowState%,,Window%+handle% 21290PBAR%=FNFindBar(Window%!scx%) 21300PP%=GPn%(PBAR%) 21310FOR n%=0 TO 7 21320 P%(n%)=BPn%(n%,PBAR%) 21330 NEXT 21340FORC%=0TO3 21350PCLEF%(C%)=Clef%(CLEFn%(C%,PBAR%)) 21360NEXT 21370PROCplay_key_sig(SIGn%(1,PBAR%)) 21380PLAYING%=TRUE 21390SCROLLING%=TRUE 21400Beats%=((SIGn%(0,PBAR%)>>1AND&F)+1)*Length%(SIGn%(0,PBAR%)>>3AND%11100) 21410Q%()=Beats% 21420TIE%=&FF 21430B2%=&10000 21440SYS Sound_QBeat,Beats% 21450SYS Sound_QSchedule,Beats%,Sch%ORSound_QTempo,Tempo%(Tempo%)*128*4096DIV6000 21460C%=Beats%/50*&1000:IFC%>&7FFF C%=&7FFF 21470SYS Sound_QTempo,C% 21480MIDI_OFF%(0,0) = -1 21490MIDI_OFF%(1,0) = -1 21500ENDPROC 21510 21520REM flush sound queue and ensure note_offs are sent to midi channels 21530DEFPROCplay_stop 21540LOCAL note%, n% 21550PLAYING%=FALSE 21560SYS Sound_QInit 21570IF MIDIpresent% THEN 21580 FOR n%=0 TO 1 21590 note%=0 21600 WHILE (MIDI_OFF%(n%,note%) > 0) 21610 SYS MIDI_TxCommand%, MIDI_OFF%(n%,note%) 21620 note%+=1 21630 ENDWHILE 21640 NEXT 21650 REM reset end markers 21660 MIDI_OFF%(0,0) = -1 21670 MIDI_OFF%(1,0) = -1 21680 ENDIF 21690ENDPROC 21700 21710REM This should give a reasonable approximation to a smooth scroll 21720DEF PROCCheckScroll 21730LOCAL PosX%, WindowWidth%, BarPos%, LastScroll%,ThisScroll% 21740IF ScoreClosed% THEN 21750 IF NOT PLAYING% SCROLLING%=FALSE 21760 ENDPROC 21770 ENDIF 21780IF BADMODE% OR PBAR%<=2 ENDPROC 21790IF PLAYING% PROCCheckQ 21800IF PLAYING% SBAR%=PBAR%-2 ELSE B1%=B2%:B2%=BEAT:IFB2%<B1%:SBAR%+=1 21810IF SBAR%>=NBars% OR SBAR%>PBAR%+2 SCROLLING%=FALSE:ENDPROC 21820SYS GetWindowState%,,ScoreWBlk%+handle% 21830WindowWidth%=ScoreWBlk%!x1%-ScoreWBlk%!x0% 21840LastScroll%=ScoreWBlk%!scx% 21850PosX%=PX%(PXn%(SBAR%)) 21860BarPos%=(PX%(PXn%(SBAR%+1))-PosX%)*BEAT DIV Beats% 21870IF BarPos%*2<Pgap% ENDPROC :REM if small amount into bar can scroll to wrong bar (sync with play) 21880PosX%+=BarPos% 21890ThisScroll% = PosX%-WindowWidth%DIV2 21900IF ThisScroll%<=0 ENDPROC 21910IF ThisScroll%<>LastScroll% THEN 21920 REM auto-scroll 21930 REM divide scroll into small bits to make it appear smooth 21940 ScoreWBlk%!scx%=(LastScroll%+ThisScroll%)/2 21950 SYS OpenWindow%,,ScoreWBlk%+handle% 21960 ScoreWBlk%!scx%=ThisScroll% 21970 SYS OpenWindow%,,ScoreWBlk%+handle% 21980 LHBAR%=FNFindBar(ThisScroll%)-1 :REM the bar number at the left of the window 21990 IF PLAYING%=FALSE THEN 22000REM stop scrolling at end of music 22010 IF ScoreWBlk%!scx%<=LastScroll% SCROLLING%=FALSE 22020 ENDIF 22030 ENDIF 22040ENDPROC 22050 22060DEF PROCplay_bar 22070LOCALC%,L%,I%,D%,S%,Q%,T%,B%,A%:REM Vars for play_bar & play_notes 22080LOCAL f 22090MIDI_Notenum%=0 22100Q%()=Beats%:REM Reset stave queue counters for next bar 22110B%=PBAR% 22120Accidental%()=0:REM No incidental accidentals initially 22130First%=TRUE 22140WHILEB%=PBAR%ANDPP%<GATE% 22150IF?PP% PROCplay_notes(?PP%):PP%+=1 ELSEPROCplay_attribute(PP%?1):PP%+=2 22160First%=FALSE 22170ENDWHILE 22180IFPP%>=GATE% PLAYING%=FALSE:SBAR%+=1 22190ENDPROC 22200 22210REM Notes for each gate start playing at Q%; the latest Q%() of the staves on 22220REM which notes are to play. This is because all notes in a gate play at the 22230REM same time and cannot start before the shortest of the notes preceding them 22240REM have finished. 22250REM Q% is the time at which the notes in the gate are played 22260REM Q%(S%) is the time at the end of the shortest note played on stave S%. 22270REM QI%(S%) is the current shortest note beats interval on stave S% 22280 22290DEF PROCplay_notes(G%) 22300LOCAL note%, packed%, Qoff%,xtraVol,tempo 22310tempo = 5 * 128 * Tempo%(Tempo%) / 6000 22320Q%=FALSE:C%=TRUE 22330REPEATREPEATC%-=TRUE:UNTILG%AND%1<<C% 22340IFQ%(S_C%(C%))>Q% Q%=Q%(S_C%(C%)) 22350UNTIL(2<<C%)>G% 22360QI%()=&10000:C%=TRUE 22370REPEAT 22380 IF First% xtraVol=1.01 ELSE xtraVol=1.0 :REM a little dynamics. stress 1st beat in bar very slightly 22390 REPEATC%-=TRUE:UNTILG%AND%1<<C% 22400 IF INT(xtraVol*Volume%(Volumes%(C%)))>&7F xtraVol=1.0 :REM ensure no overflow 22410 T%=?P%(C%):D%=P%(C%)?1:I%=D%>>3:S%=S_C%(C%):L%=T%>>3:A%=0 22420 IFL%ANDS%<=STAVE% THEN 22430 IFD%AND7 Accidental%(S%,L%)=D%AND7 22440 A%=Accidental%(S%,L%):L%+=PCLEF%(S%):IFA% ELSEA%=Key%(L%MOD7):REM If no accidental then revert to key signature 22450 ENDIF 22460 IFTIE%AND%1<<C% THEN 22470 D%=Duration%(Tempo%)?I%:IFT%AND4 TIE%=TIE%ANDNOT(%1<<C%):T%=P%(C%)+1:REPEATT%+=2:D%+=Duration%(Tempo%)?(?T%>>3):UNTILT%>FINE%(C%)OR4ANDNOTT%?TRUE:IFD%>254 D%=254 22480 IFL% THEN 22490 SOUNDC%+1,INT(xtraVol*Volume%(Volumes%(C%)))OR&100,Line(L%)+Aoff(A%),D%,Q% 22500 IF MIDIpresent% THEN 22510 IF (MIDIChannel%(C%)>=1) AND (MIDIChannel%(C%)<=16) THEN 22520 note% = 12 + INT(((Line(L%)+Aoff(A%))/&1000) * 12) 22530 packed% = (MIDIChannel%(C%)-1) OR (note%<<8) OR INT(xtraVol*(Volume%(Volumes%(C%)))<<16) 22540 MIDI_OFF%(PBAR%MOD2,MIDI_Notenum%) = M_NoteOff% OR packed% 22550 MIDI_Notenum% += 1 22560 MIDI_OFF%(PBAR%MOD2,MIDI_Notenum%) = -1 :REM end marker 22570 REM D% = no. of 5 centisecs 22580 Qoff% = Q% + D% * tempo 22590 IF Qoff% > Q% + 15 Qoff% -= 10 :REM ensure note is off after start and before next note start 22600 SYS Sound_QSchedule,Q%, Sch% OR MIDI_TxCommand%, M_NoteOn% OR packed% 22610 SYS Sound_QSchedule,Qoff%, Sch% OR MIDI_TxCommand%, M_NoteOff% OR packed% 22620 ENDIF 22630 ENDIF 22640 ENDIF 22650 ELSE 22660 IF4ANDNOTT% TIE%=TIE%OR%1<<C% 22670 ENDIF 22680 P%(C%)+=2:IFLength%(I%)<QI%(S%) QI%(S%)=Length%(I%):Q%(S%)=Q%+QI%(S%) 22690 UNTIL(2<<C%)>G% 22700ENDPROC 22710 22720DEF PROCplay_attribute(A%) 22730C%=TRUE:REPEATC%-=TRUE:UNTILA%AND%1<<C% 22740ONC%+1 PROCplay_time_sig(A%),PROCplay_key_sig(A%),PROCplay_clef(A%),PROCplay_slur(A%),PROCplay_octave(A%),PROCplay_bar_line(A%) 22750ENDPROC 22760 22770DEF PROCplay_time_sig(A%) 22780A%=((A%>>1AND&F)+1)*Length%(A%>>3AND%11100) 22790SYS Sound_QSchedule,Beats%,Sch%ORSound_QBeat,A% 22800Beats%=A% 22810ENDPROC 22820 22830DEF PROCplay_key_sig(A%) 22840LOCALN%:A%=A%>>2 22850FORN%=0TO6:Key%(N%)=Key_Sig%(A%,N%):NEXT 22860ENDPROC 22870 22880DEF PROCplay_clef(A%) 22890PCLEF%(A%>>6)=Clef%(A%>>3AND3) 22900ENDPROC 22910 22920DEF PROCplay_slur(A%) 22930ENDPROC 22940 22950DEF PROCplay_octave(A%) 22960ENDPROC 22970 22980DEF PROCplay_bar_line(A%) 22990PBAR%+=1 23000ENDPROC 23010 23020DEF FNinitialise 23030LOCAL SoundEnable% 23040PROCEnumerateSWIs 23050PROCinitialise_miscellany 23060PROCinitialise_screen 23070PROCinitialise_sprites 23080PROCinitialise_wimp 23090SoundEnable%=FNinitialise_sound 23100PROCinitialise_music 23110PROCinitialise_menu 23120IF SoundEnable%=1 IF FNCheckOK("Sound is not enabled. Do you wish to quit?", 3) PROCterminate 23130=TRUE 23140 23150DEF PROCEnumerateSWIs 23160LOCALW%:W% = &400C0 23170SpriteOp% = &2E 23180Initialise% = W%+0 23190CreateWindow% = W%+1 23200CreateIcon% = W%+2 23210OpenWindow% = W%+5 23220CloseWindow% = W%+6 23230Poll% = W%+7 23240RedrawWindow% = W%+8 23250UpdateWindow% = W%+9 23260GetRectangle% = W%+10 23270GetWindowState% = W%+11 23280SetIconState% = W%+13 23290GetIconInfo% = W%+14 23300GetPointerInfo% = W%+15 23310DragBox = W%+16 23320ForceRedraw = W%+17 23330CreateMenu = W%+20 23340DecodeMenu = W%+21 23350SetExtent = W%+23 23360OpenTemplate = W%+25 23370CloseTemplate = W%+26 23380LoadTemplate = W%+27 23390CloseDown = W%+29 23400SYS "OS_SWINumberFromString",0,"Wimp_SendMessage" TO SendMessage 23410SYS "OS_SWINumberFromString",0,"Wimp_GetWindowOutline" TO GetWindowOutline 23420SYS "OS_SWINumberFromString",0,"Wimp_SetColour" TO SetColour 23430 23440LOCAL S0,S1,S2 23450SYS "OS_SWINumberFromString",0,"Sound_Configure" TO S0 23460SYS "OS_SWINumberFromString",0,"Sound_Volume" TO S1 23470SYS "OS_SWINumberFromString",0,"Sound_QInit" TO S2 23480Sound_Configure = S0 23490Sound_Enable = S0+1 23500Sound_Stereo = S0+2 23510Sound_Volume = S1 23520Sound_InstallVoice = S1+3 23530Sound_AttachVoice = S1+5 23540Sound_Control = S1+9 23550Sound_QInit = S2 23560Sound_QSchedule = S2+1 23570Sound_QRemove = S2+2 23580Sound_QFree = S2+3 23590Sound_QTempo = S2+5 23600Sound_QBeat = S2+6 23610Sch%=&F000000 23620LOCAL M% 23630LOCAL ERROR 23640ON ERROR LOCAL MIDIpresent%=FALSE : ENDPROC 23650SYS "OS_SWINumberFromString",0,"MIDI_SoundEnable" TO M% 23660M_NoteOff% = &80 23670M_NoteOn% = &90 23680MIDI_SoundEnable% = M% 23690MIDI_SetTxChannel% = M% + 2 23700MIDI_SetTxActiveSensing% = M% + 3 23710MIDI_TxCommand% = M% + 10 23720MIDI_TxLocalControl% = M% + 15 23730MIDI_TxOmniModeOff% = M% + 17 23740MIDI_TxOmniModeOn% = M% + 18 23750MIDI_TxMonoModeOn% = M% + 19 23760MIDI_TxPolyModeOn% = M% + 20 23770MIDI_TxProgramChange% = M% + 21 23780MIDI_TxSystemReset% = M% + 30 23790MIDIpresent%=TRUE : REM disable untested MIDI bits 23800ENDPROC 23810 23820DEF PROCinitialise_miscellany 23830DIM Resourcedir 255 23840LOCAL len 23850SYS "OS_ReadVarVal", "Maestro$dir", Resourcedir, 255, 0, 0 TO ,,len 23860Resourcedir?len=13 : REM It needs a cr termination 23870Resourcedir$=$Resourcedir 23880TIME=0 23890AwaitingAck%=FALSE 23900DRAGGING%=FALSE 23910SAVING%=FALSE 23920PLAYING%=FALSE 23930SCROLLING%=FALSE 23940TRANSCRIBE%=TRUE 23950DIM String_Space% 256 23960OS_File=&8 23970Sprite$=Resourcedir$+".Sprites" 23980CHANGED%=FALSE 23990FILE%=FALSE 24000laddr%=0 24010eaddr%=0 24020ENDPROC 24030 24040DEF PROCinitialise_screen 24050DIM modeblockin 40 24060DIM modeblockout 40 24070PROCgetmodeinfo(TRUE) 24080PROCset_colours 24090ENDPROC 24100 24110DEF PROCset_colours 24120LOCALC% 24130REM colours defined in memo from WStoye 21/7/88 24140C_MenuTitlefg = 7 24150C_MenuTitlebg = 2 24160C_Menufg = 7 24170C_Menubg = 0 24180C_MenuItemfg = 7 24190C_MenuItembg = 0 24200ENDPROC 24210 24220DEF PROCgetmodeinfo(new) 24230LOCAL S_Rows%, S_Columns% 24240modeblockin!0=0 : REM ModeFlags 24250modeblockin!4=1 : REM ScrRCol 24260modeblockin!8=2 : REM ScrBCol 24270modeblockin!12=3 : REM NColour 24280modeblockin!16=4 : REM XEigFactor 24290modeblockin!20=5 : REM YEigFactor 24300modeblockin!24=11 : REM XWindLimit 24310modeblockin!28=12 : REM YWindLimit 24320modeblockin!32=-1 : REM terminate list 24330SYS "OS_ReadVduVariables",modeblockin, modeblockout 24340BADMODE% = FALSE : REM ((modeblockout!12)>15) :REM doesn't work in 256-colour modes 24350REM no point in reading sizes since they are fixed by the wimp 24360Hi%=1<<(modeblockout!16) 24370Vi%=1<<(modeblockout!20) 24380S_Width%=Hi% * ((modeblockout!24)+1) 24390S_Height%=Vi% * ((modeblockout!28)+1) 24400Hi%=2: Vi%=4 24410C_Width%=8*Hi% : C_Height%=8*Vi% 24420IF NOT new THEN 24430 IF NOT BADMODE% SYS"Wimp_ReadPixTrans",&200,SprBlk%,S%(0),,,,factors%,pixtrans% 24440 ENDIF 24450ENDPROC 24460 24470DEF PROCinitialise_sprites 24480DIM factors% 16 24490DIM pixtrans% 16 24500SYS "Wimp_SpriteOp", 11,,Resourcedir$+".!Sprites" :REM merge music file type sprite into wimp sprite area 24510SpriteLen% = 10000 24520DIM SprBlk% SpriteLen% 24530!SprBlk% = SpriteLen% :REM initialise private sprite area 24540SprBlk%!4 = 0 24550SprBlk%!8 = 16 24560SprBlk%!12 = 16 24570SYS SpriteOp%, 512+10, SprBlk%, Sprite$ :REM *SLOAD equivalent 24580SprPlot% = &234 : REM sprite plot code 24590LOCAL I%,N%,x%,y%,W%,H% 24600RESTORE 24610N%=-1 24620READS$ 24630WHILES$<>"" 24640READx%,y%,W%,H%,S$ 24650N%+=1 24660ENDWHILE 24670IFFNassert(N%>=0,"loading sprite data.") STOP 24680DIM S$(N%),x%(N%),y%(N%),X%(N%),Y%(N%), S%(N%) : REM S%() are sprite pointers 24690RESTORE 24700FORI%=0TON% 24710READ S$(I%),x%,y%,W%,H% 24720SYS SpriteOp%, 256+24, SprBlk%, S$(I%) TO ,,S%(I%) : REM get pointer to sprite 24730x%(I%)=x%*Hi% 24740y%(I%)=y%*Vi% 24750X%(I%)=(W%-x%)*Hi% 24760Y%(I%)=(H%-y%)*Vi% 24770NEXT 24780note%=0 24790rest%=16 24800accidental%=24 24810clef%=32 24820high%=36 24830dot%=44 24840ledger%=47 24850bar%=48 24860time%=55 24870key%=56 24880tie%=57 24890pointer%=58 24900DIM SL%(N%,1):REM List & item indexes for each sprite (set in list definitions) 24910SCORING%=FALSE:REM Flag indicating a sprite is to be drawn under the pointer 24920wasSCORING%=FALSE 24930stopSCORING%=TRUE 24940SCORING%=FALSE 24950DIM SCRIBE%(18):REM Details of symbol under pointer 24960REM 0-7 Channel pointers into N%() 24970sx%=8:REM Current sprite X position 24980sy%=9:REM Current sprite Y position 24990drawn%=10:REM Flag indicating sprite presence 25000sprite%=11:REM Sprite number 25010valid%=12:REM Valid stave positions 25020stave%=13:REM Current stave symbol is on 25030sclef%=14:REM Current clef applying to symbol (used for key sigs) 25040line%=15:REM Current stave line symbol is on 25050posx%=16:REM X music position 25060sgp%=17:REM Symbol gate pointer 25070sc%=18:REM Channel number if symbol specified close to note 25080PROCgetmodeinfo(FALSE) 25090ENDPROC 25100REM name, x, y, w, h 25110DATA B,7,3,26,7,SB,0,2,12,5,Mu,0,2,11,15,Cu,0,2,11,15,Qu,0,2,17,17,SQu,0,2,17,17,DSQu,0,2,17,17,SDSQu,0,2,17,17 25120DATA B,7,3,26,7,SB,0,2,12,5,Md,0,12,11,15,Cd,0,12,11,15,Qd,0,14,11,17,SQd,0,14,11,17,DSQd,0,14,11,17,SDSQd,0,14,11,17 25130DATA Rest,-1,-1,8,4,Rest,-1,-2,8,4,Rest,-1,0,8,4,Rest4,-2,5,7,12,Rest8,-1,4,9,8,Rest16,0,8,11,12,Rest32,1,8,13,16,Rest64,2,12,15,20 25140DATA M,0,2,11,5,Natural,8,6,7,13,Sharp,10,5,9,11,Flat,8,3,7,12,Sharp2,9,2,8,5,Flat2,14,3,13,12,NSharp,17,6,16,13,NFlat,15,6,14,15 25150DATA Treble,0,16,18,31,Alto,0,8,16,19,Alto,0,4,16,19,Bass,0,7,20,17 25160DATA Bh,7,3,26,7,SBh,0,2,12,5,Mh,0,2,11,5,Ch,0,2,11,5 25170DATA ldg5,2,28,15,17,ldg4,2,24,15,13,ldg3,2,20,15,9,ldg2,2,16,15,5,ldg1,2,12,15,1 25180DATA Dot1,-12,2,3,2,Dot2,-12,2,8,2,Dot3,-12,2,13,2,Bar,-1,8,2,17,C,0,2,11,5 25190DATA ldg1,2,-12,15,1,ldg2,2,-12,15,5,ldg3,2,-12,15,9,ldg4,2,-12,15,13,ldg5,2,-12,15,17 25200DATA Time,1,9,25,19,Key,0,13,0,30,Tie,-12,-3,23,3,"" 25210 25220DEF PROCinitialise_wimp 25230PROCenumerate_wimp_offsets 25240task%=ASC("T")+(ASC("A")<<8)+(ASC("S")<<16)+(ASC("K")<<24) 25250SYS Initialise%, 200, task%, "Maestro" TO ,Task_h% 25260Mouse_X%=640:Mouse_Y%=560 25270PTIME%=0 25280DIM SpriteName% 14 25290$SpriteName%="!Maestro" 25300!Icon%=-1: REM iconbar utility 25310Icon%!4=0 25320Icon%!8=0 25330Icon%!12=64 25340Icon%!16=68 25350Icon%!20=(&311A OR (0<<24) OR (7<<28)) :REM indirected 25360Icon%!24=SpriteName% :REM indirected name 25370Icon%!28=1 :REM use common sprite area 25380Icon%!32=12 :REM name length 25390SYS CreateIcon%, ,Icon% TO Maestro_h% 25400PROCload_templates 25410ENDPROC 25420 25430DEF PROCenumerate_wimp_offsets 25440DIM Wimp_Space% &4000 25450Window%=Wimp_Space%+4 25460handle%=-4 25470x0%=0:y0%=4:x1%=8:y1%=12 25480scx%=16:scy%=20 25490under%=24 25500flags=28:status=30 25510tFrgd=32:tBkgd=33:Frgd=34:Bkgd=35 25520sbo=36:sbi=37 25530tHigh=38 25540title_flags=56 25550work_area_flags=60 25560sprite_area=64 25570title=72 25580icons=84 25590icon_defs=88 25600Icon%=Wimp_Space%+4 25610iflags=16 25620Colour=19 25630idata=20 25640Mouse%=Wimp_Space% 25650buttons=8 25660window=12 25670icon=16 25680old_buttons=20 25690colour=23 25700state=4 25710mask=8 25720Clip%=Window%+24 25730key=20 25740ENDPROC 25750 25760DEF PROCload_templates 25770LOCAL size, end 25780DIM windowname 12 25790DIM ScoreWBlk% 32 25800DIM NotePBlk% 32 25810DIM SharpPBlk% 32 25820DIM RestPBlk% 32 25830DIM ScoreTitle% 256 25840size = 1000 25850dialogsize = 3000 25860DIM InstrIndirect size : REM buffer for indirected text of instruments list 25870ScoreWBlk%-=handle% 25880DIM DialogIndirect dialogsize : REM buff for indirected text of dialog boxes 25890NotePBlk%-=handle% 25900SharpPBlk%-=handle% 25910RestPBlk%-=handle% 25920SYS OpenTemplate, ,Resourcedir$+".Templates" 25930$windowname="ScoreWind" 25940SYS LoadTemplate, ,Window%, ScoreTitle%, ScoreTitle%+255, -1, $windowname, 0 25950Window%!68=&10001 :REM reserved word sets min window size. to other than title size 25960SYS CreateWindow%, ,Window% TO ScoreWind_h% 25970ScoreWBlk%!handle%=ScoreWind_h% 25980SYS GetWindowState%, ScoreWind_h%, ScoreWBlk%+handle% 25990$windowname="SharpsPane" 26000SYS LoadTemplate, ,Window%, Window%+icons, Window%+200, -1, $windowname, 0 26010Window%!64=SprBlk% :REM use private sprite area 26020SYS CreateWindow%,, Window% TO SharpsPane_h% 26030SharpPBlk%!handle%=SharpsPane_h% 26040SYS GetWindowState%,, SharpPBlk%+handle% 26050SharpPBlk%!under%=-1 26060$windowname="RestsPane" 26070SYS LoadTemplate, ,Window%, Window%+icons, Window%+200, -1, $windowname, 0 26080Window%!64=SprBlk% :REM use private sprite area 26090SYS CreateWindow%, ,Window% TO RestsPane_h% 26100RestPBlk%!handle%=RestsPane_h% 26110SYS GetWindowState%,, RestPBlk%+handle% 26120RestPBlk%!under%=SharpsPane_h% 26130$windowname="NotesPane" 26140SYS LoadTemplate, ,Window%, Window%+icons, Window%+200, -1, $windowname, 0 26150Window%!64=SprBlk% :REM use private sprite area 26160SYS CreateWindow%, ,Window% TO NotesPane_h% 26170NotePBlk%!handle%=NotesPane_h% 26180SYS GetWindowState%,, NotePBlk%+handle% 26190NotePBlk%!under%=RestsPane_h% 26200PaneHeight%=Window%!y1%-Window%!y0% 26210SelW%=NotesPane_h%:SelI%=0 26220$windowname="InstrWind" 26230 SYS LoadTemplate, ,Window%, InstrIndirect, InstrIndirect+size, -1, $windowname, 0 26240IF NOT MIDIpresent% Window%!8-=100:Window%!48-=100:REM hide MIDI column in window 26250SYS CreateWindow%, ,Window% TO InstrWind_h% 26260LOCAL n% 26270DIM StaveStr%(7), VoiceStr%(7), VolumeStr%(7), StereoStr%(7), MIDIChStr%(7) :REM pointers to icon strings 26280VoiceSize%=20 : VolSize%=4 : SterSize%=14 : MIDIChSize%=3 26290FOR n%=0 TO 7 26300 StaveStr%(n%) = InstrIndirect + n%*14 26310 NEXT 26320InstrIndirect+=8*14 26330FOR n%=0 TO 7 26340 VoiceStr%(n%) = InstrIndirect + n%*VoiceSize% 26350 VolumeStr%(n%) = InstrIndirect + 8*VoiceSize% + n%*VolSize% 26360 StereoStr%(n%) = InstrIndirect + 8*VoiceSize% + 8*VolSize% + n%*SterSize% 26370 MIDIChStr%(n%) = InstrIndirect + 8*VoiceSize% + 8*VolSize% + 8*SterSize% +n%*MIDIChSize% 26380 IF NOT MIDIpresent% PROCUpdateIcon(InstrWind_h%, 32+n%, 1<<22, 0) :REM make icons unselectable 26390 NEXT 26400end=DialogIndirect+dialogsize 26410$windowname="progInfo" 26420SYS LoadTemplate, ,Window%, DialogIndirect, end, -1, $windowname, 0 26430SYS CreateWindow%, ,Window% TO ProgInfo_h% 26440DialogIndirect+=13 : REM skip indirected window title 26450$DialogIndirect = "Maestro" : DialogIndirect+=40 26460$DialogIndirect = "Music player" : DialogIndirect+=40 26470$DialogIndirect = "Acorn Computers" : DialogIndirect+=40 26480$DialogIndirect = VersionStr$ : DialogIndirect+=30 26490$windowname="query" 26500SYS LoadTemplate, ,Window%, DialogIndirect, end, -1, $windowname, 0 26510SYS CreateWindow%, ,Window% TO AbortQuery_h% 26520DialogIndirect+=100 :REM "music not saved etc." 26530DialogIndirect+=100 26540DIM FileSpriteName% 16 26550$FileSpriteName%="file_"+STR$~MusicFileType% 26560$windowname="xfer_send" 26570SYS LoadTemplate, ,Window%, DialogIndirect, end, -1, $windowname, 0 26580Window%!64=1 :REM use common sprite area 26590SpriteIcon%=Window%+88+32*2 :REM pointer to icon number 2 in save window 26600SpriteIcon%!16=SpriteIcon%!16 OR 1<<1 OR 1<<8 :REM indirected sprite 26610SpriteIcon%!16=SpriteIcon%!16 AND NOT 1 :REM not text 26620SpriteIcon%!24=1 :REM wimp area pointer 26630SpriteIcon%!28=12 26640SYS CreateWindow%, ,Window% TO Save_h% 26650SaveText=DialogIndirect 26660$SaveText="MusicFile"+CHR$(0) : DialogIndirect+=255 26670SaveSprite%=DialogIndirect :REM address of file type sprite in save window 26680DialogIndirect+=16 26690$SaveSprite%=$FileSpriteName% 26700$windowname="dboxfile_db" 26710SYS LoadTemplate, ,Window%, DialogIndirect, end, -1, $windowname, 0 26720SYS CreateWindow%, ,Window% TO Load_h% 26730DialogIndirect+=30 : LoadText=DialogIndirect 26740$LoadText=$SaveText : DialogIndirect+=255 26750$windowname="TimeSigW" 26760SYS LoadTemplate, ,Window%, DialogIndirect, end, -1, $windowname, 0 26770SYS CreateWindow%, ,Window% TO TimeSig_h% 26780BarLength%=DialogIndirect : DialogIndirect+=3 26790NoteValue%=DialogIndirect : DialogIndirect+=3 26800$windowname="BarW" 26810SYS LoadTemplate, ,Window%, DialogIndirect, end, -1, $windowname, 0 26820SYS CreateWindow%, ,Window% TO Bar_h% 26830BarNum%=DialogIndirect : DialogIndirect+=15 :REM allow for validation str 26840$windowname="FileInfo" 26850SYS LoadTemplate, ,Window%, DialogIndirect, end, -1, $windowname, 0 26860Window%!64=1 :REM use common sprite area 26870SpriteIcon%=Window%+88+32*6 :REM pointer to icon number 6 in save window 26880SpriteIcon%!16=SpriteIcon%!16 OR 1<<1 OR 1<<8 :REM indirected sprite 26890SpriteIcon%!16=SpriteIcon%!16 AND NOT 1 :REM not text 26900SpriteIcon%!24=1 :REM wimp area pointer 26910SpriteIcon%!28=12 26920SYS CreateWindow%, ,Window% TO FileInfo_h% 26930ThisFile%=DialogIndirect : DialogIndirect+=255 26940Updated%=DialogIndirect : DialogIndirect+=12 26950FileType%=DialogIndirect : DialogIndirect+=20 26960FileSize%=DialogIndirect : DialogIndirect+=20 26970FileDate%=DialogIndirect : DialogIndirect+=100 26980FileTypeSprite%=DialogIndirect :REM address of file type sprite in window 26990$FileTypeSprite%=$FileSpriteName% : DialogIndirect+=16 27000$ThisFile%="<untitled>" 27010$Updated%="NO" 27020F$="<untitled>" 27030$ThisFile%=F$+CHR$(0) 27040$ScoreTitle%=F$+CHR$(0) 27050SYS CloseTemplate 27060IF FNassert(DialogIndirect<end-10, "Not enough memory to load window templates.") : STOP 27070ScoreClosed%=FALSE 27080ENDPROC 27090 27100DEF PROCinitialise_menu 27110LOCAL item$, sub%, MenuBlock, SubMenuBlock, MenuEnd, MenuItemsList 27120LOCAL nextsub%, flags%, m%, width% 27130MenuSize% = 28+(20*24) 27140DIM MenuStart 15*MenuSize% :REM allow 15 menus max 27150MenuEnd=MenuStart+15*MenuSize% 27160DIM MenuString 14*4 27170DIM StaveNum% 1 : REM buffers for writeable icons 27180DIM ValstrS 10 27190RESTORE +0 27200MenuBlock=MenuStart 27210READ item$ 27220WHILE item$>"" 27230 CASE LEFT$(item$,3) OF 27240 WHEN "Mae" : IconMenu%=MenuBlock 27250REM note there are 2 "Maestro" menus. IconMenu% is the 2nd 27260 WHEN "Sta" : StaveMenu%=MenuBlock 27270 WHEN "Vol" : VolumeMenu%=MenuBlock 27280 WHEN "Tem" : TempoMenu%=MenuBlock 27290 WHEN "Maj" : MajorMenu%=MenuBlock 27300 WHEN "Min" : MinorMenu%=MenuBlock 27310 ENDCASE 27320 $MenuBlock = item$ 27330 MenuBlock?12 = C_MenuTitlefg 27340 MenuBlock?13 = C_MenuTitlebg 27350 MenuBlock?14 = C_Menufg 27360 MenuBlock?15 = C_Menubg 27370 READ width% 27380REM adjust menu width 27390 MenuBlock!16 = width% * C_Width% 27400 MenuBlock!20 = 44 27410 MenuBlock!24 = 0 27420 MenuItemsList=MenuBlock+28 27430 SubMenuBlock=MenuBlock+MenuSize% 27440 nextsub%=SubMenuBlock 27450 READ item$ 27460 WHILE item$>"" 27470 READ sub% 27480 IF sub%=0 sub%=-1 ELSE sub%=nextsub% : nextsub%+=MenuSize% 27490 IF FNassert(sub%<MenuEnd, "Menu too big.") STOP 27500REM pointers to windows 27510 CASE LEFT$(item$,4) OF 27520 WHEN "Inst" : sub%=InstrWind_h% 27530 WHEN "Info" : sub%=ProgInfo_h% 27540 WHEN "Save" : sub%=Save_h% 27550 WHEN "File" : sub%=FileInfo_h% 27560 WHEN "Time" : sub%=TimeSig_h% 27570 WHEN "Goto" : sub%=Bar_h% 27580 ENDCASE 27590 $(MenuItemsList+12) = item$+CHR$(0) 27600 MenuItemsList!4 = sub% 27610 MenuItemsList!8 = &21 OR (C_MenuItemfg<<24) OR (C_MenuItembg<<28) 27620 READ flags% 27630 !MenuItemsList=flags% AND %111 27640 REM indirect writeable icons 27650 IF flags%AND4 THEN 27660 MenuItemsList!8 = (MenuItemsList!8) OR 1<<8 :REM set indirect bit 27670 CASE LEFT$(item$,4) OF 27680 WHEN "Stav" 27690 MenuItemsList!12=StaveNum% :REM buffer pointer 27700 $ValstrS="a1-4" 27710 MenuItemsList!16 = ValstrS :REM validation string 27720 MenuItemsList!20 = 2 :REM buffer length 27730 ENDCASE 27740 ENDIF 27750 MenuItemsList+=24 27760 READ item$ 27770 ENDWHILE 27780 REM last item 27790 MenuItemsList-=24 27800 !MenuItemsList = !MenuItemsList OR &80 : REM last item 27810 READ item$ 27820 MenuBlock=SubMenuBlock 27830ENDWHILE 27840$BarLength%="4" 27850PROCSetVolume(6) : REM ff 27860PROCSetTempo(8) : REM moderato 27870$StaveNum%=LEFT$(STR$(STAVE%+1),1) 27880item% = FNFindMenuItem("+percussion", StaveMenu%) 27890IF (item%>=0) !item% = FNSetBit(PERC%=1, !item%, 0):REM set or clear tick 27900REM abstracted from set key sig 27910LOCAL n 27920IF KEY_SIG%(1) n=accidental%+2+KEY_SIG%(0) : X%(key%)=(x%(n)+X%(n))*KEY_SIG%(1) ELSE X%(key%)=x%(accidental%+2)+X%(accidental%+2) 27930CONFIRM%=FALSE 27940ENDPROC 27950REM [title, width, [item, 1 if sub_menu pointer, flags] ] 27960DATA "Maestro", 12 27970DATA "Save",0,0, "File",0,0, "Clear",0,2 27980DATA "Staves",1,0, "Instruments",0,0, "Volume",1,0, "Tempo",1,2 27990DATA "Time sig.",0,0, "Key sig.",1,2 28000DATA "Goto",0,0, "Play",0,0,"" 28010DATA "Staves",12 28020DATA "StaveNum",0,4, "+percussion",0,0,"" 28030REM 4 indicates writeable 28040DATA "Volume",4 28050DATA "ppp",0,0, "pp",0,0, "p",0,0, "mp",0,0, "mf", 0,0 28060DATA "f",0,0, "ff",0,1, "fff",0,0,"" 28070DATA "Tempo",12 28080DATA "Largissimo",0,0, "Largo",0,0, "Larghetto",0,0, "Grave",0,0 28090DATA "Adagio",0,0, "Adagietto",0,0, "Andante",0,0, "Andantino",0,0 28100DATA "Moderato",0,1, "Allegretto",0,0, "Allegro",0,0, "Vivace",0,0 28110DATA "Veloce",0,0, "Presto",0,0, "Prestissimo",0,0,"" 28120DATA "Key sig.",6 28130DATA "Major",1,0, "Minor",1,0,"" 28140DATA "Major",3 28150DATA "Cb",0,0, "Gb",0,0, "Db",0,0, "Ab",0,0, "Eb",0,0, "Bb",0,0, "F",0,2 28160DATA "C", 0,3 : REM dotted line and tick 28170DATA "G", 0,0, "D", 0,0, "A", 0,0, "E", 0,0, "B", 0,0, "F#",0,0, "C#",0,0,"" 28180DATA "Minor",3 28190DATA "Ab",0,0, "Eb",0,0, "Bb",0,0, "F", 0,0, "C", 0,0, "G", 0,0, "D",0,2 28200DATA "A", 0,3 : REM dotted line and tick 28210DATA "E", 0,0, "B", 0,0, "F#",0,0, "C#",0,0, "G#",0,0, "D#",0,0, "A#",0,0,"" 28220DATA "Maestro",5 28230DATA "Info",0,0, "Quit",0,0,"" 28240DATA "" 28250 28260DEF FNFindMenuItem(item$, menu%) : REM return pointer to menu item 28270LOCAL item%,this$ 28280item$=LEFT$(item$,3) 28290item%=menu%+28 28300this$=LEFT$($(item%+12),3) 28310IF (this$ <> item$) THEN 28320 REPEAT 28330 item%+=24 28340 this$=LEFT$($(item%+12),3) 28350 UNTIL ( (this$ = item$) OR (!item% AND &80)>0 ) 28360 ENDIF 28370IF (this$ <> item$) THEN =-1 : REM not found 28380=item% 28390 28400DEF FNinitialise_sound 28410LOCAL SoundEnable% 28420SYS Sound_Configure,8 TO PrevConfigure 28430SYS Sound_Enable,0 TO SoundEnable% 28440REM disconnect midi interpreter 28450IF MIDIpresent% SYS MIDI_SoundEnable%,0 28460=SoundEnable% 28470 28480DEF PROCClearAllMusic 28490FINE%()=MUSIC%() 28500PP%=MUSIC%:P%()=MUSIC%() 28510NBars%=0 :REM number of bars 28520BAR%=0:REM Current bar number 28530PBAR%=0:REM Playing bar counter 28540SBAR%=0:REM scrolling bar number 28550PROCstart_music:REM Set pointers to start of music store 28560EP%=GP% 28570PROCbar:REM Music always starts off with a bar 28580GATE%=MUSIC%+2:REM End of minimum score 28590PX%(0)=0:REM Score starts at left window edge 28600PXn%(BAR%)=0 28610PW%(0)=4*Hi%:REM Bar width 28620PTYPE%(0)=Bar%:REM Score starts with a bar 28630GP%=MUSIC%:REM Reset gate pointer for set score 28640GPn%(BAR%)=GP% 28650PROCrescore(0) 28660PROCSetExtent(S_Width%) 28670PROCrelease 28680wasSCORING%=FALSE 28690stopSCORING%=TRUE 28700SCORING%=FALSE 28710CHANGED%=FALSE 28720$Updated%="NO" 28730PROCUpdateTitle("<untitled>") 28740$SaveText="MusicFile"+CHR$(0) 28750$LoadText="MusicFile"+CHR$(0) 28760n=FNGetFileInfo("") :REM clear file info stuff 28770$FileDate%="" 28780ENDPROC 28790 28800REM PROCEDURE: initialise_music 28810REM 28820REM STRUCTURES: Queue of Gate; 28830REM Queue of Music; 28840REM 28850REM TYPES: Gate= byte0>0 -> Gate_Mask 28860REM byte0=0 -> Music_Attribute 28870REM 28880REM Gate_Mask= byte; bitn=1 -> gate 1 note/rest from music queue n (n=0-7) 28890REM 28900REM Music_Attribute= word; bit0_7=0 28910REM bit8=1 -> Time signature bit12_9 No. beats-1 28920REM bit15_13 Beat type 28930REM bit9=1 -> Key signature bit10 0-#, 1-b 28940REM bit13_11 0-7 28950REM bit10=1 -> Clef bit12_11 Treble,Alto,Tenor,Bass 28960REM bit15_14 Stave 1-4 28970REM bit11=1 -> Slur switch bit12 on/off 28980REM bit15_14 Stave 1-4 28990REM bit12=1 -> Octave shift bit13 0-up,1-down 29000REM bit15_14 Stave 1-4 29010REM bit13=1 -> bar 29020REM (bit13_0=0 -> Reserved) 29030REM 29040REM Music= word; bit7_3>0 -> Note 29050REM bit7_3=0 -> Rest 29060REM 29070REM Note= word; bit0= Stem orientation: 0-up,1-down 29080REM bit1=1 -> Join barbs to next note 29090REM bit2=1 -> Tie with next note 29100REM bit7_3>0 Note stave line position 1 to 31 (16=centre line) 29110REM bit10_8>0 -> Accidental N,#,b,X,bb,N#,Nb 29120REM bit12_11= Number of dots 0 to 3 29130REM bit15_13= Type: Breve to Semi-demi-semiquaver 29140REM 29150REM Rest= word; bit0=0 NB If a rest coincides with a note, its 29160REM bit1=0 position is determined by the 29170REM bit2=0 following note on the same channel. 29180REM bit7_3=0 29190REM bit10_8=0 29200REM bit12_11= Number of dots 0 to 3 29210REM bit15_13= Type: Breve rest to Semi-demi-semiquaver rest 29220REM 29230REM Position_type= 0 -> Note 29240REM 1 -> Time Signature 29250REM 2 -> Key Signature 29260REM 3 -> Clef 29270REM 4 -> Slur 29280REM 5 -> Octave shift 29290REM 6 -> Bar 29300: 29310DEF PROCinitialise_music 29320LOCALN%,C%:REM Note,channel 29330PROCinitialise_options 29340Note%=0:Time%=1:Key%=2:Clef%=4:Slur%=8:Octave%=16:Bar%=32:REM Stave attribute enumerators 29350DIM Ninc%(6),Line(42),Aoff(7),Clef%(3),Key%(6),Key_Sig%(15,6),Length%(31),Duration%(NTempos%),Accidental%(3,31) 29360FORN%=0TO6:Ninc%(N%)=ASCMID$("024579;",N%+1)AND15:NEXT:REM Note increment 29370LOCALST:ST=&1000/12:REM Semitone increment 29380FORN%=0TO42 29390Line(N%)=(1+N%DIV7<<12)+Ninc%(N%MOD7)*ST+.49 29400NEXT:REM Notes corresponding to stave lines (C octave 1 TO C octave 7) 29410Aoff(2)=ST:Aoff(3)=-ST:Aoff(4)=ST*2:Aoff(5)=-ST*2:Aoff(6)=ST:Aoff(7)=-ST:REM Accidental offsets 29420Clef%(0)=11:Clef%(1)=5:Clef%(2)=3:Clef%(3)=-1:REM Line offsets for each clef 29430FORC%=2TO15 29440FORN%=0TO(C%>>1)-1 29450Key_Sig%(C%,(7+Key_Y%(1,C%AND%1,N%))MOD7)=C%MOD2+2 29460NEXT 29470NEXT:REM Set up note offsets for each key signature 29480FORC%=0TO31 29490Length%(C%)=(%1<<7-(C%>>2))*(%1111000>>(C%AND3)AND%1111):REM Length of each possible note/rest (dotted) in tempo beats 29500NEXT 29510LOCALD%:REM Duration 29520FORN%=0TONTempos% 29530DIM C% 32:Duration%(N%)=C%:REM Reserve space for each tempo 29540FORC%=0TO31 29550D%=75/Tempo%(N%)*Length%(C%)/8+.5:REM Durations of note+dot combinations in 20ths of a second for each tempo (Max 22.5 Seconds) 29560IFD%>254 D%=254:REM Limit to maximum possible duration (12.7 Seconds) 29570Duration%(N%)?C%=D% 29580NEXT 29590NEXT 29600TIE%=&FF:REM Tie state of channels - Each bit corresponds to a channel, 0 if tied 29610SPACE%=HIMEM-END :REM find available space to tailor allocation 29620IFFNassert(SPACE%>1024,"Not enough memory available for music storage.") STOP 29630Max_Gate%=SPACE%/100 :REM max no. of gates (events, chords) 29640Max_Bar%=Max_Gate%/4 :REM maximum number of bars 29650PLAYING%=FALSE:REM Flag indicating play in process 29660SCROLLING%=FALSE:REM Flag indicating auto-scrolling while playing 29670DIM Q%(Max_Stave%+2):REM Time positions of next notes on each stave 29680DIM QI%(Max_Stave%+2):REM Time increments of Q%() for each stave 29690B1%=0:B2%=0:REM Alternate beat counters used to detect zero wrap 29700:: 29710DIM GPn%(Max_Bar%) :REM GP% at the start of each bar 29720DIM PX%(Max_Gate%),PW%(Max_Gate%),PTYPE%(Max_Gate%):REM Notation screen positions, widths & types 29730REM PX% is PX%() index to screen positions & types - Always refers to the note/attribute just passed 29740DIM PXn%(Max_Bar%) :REM PX% at start of each bar 29750DIM BPn%(7,Max_Bar%):REM Indices to (8) note queues at the start of each bar 29760DIM MUSIC%(7),FINE%(7):REM Pointers delimiting music storage 29770DIM N%(7),n%(7):REM Pointers to current notes (n%()=copy, cf PROCproximate) 29780DIM C%(7),c%(7):REM Indexes of gate channels used in sorting 29790DIM CLEF%(Max_Stave%),clef%(Max_Stave%):REM Current clef on each stave (& clef copy) 29800DIM CLEFn%(Max_Stave%,Max_Bar%) :REM CLEF% at start of each bar 29810DIM SIG%(1),sig%(1):REM Base bar key & time sigs, current and copy 29820DIM SIGn%(1,Max_Bar%) :REM SIG% at the start of each bar 29830DIM P%(7),PCLEF%(3):REM Playing note pointers, clef 29840MaxNotesInBar%=128 29850REM while one half of draw q is being filled, the other half is being used for scrolling. 29860LOCAL n% 29870n%=MaxNotesInBar%*4 29880DIM MIDI_OFF%(1,n%) :REM an array of MIDI noteoffs if playing is stopped in the middle of a bar 29890MIDI_OFF%(0,0)=-1 29900MIDI_OFF%(1,0)=-1 29910MIDI_Notenum%=0 29920SPACE%=HIMEM-END 29930SPACE%-=&4000:REM Leave a few K for the program and Basic stack 29940IFFNassert(SPACE%>1024,"Not enough memory available for music storage.") STOP 29950DIM MUSIC% SPACE%+8:REM Allocate main music space (+8: Extra bytes in case of overrun) 29960FINE%=MUSIC%+SPACE%:REM End of music memory 29970GATE%=MUSIC%:REM No gate space used as yet 29980FORC%=0TO7 29990MUSIC%(C%)=MUSIC%+(C%+1)*SPACE%/9 30000NEXT:REM Share out storage (NB No bounds checking ever occurs!) 30010FINE%()=MUSIC%():REM No music defined yet 30020Pgap%=X%(2)DIV2+1:REM Symbol spacing (half note blob width) 30030: 30040REM Now set up basic score 30050PROCClearAllMusic 30060ENDPROC 30070 30080DEF PROCinitialise_options 30090LOCALN%,C% 30100NTempos%=14 30110DIM Tempo%(NTempos%) 30120Tempo%(0)=40 30130Tempo%(1)=50 30140Tempo%(2)=60 30150Tempo%(3)=65 30160Tempo%(4)=70 30170Tempo%(5)=80 30180Tempo%(6)=90 30190Tempo%(7)=100 30200Tempo%(8)=115 30210Tempo%(9)=130 30220Tempo%(10)=145 30230Tempo%(11)=160 30240Tempo%(12)=175 30250Tempo%(13)=190 30260Tempo%(14)=210 30270 30280DIM TIME_SIG%(1):REM Current time signature numerator(0) and denominator(1) 30290TIME_SIG%()=3:REM 4/4 time (= (n+1)/2^(d-1)) 30300 30310DIM KEY_SIG%(1):REM Current key signature 30320DIM Key_Y%(3,1,6):REM Key signature 0-sharp/1-flat stave line positions 30330LOCAL C%,A%,P%:REM Indices 30340FOR C%=0 TO 3:REM For each clef 30350FOR A%=0 TO 1:REM For each accidental type 30360FOR P%=0 TO 6:REM For each accidental position 30370Key_Y%(C%,1-A%,P%)=3*(P%AND%1)-P%DIV2+(P%-3)*A%+(A%ANDC%<>2AND(P%AND5)=0)*7-1-(C%-1>>1)-2*(C%=2) 30380REM Position offsets of key signature accidentals from centre stave line 30390NEXT 30400NEXT 30410NEXT 30420KEY_SIG%(0)=1 30430KEY_SIG%(1)=0 30440LOCAL item% 30450Max_Stave%=3 30460Li%=2*Vi% 30470Stave_Height%=Li%*8 30480DIM Y_STAVE%(Max_Stave%+2) 30490STAVE%=0 :REM means 1 stave 30500PERC%=0 :REM means no percussion 30510Score_Width%=S_Width% 30520PROCposition_staves 30530 30540NVolumes%=7 30550DIM Volume%(NVolumes%),Volumes%(7) 30560FORR%=0TONVolumes% 30570Volume%(R%)=(R%+1)*120/(NVolumes%+1)-1 :REM don't permit full volume so that dynamics are possible 30580NEXT 30590SYS Sound_Volume TO R% 30600RestoreVolume=R% 30610Volume%=R%*(NVolumes%+1)/120-.5:IFVolume%<0 Volume%=0 :REM don't permit full volume. This is reserved for dynamics 30620SYS Sound_Volume,Volume%(Volume%) 30630FORR%=0TO7:Volumes%(R%)=6:NEXT 30640 30650LOCALS% 30660DIM Stave_Channels%(Max_Stave%+2,7):REM Primary stave allocation of channels 0-7 for each stave structure 30670FOR S%=0 TO Max_Stave% 30680FOR R%=0 TO 7 30690Stave_Channels%(S%,R%)=(S%+1)*R%DIV8:REM Close formula to desired data 30700NEXT 30710NEXT 30720Stave_Channels%(2,1)=1 30730Stave_Channels%(2,2)=1 30740Stave_Channels%(2,5)=2:REM Correct the exceptions to formula 30750DIM S_C%(7):REM Current stave allocation 30760FORR%=0TO7 30770S_C%(R%)=Stave_Channels%(STAVE%,R%):REM Initialise channel allocation (Also reset each time stave structure is changed) 30780NEXT 30790:REM Now get names and channel allocation of instruments 30800LOCALI$,L%,M%:REM Instrument name, Number of instruments, Instrument name length, Max 30810MAX_Voices%=20 30820DIM Voice$(20):REM Instrument voice descriptions 30830DIM RestoreVoice%(7) 30840DIM Instrument%(7,1):REM Instrument information 0=Stave, 1=Voice 30850DIM Nth$(6):REM First,Second stave etc 30860Nth$(1)="1st stave":Nth$(2)="2nd stave":Nth$(3)="3rd stave":Nth$(4)="4th stave":Nth$(5)="1st perc":Nth$(6)="2nd perc" 30870SYS Sound_InstallVoice TO I$,NVoices%:NVoices%-=1:REM NVoices% is now number of voices/instruments available 30880IF FNassert(NVoices%>0,"No sound voices are installed.") STOP 30890FORR%=1TONVoices% 30900SYS Sound_InstallVoice,0,R% TO Voice$(R%) 30910NEXT:REM Get names of voices/instruments 30920FORR%=0TO7 30930SYS Sound_AttachVoice,R%+1,0 TO L%,S% 30940RestoreVoice%(R%)=S% 30950IFS%<1ORS%>NVoices% S%=1:REM Make sure a voice is attached to all channels 30960SYS Sound_AttachVoice,L%,S% 30970Instrument%(R%,0)=S_C%(R%)+1:REM Instrument stave 30980Instrument%(R%,1)=S%:REM Instrument voice 30990$(VoiceStr%(R%)) = LEFT$(Voice$(S%), VoiceSize%) 31000NEXT:REM Get details of each channel 31010PROCSetDefaultChannels 31020DIM Volume$(NVolumes%) 31030Volume$(0)="ppp" : Volume$(1)="pp" : Volume$(2)="p" : Volume$(3)="mp" : Volume$(4)="mf" : Volume$(5)="f" : Volume$(6)="ff" : Volume$(7)="fff" 31040FORR%=0TO7 31050$(VolumeStr%(R%)) = LEFT$(Volume$(Volumes%(R%)), VolSize%) 31060NEXT 31070NStereos%=6 31080DIM Stereo%(NStereos%),Stereo$(NStereos%,1),Stereo_Position%(7) 31090Stereo$(0,0)="Full L.":Stereo$(1,0)="Left":Stereo$(2,0)="Centre L.":Stereo$(3,0)="Centre":Stereo$(4,0)="Centre R.":Stereo$(5,0)="Right":Stereo$(6,0)="Full R." 31100FORR%=0TONStereos% 31110Stereo%(R%)=(2*R%/NStereos%-1)*127 31120Stereo$(R%,1)="Stereo position ("+STR$Stereo%(R%)+")" 31130NEXT 31140FORR%=0TO7 31150Stereo_Position%(R%)=NStereos%DIV2 31160SYS Sound_Stereo,R%+1,Stereo%(Stereo_Position%(R%)) 31170$(StereoStr%(R%)) = LEFT$(Stereo$(Stereo_Position%(R%), 0), SterSize%) 31180NEXT 31190 31200NMIDIChannels%=16 31210DIM MIDIChannel%(7) 31220FORR%=0TO7 31230MIDIChannel%(R%)=1 31240IF MIDIpresent% THEN 31250 $(MIDIChStr%(R%))="1" 31260ELSE 31270 $(MIDIChStr%(R%))=" " 31280 ENDIF 31290NEXT 31300 31310ENDPROC 31320 31330DEF PROCrestore 31340REMOSCLI("audio off") 31350FORR%=0TO7 :REM restore channel/voice allocation 31360SYS Sound_AttachVoice,R%+1,RestoreVoice%(R%) 31370NEXT 31380SYS Sound_Volume, RestoreVolume :REM restore volume 31390SYS Sound_Configure,PrevConfigure 31400ENDPROC 31410 31420DEF PROCexit 31430PROCremove_panes 31440PROCCloseWindow(ScoreWind_h%) 31450PROCrestore 31460ENDPROC 31470 31480DEF PROCterminate 31490IF INITIALISED% IF PLAYING% PROCplay_stop 31500IF Task_h%>0 THEN 31510 ON ERROR SYS CloseDown, task%, Task_h% : END 31520ELSE 31530 ON ERROR END 31540 ENDIF 31550IF INITIALISED% PROCexit :PROCCloseWindow(AbortQuery_h%) 31560REMCLOSE#debug 31570ON ERROR END 31580IF Task_h%>0 THEN SYS CloseDown, task%, Task_h% 31590END 31600ENDPROC 31610 31620DEF FNassert(E%,A$) 31630LOCAL e% 31640IFE% THEN=FALSE ELSE e%=FNCheckOK("ERROR: "+A$+" Program will exit.",1) 31650PROCterminate 31660=TRUE 31670 31680DEF PROCerror 31690LOCAL e% 31700LOCAL ERROR 31710ON ERROR LOCAL PROCterminate: STOP 31720SYS "Hourglass_Smash" 31730E$=REPORT$+" at line "+STR$ERL+". Exit program?" 31740FILE%=FILE%:IFFILE% CLOSE#FILE%:FILE%=FALSE 31750IF INITIALISED% THEN 31760 IF FNCheckOK(E$,3) PROCterminate 31770ELSE 31780 e%=FNCheckOK(E$,1) : PROCterminate 31790 ENDIF 31800ENDPROC 31810 31820DEF PROCOpenAbortQuery(x, y) 31830LOCAL xsize%, ysize% 31840Window%!handle%=AbortQuery_h% 31850SYS GetWindowState%, ,Window%+handle% 31860xsize% = Window%!x1%-Window%!x0% 31870ysize% = Window%!y1%-Window%!y0% 31880Window%!x0% = x - xsize%/2 31890Window%!x1% = x + xsize%/2 31900Window%!y0% = y - ysize%/2 31910Window%!y1% = y + ysize%/2 31920SYS OpenWindow%, ,Window%+handle% 31930ENDPROC 31940 31950DEF FNCheckOK(E$, boxes%) 31960LOCAL E% 31970!ERRBLOCK%=0 31980$(ERRBLOCK%+4)=LEFT$(E$,100)+CHR$0 31990SYS "Wimp_ReportError", ERRBLOCK%, boxes%, "Maestro" TO ,E% 32000=E%=1 : REM return TRUE if OK pressed
� > Music.Maestxt � (c) Acorn Computers 1988 (!VersionStr$="1.65 (4-Jan-89)" 2 < Task_h%=0 FMusicFileType%=&AF1 PINITIALISED%=� Z� ERRBLOCK% 200 d� space for an error window n.SPACE%=�-� :� check enough space available x� SPACE%<100000 � ��debug=OPENOUT "debugfile" �� � �error:� �� get name of file to load �ș "OS_GetEnv" � EnvStr$ �� �EnvStr$," -quit ") � � I%=�EnvStr$,"""") � I%=�EnvStr$,"""",I%+1) �! �I%+=1:��EnvStr$,I%,1)<>" " � f$=�EnvStr$,I%) � � �INITIALISED%=�initialise �.mask%=0 : � mask out unwanted reason codes �� � �error � � PLAYING% �CheckQ ) ș Poll%,mask%,Window%+handle% � R% "Q � PLAYING% �CheckQ: � recheck since poll might have stayed away for a while , Ȏ R% � 6 � 0 @l � AwaitingAck% �CheckOK("Bad Data Transfer, Receiver Dead",3) :AwaitingAck%=� : CHANGED%=wasCHANGED% J! � SCORING% �symbol_pointer T' � f$<>"" �load_music(f$) : f$="" ^2 � SCROLLING% �CheckScroll :� auto-scrolling h � 1:�redraw_window_request r � 2:�open_window_request | � 3:�close_window_request �, � 4 :� pointer leaving window �' � Window%!handle%=ScoreWind_h% � � �release � wasSCORING%=SCORING% � SCORING%=� � � �D � Window%!handle%=AbortQuery_h% �CloseWindow(AbortQuery_h%) � � �U � 5: � Window%!handle%=ScoreWind_h% SCORING% = (wasSCORING% � � stopSCORING%)=� � � 6:�mouse_button_click � � 7:�UserDragBox � � 8:�KeyPressed � � 9:�MenuSelect B � 10: �ScrollReq(Window%!(handle%+32), Window%!(handle%+36)) � 17,18:�receive � & � � 0� : D � �CheckQ NB1%=B2%: B2%=Ə X�B2%<B1% �play_bar b� l v� �receive �� task%, ref%, block,F$ �%block=Window% :� temporary buffer �ref%=!(Window%+handle%+8) �task%=!(Window%+handle%+4) �8� task%=Task_h% � : � ignore messages from this task �Ȏ Window%!(handle%+16) � � � 0 � � � CHANGED% � � �terminate � � � !block=20 � block!12=ref% �# block!16=0 :� quit block G ș SendMessage,19,block :� acknowledge, and refuse quit request D � �CheckOK("Unsaved music. Do you really want to quit?",3) � �terminate � *# ș GetPointerInfo%,,Mouse% 45 �OpenWindow(Save_h%, Mouse%!x0%, Mouse%!y0%) > � H � R � 2 : � save file \ � SAVING% � f wasCHANGED%=CHANGED% p0 �save_music(�GetStr(Window%+handle%+44)) z SAVING%=� �" ș GetPointerInfo%, ,block � block!20=block!12 � block!24=block!16 � block!28=block!0 � block!32=block!4 � block!0=44 � block!12=ref% �3 block!16=3 :� DataLoad application to filer � block!40=MusicFileType% � ș SendMessage,17,block � AwaitingAck%=� � �CloseMenu � � � 3 : � load file . �load_music(�GetStr(Window%+handle%+44)) �DataLoadAck(ref%) $B � 4 :AwaitingAck%=� : � DataLoadAck. End of DataSave protocol .% � 5 : � open double-clicked file 80 � !(Window%+handle%+40) = MusicFileType% � B0 �load_music(�GetStr(Window%+handle%+44)) L �DataLoadAck(ref%) V � ` � &502:�Help(ref%) j � &400C1:�getmodeinfo(�) t � ~� � �� �Help(ref%) �� block%,text$ �block%=Window%+handle% �block%!12 = ref% �)block%!16 = &503 :� Send help message �text$="" �Ȏ block%!32 � �J � -2 : text$="This is the Maestro icon.|MClick SELECT to open score." � � ScoreWind_h% �! �SCORING%�SCRIBE%(drawn%) � �2 text$="Click SELECT to place item in score" � = text$="Select an item in a pane to place on the score" � � NotesPane_h% (' text$="Click SELECT to select a " 2 Ȏ block%!36 � <" � 0 : text$=text$+"breve." F& � 1 : text$=text$+"semibreve." P" � 2 : text$=text$+"minim." Z$ � 3 : text$=text$+"crochet." d# � 4 : text$=text$+"quaver." n' � 5 : text$=text$+"semiquaver." x+ � 6 : text$=text$+"demisemiquaver." �/ � 7 : text$=text$+"hemidemisemiquaver." � text$="" � � � � SharpsPane_h% �' text$="Click SELECT to select a " � Ȏ block%!36 � �$ � 0 : text$=text$+"natural." �" � 1 : text$=text$+"sharp." �! � 2 : text$=text$+"flat." �) � 3 : text$=text$+"double-sharp." �( � 4 : text$=text$+"double-flat." �. � 5 : text$=text$+"naturalised sharp." �- � 6 : text$=text$+"naturalised flat." � 7 : text$=text$+"dot." ' � 8 : text$=text$+"double-dot." ' � 9 : text$=text$+"triple-dot." "! � 10 : text$=text$+"tie." ,& � 11 : text$=text$+"bar line." 6) � 12 : text$=text$+"treble clef." @' � 13 : text$=text$+"bass clef." J+ � 14 : text$=text$+"key signature." T, � 15 : text$=text$+"time signature." ^ text$="" h � r � RestsPane_h% |' text$="Click SELECT to select a " � Ȏ block%!36 � �' � 0 : text$=text$+"breve rest." �+ � 1 : text$=text$+"semibreve rest." �' � 2 : text$=text$+"minim rest." �) � 3 : text$=text$+"crochet rest." �( � 4 : text$=text$+"quaver rest." �, � 5 : text$=text$+"semiquaver rest." �0 � 6 : text$=text$+"demisemiquaver rest." �4 � 7 : text$=text$+"hemidemisemiquaver rest." � text$="" � � � � InstrWind_h% � � (block%!36>7) � � (block%!36<16) � M text$="Click SELECT or ADJUST to select an instrument for this stave" � & � (block%!36<24) � 0I text$="Click SELECT or ADJUST to set the volume of this channel" :e � � (block%!36<32) text$="Click SELECT or ADJUST to set the stereo position of this channel" D � N � X � b � Save_h% l� � block%!36=2 text$="Drag this icon into a directory window to save it in that directory" � text$="Fill in the file name and then drag the icon into a filer directory window to save it" v � TimeSig_h% �I text$="use SELECT and ADJUST on each field to set a time signature" � � AbortQuery_h% �, text$="click YES to terminate Maestro" � � �$(block%+20)=text$ �(block%!0 = (((20+�(text$)+1)�4)*4)+4 �2$(block%+21+�(text$)) = �(0) :� null-terminate �3ș SendMessage,17,block% :� acknowledge message �� � �� �DataLoadAck(ref%) �� block �block=Window% block!0 = 20 block!12 = ref% block!16 = 4 :� DataLoadAck 2ș SendMessage,17,block :� acknowledge message *� 4 >� �redraw_window_request H� R% R*ș RedrawWindow%,,Window%+handle% � R% \ ȕ R% fF � Window%!handle% = ScoreWind_h% �draw_staves:� PLAYING% �CheckQ p-� try to avoid interruptions in the music z, ș GetRectangle%,,Window%+handle% � R% � � �� � �� �place_top_panes(behind) �� xsize% �"xsize%=Window%!x1%-Window%!x0% �RestPBlk%!x1%=Window%!x1% �&RestPBlk%!x0%=Window%!x0%+xsize%/2 �RestPBlk%!y1%=Window%!y1% �+RestPBlk%!y0%=RestPBlk%!y1%-PaneHeight% �RestPBlk%!under%=behind �3ș OpenWindow%, RestsPane_h%, RestPBlk%+handle% �NotePBlk%!x0%=Window%!x0% NotePBlk%!x1%=RestPBlk%!x0% NotePBlk%!y1%=Window%!y1% +NotePBlk%!y0%=NotePBlk%!y1%-PaneHeight% $!NotePBlk%!under%=RestsPane_h% .3ș OpenWindow%, NotesPane_h%, NotePBlk%+handle% 8� B L!� �place_bottom_panes(behind) V� xsize% `"xsize%=Window%!x0%+Window%!x1% jSharpPBlk%!x0%=Window%!x0% t(SharpPBlk%!x1%=SharpPBlk%!x0%+xsize% ~SharpPBlk%!x1%=Window%!x1% �SharpPBlk%!y0%=Window%!y0% �-SharpPBlk%!y1%=SharpPBlk%!y0%+PaneHeight% �SharpPBlk%!under%=behind �5ș OpenWindow%, SharpsPane_h%, SharpPBlk%+handle% �� � �� �remove_panes ��CloseWindow(NotesPane_h%) ��CloseWindow(SharpsPane_h%) ��CloseWindow(RestsPane_h%) �� � � �open_window_request � bhandle% bhandle%=Window%!under% �release ($� Window%!handle%=ScoreWind_h% � 2 � TRANSCRIBE% � <P� define window stack as top->bottom sharpspane->restspane->notespane->score FJ� open top or bottom panes before score depending on direction of drag P, ș GetWindowState%,,SharpPBlk%+handle% Z> � SharpPBlk%!under%=bhandle% Window%!under%=NotesPane_h% d, ș GetWindowState%,,ScoreWBlk%+handle% n$ � Window%!y1%>ScoreWBlk%!y1% � x! �place_top_panes(bhandle%) � � �$ �place_bottom_panes(bhandle%) � � � � �S � PLAYING% � Window%!scx%<>ScoreWBlk%!scx% �:� no user-scrolling while playing �$ ș OpenWindow%,,Window%+handle% � ScoreClosed%=� � � TRANSCRIBE% � � � bhandle%=-2 � �2 � find behind handle% if pushed to the back �- ș GetWindowState%,,ScoreWBlk%+handle% �# bhandle% = ScoreWBlk%!under% � � � re-open all panes # �place_bottom_panes(bhandle%) % �place_top_panes(SharpsPane_h%) "o � bhandle%=ScoreWind_h% ș OpenWindow%,,Window%+handle% :� ensure window is behind panes in unusual case , � 6Q LHBAR%=�FindBar(ScoreWBlk%!scx%) :� the bar number at the left of the window @ � J$ ș OpenWindow%,,Window%+handle% T � ^� h r� �close_window_request |$ș CloseWindow%,,Window%+handle% �A� Window%!handle%=ScoreWind_h% �remove_panes : ScoreClosed%=� �� � �� �mouse_button_click ��B%,C%,W%,I%,inc% �#W%=Mouse%!window:I%=Mouse%!icon �B%=%111�Mouse%!buttons �+Mouse_X%=Mouse%!x0%:Mouse_Y%=Mouse%!y0% �� B%=%010 � � �CheckInstalledVoices � �StopScoring �2 � W%=-2 �OpenMenu(IconMenu%) � �OpenMainMenu �� 1� B%=%100 inc%=-1 � � B%=%001 inc%=1 � inc%=0 Ȏ W% � A� -2 : � ScoreClosed% � � PLAYING% �setup_staves:� :� iconbar &� AbortQuery_h% 0 � I%=2 � : �terminate D � N �CloseMenu X% �CloseWindow(AbortQuery_h%) b � l� NotesPane_h% v � I%>=0 � � �release � wasSCORING%=� � stopSCORING%=� �( �UpdateIcon(SelW%, SelI%, 0, 1<<2) �" �UpdateIcon(W%, I%, 1<<2, 0) � SelW%=W% � SelI%=I% � �attach(note%+I%,%111000) � � �� RestsPane_h% � � I%>=0 � � �release � wasSCORING%=� stopSCORING%=� ( �UpdateIcon(SelW%, SelI%, 0, 1<<2) " �UpdateIcon(W%, I%, 1<<2, 0) SelW%=W% * SelI%=I% 4 �attach(rest%+I%,%11000) > � H� SharpsPane_h% R � I%>=0 � \ �release f wasSCORING%=� p stopSCORING%=� z( �UpdateIcon(SelW%, SelI%, 0, 1<<2) �" �UpdateIcon(W%, I%, 1<<2, 0) � SelW%=W% � SelI%=I% �U � I%<7 �attach(accidental%+I%+1,%1100000) �� I%<11 �attach(dot%+I%-6,%1101000) �$ � I%=10 �attach(tie%,%1101000) �% � I%=11 �attach(bar%,%10010000) �1 � I%=12 �attach(clef%,%100) :� Treble clef �/ � I%=13 �attach(clef%+3,%100):� Bass clef �3 � I%=14 �attach(key%,%10) :� key signature �4 � I%=15 �attach(time%,%1) :� time signature � � �� ScoreWind_h% �3 � B%=%100 �SCORING%�SCRIBE%(drawn%) �put_down � InstrWind_h% � chan%, v% �CheckInstalledVoices $ �StopScoring . � I%>=8 � 8 chan%=I%-8 B � chan%<8 � L& v%=�AttachVoice(chan%, inc%) V+ ș Sound_AttachVoice, chan%+1, v% `6 $(VoiceStr%(chan%))=�Voice$(v%), VoiceSize%) j# Instrument%(chan%,1) = v% t" �UpdateIcon(W%, I%, 0,0) ~ � � chan%-=8 � � chan%<8 � � v%=Volumes%(chan%) �= v%+=inc% : � v%>NVolumes% v%=NVolumes% �� v%<0 v%=0 � Volumes%(chan%)=v% �C $(VolumeStr%(chan%))=�Volume$(Volumes%(chan%)), VolSize%) �" �UpdateIcon(W%, I%, 0,0) � � � chan%-=8 � � chan%<8 � �$ v%=Stereo_Position%(chan%) �H v%+=inc% : � v%>NStereos% v%=NStereos% �� v%<0 v%=0: � no wrap $ Stereo_Position%(chan%)=v% B ș Sound_Stereo,chan%+1,Stereo%(Stereo_Position%(chan%)) Q $(StereoStr%(chan%)) = �Stereo$(Stereo_Position%(chan%), 0), SterSize%) " �UpdateIcon(W%, I%, 0,0) ( � 2 � MIDIpresent% � < chan%-=8 F � chan%<8 � P" v%=MIDIChannel%(chan%) ZI v%+=inc% : � v%>NMIDIChannels% v%=1 �� v%<1 v%=NMIDIChannels% d" MIDIChannel%(chan%)=v% n9 $(MIDIChStr%(chan%)) = �(MIDIChannel%(chan%)) x$ �UpdateIcon(W%, I%, 0,0) � � � � � � � � � � � � � � Save_h% � �StopScoring �@ � I%=0 �save_music(�GetStr(SaveText)) : � 0 is OK. � � I%=2 � �; � x%, y% : � dragging icon � Window%!handle%=W% �+ ș GetWindowState%,,Window%+handle% & ysize%=Window%!y1%-Window%!y0% x%=Window%!x0% y%=Window%!y0% " !Window% = W% , Window%!4 = I% 6R ș GetIconInfo%, ,Window% : � returns icon box in right place for drag box @ Window%!8 += x% J! Window%!12 += y% + ysize% T Window%!16 += x% ^! Window%!20 += y% + ysize% hG� get size in appropriate part of block: parent box=screen boundary r Window%!24 = 0 | Window%!28 = 0 � Window%!32 = S_Width% � Window%!36 = S_Height% � !Window%=0 �* Window%!4=5: � fixed size drag box � SAVING%=� � DRAGGING%=� � ș DragBox, ,Window% � � � �CloseWindow(Save_h%) � �CloseMenu � � � � Load_h% � �StopScoring @ � I%=0 �load_music(�GetStr(LoadText)) : � 0 is OK. �CloseWindow(Load_h%) �CloseMenu &� TimeSig_h% 0 Ȏ I% � : � 0 D0 TIME_SIG%(0)=1+(TIME_SIG%(0)+inc%+14)�15 N% $BarLength%=�(TIME_SIG%(0)+1) X � 1 b, TIME_SIG%(1)=(TIME_SIG%(1)-inc%)�4+2 l* $NoteValue%=�(1<<(TIME_SIG%(1)-1)) v � �* � I%=0 � I%=1 �UpdateIcon(W%,I%,0,0) �� �� �� � �� �CheckInstalledVoices �,� NewVoice$, NewNVoices%, changedVoices% �changedVoices%=� �9ș Sound_InstallVoice � I$,NewNVoices%:NewNVoices%-=1 �<� �assert(NVoices%>0,"No sound voices are installed.") � �q� MIDIpresent% NewNVoices%+=1:Voice$(NewNVoices%)="":� allow a NULL voice to permit just MIDI on this channel �� NewNVoices%<>NVoices% � � changedVoices%=� NVoices%=NewNVoices% � /� NVoices%>MAX_Voices% NVoices%=MAX_Voices% �R%=1�NVoices% *$� (MIDIpresent% � R%=NVoices%) � 4 Voice$(R%)="" >� H+ ș Sound_InstallVoice,0,R% � NewVoice$ R � NewVoice$<>Voice$(R%) � \ changedVoices%=� f Voice$(R%)=NewVoice$ p � z � �(�:� find if instruments have changed �� � changedVoices% � ��R%=0�7 �'ș Sound_AttachVoice,R%+1,0 � L%,S% �J�S%<1�S%>NVoices% S%=1:� Make sure a voice is attached to all channels �ș Sound_AttachVoice,L%,S% �3Instrument%(R%,0)=S_C%(R%)+1:� Instrument stave �+Instrument%(R%,1)=S%:� Instrument voice �/$(VoiceStr%(R%)) = �Voice$(S%), VoiceSize%) �(�UpdateIcon(InstrWind_h%, R%+8, 0,0) �#�:� Get details of each channel ��SetDefaultChannels �� G� �AttachVoice(chan%,inc%) :� inc% is +1 or -1 or 0 to find nearest � stop%,v%,perc% $�CheckInstalledVoices .6� NVoices%<2 ș Sound_AttachVoice, chan%+1, 1 : =1 8e� attach next voice to channel. Attach percussion voice only on perc line, and not on stave lines BGperc%=(�$StaveStr%(chan%),"perc")>0) :� is it a percussion channel? L(ș Sound_AttachVoice, chan%+1 � , v% V� v%=0 v%=1 `4ș Sound_AttachVoice, chan%+1, v% :� restore it j6� check if current voice is valid for this channel t8� inc%=0 � � (perc% = (�Voice$(v%),"Perc")>0)) � =v% ~� inc or dec until found �� �(inc%)<>1 � inc%=1 �stop%=v% �� �6 v%+=inc% : � v%>NVoices% v%=1 �� v%<1 v%=NVoices% �b � MIDIpresent% � Voice$(v%)="" stop%=v% :� permit NULL voice on any channel if MIDI installed �3 � (perc% = (�Voice$(v%),"Perc")>0)) � stop%=v% �=v% � �$� �UpdateIcon(W%, I%, st%, msk%) � Window%!handle%=W%:!Icon%=I% �#Icon%!state=st%:Icon%!mask=msk% �:ș SetIconState%,,Window%+handle% : � update icon text � � �UserDragBox � block (DRAGGING%=� 2%block=Window% :� temporary buffer <� SAVING% � F ș GetPointerInfo%, ,block P block!32=block!4 Z block!28=!block d block!24=block!16 nB block!20=block!12 : � this is the destination window handle% x$ block!16=1 : � DataSave � block!12=0 �) block!36=0 :� don't know file size � block!40=MusicFileType% �( $(block+44)=�GetLeafName(SaveText) � !block = 60 �) ș SendMessage, 17, block, block!20 � � �� � �H� �SetBit(test, word, bitnum) : � set or clear bit depending on test �� test � � = word � (1<<bitnum) �� = word � � (1<<bitnum) � "� �MenuSelect ,*� item%, n, selection, SoundEnable%,F$ 6selection=Window%+handle% @7ș DecodeMenu, ,CurrentMenu%, selection, MenuString J+Ȏ �$MenuString,�$MenuString, ".")-1) � T � "Save" ^ F$=�GetStr(SaveText) h& � ( �F$,".")=0 � �F$,":")=0 ) � r0 �OpenWindow(Save_h%, Mouse_X%, Mouse_Y%) | � � �save_music(F$) � � � � "Staves" � ș "Hourglass_On" �) � �$StaveNum%,1)="" $StaveNum%="1" �! STAVE%=�(�$StaveNum%,1))-1 �" � �$MenuString,"+perc",6) � �# � PERC%=1 PERC%=0 � PERC%=1 � � �7 item% = �FindMenuItem("+percussion", StaveMenu%) �L � (item%>=0) !item% = �SetBit(PERC%=1, !item%, 0):� set or clear tick � �setup_score � �start_music �rescore(0) ș "Hourglass_Off" C � "Instruments" : �OpenWindow(InstrWind_h%,Mouse_X%,Mouse_Y%) & � "Volume" 0 � selection!4>=0 � :! �SetVolume(selection!4) D0 �SetMenuTick(VolumeMenu%, selection!4) N � X � "Tempo" b � selection!4>=0 � l �SetTempo(selection!4) v/ �SetMenuTick(TempoMenu%, selection!4) � � �2 � "Time sig" : TIME_SIG%(0)=�($BarLength%)-1 � � "Key sig" � � selection!4>=0 � �+ KEY_SIG%(0) = ((selection!8)>=7)+1 �) KEY_SIG%(1) = �((selection!8)-7) �. �SetMenuTick(MajorMenu%, selection!8) �. �SetMenuTick(MinorMenu%, selection!8) І � KEY_SIG%(1) n=accidental%+2+KEY_SIG%(0) : X%(key%)=(x%(n)+X%(n))*KEY_SIG%(1) � X%(key%)=x%(accidental%+2)+X%(accidental%+2) � � � � "Play" �j ș Sound_Enable,0 � SoundEnable%:� dont pretend to be able to play if the sound system is disabled � � SoundEnable%=2 � SCORING%=� PLAYING%=� PLAYING% SCROLLING%=PLAYING% , � PLAYING% �play_start � �play_stop *@ � n=�CheckOK("Sound is not enabled. You cannot play", 1) 4 � > � "Clear" HM � CHANGED% � � �CheckOK("Are you sure? Current music is unsaved",3) � R �ClearAllMusic \$ Window%!handle%=ScoreWind_h% f+ ș GetWindowState%,,Window%+handle% p Window%!scx%=0 z LHBAR%=0 �' ș OpenWindow%,,Window%+handle% �. ș GetWindowState%,,ScoreWBlk%+handle% �= � "Info" : �OpenWindow(ProgInfo_h%, Mouse_X%, Mouse_Y%) �L � "Quit" : � CHANGED% �OpenAbortQuery(Mouse_X%, Mouse_Y%) � �terminate � � "Goto" �$ Window%!handle%=ScoreWind_h% �+ ș GetWindowState%,,Window%+handle% � Window%!scx%=0 �; ș OpenWindow%,,Window%+handle% : � set scroll to 0 �. ș GetWindowState%,,ScoreWBlk%+handle% �< LHBAR%=0 :� the bar number at the left of the window � � �" � (CurrentMenu%=MenuStart) � ! ș GetPointerInfo%,,Mouse% ? � %001 � Mouse%!buttons �OpenMainMenu :� persistent menu � $� . 8 � �SetMenuTick(menu%, this%) B-� set 1 tick in menu and clear all others L� n, item% V n = 0 `item%=menu%+28 j>!item% = �SetBit(n=this%, !item%, 0) :� set or clear tick t� ~ item% += 24 � n += 1 �? !item% = �SetBit(n=this%, !item%, 0) :� set or clear tick � � (!item% � &80) �� � �� �KeyPressed �� ThisWindow% � � !(Window%+handle%+24)=13 � �! ThisWindow%=Window%!handle% � Ȏ (ThisWindow%) � �I � Save_h% : �save_music(�GetStr(SaveText)) : � c/r in save window �I � Load_h% : �load_music(�GetStr(LoadText)) : � c/r in load window � Bar_h% BAR%=�($BarNum%) 3 � BAR%>NBars% BAR%=NBars% �� BAR%<0 BAR%=0 % Window%!handle%=ScoreWind_h% (, ș GetWindowState%,,Window%+handle% 2% Window%!scx%=PX%(PXn%(BAR%)) <O ș OpenWindow%,,Window%+handle% : � set scroll to requested bar number F/ ș GetWindowState%,,ScoreWBlk%+handle% PU LHBAR%=�FindBar(ScoreWBlk%!scx%) :� the bar number at the left of the window ZU : ș "Wimp_ProcessKey",!(Window%+handle%+24) : � ie. pass on key code in R0 d � n �CloseWindow(ThisWindow%) x �CloseMenu � � �O ș "Wimp_ProcessKey",!(Window%+handle%+24) : � ie. pass on key code in R0 � � �� � �&� �ScrollReq(x_scroll%, y_scroll%) �G� if bad mode disallow scroll to prevent mode warning being garbled �� BADMODE% � �$� Window%!handle%=ScoreWind_h% � �! � PLAYING%�(x_scroll%<>0) � � Ȏ �(x_scroll%) � �+ � 1:Window%!scx%+=x_scroll%*4*Pgap% �A � 2:Window%!scx%+=(x_scroll%/2)*(Window%!x1%-Window%!x0%) � Ȏ �(y_scroll%) � - � 1:Window%!scy%+=y_scroll%*C_Height% "A � 2:Window%!scy%+=(y_scroll%/2)*(Window%!y1%-Window%!y0%) , � 6& ș OpenWindow%, ,Window%+handle% @, ș GetWindowState%,,ScoreWBlk%+handle% J ScoreClosed%=� TR LHBAR%=�FindBar(ScoreWBlk%!scx%) :� the bar number at the left of the window ^ � h� r |� �OpenMainMenu �� item% �,item% = �FindMenuItem("Play", MenuStart) �6� (item%>=0) !item% = �SetBit(PLAYING%, !item%, 0) �� set or clear tick �,item% = �FindMenuItem("Goto", MenuStart) �9� (item%>=0) item%!8 = �SetBit(PLAYING%, item%!8, 22) �+� shaded bit. disable Goto when playing �Hș CreateMenu, ,MenuStart, Mouse_X%-C_Width%*4, Mouse_Y%+C_Height%*4 �CurrentMenu%=MenuStart ��CloseWindow(Save_h%) ��CloseWindow(Load_h%) �� � � �OpenMenu(Menu%) � (Menu%=IconMenu%) � ] ș CreateMenu, ,IconMenu%, Mouse_X%-C_Width%*4, 112+C_Height%*2:� y adjusted to line up &� 0D ș CreateMenu, ,Menu%, Mouse_X%-C_Width%*4, Mouse_Y%+C_Height% :� DCurrentMenu%=Menu% N�CloseWindow(Save_h%) X�CloseWindow(Load_h%) b� l v� �CloseMenu �ș CreateMenu, ,-1 ��CloseWindow(Save_h%) ��CloseWindow(Load_h%) �� � �� �symbol_pointer �ș GetPointerInfo%,,Mouse% �A� (Mouse%!window=ScoreWind_h%) �scribe(Mouse%!x0%,Mouse%!y0%) �� � �� �StopScoring �stopSCORING%=� ��release J�UpdateIcon(SelW%, SelI%, 0, 1<<2) :� remove highlight on icon in pane � � �UpdateTitle(T$) * � a,b,c,d 4$ScoreTitle%=T$+�(0) > Window%!handle%=ScoreWind_h% H'ș GetWindowState%,,Window%+handle% RTa=Window%!x0% : b=Window%!y1% : c=Window%!x1% :� get title area and force redraw \(ș GetWindowOutline,,Window%+handle% fd=Window%!y1% p-ș ForceRedraw,-1,a+Hi%,b+Vi%,c-Hi%,d+Vi% z� � �� �OpenWindow(h%, x%, y%) �� xsize%, ysize% �Window%!handle% = h% �(ș GetWindowState%, ,Window%+handle% �"xsize%=Window%!x1%-Window%!x0% �"ysize%=Window%!y1%-Window%!y0% �Window%!under%=-1 �Window%!x0%=x% �"Window%!x1%=Window%!x0%+xsize% �Window%!y0%=y% �"Window%!y1%=Window%!y0%+ysize% �$ș OpenWindow%, ,Window%+handle% � � �CloseWindow(h%) $Window%!handle%=h% .%ș CloseWindow%, ,Window%+handle% 8� B L� �SetExtent(W%) VScore_Width%=W% `Window%!x0%=0 j*Window%!y0%=-Score_Height%-PaneHeight% tWindow%!x1%=Score_Width% ~Window%!y1%=PaneHeight% �%ș SetExtent,ScoreWind_h%,Window% �� � �.� �GetLeafName(name%) :� returns leaf name �� ch$,n%,name$ �name$=�GetStr(name%) �3� ( (�name$,".")=0) � (�name$,":")=0) ) �=name$ �n%=�(name$) �+� scan string to find leaf name of file �� � ch$= �name$, n%, 1) � n%-=1 # � (n%<=0 � ch$="." � ch$=":") $� n%>0 � =�name$, �(name$)-n%-1) � �GetStr(s%) : � get string (� n$ 2ȕ?s%:n$+=�?s%:s%+=1:� <=n$ F P� �SetVolume(R%) Zș Sound_Volume,Volume%(R%) d� n x� �SetDefaultChannels � �S%,P% �-� only 1 percussion channel permitted now �_�S%=0�7:S_C%(S%)=Stave_Channels%(STAVE%,S%):�:� Channel assignment changes if staves change �A� PERC% S_C%(7)=STAVE%+1:� Steal channel for percussion lines ��S%=0�7 � Instrument%(S%,0)=S_C%(S%)+1 ��$StaveStr%(S%)=Nth$(Instrument%(S%,0)+(STAVE%-3)*((Instrument%(S%,0)-1)>STAVE%))+";" :� set up stave names in instrument wimdow �<�UpdateIcon(InstrWind_h%,S%,0,0) :� update text in icons �v%=�AttachVoice(S%,0) � ș Sound_AttachVoice,S%+1,v% �-$(VoiceStr%(S%))=�Voice$(v%), VoiceSize%) �Instrument%(S%,1) = v% �'�UpdateIcon(InstrWind_h%,S%+8, 0,0) �:� Instrument allocation G� PERC% $StaveStr%(7)=Nth$(5)+";" :� steal 1 channel for percussion � " ,� �setup_score 6 �S%,P% @-� only 1 percussion channel permitted now J1�setup_staves:� Calculate new stave positions T�SetDefaultChannels ^� h r� �GetFileInfo(F$) |&�T%,L%,A%,M$,time%,FileType$,r2,r3 �5� F$<>"" șOS_File,5,F$ � T%,,laddr%,eaddr%,L%,A% �2� (F$="") � ((T%=1) � (A% � 1) � (L%>8)) = 0 � � $ThisFile%="<untitled>"+�(0) �$FileSize%="" �$FileType%="" �$FileDate%="" �=� �� �$ThisFile%=F$ �$FileSize%=�(L%) � � ((laddr%>>20)�&FFF)=&FFF � �- � (laddr%>>8 � &FFF) = MusicFileType% � � FileType$= "Music " � 8 ș "OS_FSControl",18,,laddr%>>8 � &FFF � ,,r2,r3 X FileType$=�(r2 � &FF) + �((r2>>8) � &FF) + �((r2>>16) � &FF) + �((r2>>24) � &FF) &[ FileType$ += �(r3 � &FF) + �((r3>>8) � &FF) + �((r3>>16) � &FF) + �((r3>>24) � &FF) 0 � :/ $FileType%=FileType$+�~(laddr%>>8 � &FFF) D* time%=Window% :� a convenient buffer N;� load and execution addresses are, in fact, time stamp X time%?4=laddr% � &FF b time%?3=eaddr%>>24 � &FF l time%?2=eaddr%>>16 � &FF v time%?1=eaddr%>>8 � &FF � time%?0=eaddr% � &FF �> ș "OS_ConvertStandardDateAndTime", time%, FileDate%, 28 �3 � put timestamp of file into file info window � � �� �=� � �� �load_music(F$) �� F%,M$ �� � �I� CHANGED% � � �CheckOK("Are you sure? Current music is unsaved",3) � �SCORING%=� �� PLAYING% �play_stop !SCROLLING%=� !8� �F$=0 � �7 : T%=�CheckOK("Invalid filename",1) : � !ș "Hourglass_On" ! Y� � � �7: �("FX 229,1") : �ClearAllMusic : ș "Hourglass_Off" : T%=�CheckOK(�$,1) : � !*&�("FX 229,0") :� enable escape key !4 FILE%=�F$ !> M$="":�R%=1�7:M$+=��#FILE%:� !HB%=�#FILE% !R�M$="Maestro" � !\$LoadText=F$+�(0) !f$SaveText=F$+�(0) !pn� � �GetFileInfo(F$) � �7 :�("FX 229,1") : ș "Hourglass_Off" :T%=�CheckOK("Invalid or locked file",1) : � !zT%=� !�NBars%=0 !�Ȏ �#FILE% � !�� 0:T%=� !�� 1 !�*�lTempo:�lInstruments:�lStaves:�lMusic !�"� File id version 2 and above !�A%=� !�� !�N� �#FILE% �lMusic,�lStaves,�lInstruments,�lVolumes,�lStereos,�lTempo �A%=� !���#FILE%�A% !�� !��#FILE%:FILE%=� !��("FX 229,1") "$Updated%="NO" "�UpdateTitle(F$) "ș "Hourglass_Off" "$ș "Hourglass_On" ". �T% � "8 �position_staves "B �start_music "L �set_score(0) "V �SetupBarStarts(0) "` �setup_score "j3 �update_score(0,-Score_Height%,Score_Width%,0) "t �StopScoring "~ CHANGED%=� "� � "�� "��("FX 229,1") "�T%=� "�� "�5� � T% � �7 : T%=�CheckOK("Invalid music file",1) "�ș "Hourglass_Off" "�� "� "� � �lMusic "� �C%,B% "��#FILE%,GATE%:GATE%+=MUSIC% # �C%=0�7 # +�#FILE%,FINE%(C%):FINE%(C%)+=MUSIC%(C%) #� #,B%=MUSIC%:ȕB%<GATE%:?B%=�#FILE%:B%+=1:� #(�C%=0�7 #24B%=MUSIC%(C%):ȕB%<FINE%(C%):?B%=�#FILE%:B%+=1:� #<� #FPP%=MUSIC%:P%()=MUSIC%() #P� #Z #d� �lStaves #n� item% #xSTAVE%=�#FILE% #�$StaveNum%=��(STAVE%+1),1) #�PERC%=�#FILE% #�4item% = �FindMenuItem("+percussion", StaveMenu%) #�E� item%>0 !item%=�SetBit(PERC%=1, !item%, 0) :� set or clear tick #�� #� #�� �lInstruments #��C%, chan%,v% #��C%=0�7 #�chan%=�#FILE%:� Channel #�Kv%=�#FILE%�(NVoices%+1):� Write voice numbers allocated to each channel #�� v%=0 v%=1 #�%ș Sound_AttachVoice, chan%+1, v% $=v%=�AttachVoice(chan%, 0) :� check if it is a valid voice $%ș Sound_AttachVoice, chan%+1, v% $Instrument%(chan%,1) = v% $"0$(VoiceStr%(chan%))=�Voice$(v%), VoiceSize%) $,+�UpdateIcon(InstrWind_h%, chan%+8, 0,0) $6� $@� $J $T� �lVolumes $^�C% $h�C%=0�7 $rVolumes%(C%)=�#FILE% $|"�Volumes%(C%)>7 Volumes%(C%)=7 $�"�Volumes%(C%)<0 Volumes%(C%)=0 $�7$(VolumeStr%(C%))=�Volume$(Volumes%(C%)), VolSize%) $�O�UpdateIcon(InstrWind_h%, C%+16, 0,0) :� update icon in instrument window $�� $�� $� $�� �lStereos $��C% $��C%=0�7 $� Stereo_Position%(C%)=�#FILE% $�6ș Sound_Stereo,C%+1,Stereo%(Stereo_Position%(C%)) $�E$(StereoStr%(C%)) = �Stereo$(Stereo_Position%(C%), 0), SterSize%) $�)�UpdateIcon(InstrWind_h%, C%+24, 0,0) %� %� % %& � �lTempo %0� t %: t=�#FILE% %D�SetTempo(t) %N�SetMenuTick(TempoMenu%, t) %X� %b %l� �save_music(F$) %v � block,n %�� � %�block=Window% %�$SaveText=F$+�(0) %�$LoadText=F$+�(0) %�6� simple check for pathname rather than local name %�#� ( �F$,".")=0 � �F$,":")=0 ) � %�B n=�CheckOK("To save, drag the icon to a directory viewer.",1) %� � %� � %�ș "Hourglass_On" %�D� � � �("FX 229,1") : ș "Hourglass_Off" : T%=�CheckOK(�$,1) : � %�&�("FX 229,0") :� enable escape key %�1� CHANGED% � (((laddr%>>20)�&FFF) <> &FFF) � &* � file changed or wasn't timestamped & � get current time && block?0=3:ș "OS_Word",&0E,block & laddr%=block?4 &* eaddr%=block!0 &4 � &>3� force music file type, and preserve timestamp &H<laddr%=(laddr% � &FF) � (&FFF<<20) � (MusicFileType%<<8) &R7� I don't know what the length will be, so use zero &\/ș "OS_File", &07, F$, laddr%, eaddr%, 0, 0 &f-� OPENUP, error if directory or not found &p!ș "OS_Find", &CC, F$ � FILE% &z:� timestamp is automatically updated on 1st byte write &��#FILE%,"Maestro" &� �#FILE%,2 &��sMusic &��sStaves &��sInstruments &� �sVolumes &� �sStereos &��sTempo &��#FILE%:FILE%=� &�6� (� CHANGED%) � (((laddr%>>20) � &FFF) = &FFF) � &�, � file not changed and was timestamped &�# � preserve original timestamp &�7 ș OS_File,2,F$,laddr% :� re-stamp with old stamp '0 ș OS_File,3,F$,,eaddr% :� nb eaddr% in r3 ' � '�("FX 229,1") '$F%=�GetFileInfo(F$) '.CHANGED%=� '8$Updated%="NO" 'B�UpdateTitle(F$) 'L5� � T% � �7 : T%=�CheckOK("Invalid music file",1) 'Vș "Hourglass_Off" '`� 'j 't � �sMusic '~ �C%,B% '� �#FILE%,1 '��#FILE%,GATE%-MUSIC% '��C%=0�7 '� �#FILE%,FINE%(C%)-MUSIC%(C%) '�� '�,B%=MUSIC%:ȕB%<GATE%:�#FILE%,?B%:B%+=1:� '��C%=0�7 '�4B%=MUSIC%(C%):ȕB%<FINE%(C%):�#FILE%,?B%:B%+=1:� '�� '�� '� '�� �sStaves ( �#FILE%,2 ( �#FILE%,STAVE% (�#FILE%,PERC% (� (( (2� �sInstruments (<�C% (F �#FILE%,3 (P�C%=0�7 (Z�#FILE%,C% (d�#FILE%,Instrument%(C%,1) (n� (x� (� (�� �sVolumes (��C% (� �#FILE%,4 (��C%=0�7 (��#FILE%,Volumes%(C%) (�� (�� (� (�� �sStereos (��C% (� �#FILE%,5 (��C%=0�7 ) �#FILE%,Stereo_Position%(C%) )� )� )" ), � �sTempo )6 �#FILE%,6 )@�#FILE%,Tempo% )J� )T )^7� �sprite(s%,X%,Y%) : � plot sprite S%(s%) at X%,Y% )hXș SpriteOp%, SprPlot%, SprBlk%, S%(s%), X%-x%(s%),Y%-y%(s%), 8, factors%, pixtrans% )r4� overwrite screen colour, but using sprite mask )|� )� )�� �float(s%,X%,Y%) )��R% )� Window%!handle%=ScoreWind_h% )�Window%!x1%=X%+X%(s%) )�X%-=x%(s%) )�Window%!x0%=X% )�Window%!y1%=Y%+Y%(s%) )�Y%-=y%(s%) )�Window%!y0%=Y% )�*ș UpdateWindow%,,Window%+handle% � R% )� X%+=Window%!x0%-Window%!scx% )� Y%+=Window%!y1%-Window%!scy% *ChSprite%=S%(s%) * ȕ R% * Ȏ s% � *&. � key% : �float_key_sig(X%,Y%+y%(s%)) *0( � time% : �float_time_sig(X%,Y%) *:4 : pixtrans%?1 = pixtrans%?0 � pixtrans%?1 *D_ ș SpriteOp%, SprPlot%, SprBlk%, ChSprite%, X%,Y%, 11, factors%, pixtrans% *N< pixtrans%?1 = pixtrans%?0 � pixtrans%?1 *X � *b, ș GetRectangle%,,Window%+handle% � R% *l � *v� *� *�� �float_key_sig(X%,Y%) *��I%,A%,C%,W% *��KEY_SIG%(1) � *�C%=SCRIBE%(sclef%) *�A%=KEY_SIG%(0) *�I%=accidental%+2+A% *�W%=x%(I%)+X%(I%):Y%-=y%(I%) *�ChSprite%=S%(I%) *�� I%=0 � KEY_SIG%(1)-1 *�cș SpriteOp%, SprPlot%, SprBlk%, ChSprite%, X%, Y%+Li%*Key_Y%(C%,A%,I%), 3, factors%, pixtrans% *� X%+=W% *�� +� +Uș SpriteOp%, SprPlot%, SprBlk%, ChSprite%, X%, Y%-y%(s%), 3, factors%, pixtrans% +� + � +* +4� �float_time_sig(X%,Y%) +>ș SetColour, 7 � 3<<4 +HR� �($NoteValue%)>1 � X%+C_Width%�2, Y%+C_Height% � � X%+C_Width%, Y%+C_Height% +R� $NoteValue% +\V� �($BarLength%)>1 � X%+C_Width%�2, Y%+2*C_Height% � � X%+C_Width%, Y%+2*C_Height% +f� $BarLength% +p� +z +�Q� *********************************************************************** REM +�Q� REM +�Q� M U S I C T R A N S C R I P T I O N R O U T I N E S REM +�Q� REM +�Q� *********************************************************************** REM +�:: +�� PROCEDURE: start_music +�� +�/� DESCRIPTION: Initialise to start of music +�: +�� �start_music +�� n% +�BAR%=0 :� current bar ,EGP%=MUSIC%:� Set current gate pointer to start of displayed music ,N%()=MUSIC%() ,1CLEF%()=0:� Start with base clefs (NOT BASS!) ,$6SIG%(0)=%01100111:� (Default time sig of 4/4 time) ,.VSIG%(1)=%00000010:� (Default of C Major) First displayed signatures attribute byte ,8 PX%=0 ,B�PutBarInfo(0) ,L� ,V ,`1� PROCEDURE: note_type(Channel C%, Type T%) ,j ,t� �note_type(C%,T%) ,~ N%(C%)?1=N%(C%)?1�&1F �T%<<5 ,�� ,� ,�� �note_dots(C%,D%) ,� N%(C%)?1=N%(C%)?1�&E7 �D%<<3 ,�� ,� ,�� �note_accidental(C%,A%) ,�N%(C%)?1=N%(C%)?1�&F8 �A% ,�� ,� ,�7� PROCEDURE: note_line(Channel C%, Stave line L%) ,�� - c� NOTE: If a note's position is not defined or specified as -16, it is treated as a rest - -� �note_line(C%,L%) -!?N%(C%)=?N%(C%)�7 �(16+L%)<<3 -(� -2 -<� �note_tie(C%,T%) -F"?N%(C%)=?N%(C%)�&FB �(T%<>0)�4 -P� -Z -d� �note_join(C%,J%) -n"?N%(C%)=?N%(C%)�&FD �(J%<>0)�2 -x� -� -�� �note_stem(C%,D%) -�#?N%(C%)=?N%(C%)�&FE �(D%<>0)�%1 -�� -� -�� �note_clear(C%) -�?N%(C%)=0:N%(C%)?1=0 -�� -� -�>� PROCEDURE: time_sig(Number of beats-1 N%,Beat type B%) -� -�� �time_sig(N%,B%) -�"?GP%=0:GP%?1=Time%�N%<<1�B%<<5 .� . ."� PROCEDURE: key_sig(Key K%) ." .,� �key_sig(A%,N%) .6!?GP%=0:GP%?1=Key%�A%<<2�N%<<3 .@� .J .T*� PROCEDURE: clef(Stave S%, Clef C%) .^ .h� �clef(S%,C%) .r"?GP%=0:GP%?1=Clef%�C%<<3�S%<<6 .|� .� .� � �bar .�?GP%=0:GP%?1=Bar% .�� .� .�� �insert_gate(W%) .��G% .��GP%<GATE% � .�C�G%=GATE%-W%�GP%�-4:G%!W%=!G%:�:� Shift up by W% from insertion .�#G%+=3:� Byte before last copied .�6ȕG%>=GP%:G%?W%=?G%:G%+=�:�:� Clear up in odd word .�� .�6GATE%+=W%:� Insert gate of size W% into gate queue /@EP%+=W%:� This assumes gates will only be inserted below EP% //?GP%=0:GP%?(W%-1)=0:� Zeroise inserted gate /� /& /0� �insert_note(C%) /:�N% /D�N%(C%)<FINE%(C%) � /NB�N%=FINE%(C%)-2�N%(C%)�-4:N%!2=!N%:�:� Shift up from insertion /XN%+=3:� Last copied word /b8ȕN%>=N%(C%):N%?2=?N%:N%+=�:�:� Clear up in odd word /l� /v5FINE%(C%)+=2:� Insert a note word into this queue /�#?GP%=?GP%�%1<<C%:� Mark in gate /��note_clear(C%) /�� /�:: /�� �delete_gate(W%) /��G% /� GATE%-=W% /�*�GP%<GATE% �G%=GP%�GATE%�4:!G%=G%!W%:� /�?EP%-=W%:� This assumes gates will only be deleted below EP% /�� /�:: /�� �delete_note(C%) /��N% 0FINE%(C%)-=2 07�N%(C%)<FINE%(C%) �N%=N%(C%)�FINE%(C%)�4:!N%=N%!2:� 0?GP%=?GP%��(%1<<C%) 0 � 0* 04� �allocate_channel(S%) 0> �C%,c%,G% 0HG%=?GP% 0RC%=-1:c%=7 0\� 0fȕc%>=0�G%�%1<<c%:c%+=�:� 0p�c%>=0 �S_C%(c%)=S% C%=c% 0z c%+=� 0� �c%<0 0�=C% 0� 0�� �arrange_stave(S%) 0� �C%,B% 0� B%=�:C%=� 0�#�?GP% ��GP%+=2:�?GP%�GP%>=GATE% 0�ȕB%�GP%<GATE% 0�C%=C%��sort_gate 0��skip_notes(?GP%):GP%+=1 0�.�?GP% �B%=C%:C%=�:�GP%+=2:�?GP%�GP%>=GATE% 0�� 0�� 1 1� �sort_gate 10�C%,NC%,NN%,G%,g%,pg%,d%,shortest%,Gchanged% 1$shortest%=255 1.G%=?GP% 18g%=�previous_gate(GP%) 1Bpg%=�preceding_gate(GP%) 1L NC%=-1 1V NN%=-1 1`�C%=0�7 1j�S_C%(C%)=S% � 1t2NC%+=1:n%(NC%)=C%:�G%�%1<<C% NN%+=1:C%(NN%)=C% 1~A�pg%�%1<<C% d%=N%(C%)?-1>>3�%11100:�d%<shortest% shortest%=d% 1�� 1�� 1�shortest%=shortest%�%11100 1��g%�NC%>0�NN%>=0 �sort 1�=Gchanged% 1� 1�� �sort 1� �N%,M% 1�c%()=-1 1� �M%=0�NC% 1� �N%=0�NN% 1�-�same_pitch(n%(M%),C%(N%)) c%(N%)=n%(M%) 2 � 2 � 2 �N%=0�NN% 2�c%(N%)<0 c%(N%)=�best 2(� 22 �N%=0�NN% 2<]�C%(N%)=c%(N%) �Gchanged%=�:M%=�in(c%(N%),C%()):�M%>N% �swap_notes(N%,M%) ��move_note(N%) 2F� 2P� 2Z 2d� �swap_notes(N%,M%) 2n �s%,d% 2xs%=C%(N%):d%=c%(N%) 2�ȔC%(N%),C%(M%) 2�Ȕ?N%(s%),?N%(d%) 2�ȔN%(s%)?1,N%(d%)?1 2�� 2� 2�� �move_note(N%) 2� �s%,d% 2�s%=C%(N%):d%=c%(N%) 2��insert_note(d%) 2�?N%(d%)=?N%(s%) 2�N%(d%)?1=N%(s%)?1 2��delete_note(s%) 2�� 3 3� �best 3 �N%,C% 3"#� short%,free%,rest%,any%,tied% 3,� N%=NC%�0�-1 36 C%=n%(N%) 3@�in(C%,c%())<0 � 3J�N%(C%)?-2�4 � 3Ttied%=C%+1 3^� 3h�pg%�%1<<C% � 3r)�(N%(C%)?-1>>3)=shortest% short%=C%+1 3|�N%(C%)?-2�&F8 �rest%=C%+1 3�� 3�free%=C%+1 3�� 3� any%=C%+1 3�� 3�� 3�� 3�P�short% C%=short% ��free% C%=free% ��rest% C%=rest% ��any% C%=any% �C%=tied% 3� =C%-1 3� 3�� �in(U%,U%()) 3��I%:I%=NN% 3�ȕI%�U%<>U%(I%):I%-=1:� 4=I%+(U%<>U%(I%)) 4 4�� �same_pitch(c%,C%):�R%,r%:R%=?N%(C%)�&F8:r%=N%(c%)?-2�&F8:=N%(c%)-2>=MUSIC%(c%)�(g%�(N%(c%)?-2�4)=4)�%1<<c%�(R%�r%)=� �(�<>R%�r%=�) 4& 40� �preceding_gate(gp%) 4:�C%,gm% 4D'�C%=0�7:�S_C%(C%)=S% gm%=gm%�%1<<C% 4N� 4X� 4b gp%-=1 4l#�gm%�?gp%�gp%<MUSIC%+2�gp%?-1=� 4v =?gp%�gp%>MUSIC%+1�gp%?-1<>� 4� 4�� �previous_gate(gp%) 4��C%,gm% 4�'�C%=0�7:�S_C%(C%)=S% gm%=gm%�%1<<C% 4�� 4�� 4� gp%-=1 4�"ȕgp%>MUSIC%�gp%?-1=�:gp%-=2:� 4��gm%�?gp%�gp%<MUSIC%+2 4�=?gp%�gp%>MUSIC%+1 4� 4�� �conflict(T%,S%,L%) 4��C%,co% 5 L%+=16 5C%=7 5� 5 /co%=?GP%�%1<<C%�S_C%(C%)=S%�(?N%(C%)>>3)=L% 5* C%+=� 54 �co%�C%<� 5>=C%-(co%<>0) 5H 5RQ� *********************************************************************** REM 5\Q� REM 5fQ� M U S I C T Y P E S E T T I N G R O U T I N E S REM 5pQ� REM 5zQ� *********************************************************************** REM 5�:: 5�3� PROCEDURE: set_score(Starting position PX%) 5�� 5�N� DESCRIPTION: Typeset music score from current bar to end of music/screen 5�K� No drawing is done as only the positions are calculated. 5�� 5�F� EFFECTS: Stores gate X positions & types in PX%() & PTYPE%() 5�: 5�� �set_score(PX%) 5�ȕ GP%<GATE% 5�?�?GP% �set_notes(?GP%):GP%+=1 ��set_attribute(GP%?1):GP%+=2 5�,�:� Until edge of screen or end of music 5�5EP%=GP%:� Last GP%, pointer to first undrawn gate 6.EX%=PX%:� Last PX%, index to last position 6OPX%(PX%+1)=PX%(PX%)+PW%(PX%)+Pgap%:� Appendation position after last symbol 6O� PX%(PX%+1)>S_Width% �SetExtent(PX%(PX%+1)+100*Hi%) � �SetExtent(S_Width%) 6$PXn%(NBars%)=PX% 6..PTYPE%(PX%+1)=Note%:� Note type by default 68� 6B:: 6Lr� NOTE: The key signature is the only attribute that must be kept track of in order to ensure correct setting. 6V�� This is because a naturalising signature consists of the same number of naturals as accidentals in the previous key signature 6`: 6j� �set_attribute(A%) 6t(�A%�PTYPE%(PX%)+� ��A%�PTYPE%(PX%) � 6~&�T%:T%=%1:�A%�%1 ��T%=T%<<1:�A%�T% 6�&PX%(PX%+1)=PX%(PX%)+PW%(PX%)+Pgap% 6� PX%+=1 6�PTYPE%(PX%)=T% 6�Ȏ T% � 6��Time%:PW%(PX%)=20*Hi% 6� �Key% 6�c�A%�56 T%=accidental%+(A%>>2�%1)+2:SIG%(1)=A% �T%=accidental%+1:ȔA%,SIG%(1):�A%�56 �A%=8:T%+=1 6�&PW%(PX%)=(A%>>3�7)*(x%(T%)+X%(T%)) 6�+�Clef%:PW%(PX%)=x%(clef%+3)+X%(clef%+3) 6��Bar%:PW%(PX%)=Hi%*4 6�� 6�� 7 7 � �set_notes(G%) 7�lx0%,lx1%,ly0%,ly1% 7B�C%,P%,R%,s%:� Channel, Note prefix & remainder widths, Sprite 7( C%=-1 72� 7<�C%-=�:�G%�%1<<C% 7F�bound_note(!N%(C%)) 7P%�lx0%>P% P%=lx0%:� Maximum prefix 7Z(�lx1%>R% R%=lx1%:� Maximum remainder 7d$N%(C%)+=2:� Pull from note queue 7n.�(2<<C%)>G%:� Until no more notes (1 bits) 7xnPX%(PX%+1)=PX%(PX%)+PW%(PX%)+Pgap%+P%:� Next position is previous position + width+gap+prefix of next note 7�%PX%+=1:� next note position index 7�#PW%(PX%)=R%:� Width of new note 7�!PTYPE%(PX%)=Note%:� Note type 7�� 7� 7�� �bound_note(L%) 7� �H%,S%,s% 7�H%=L%>>8�&FF 7�?�L%�&F8 S%=H%>>5�L%<<3�8 �S%=rest%�H%>>5:� Note/rest sprite 7�lx0%=x%(S%):� Prefix width 7�lx1%=X%(S%):� Suffix width 7�!ly0%=y%(S%):� Decender height 7�!ly1%=Y%(S%):� Ascender height 8�H%�7 � 8s%=accidental%�H%�7 8'lx0%+=x%(s%):� Add accidental width 8"&�y%(s%)>ly0% ly0%=y%(s%):� Lower ? 8,'�Y%(s%)>ly1% ly1%=Y%(s%):� Higher ? 86� 8@k�H%�24 s%=dot%+(H%>>3�3):lx1%=x%(S%)+X%(s%):�y%(s%)>ly0% ly0%=y%(s%):� Dot adds suffix and may be lower 8J� 8T:: 8^� �position_staves 8h� Y%,S% 8r8Score_Height%=(PERC%+1+3*(STAVE%+1)+1)*Stave_Height% 8|%Y%=-Score_Height%-Stave_Height%�2 8�D�PERC% �S%=PERC%�1�-1:Y%+=Stave_Height%:Y_STAVE%(STAVE%+S%)=Y%:� 8�:� S%=STAVE%�0�-1:Y%+=3*Stave_Height%:Y_STAVE%(S%)=Y%:� 8�� 8� 8�� �setup_staves 8�� O% 8��position_staves 8�#ScoreWBlk%!handle%=ScoreWind_h% 8�*ș GetWindowState%,,ScoreWBlk%+handle% 8�;ScoreWBlk%!y0%=ScoreWBlk%!y1%-Score_Height%-PaneHeight% 8�3ScoreWBlk%!scx%=0:ScoreWBlk%!scy%=PaneHeight%/2 8�ScoreWBlk%!under%=-1 8�&ș OpenWindow%,,ScoreWBlk%+handle% 9LHBAR%=0 9ScoreClosed%=� 9 Window%!handle%=ScoreWind_h% 9&'ș GetWindowState%,,Window%+handle% 90?� TRANSCRIBE% �place_top_panes(-1): �place_bottom_panes(-1) 9:� PLAYING% �CheckScroll 9D� 9N 9XD� �update_score(Window%!x0%,Window%!y0%,Window%!x1%,Window%!y1%) 9b Window%!handle%=ScoreWind_h% 9l*ș UpdateWindow%,,Window%+handle% � R% 9v ȕ R% 9��:�draw_staves 9�*ș GetRectangle%,,Window%+handle% � R% 9�� 9�� 9� 9�� PROCEDURE: draw_staves 9�� 9�/� DESCRIPTION: Draw current stave structure 9�&� 1 stave for 1 voice 9�(� 2 staves for keyboard 9�4� 3 staves for 1 voice and keyboard 9�.� 4 staves for 4 voice chorus 9�: :� �draw_staves :c� Y%,T%,B%,S%,L%:� Y%,T%,B%=Position & Y bounds of each stave, S%=Stave index, L%=Line position :Q� x%,y%,lx1%:� Virtual coordinates of bottom left & top right of score window : 6� c%,t%,b%:� Left edge of clip window and Y bounds :*y%=Window%!y1%-Window%!scy% :4x%=Window%!x0%-Window%!scx% :>8lx1%=x%+Score_Width%:� lx1%>Clip%!x1% lx1%=Clip%!x1% :H%c%=Clip%!x0%:�c%<x%+Hi% c%=x%+Hi% :Rb%=Clip%!y0%:t%=Clip%!y1% :\�PERC% � :f� S%=STAVE%+1�STAVE%+PERC% :pY%=y%+Y_STAVE%(S%) :z!�b%<=Y%�t%>=Y% �c%,Y%,lx1%,Y% :�� :�� :�� S%=0 � STAVE% :�@Y%=y%+Y_STAVE%(S%):T%=Y%+Stave_Height%�2:B%=T%-Stave_Height% :��b%<=T%�t%>=B% � :�)�c%,Y%,lx1%,Y%:� Plot centre bar line :��L%=Li%*2�L%*2�L% :�*�c%,Y%+L%,lx1%,Y%+L%:� Plot upper line :�*�c%,Y%-L%,lx1%,Y%-L%:� Plot lower line :�� :�� :�� :�B%=Score_Width% ;.T%=Clip%!x1%-x%:�T%<B% B%=T%:� Right bound ;+T%=Clip%!x0%-x%:�T%<0 T%=0:� Left bound ;� � BADMODE% � ;$6 �draw_score(x%,y%,T%,B%):� Draw symbols on stave ;.� ;8$ � Window%!x0%, Window%!y1%-100 ;B8 � "Cannot display score in this (256-colour) mode" ;L � ;V� ;`:: ;j;� PROCEDURE: draw_score(Based X%,Y%, PX bounds A%,B%) ;t� ;~O� DESCRIPTION: Write current section of music score that appears between A% ;�� and B% ;�: ;�� �draw_score(X%,Y%,A%,B%) ;��PX% ;� BAR%=0 ;�t� must be subtle about redrawing last note (or other item) of score to prevent picking up rubbish data after end ;�� A%>PX%(PXn%(NBars%)) � ;�= � A%>PX%(PXn%(NBars%))+2*Pgap% � � A%=PX%(PXn%(NBars%)) ;� � ;�T� ensure bar numbers are always completely updated; but don't lose 1st-note draw ;�� NBars%>2 � ;�,ȕ PX%(PXn%(BAR%+2))<A% � BAR%<=NBars%-1 <