home *** CD-ROM | disk | FTP | other *** search
- '-------------------------------------------------------------------
- '
- ' Q U I C K B A S I C
- '
- ' ███ ███ █████ ████ █████
- ' █ █ █ █ █ █ █ █
- ' █ █ █ █ █ █ █
- ' █ █ █ █████ ████ █████
- '
- ' QBMIDI(TM) Library Sample Programs
- '
- ' Q B M - D E M 2 . B A S
- '
- ' M U S I C G E N E R A T O R
- '
- ' S H A R E W A R E V E R S I O N 1 . 0
- '
- ' Developed by:
- ' AskUs! Technology Specialists
- ' PO Box 737
- ' Bountiful, UT 84011-0737
- '
- '-------------------------------------------------------------------
-
- DECLARE SUB GetKeypress (AsciiValueOfKey%, WaitUntilKeyIsPressed%)
- DECLARE SUB DispTextLeftJust (Row%, Col%, Text$, Attribute%)
- DECLARE SUB DispTextCenter (Row%, Text$, Attribute%)
- DECLARE SUB DispNumbLeftJust (Row%, Col%, Number%, Attribute%)
-
-
- DEFINT A-Z 'Set all variables to integer unless specified
-
- CONST False = 0, True = NOT False 'Set true and false constants (usable in all subs)
- CONST Bright = 15, Normal = 7 'Set colors to use (also usable in all subs)
- CONST EscapeKey = 27, SpaceBar = 32 'Set values to check for when keys are pressed
- CONST UpArrow = -72, DownArrow = -80
- CONST LeftArrow = -75, RightArrow = -77
- CONST HomeKey = -71, EndKey = -79
- CONST PageUp = -73, PageDown = -81
- CONST JKey = 74, NKey = 78, PKey = 80
- CONST RKey = 82, TKey = 84, VKey = 86
- CONST SKey = 83, Minus = 45, Plus = 43
-
- DIM Note(1 TO 6), Text$(1 TO 7) 'Make small array for notes and functions that are displayed
-
- Text$(1) = " Jump Method " 'Set Functions to be displayed
- Text$(2) = " Random Pause "
- Text$(3) = " Patch Number "
- Text$(4) = " Tempo % "
- Text$(5) = " Step Per Jump "
- Text$(6) = " Notes/Chord "
- Text$(7) = " Velocity "
-
- '-------------------------------------------------------------------
- ' See if a midi unit is installed in system
- '-------------------------------------------------------------------
-
- CALL SeeIfMPUExists(Found) 'See if unit exists in system
- IF Found = False THEN 'If MPU controller not found then error message and exit
- PRINT "Midi Controller not found or not responding."
- END
- END IF
- CALL ResetMpu 'Reset just in case some other program left if modified
- CALL SetDataInStopMode 'Minimize intelligence provided by MPU 401 or equivalent
- CALL OmniModeOn 'Set all midi data going to all midi channels
- CALL SetToPolyMode 'Set multivoice on
-
- '-------------------------------------------------------------------
- ' Display titles and a border
- '-------------------------------------------------------------------
-
- GOSUB DisplayBorderAndTitles 'Call local SUB to clear screen and display border and initial screen of text
-
-
- '-------------------------------------------------------------------
- ' Set defaults - at initial runtime for starting point
- '-------------------------------------------------------------------
-
- JumpMethod = False 'Random Method (True) or Drunk (False)
- RandomPause = False 'Insert Random pauses enabled on True
- PatchNumber = 64 'Sounds like a good number to start with
- Tempo = 50 'Set tempo to 100, moderate- May need to be changed when compiled
- JumpStep = 5 'Jump by fives when in drunken mode
- NotesPerChord = 2 'Play one note at a time to start
- Velocity = 64 'Moderate strike velocity
-
- GOSUB RedisplaySettings 'Show them on screen for the first time
- Selected = 1 'Which item is selected for editing
- GOSUB UpdateSelectedItem 'Show selected item
-
-
- '-------------------------------------------------------------------
- ' Check to see if they wish to continue
- '-------------------------------------------------------------------
-
- Text$ = "Press any key to begin or Esc to exit"
- Row = 22
- CALL DispTextCenter(Row, Text$, Normal) 'Call local sub to display centered text
-
- WaitUntilKeyIsPressed = True
- CALL GetKeypress(Keypress, WaitUntilKeyIsPressed) 'Keypress contains ASCII value of key, -ASCII if extended key
- IF Keypress = 27 THEN CLS : END 'Exit program if escape key was kit
-
-
- '-------------------------------------------------------------------
- ' Change message at bottom
- '-------------------------------------------------------------------
-
- Text$ = " Press Space to Pause, Esc to stop "
- CALL DispTextCenter(22, Text$, Normal)
-
-
- '-------------------------------------------------------------------
- ' Change patch to default patch before sending any notes
- '-------------------------------------------------------------------
-
- CALL ChangePatchTo(PatchNumber) 'Call QBMIDI function
-
-
- '-------------------------------------------------------------------
- ' Start loop to play notes based on Random numbers and constraints
- ' given. Allow user to change constraints while running (listening).
- '-------------------------------------------------------------------
-
- RANDOMIZE TIMER 'Setup random number generator seed using internal clock
-
- DO
-
- '-------------------------------------------------------------------
- ' If pause hasn't been turned on then go play new notes, otherwise skip and just look for keypresses
- '-------------------------------------------------------------------
-
- IF PauseOn = 0 THEN
-
- '-------------------------------------------------------------------
- 'Select New Starting Note based on Jump Method selected
- 'where Random is truly random and drunk simulates a drunk stagger
- 'moving from side to side based on Random number given
- '-------------------------------------------------------------------
-
- IF JumpMethod THEN 'Random method
- StartingNote = (RND * 60) + 36 'Select random Starting note between 36 and 96
-
- ELSE 'Drunk method
- SeedNote = (RND * 99) + 1 'Get seed between 1 and 100
- IF SeedNote > 50 THEN 'If over fifty then jump up by Jump Step increment
- StartingNote = StartingNote + JumpStep 'Set Starting note up by Jump step
- IF StartingNote > 90 THEN StartingNote = 90 'If too high, then set at 80
- ELSE
- StartingNote = StartingNote - JumpStep 'Jump down by JumpStep increment
- IF StartingNote < 42 THEN StartingNote = 42 'If too low, set bottom at 42
- END IF
-
- END IF
-
- '-------------------------------------------------------------------
- ' Get ready to play next selected notes by truning off the ones
- ' currently playing - if any
- '-------------------------------------------------------------------
-
- i = 0 'Set counter to zero
- DO 'Start loop
- i = i + 1 'Increment counter
- IF Note(i) THEN 'If not was on, turn it off
- CALL PlayNote(Note(i), 0) 'Call PlayNote with velocity of zero
- ELSE 'Until Note(i)=0
- EXIT DO 'Exit sub
- END IF
- Note(i) = 0 'Clear the Note to 0
- LOOP UNTIL i = 6 'Loop until all six have been turned off
-
- '-------------------------------------------------------------------
- ' Set values for notes to play or leave at zero if not to play
- '-------------------------------------------------------------------
-
- Note(1) = StartingNote 'Set center point note
- IF NotesPerChord > 1 THEN Note(2) = StartingNote + 4 'If two notes are to be played, then calc second note
- IF NotesPerChord > 2 THEN Note(3) = StartingNote - 5 'If three then ... same
- IF NotesPerChord > 3 THEN Note(4) = StartingNote + 7 'And so on ..
- IF NotesPerChord > 4 THEN Note(5) = StartingNote + 12
- IF NotesPerChord > 5 THEN Note(6) = StartingNote - 12
-
- '-------------------------------------------------------------------
- ' Play the actual notes until you find a 0 then exit do loop
- '-------------------------------------------------------------------
-
- i = 0 'Set counter to zero
- DO 'Start loop
- i = i + 1 'Increment counter
- IF Note(i) THEN 'If a note value exists then play it
- CALL PlayNote(Note(i), Velocity) 'Call the play routine
- ELSE 'Until no more notes are found
- EXIT DO 'Exit loop early if less than 6 notes are to be played
- END IF
- LOOP UNTIL i = 6 'Exit if all six have been played
-
- ELSE 'If already paused
- IF RandomPause THEN 'If Ok to use random pause then
- PauseOn = PauseOn + 1 'If already paused increment counter
- IF PauseOn > LengthOfPause THEN 'If Time limit exceeded then
- PauseOn = 0 'Turn off pause flag
- GOSUB ClearPauseMessage 'Clear message off screen and continue
- LengthOfPause = 0 'Clear length of pause so we know to reset it later
- END IF
- END IF
- END IF
-
- '-------------------------------------------------------------------
- ' If Random Pauses allowed then calculate pause delay and time to next pause
- ' or increment counter while waiting for next pause
- '-------------------------------------------------------------------
-
- IF RandomPause THEN 'If random pause OK
- IF LengthOfPause = 0 THEN 'And length has not been set
- ChordsToPlayBeforePause = RND * 70 + 5 'Set number of chords to play before pausing
- LengthOfPause = RND * 75 'Set length of pause
- ChordsPlayed = 0 'Set chords played counter to zero (for when we need it)
- END IF
-
- IF PauseOn = 0 THEN 'If pause is not on then
- ChordsPlayed = ChordsPlayed + 1 'Increment chord counter
- IF ChordsPlayed > ChordsToPlayBeforePause THEN 'and check against number of chords to play before pause
- PauseOn = 1 'And if equal, set pause to on
- GOSUB DisplayPauseMessage 'Display pause message
- END IF
- END IF
- END IF
-
-
- '-------------------------------------------------------------------
- ' Wait for correct time with regards to tempo setting, checking KB for valid keypresses
- '-------------------------------------------------------------------
-
- Time = 0 'Clear time counter
- DO 'Start timing delay loop
- Time = Time + 1 'Increment time counter
- CALL GetKeypress(Keypress, False) 'See if key has been pressed
- IF Keypress THEN GOSUB HandleKeypress 'If so then gosub to check it
- IF Time > Tempo * 2 THEN EXIT DO 'Check if enough time has passed
-
- '-------------------------------------------------------------------
- ' While waiting - look at the midi port for data being sent back to us
- ' from the MPU and from devices attached .. ie keyboards, etc.
- '
- ' For this example, we'll look for patch changes and reflect them
- ' on screen.
- '
- ' The CALL ReceiveMidiData(Value) routine returns a -1 if no
- ' data is coming in from MIDI port, and the actual values if
- ' data is present. See the Midi 1.0 specification for a full
- ' list of commands returned from devices connected. Many devices
- ' send only the command change once until functions are changed.
- ' Meaning, if you change the patch from the keyboard, you'll get
- ' a 192 as the command then the number as the patch pressed. If you
- ' press another patch, it skips sending the 192 since you're already
- ' in that mode. Pressing a note on the keyboard sends a 144 then the
- ' note and then velocity. Each subsequent note will not be preceeded
- ' by a 144 unless another command occurred inbetween (for example
- ' a patch change).
- '
- ' Some opular commands returned are (See your MIDI spec for more):
- ' Value = 192 Patch Change, followed by patch number
- ' Value = 144 Note on/off, followed by Note and velocity
- ' Value = 176 Portamento On/off
- '
- 'Suggestion:
- ' Insert a print statement to view what's happening when you
- ' select functions or play from your Keyboard
- '-------------------------------------------------------------------
-
- CALL ReceiveMidiData(Value) 'Look at data coming in from Midi
- IF Value <> -1 THEN 'If -1, no data is present
- IF PatchChangeOn THEN 'If Previous data was patchchange then this data is patch number so make the change
- IF Value < 127 THEN 'If not a command then it's still a patch
- PatchNumber = Value 'Set patch to Value received
- GOSUB RedisplaySettings 'Show them on screen for the first time
- END IF
- END IF
- IF Value > 127 THEN 'If value >127 then command was received
- IF Value = 192 THEN 'If 192 then a patch change came in
- PatchChangeOn = True 'So set Patch change on so next value read will be read above
- ELSE 'Otherwise ignore
- PatchChangeOn = False
- END IF
- END IF
- END IF
-
- LOOP 'Loop until time passes
-
- LOOP 'Loop for next note
- END 'Should never get to this end
-
-
- ChangeKeyToRightArrow:
-
- '-------------------------------------------------------------------
- ' If item is already selected then control jumps here to change the key pressed to right arrow
- ' before entering handle Keypress routine. This lets you press the key letter and increment the value
- '-------------------------------------------------------------------
-
- Keypress = RightArrow
-
-
- HandleKeypress:
-
- '-------------------------------------------------------------------
- ' Handle Keypressed or ignore if not value
- '-------------------------------------------------------------------
-
- SELECT CASE Keypress
- CASE RightArrow, Plus
- SELECT CASE Selected
- CASE 1 'JumpMethod
- IF JumpMethod = False THEN JumpMethod = True ELSE JumpMethod = False
- CASE 2 'Random Pause
- IF RandomPause = True THEN RandomPause = False ELSE RandomPause = True
- CASE 3 'Patch Number
- PatchNumber = PatchNumber + 1
- IF PatchNumber > 127 THEN PatchNumber = 0
- CALL ChangePatchTo(PatchNumber)
- CASE 4 'Tempo
- Tempo = Tempo - 5
- IF Tempo < 20 THEN Tempo = 20
- CASE 5 'Jump per step
- JumpStep = JumpStep + 1
- IF JumpStep > 12 THEN JumpStep = 12
- CASE 6 'Notes/Chord
- NotesPerChord = NotesPerChord + 1
- IF NotesPerChord > 6 THEN NotesPerChord = 6
- CASE 7 'Velocity
- Velocity = Velocity + 2
- IF Velocity > 127 THEN Velocity = 127
- END SELECT
- GOSUB RedisplaySettings 'Show them on screen for the first time
-
- CASE LeftArrow, Minus
- SELECT CASE Selected
- CASE 1 'JumpMethod
- IF JumpMethod = False THEN JumpMethod = True ELSE JumpMethod = False
- CASE 2 'Random Pause
- IF RandomPause = True THEN RandomPause = False ELSE RandomPause = True
- CASE 3 'Patch Number
- PatchNumber = PatchNumber - 1
- IF PatchNumber < 0 THEN PatchNumber = 127
- CALL ChangePatchTo(PatchNumber)
- CASE 4 'Tempo
- Tempo = Tempo + 5
- IF Tempo > 500 THEN Tempo = 500
- CASE 5 'Jump per step
- JumpStep = JumpStep - 1
- IF JumpStep < 1 THEN JumpStep = 1
- CASE 6 'Notes/Chord
- NotesPerChord = NotesPerChord - 1
- IF NotesPerChord < 1 THEN NotesPerChord = 1
- CASE 7 'Velocity
- Velocity = Velocity - 2
- IF Velocity < 1 THEN Velocity = 1
- END SELECT
- GOSUB RedisplaySettings 'Show them on screen for the first time
-
- CASE SpaceBar
- IF PauseOn THEN
- PauseOn = 0
- GOSUB ClearPauseMessage 'Clear the message on screen
- ELSE
- PauseOn = 1
- GOSUB DisplayPauseMessage 'Display message
- END IF
- RETURN
-
- CASE EscapeKey 'Check for keypress
- GOTO EndNow
- CASE JKey
- IF Selected = 1 THEN GOTO ChangeKeyToRightArrow 'If already selected then change keypress to right arrow allowing them to increment value
- Selected = 1 'Otherwise set selected item at 1
- CASE RKey
- IF Selected = 2 THEN GOTO ChangeKeyToRightArrow 'Ditto
- Selected = 2
- CASE PKey
- IF Selected = 3 THEN GOTO ChangeKeyToRightArrow
- Selected = 3
- CASE TKey
- IF Selected = 4 THEN GOTO ChangeKeyToRightArrow
- Selected = 4
- CASE SKey
- IF Selected = 5 THEN GOTO ChangeKeyToRightArrow
- Selected = 5
- CASE NKey
- IF Selected = 6 THEN GOTO ChangeKeyToRightArrow
- Selected = 6
- CASE VKey
- IF Selected = 7 THEN GOTO ChangeKeyToRightArrow
- Selected = 7
- CASE UpArrow
- Selected = Selected - 1: IF Selected = 0 THEN Selected = 7
- CASE DownArrow
- Selected = Selected + 1: IF Selected = 8 THEN Selected = 1
- CASE PageUp, HomeKey
- Selected = 1
- CASE PageDown, EndKey
- Selected = 7
- END SELECT
- GOSUB UpdateSelectedItem 'Redraw items and highlight selected item
- RETURN
-
-
- RedisplaySettings:
-
- '-------------------------------------------------------------------
- ' Update settings on screen
- '-------------------------------------------------------------------
-
- 'Note: Col and Offset were already set in Borders routine
-
- IF JumpMethod THEN Text$ = "Random" ELSE Text$ = "Drunk "
- CALL DispTextLeftJust(14, Col + Offset, Text$, Bright)
-
- IF RandomPause THEN Text$ = "On " ELSE Text$ = "Off"
- CALL DispTextLeftJust(15, Col + Offset, Text$, Bright)
-
- CALL DispNumbLeftJust(16, Col + Offset, PatchNumber, Bright)
- T1 = (Tempo - 50) * 100 'Calc Tempo in Percent
- T1 = T1 / 450
- T1 = 100 - T1
- CALL DispNumbLeftJust(17, Col + Offset, T1, Bright)
- CALL DispNumbLeftJust(18, Col + Offset, JumpStep, Bright)
- CALL DispNumbLeftJust(19, Col + Offset, NotesPerChord, Bright)
- CALL DispNumbLeftJust(20, Col + Offset, Velocity, Bright)
-
- RETURN
-
-
-
- ClearPauseMessage:
-
- '-------------------------------------------------------------------
- ' Display Paused messages
- '-------------------------------------------------------------------
-
- CALL DispTextLeftJust(15, Col + Offset + 12, " ", Normal)
- Pause = 0
- LengthOfPause = 0
- Text$ = " Press Space to Pause, Esc to stop "
- CALL DispTextCenter(22, Text$, Normal)
- RETURN
-
- DisplayPauseMessage:
-
- '-------------------------------------------------------------------
- ' Clear Paused messages and redisplay what to do at bottom
- '-------------------------------------------------------------------
-
- COLOR 0, Normal 'Set to Reverse momentairly
- CALL DispTextLeftJust(15, Col + Offset + 12, " Paused ", 0) 'Display as black
- COLOR Normal, 0 'Restore to normal
- Text$ = " Press Space to Continue, Esc to stop "
- CALL DispTextCenter(22, Text$, Normal)
- RETURN
-
-
- DisplayBorderAndTitles:
-
- '-------------------------------------------------------------------
- ' Borders and titles are used just once, so we've put them down
- ' here and Gosub once to get things started. This could have been
- ' placed in a SUB function and called instead, but we like to only
- ' put routines called often in Subs.
- '-------------------------------------------------------------------
-
- SCREEN 0 'Set text screen
- CLS 0 'Clear screen to black
-
- Row = 1 'Which Row
- Col = 1 'Which Column
- Text$ = "╔" + STRING$(77, 205) + "╗" 'Text to be displayed
- CALL DispTextLeftJust(Row, Col, Text$, Normal) 'Call local SUB that displays text left justified
-
- Text$ = "║"
- FOR Row = 2 TO 24
- CALL DispTextLeftJust(Row, 1, Text$, Normal)
- CALL DispTextLeftJust(Row, 79, Text$, Normal)
- NEXT Row
-
- Row = 24
- Text$ = "╚" + STRING$(77, 205) + "╝"
- CALL DispTextLeftJust(Row, Col, Text$, Normal)
-
- Row = 1
- Text$ = " QBMIDI(TM) DEMO - MUSIC GENERATOR "
- Attribute = Bright
- CALL DispTextCenter(Row, Text$, Attribute)
-
- Text$ = " (C) 1990 AskUs! Technology Specialists, Box 737, Bountiful, UT 84011 " 'Bottom title
- CALL DispTextCenter(25, Text$, Normal)
-
- Text$ = "This demonstration program uses the QBMIDI library to provide access"
- CALL DispTextCenter(4, Text$, Normal)
-
- Text$ = "your MIDI instruments via an MPU401 or compatible controller. Change"
- CALL DispTextCenter(5, Text$, Normal)
-
- Text$ = "the parameters below to hear different sound combinations. "
- CALL DispTextCenter(6, Text$, Normal)
-
- Text$ = "Use the Cursor Up/Down keys or Key letter to select function"
- CALL DispTextCenter(8, Text$, Normal)
-
- Text$ = "Right/Left Cursor to change value, space to pause/re-start"
- CALL DispTextCenter(9, Text$, Normal)
-
- Col = 27
- Offset = 17
-
- Text$ = "Function"
- CALL DispTextLeftJust(12, Col, Text$, Normal)
-
- Text$ = "Setting"
- CALL DispTextLeftJust(12, Col + Offset, Text$, Normal)
-
- Text$ = "-----------"
- CALL DispTextLeftJust(13, Col, Text$, Normal)
-
- Text$ = "-------"
- CALL DispTextLeftJust(13, Col + Offset, Text$, Normal)
-
-
- UpdateSelectedItem:
-
- '-------------------------------------------------------------------
- ' Redray items and highlight the one that Selected =
- '-------------------------------------------------------------------
-
- Item = 0
- StartRow = 13
- DO
- Item = Item + 1
- IF Item = Selected THEN
- Attribute = 0
- COLOR 0, Normal
- CALL DispTextLeftJust(StartRow + Item, Col - 1, Text$(Item), 0)
- COLOR Normal, 0
- ELSE
- CALL DispTextLeftJust(StartRow + Item, Col - 1, Text$(Item), Normal)
- CALL DispTextLeftJust(StartRow + Item, Col - 1, LEFT$(Text$(Item), 2), Bright)
- END IF
- LOOP UNTIL Item = 7
- RETURN
-
-
- EndNow:
-
- '-------------------------------------------------------------------
- ' End the program, but shut off all notes before leaving
- '-------------------------------------------------------------------
-
- CALL AllNotesOff 'Don't exit without shutting off all notes (it shuts off immediately, unlike Velocity=0 that uses normal decay value of patch)
- CLS 'Clear screen just to keep things tidy
- END
-
- SUB DispNumbLeftJust (Row, Col, Number, Attribute) STATIC
-
- LOCATE Row, Col - 1
- COLOR Attribute
- PRINT Number; " ";
- COLOR Normal
-
-
-
- END SUB
-
- SUB DispTextCenter (Row, Text$, Attribute) STATIC
-
- LOCATE Row, 40 - LEN(Text$) / 2
- COLOR Attribute
- PRINT Text$;
- COLOR Normal
-
- END SUB
-
- SUB DispTextLeftJust (Row, Col, Text$, Attribute) STATIC
-
- LOCATE Row, Col
- COLOR Attribute
- PRINT Text$;
- COLOR Normal
-
- END SUB
-
- SUB GetKeypress (AsciiValueOfKey, WaitUntilKeyIsPressed)
-
- AsciiValueOfKey = 0 'Clear variable
- ExtendedKey = 0 'Turn off extended key flag (used to show that function key was pressed)
-
- IF WaitUntilKeyIsPressed THEN
-
- DO: LOOP UNTIL INKEY$ = "" 'Clear out keys that may be sitting in buffer
-
- DO 'Loop until a key is pressed
- Key$ = INKEY$
- LOOP WHILE Key$ = ""
-
- ELSE
-
- Key$ = INKEY$
- WaitUntilKeyIsPressed = 0
- IF LEN(Key$) = 0 THEN EXIT SUB
- END IF
-
- IF LEN(Key$) > 1 THEN 'Check for extended key (F1, Cursor, etc.) by checking for length variable >1
- Key$ = RIGHT$(Key$, 1) 'If extended then get right character in variable
- ExtendedKey = -1 'Set flag to show extended key was pressed
- END IF
-
- AsciiValueOfKey = (ASC(UCASE$(Key$))) 'Place ASCII value in variable to be returned
-
-
- IF ExtendedKey THEN 'If extended then convert to minus
- AsciiValueOfKey = -AsciiValueOfKey 'Convert to minus number to show extended key
- END IF
-
- END SUB
-
-