' ************************* ALEX'S COOL, FLASHY MIDI PROG ******************* ' Version C is the tidied up fixed verion ' Version D displays no messages ' Version E has complete rewrite of graph routine which was too messy ' making it run too slow. + intro built in to start ' Version f has vu_meters routine (v. crappy) ' Version g has vel vs pitch routine with rainbow. realy nice! ' Version h has dodgy picture viewer ' Version i has new picture viewer and ravey circles ' version j has ghost player piano taken out the crappy vu_meters ' verison k has music score routine completed ' version l has verical bars routine (v1) ' **************** INITIALISE, SETUP SCREEN AND VARIABLES ******************* ' Dimention arrays Dim CHANEL_MESSAGE$(113) Dim COMMON_MESSAGE$(7) Dim REAL_TIME_MESSAGE$(15) Dim NOEON(2) Dim EBONY_N_IVORY$(12),EBONY_N_IVORY(12) Dim PITCH_2KEY_CONVERSION_TABLE(24) Dim GRAPHX_OLD(16) Dim GRAPHY_OLD(16) Dim PY(85) Dim SCR(2) Dim CX(360) Dim SPRYT(110) Dim MSCORE_YCORD(46),MSCORE_SHAPE(46) Dim SCRDATA(5),CHANEL_COLOURS(16) Dim HORIS_SLIDERX(16),OLD_HORIS_SLIDERX(16) ' Allow these variables to be used throughout all procedures Global CHANEL_MESSAGE$(),COMMON_MESSAGE$(),REAL_TIME_MESSAGE$(),X,PITCH,VEL Global BEEN_TO_NOTE_ON,NOEON(),EBONY_N_IVORY$(),EBONY_N_IVORY(),NOE,COUNT,KOUNT Global PITCH_2KEY_CONVERSION_TABLE(),CHANEL,NEED_A_ROUTINE,CHANGEIT,S Global GRAPHX,GRAPHX_OLD(),GRAPHY,GRAPHX_MAX,GRAPHX_MIN,GRAPHY_MIN,GRAPH_SPACE Global GRAPHY_OLD(),FILTER,ALREADY_PULSED,OLD_TIME,TIME Global ROUTINE_COUNTER,CYCLE_PIANO_SKY_CHANGE,CYCLE_PIANO_SKY_CHANGE_MAX Global VUHEIGHT,VUHEIGTMAX,VUWIDTH,VUY Global PY(),EX_ROUTINE Global OLDPIC Global CX() Global SPRYT(),SPRY_NUMBER Global MSCORE_YCORD(),MSCORE_SHAPE(),MSCOREX,MSCOREY,MSCOREX_MAX,MSCOREX_MIN Global MSCORE_SPACE,MSCORE_TOP_OR_BOTTOM_OFFSET,MSCORE_TOP_OR_BOTTOM Global SCRDATA(),CHANEL_COLOURS() Global HORIS_SLIDERX(),OLD_HORIS_SLIDERX(),LISTEN_TO ' Turn off disk operating system and text editor Close Workbench : Close Editor ' Do the intro and initialise main program Proc FLOATING_NOTES_INTRO Proc INIT Proc SLIDER_PREFS ' Turn off external interupts (eg. test for mouse movement) Dreg(0)=Execall(-132) ' Make a beep when ready to start Play 60,1 ' * * * * * * * * * * * * M A I N L O O P * * * * * * * * * * * Do Proc FETCHMIDI Proc ANALYSE_MIDI If BEEN_TO_NOTE_ON=1 Then Proc PICK_OUTPUT_ROUTINE Loop Proc _CLOSEDOWN End ' ************************** E N D O F P R O G R A M *************** ' ---------------------------------------------------------------------- ' ---------------------------------------------------------------------- ' ***************************** P R O C E D U R E S ******************** ' ***--- MIDI DECODING/TRANSLATION ROUTINES ---*** Procedure INIT Screen Open 0,360,256,2,Lowres Cls 0 'Set up Serial Port Serial Open 1,0,0,0,0 Serial Speed 1,31250 Serial Bits 1,8,1 Serial Parity 1,-1 Serial Buf 1,2048 ' Set up messages for text output CHANEL_MESSAGE$(0)="Note off" CHANEL_MESSAGE$(16)="Note on message" CHANEL_MESSAGE$(32)="Poly key pressure" CHANEL_MESSAGE$(48)="Control change" CHANEL_MESSAGE$(64)="Program change" CHANEL_MESSAGE$(80)="Channel pressure" CHANEL_MESSAGE$(96)="Pitch bend" CHANEL_MESSAGE$(112)="System message" COMMON_MESSAGE$(0)="System exclusive" COMMON_MESSAGE$(1)="MIDI Time code" COMMON_MESSAGE$(2)="Song position pointer" COMMON_MESSAGE$(3)="Song select" COMMON_MESSAGE$(4)="Undefined com message1" COMMON_MESSAGE$(5)="Undefined com message2" COMMON_MESSAGE$(6)="Tune request" COMMON_MESSAGE$(7)="End of system exclusive" 'REAL_TIME_MESSAGE$(0)="Timing Clock" REAL_TIME_MESSAGE$(1)="Undefined Real Time message1" REAL_TIME_MESSAGE$(2)="Start" REAL_TIME_MESSAGE$(3)="Continue" REAL_TIME_MESSAGE$(4)="Stop" REAL_TIME_MESSAGE$(5)="Undefined Real Time message2" REAL_TIME_MESSAGE$(6)="Active sensing" REAL_TIME_MESSAGE$(7)="System reset" ' Keys data for Player_piano_routine For LOUP=1 To 12 Read EBONY_N_IVORY$(LOUP) Next LOUP Data "C","#","D","#","E","C","#","D","#","D","#","E" For LOUP=1 To 12 Read EBONY_N_IVORY(LOUP) Next LOUP Data 0,5,13,21,27,40,44,53,59,65,74,78 ' Get the cycle_piano routine ready for imediate use Proc CYCLE_PIANO_SETUP ' Set up graph variables ready for imediate use Proc GRAPH_SETUP ' set up defalt prefs Restore PREFS For LOUP=8 To 1 Step -1 Read HORIS_SLIDERX(LOUP) Next LOUP PREFS: Data 98,24,99,104,103,102,101,100 ' Reset routine counter ROUTINE_COUNTER=101 Proc ROUTINE_SWAP ' set up vel_vs_pitch_vector_graph for use. Proc VEL_VS_PITCH_SETUP ' set up picture screen for use Proc PIC_VIEWER_SETUP ' set up player_piano for use Proc PIANO_PLAYER_SETUP ' set up music score maker for use Proc MSCORE_SETUP End Proc Procedure FETCHMIDI 'Read SERIALPort Repeat FETCH_DATA[X] If FILTER=False and X=$FE Then Proc CLOCK_PULSE Until X<>$FE and X<>$F8 ' Not all routines need all data therefore do filtering other wise ' recognise a midi clock pulse and go no further. End Proc Procedure ANALYSE_MIDI 'CHECK BIT 7 To SEE WHAT TYPE OF MESSAGE : STATUS or Data If(X and $80) Then Proc STATUS_BYTE Else Proc DAT_BYTE End Proc Procedure FETCH_DATA[X] ' Read data procedure. Ignores -1 (no data found) Repeat X=Serial Get(1) Until X<>-1 End Proc[X] ' *STATUS BYTE ROUTINES* Procedure STATUS_BYTE ' Test and go to appropriate proc If(X<$F0) Then Proc CHANEL_MESSAGE Else Proc SYS_MESSAGE End Proc Procedure CHANEL_MESSAGE CHANEL=(X and $F)+1 STATUS=(X and $70) ' The print statement below for debugging only. ' Print CHANEL_MESSAGE$(STATUS);" on channel ";CHANEL ' if PROGRAM CHANGE message occurs (64) then this may be voice 99 to change ' the output routine. If STATUS=64 Then CHANGEIT=True : Proc ROUTINE_CHANGE ' Ignore pitch bend data (this is part of note on messages and is not required.) If STATUS=96 Then BEEN_TO_NOTE_ON=0 : Pop Proc ' If STATUS=16 and BEEN_TO_NOTE_ON=0 Then BEEN_TO_NOTE_ON=0 : Proc NOE_ON ' *** (resets the been_to_note_on flag. A diffent sys message has) ' *** (been encountered that is not going to be pitch or velocity.) If STATUS=16 Then BEEN_TO_NOTE_ON=0 : Proc NOE_ON If STATUS=0 Then BEEN_TO_NOTE_ON=0 : Proc NOE_OFF End Proc Procedure SYS_MESSAGE BEEN_TO_NOTE_ON=0 If(X and $8) Then Proc REAL_TIME_MESSAGE Else Proc COMMON_MESSAGE End Proc ' (messages taken out, these are now empty routines!) proc then endproc! Procedure REAL_TIME_MESSAGE ' THE BELOW MESSAGE Not NEEDED ANYMORE ' If(X and 7)<>0 Then Print REAL_TIME_MESSAGE$(X and 7) End Proc Procedure COMMON_MESSAGE ' Print "COMMON routine" ' Print REAL_TIME_MESSAGE$(X and $7) End Proc ' *DATA BYTE ROUTINES* Procedure DAT_BYTE If BEEN_TO_NOTE_ON=1 Then Proc NOE_ON : Rem Else Print "DATA ignored" ' ^^^^^ message taken out ' *********************** ' *** ( if the program has just been to the note on procedure) ' *** ( Then the data is still pitch and velocity data) End Proc Procedure NOE_ON ' Read PITCH If BEEN_TO_NOTE_ON=0 Then FETCH_DATA[X] : PITCH=X If BEEN_TO_NOTE_ON=1 Then PITCH=X : Rem (Don't have to read pitch again.) ' (the x variable is data which is pitch) ' Read Velocity FETCH_DATA[X] VEL=X ' Output results ' Print "Note ";PITCH; If VEL>0 Then NOE=1 Else NOE=0 ' Put results into a form suitable to be passed to the gfx routines ' a nice, neat array containing pitch and note on/off status. NOEON(1)=PITCH NOEON(2)=NOE ' Set been_to_note_on flag as 1 so if NOE_ON proc is called again straight ' away the procedure will remember not to read the serial port again as ' the data in the x variable is the pitch. BEEN_TO_NOTE_ON=1 End Proc Procedure NOE_OFF 'Say "Note off. HELP! help. help!" ' Read PITCH If BEEN_TO_NOTE_ON=0 Then FETCH_DATA[X] : PITCH=X If BEEN_TO_NOTE_ON=1 Then PITCH=X : Rem (Don't have to read pitch again.) ' (the x variable is data which is pitch) ' Output results ' Print "Note ";PITCH; NOE=0 ' Put results into a form suitable to be passed to the gfx routines ' a nice, neat array containing pitch and note on/off status. NOEON(1)=PITCH NOEON(2)=NOE ' Set been_to_note_on flag as 1 so if NOE_ON proc is called again straight ' away the procedure will remember not to read the serial port again as ' the data in the x variable is the pitch. BEEN_TO_NOTE_ON=1 End Proc Procedure _CLOSEDOWN 'Dreg(0)=Execall(-138) Play 60,1 End Proc ' *********************************************************************** ' ***--- GRAPHICAL OUTPUT ROTINES (THE FLASHY STUFF!) ---*** ' Pick a routine from all the below Procedure ROUTINE_CHANGE Proc FETCH_DATA[X] 'check the 8 horis_slider variables incase a change of routine is called for For LOUP=1 To 8 If X=HORIS_SLIDERX(LOUP) Then Proc ROUTINE_SWAP Next LOUP End Proc Procedure ROUTINE_SWAP ROUTINE_COUNTER=X ' Closedown old routines if necessary If EX_ROUTINE=4 Then Proc VEL_VS_PITCH_DISAPPEAR If EX_ROUTINE=3 Then Proc PIANO_PLAYER_DISAPPEAR If EX_ROUTINE=-1 Then Proc VERTICAL_BARS_DISAPPEAR ' Set up screens for the new routines If ROUTINE_COUNTER=HORIS_SLIDERX(1) Then Proc GRAPH_APPEAR If ROUTINE_COUNTER=HORIS_SLIDERX(2) Then Proc CYCLE_PIANO_APPEAR If ROUTINE_COUNTER=HORIS_SLIDERX(3) Then Proc PIANO_PLAYER_APPEAR If ROUTINE_COUNTER=HORIS_SLIDERX(4) Then Proc VEL_VS_PITCH_APPEAR If ROUTINE_COUNTER=HORIS_SLIDERX(5) Then Proc PIC_VIEWER_APPEAR If ROUTINE_COUNTER=HORIS_SLIDERX(7) Then Proc MSCORE_APPEAR If ROUTINE_COUNTER=HORIS_SLIDERX(8) Then Proc VERTICAL_BARS_APPEAR End Proc Procedure PICK_OUTPUT_ROUTINE ' routine currently tested ' ROUTINE_COUNTER=5 ' Proc TXT_DISPLAY ' Pop Proc ' Proc PITCHNO_2_KEY If ROUTINE_COUNTER=HORIS_SLIDERX(1) Then Proc GRAPH If ROUTINE_COUNTER=HORIS_SLIDERX(2) Then Proc CYCLE_PIANO If ROUTINE_COUNTER=HORIS_SLIDERX(3) Then Proc PIANO_PLAYER If ROUTINE_COUNTER=HORIS_SLIDERX(4) Then Proc VEL_VS_PITCH If ROUTINE_COUNTER=HORIS_SLIDERX(5) Then Proc PIC_VIEWER If ROUTINE_COUNTER=HORIS_SLIDERX(6) Then Proc CIRC If ROUTINE_COUNTER=HORIS_SLIDERX(7) Then Proc MSCORE If ROUTINE_COUNTER=HORIS_SLIDERX(8) Then Proc VERTICAL_BARS End Proc Procedure CLOCK_PULSE ' what to do if pitch vs time graph is running If ROUTINE_COUNTER=1 and ALREADY_PULSED=False Then Proc _INCREMENT_GRAPHX : Proc _INCREMENT_GRAPHX ' what to do if velocity vs pitch graph is running If ROUTINE_COUNTER=4 Then Proc VECTOR_PTS_DECREASE_YET[1] ALREADY_PULSED=True End Proc ' *****TEXT OUTPUT ROUTINES***** ' Mainly for debuging and testing ideas Procedure TXT_DISPLAY S=Screen If S<>0 Then Bell : Screen Open 0,320,250,2,LORES : Screen To Front 0 : Screen 0 Print "Pitch =";NOEON(1);PITCH If NOEON(2)=0 Then Print " off!" Else Print " on!" : Play 1,PITCH,0 End Proc Procedure PITCHNO_2_KEY Screen To Front 0 Screen 0 ' This procedure is used to work out from the pitch, the key that is played ' ie. pitch=32 might be the key C#. This information is useful to the ' player_piano routine. ' NOTES: PITCH24 IS LOWEST C PRESSED=PITCH Add PRESSED,1 ' get pressed between 1 and 12 While PRESSED>12 Add PRESSED,-12 Wend Bell Print EBONY_N_IVORY$(PRESSED),PRESSED,PITCH, If NOE=1 Then Print "on" Else Print "off" End Proc Procedure FLOATING_NOTES_INTRO Degree Dim XC(4),YC(4),XIC(4),YIC(4) Hide On No Mask : For F=1 To 3 : Make Mask F : Next F BUBBLE$=" R: L R1=Z(2)+1; A 1,(R1,1); L R0=Z(6)+1; L Y=296; L: L Y=Y-R0; I Y<0 J R; P; J L;" BUBBLE2$=" R: L Y=1; P; L: L Y=Y+2; I Y>256 J R; P; J L;" Unpack 5 To 0 Unpack 7 To 1 Palette 0,0 Wait Vbl : Dual Playfield 0,1 Screen 0 For F=8 To 15 : Sprite F,((F-8)*40)+128,1,1 : Channel F To Sprite F : Amal F,BUBBLE$ : Next F Channel 1 To Screen Offset 1 : Amal 1,BUBBLE2$ : Amal On Fade 3,0,4072,3490,3202,$400,$600,$EEE,$A50,0,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF,$FFF Repeat Until Mouse Key=1 or Joy(1)=16 Fade 3 : Wait 45 For F=8 To 15 : Amal Off F : Sprite Off F : Next F Amal Off 1 : Screen Close 1 End Proc ' *****CYCLE_PIANO_ROUTINES!******* ' The futuristic keyboard. Keys flashed by colour cycling technique ' (ie changing the palette colours) Procedure CYCLE_PIANO '******************************************************************* ' ' C Y C L E P I A N O N O T E S. ' ' ' If get a better cycle piano routine (ie full 5 octaves) then make ' the original screen back to like in demo. Don't bother about ' drawing out the extra black notes that arn't there realy. ' and don't worry about acuracy. just have it as a flashy routine. Not ' accurate. ' Make it so that keys just flash black then fade out. dont have ' red until the right noe off message recived. this will halve ' the amount of processing! (no noe offs) ' do this by having a sepearate proc fade_keys to do the keys 'and a pop proc if noe=0. '******************************************************************** 'Count how many times the procedure has been run and change the sky colour! Add COUNT,1,1 To 200 If COUNT=199 Then Proc CYCLE_PIANO_CHANGE_SKY ' Flash keys Proc CYCLE_PIANO_KEYS_FLASH End Proc Procedure CYCLE_PIANO_SETUP Unpack 8 To 1 Screen Hide 1 ' pitch to key conversion table' Restore CONV_TABLE For LOUP=0 To 24 Read PITCH_2KEY_CONVERSION_TABLE(LOUP) Next LOUP CYCLE_PIANO_SKY_CHANGE_MAX=4 ' ********* conversion table *********** CONV_TABLE: Data 0,-1,1,-1,2,3,-1,4,-1,5,-1,6,7,-1,8,-1,9,10,-1,11,-1,5,-1,6,7 ' *************************************** End Proc Procedure CYCLE_PIANO_APPEAR ' hide old screen S=Screen Screen Hide S ' Display cycle_piano screen Screen Show 1 Screen To Front 1 Screen 1 'turn the read data filter on FILTER=True CYCLE_PIANO_SKY_CHANGE=1 End Proc Procedure CYCLE_PIANO_KEYS_FLASH ' Change pitch (a value between about 1 and 70) to pressed ' (a value between 1 and 12) PRESSED=PITCH ' Decrese pitch to a value between 1 and 24 (covers the 1 and a bit octaves of keyboard) While PRESSED>23 Add PRESSED,-24 Wend ' Convert key PRESSED to screen palette colour number PRESSED=PITCH_2KEY_CONVERSION_TABLE(PRESSED) ' Ignore the black keys ' Quit the procedure now if key PRESSED is a black key (-1) If PRESSED=-1 Then Pop Proc ' first colour in palette is no 20 so add 20 Add PRESSED,20 ' Change colours If NOE=0 Then Colour PRESSED,$FFF Else Colour PRESSED,$F00 End Proc Procedure CYCLE_PIANO_CHANGE_SKY ' Change the colour of the sky! 'Add CYCLE_PIANO_SKY_CHANGE,1,1 To CYCLE_PIANO_SKY_CHANGE_MAX Add KOUNT,1,1 To 3 If KOUNT=3 Then C=$EEF : D=$221 : Rem BLUE! If KOUNT=2 Then C=$EFE : D=$212 : Rem GREEN! If KOUNT=1 Then C=$FEE : D=$122 : Rem RED! For LOUP=1 To 7 : Rem Go through the 7 colours used in the sky and change 'em Add C,-D Colour LOUP,C ' Wait until the next video blank ' Slows down the colouring so looks more like a nice fade ' rather than a sudden change Wait Vbl Next LOUP End Proc ' ****** MUSICAL SCORE ROUTINES! *********** '****** this was tricky! **************** Procedure MSCORE Proc _INCREMENT_MSCOREX If NOE=0 ALREADY_PULSED=False Pop Proc Else Proc STICK_NOTES_DOWN ALREADY_PULSED=False End If End Proc Procedure MSCORE_SETUP ' set up variables MSCOREX_MIN=60 MSCOREX_MAX=600 MSCORE_SPACE=5 ' read in notes data Restore MSCORE_DATA For LOUP=1 To 46 Read MSCORE_YCORD(LOUP) Read MSCORE_SHAPE(LOUP) Next LOUP Make Icon Mask ' Comma separated variable data statement in the format ' Data y-coordinate,sprite(ie note shape)number ' **************************************************************************** ' b a# a g# g f# f e d# d c# c b a# MSCORE_DATA: Data 11,7,11,16,15,9,14,12,18,5,17,12,21,5,25,5,25,12,29,5,28,12,32,5,13,6,16,13 ' a g# g f# f e d# d c# c b Data 16,6,20,13,20,6,23,13,23,6,27,6,30,13,30,6,36,17,36,10,65,5 ' a# a g# g f# f e d# d c# c b a# Data 65,12,69,5,68,12,72,5,72,12,76,5,79,5,59,13,59,6,63,13,63,6,66,6,70,13 ' a g# g f# f e d# d Data 70,6,74,13,74,6,77,13,77,6,82,10,86,15,86,8 '******************************************************************************* End Proc Procedure MSCORE_APPEAR ' hide last screen S=Screen Screen Hide S ' create screen and Load in background screen Screen Open 0,640,256,2,Hires Load Iff "ram:pics/music_sheet" 'turn read data filter on FILTER=True End Proc Procedure _INCREMENT_MSCOREX Proc TIMECHECK TIME=Param ' time is set to value returned by timecheck procedure (parameter passing) MOVEUP=Abs(OLD_TIME-TIME) If MOVEUP46 or PRESSED<1 Then Pop Proc ' Set up y-coordinate according to which sheet to print the notes on ' top sheet or the bottom sheet MSCORE_Y=MSCORE_YCORD(PRESSED)+MSCORE_TOP_OR_BOTTOM_OFFSET ' Decrese pitch to a value between 1 and 12 (to check if a black note was played) BLK_OR_WHITE=PITCH+1 While BLK_OR_WHITE>12 Add BLK_OR_WHITE,-12 Wend ' Use the ebony_n_ivory array (set up in initailisation proc) to check ' if the PRESSED key is a "#" sharp ie black key and take that into ' account when working out x,y co-ords If EBONY_N_IVORY$(BLK_OR_WHITE)="#" ' move up the x-coord to make room for the # sign Add MSCOREX,10,MSCOREX_MIN To MSCOREX_MAX OLD_TIME=TIME If MSCOREX=MSCOREX_MIN Proc MSCORE_CLEAR_SCREEN End If Paste Icon MSCOREX,MSCORE_Y,MSCORE_SHAPE(PRESSED) Else ' Put the right shaped note at the right coordinate on the screen Paste Icon MSCOREX,MSCORE_Y,MSCORE_SHAPE(PRESSED) End If End Proc Procedure MSCORE_CLEAR_SCREEN If MSCORE_TOP_OR_BOTTOM=0 ' Overlay blank graph background picture that has been saved in main memory Load Iff "ram:pics/music_sheet" 'reset the top_or_bottom_y-coordinat offset MSCORE_TOP_OR_BOTTOM_OFFSET=0 Else MSCORE_TOP_OR_BOTTOM_OFFSET=118 End If ' reset time axis base Proc TIMECHECK OLD_TIME=Param ' reverse the top or bottom flag Add MSCORE_TOP_OR_BOTTOM,1,0 To 1 End Proc ' ******* PITCH vs TIME GRAPH ' V2 after complete re-write (got too messy and slow) Procedure GRAPH Proc _INCREMENT_GRAPHX If NOE=0 ALREADY_PULSED=False Pop Proc Else Proc GRAPH_PLOT ALREADY_PULSED=False End If End Proc Procedure GRAPH_SETUP 'set up screen Hide : Flash Off : Curs Off Unpack 4 To 3 Save Iff "ram:graph_background.iff" Screen Hide 3 ' set up variables GRAPHY_MIN=250 GRAPHX_MIN=10 GRAPHX_MAX=310 GRAPH_SPACE=5 'reset graph coords to start position For LOUP=1 To 16 GRAPHY_OLD(LOUP)=GRAPHY_MIN/2 : Rem set graph y to mid position GRAPHX_OLD(LOUP)=GRAPHX_MIN Next LOUP End Proc Procedure GRAPH_APPEAR ' hide last screen S=Screen Screen Hide S GRAPHX=GRAPHX_MIN Screen Show 3 Screen To Front 3 Screen 3 Proc GRAPH_CLEAR_SCREEN FILTER=False End Proc Procedure _INCREMENT_GRAPHX Proc TIMECHECK TIME=Param ' time is set to value returned by timecheck procedure (parameter passing) MOVEUP=Abs(OLD_TIME-TIME) If MOVEUP200 Then PY(LOUP)=200 Next End Proc Procedure VECTOR_PTS_REDRAW ' redraw the vector points in the background and then swap screens Ink 1 ' plot first point Plot 0,200 ' draw the rest of the points that arn't 0 (ie worth plotting) For LOUP=1 To 85 If PY(LOUP)<200 Then Draw To 4*LOUP,PY(LOUP) Next LOUP ' draw to last dot Draw To 360,200 Screen Swap : Wait Vbl Cls 0 End Proc Procedure VEL_VS_PITCH_SETUP Screen Open 2,360,256,2,Lowres : Flash Off : Curs Off : Cls 0 : Hide On Palette $0,$FFF 'Screen Display 2,10,0,, Screen 2 : Double Buffer : Autoback 0 ' setup initial values for vector points For LOUP=1 To 60 PY(LOUP)=200 Next LOUP End Proc Procedure VEL_VS_PITCH_APPEAR ' hide old screen S=Screen Screen Hide S ' show screen for this routine Screen Show 2 Cls 0 Screen To Front 2 Screen 2 FILTER=False : Rem DONT ignore clock pulses (important to this routine 'because used to slowly decrease the points) ' Make rainbow background Restore RDATA Set Rainbow 0,1,180,"","","" Rainbow 0,80,93,200 For F=0 To 178 Step 2 Read R : Rain(0,F)=R : Rain(0,F+1)=R Next F Rainbow 0,80,93,200 RDATA: Data $F00,$F10,$F20,$F30,$F40,$F50,$F60,$F70,$F80,$F90,$FA0,$FB0,$FC0,$FD0,$FE0 Data $FF0,$EF0,$DF0,$CF0,$BF0,$AF0,$9F0,$8F0,$7F0,$6F0,$5F0,$4F0,$3F0,$2F0,$1F0 Data $F0,$F1,$F2,$F3,$F4,$F5,$F6,$F7,$F8,$F9,$FA,$FB,$FC,$FD,$FE Data $FF,$EF,$DF,$CF,$BF,$AF,$9F,$8F,$7F,$6F,$5F,$4F,$3F,$2F,$1F Data $F,$10F,$20F,$30F,$40F,$50F,$60F,$70F,$80F,$90F,$A0F,$B0F,$C0F,$D0F,$E0F Data $F0F,$F0E,$F0D,$F0C,$F0B,$F0A,$F09,$F08,$F07,$F06,$F05,$F04,$F03,$F02,$F01 CAT: Data 0,90,0,4,95,95 Data 225,315,0,0,75,75 Data 90,180,4,0,95,95 Data 315,45,0,0,75,75 Data 180,270,0,4,95,95 Data 45,135,0,0,75,75 Data 270,0,4,0,95,95 Data 135,225,0,0,75,75 ' Data 0,90,1,1,95,95 Data 45,135,355,355,55,55 Data 90,180,1,1,95,95 Data 135,225,355,355,55,55 Data 180,270,1,1,95,95 Data 225,315,355,355,55,55 Data 270,0,1,1,95,95 Data 315,45,355,355,55,55 Data 0,90,1,1,95,95 Data 45,135,4,4,95,95 Data 90,180,2,2,95,95 Data 135,225,3,3,95,95 Data 180,270,3,3,95,95 Data 225,315,2,2,95,95 Data 270,0,4,4,95,95 Data 315,45,1,1,95,95 Data 0,90,5,4,95,95 Data 225,315,5,4,45,45 Data 90,180,5,4,95,95 Data 315,45,5,4,45,45 Data 180,270,5,4,95,95 Data 45,135,5,4,45,45 Data 270,0,5,4,95,95 Data 135,225,5,4,45,45 ' set ex_routine flag so the rainbow effect is turned off before next ' routine EX_ROUTINE=4 End Proc Procedure VEL_VS_PITCH_DISAPPEAR ' end the rainbow effect which slows down processing Rainbow Del 0 ' RESET EX_ROUTINE FLAG EX_ROUTINE=0 End Proc Procedure PIC_VIEWER_SETUP Screen Open 5,320,256,2,Lowres : Flash Off : Curs Off : Cls 0 : Hide On Double Buffer : Autoback 0 Palette $0,$FFF End Proc Procedure PIC_VIEWER ' quit this proc if note off message is recived(ie finger is lifting off the key) If VEL=0 Then Pop Proc ' Change pitch (a value between about 1 and 70) to pressed ' (a value between 1 and 12) PRESSED=PITCH ' Decrese pitch to a value between 1 and 12 (to select one of the 12 pics) While PRESSED>12 Add PRESSED,-12 Wend ' load picture into the background (as long as it is a different one) If PRESSED<>OLDPIC Load Iff "ram:pics/"+Str$(PRESSED)-" " OLDPIC=PRESSED Palette Rnd(4096),Rnd(4096) ' R*256+G*16+B)4 ' when picture has finished loading flip the logical & physical screens ' to show the new picture that has loaded into the background Screen Swap End If End Proc Procedure PIC_VIEWER_APPEAR ' hide old screen S=Screen Screen Hide S ' show screen for this routine Screen Show 5 Screen To Front 5 Screen 5 ' don't need to process clock pulses. FILTER=True End Proc Procedure CIRC S=Screen Screen Hide S Curs Off : Degree : Hide On Screen Open 0,320,180,2,Lowres : Hide On : Curs Off : Cls 0 Screen Display 0,128,70,, : Palette 0,0 Unpack 6 To 6 Screen To Front 0 : Screen Hide 6 Screen Open 7,400,32,2,Lowres : Screen Hide 7 : Screen 0 Double Buffer : Bob Update Off : Autoback 0 : Curs Off For F=1 To 360 : CX(F)=(Sin(F)*100)+128 : Next F Y1=90 : Y2=90 : CH=0 : SCAR=7 : Def Scroll 1,0,0 To 390,32,-2,0 T$=" ALEXS MIDI MAGIX *" Sprite Update Off Do Add X1,1,1 To 360 Add X2,2,1 To 359 Add Y1,3,1 To 358 Add Y2,1,1 To 360 XP1=CX(X1)+32 YP1=CX(Y1) XP2=CX(X2)+32 YP2=CX(Y2) Screen 7 Scroll 1 Add SCAR,1,0 To 15 : If SCAR=0 Then Gosub PCHAR Screen Copy 6,XP1,YP1,XP1+319,YP1+180 To 0,0,0 Screen Copy 6,XP2,YP2,XP2+319,YP2+180 To 0,0,0,%1100000 Screen Copy 7,0,0,320,31 To 0,0,80,%1100000 Screen 0 Add T,1,0 To 89 : If T=0 Then Gosub CCOL : Rem change col Screen Swap : Wait Vbl ' If ascii value of the text$ gives 42 ("*") then quit If B=42 Then Goto CIRCLOSE Loop CCOL: Add CT,1,0 To 5 If CT=0 Then Fade 3,$F00,$F0F If CT=1 Then Fade 3,$0,$F If CT=2 Then Fade 3,$FF0,$F0 If CT=3 Then Fade 3,$FF0,$0 If CT=4 Then Fade 3,$F0F,$FF If CT=5 Then Fade 3,$F,$FF Return PCHAR: Add CH,1,1 To Len(T$) B=Asc(Mid$(T$,CH,1)) Paste Bob 354,0,B+3 Return CIRCLOSE: Screen 0 : Wait 45 : Fade 3 : Wait 45 : Screen Close 0 Screen Close 6 : Screen Close 7 If S<>0 Then Screen Show S X=HORIS_SLIDERX(1) : Proc ROUTINE_SWAP End Proc Procedure PIANO_PLAYER_SETUP End Proc Procedure PIANO_PLAYER_APPEAR ' hide old screen S=Screen Screen Hide S 'make this screen and unpack the compressed screen in memory bank 3 into it Screen Open 6,640,44,16,Hires Hide On : Curs Off Unpack 3 To 6 ' Set the sprites' colours all to red (colour indexes 17 to 31) For LOUP=17 To 31 Colour LOUP,$F00 Next LOUP ' don't need to process clock pulses. FILTER=TURE 'set ex_routine flag so this routine will be "disapeared" properly EX_ROUTINE=3 End Proc Procedure PIANO_PLAYER_DISAPPEAR For LOUP=0 To 7 Sprite Off LOUP Next LOUP EX_ROUTINE=0 End Proc Procedure PIANO_PLAYER ' if Note off the make the sprite dissapear and leave procedure If VEL=0 Sprite Off SPRYT(PITCH) Pop Proc End If ' Work out x,y co-ordinates for the new sprite taking into account ' the way a real keyboard is laid out with black notes halfway between ' some of the white notes. ' Change pitch (a value between about 1 and 70) to pressed ' (a value between 1 and 12) PRESSED=PITCH+1 ' Decrese pressed to a value between 1 and 12 (to select one of the 12 keys) ' but work out the octave the note was played in too While PRESSED>12 Add PRESSED,-12 Add OCTAVE,1 Wend Add OCTAVE,-2 ' Use the ebony_n_ivory array (set up in initailisation proc) to check ' if the PRESSED key is a "#" sharp ie black key and take that into ' account when working out x,y co-ords If EBONY_N_IVORY$(PRESSED)="#" XKEY=(OCTAVE*91)+EBONY_N_IVORY(PRESSED)+50 YKEY=223 Else XKEY=(OCTAVE*91)+EBONY_N_IVORY(PRESSED)+50 YKEY=238 End If 'Increment the Sprite_number counter so that different sprite is used ' each time. Add SPRY_NUMBER,1,0 To 7 ' Put sprite onto screen Sprite SPRY_NUMBER,X Hard(XKEY),Y Hard(YKEY),4 ' Put into sprite array at position according to pitch of the note ' the sprite number used so that when the pitch?? vel0 message is recived ' when the player lifts their finger off the procedure can work out from the ' pitch of the message which sprite to make dissapear. SPRYT(PITCH)=SPRY_NUMBER End Proc Procedure VERTICAL_BARS_APPEAR ' hide old screen S=Screen Screen Hide S ' don't need to process clock pulses. FILTER=TURE WIDTH=352 HEIGHT=16*3 X=X Hard(-5) Y=Y Hard(0) ' Create 5 screens and load in the stripes to each of them ' Use screens 0,4,5,6 and 7 which can be cleared (others in ' use from other routines eg. screen one reserved for cycle piano.) ' Use data statement (SCRDATA) to know which screens to use Restore SCRDATAS For LOUP=0 To 4 Read SCRDATA(LOUP) Screen Open SCRDATA(LOUP),WIDTH,HEIGHT,16,Lowres Flash Off : Curs Off Load Iff "ram:pics/stripes2",SCRDATA(LOUP) Next LOUP 'place the screens one below the other For LOUP=0 To 4 Screen Display SCRDATA(LOUP),X,Y+(LOUP*HEIGHT),WIDTH,HEIGHT Next LOUP ' reset all the screens' 16 colours to black ($0) For LOUP=0 To 4 Screen SCRDATA(LOUP) For L=0 To 16 Colour L,$0 Next L Next LOUP ' read in the channel values Restore CHANEL_COLOURS_DATA For LOUP=0 To 15 Read CHANEL_COLOURS(LOUP) Next LOUP SCRDATAS: Data 0,4,5,6,7 CHANEL_COLOURS_DATA: Data $4,$F00,$F60,$FC0,$CF0,$6F0,$F0,$F5,$FA,$FF,$AF,$5F,$F,$CCC,$444,$777 ' set ex_routine flag so that this routine will dissapear properly and ' release the screens back EX_ROUTINE=-1 End Proc Procedure VERTICAL_BARS_DISAPPEAR ' close the 5 screens that were used ' so they are free to be used again by the other procedures For LOUP=0 To 4 Screen Close SCRDATA(LOUP) Next LOUP 'reset ex_routine flag EX_ROUTINE=0 End Proc Procedure VERTICAL_BARS ' work out variables for screen and bar number BRR=109-PITCH '-24 BRR2=BRR Add BRR2,-1 BRR2=BRR2/16 SCR=Int(BRR2) If SCR>5 Then Pop Proc : Rem note is out of range ' bar is between 0 and 16 While BRR>16 Add BRR,-16 Wend Add BRR,-1 'Screen 0 'Ink 1 'Colour 1,$FFF 'Locate 1,1 : Print "Pitch=";PITCH;" Bar=";BRR;" scr=";SCR;" " ' select screen and change the bar to red if note on or black if note off Screen SCRDATA(SCR) If NOE=0 Then Colour BRR,$0 If NOE=1 Then Colour BRR,CHANEL_COLOURS(CHANEL) End Proc Procedure SLIDERS_APPEAR ' hide old screen S=Screen Screen Hide S Screen Open 0,360,256,4,Lowres Cls 0 : Curs Off : Flash Off Load Iff "ram:Pics/sliders_screen",0 Rem draw the sliders Reserve Zone 16 Set Slider ,,11,,,,, LISTEN_TO=1 For LOUP=1 To 8 : Rem 8 routines Hslider 30,30*(LOUP) To 150,(30*LOUP)+10,116,HORIS_SLIDERX(LOUP),2 Set Zone LOUP,30,30*(LOUP) To 150,(30*LOUP)+10 Next LOUP Rem set up text windows for channel data For LOUP=1 To 8 Wind Open LOUP,170,30*(LOUP),4,1 Curs Off Paper 0 Scroll Off Next LOUP Window 1 : Paper 0 : Clw For LOUP=1 To 8 Window LOUP Print HORIS_SLIDERX(LOUP) Next LOUP Rem *** set up LISTEN box and surround it with a mouse zone Wind Open 9,255,230,11,3,2 Set Zone 9,255,230 To 334,253 Curs Off Paper 4 Scroll Off Clw Print "" : Print "Listen"; End Proc Procedure CHECK_HORIS_SLIDER[MZ] Rem *** check horizontal slider and change pattern if left key is pressed If Mouse Zone=MZ and Mouse Key=1 LOUP=MZ Limit Mouse X Hard(30),Y Hard(30*(MZ)) To X Hard(145),Y Hard((30*MZ)+10) Hslider 30,30*(LOUP) To 150,(30*LOUP)+10,116,1,2 HORIS_SLIDERX(MZ)=X Screen(X Mouse)-30 SLIDE[HORIS_SLIDERX(MZ),MZ] Else Limit Mouse End If End Proc Procedure CHECK_LISTENING_BOX If Mouse Zone=9 and Mouse Key=1 ' keep the mouse in the listen box Limit Mouse X Hard(255),Y Hard(230) To X Hard(334),Y Hard(253) Window 9 Clw Print "" : Print "Listenin"; Wait Vbl : Wait Vbl ' empty out the serial buffer of any left over midi data While TRASH<>-1 TRASH=Serial Get(1) Wend ' listen for intrument change messages an alter the horisontal sliders ' until the mouse button is pressed again While Mouse Key<>1 Repeat Proc FETCH_DATA[X] Exit If Mouse Key=1 Until X<>$FE and X<>$F8 ' check to see if the MIDI data is a system message and a channel message If(X and $80) and X<$F0 'check to see if the channel message is a program change message (64) If(X and $70)=64 ' if PROGRAM CHANGE message occurs (64) then read the next byte of data which 'contains the instrument number Proc FETCH_DATA[X] HORIS_SLIDERX(LISTEN_TO)=X Proc SLIDE[X,LISTEN_TO] End If End If Wend Limit Mouse Window 9 : Clw Print "" : Print "Listen"; Wait Vbl : Wait Vbl End If End Proc Procedure SLIDER_PREFS Show Proc SLIDERS_APPEAR Do For LOUP=1 To 8 Proc CHECK_HORIS_SLIDER[LOUP] Next LOUP Proc CHECK_LISTENING_BOX Rem *** quit if right mouse key is pressed Exit If Mouse Key=2 Loop Hide Screen Close 0 End Proc Procedure SLIDE[HORIS_SLIDERX,MZ] If LISTEN_TO<>MZ Set Slider ,,11,,,,, Hslider 30,30*(LISTEN_TO) To 150,(30*LISTEN_TO)+10,116,HORIS_SLIDERX(LISTEN_TO),2 End If Set Slider ,,2,,,,, Hslider 30,30*(MZ) To 150,(30*MZ)+10,116,HORIS_SLIDERX(MZ),2 Window MZ Ink 0 : Print HORIS_SLIDERX;" " LISTEN_TO=MZ Wait Vbl End Proc Procedure _NOTES_TO_READ ' ' ' WIPE GRAPH SCREEN AFTER DOING A VOICE 99. THIS IS DONE IN PICK_OUTPUT ' ROUTINE BUT DOESN'T RESET X COORDS. ' ' IF A NOTE OFF MESSAGE IS SENT BY SEQUENCER THEN THE PROGRAM MAY 'NOT WORK BECAUSE PROGRAMED TO RECOGNISE NOTE_ON_VEL=0 AS NOTE OFF ' End Proc