Define CONFIG1L = 0x00
Define CONFIG1H = 0x0c
Define CONFIG2L = 0x18
Define CONFIG2H = 0x1e
Define CONFIG3L = 0x00
Define CONFIG3H = 0x01
Define CONFIG4L = 0x80
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40
Define CLOCK_FREQUENCY = 20
AllDigital
declarations:
Define LCD_BITS = 4 'allowed values are 4 and 8 - the number of data interface lines
Define LCD_DREG = PORTA
Define LCD_DBIT = 0 '0 or 4 for 4-bit interface, ignored for 8-bit interface
Define LCD_RSREG = PORTA
Define LCD_RSBIT = 4
Define LCD_EREG = PORTA
Define LCD_EBIT = 5
Define LCD_RWREG = PORTA 'set to 0 if not used, 0 is default
Define LCD_RWBIT = 0 'set to 0 if not used, 0 is default
Define LCD_COMMANDUS = 2000 'delay after LCDCMDOUT, default value is 5000
Define LCD_DATAUS = 50 'delay after LCDOUT, default value is 100
Define LCD_INITMS = 2 'delay used by LCDINIT, default value is 100
'the last three Define directives set the values suitable for simulation; they should be omitted for a real device
Dim state As Byte
Dim mode As Byte
Dim output_buffer(8) As Byte 'we can display up to 64 leds
Dim scale_notes(8) As Byte 'we can store up to 64 notes
Dim scale_pattern(3) As Byte 'each 24 note (two octave) pattern repeats over 3 bytes
Dim req_pattern_type As Byte
Symbol rotary_pulse = PORTE.1
Symbol rotary_direction = PORTE.0
Symbol rotary_button = PORTE.2
Dim last_pulse As Bit
Dim curr_direction As Byte
Dim curr_button As Bit
Dim current_key As Byte
Dim notes_pattern As Long '(4 byte value, 3 bytes + 1st byte repeated)
Dim pattern_mask As Long
Dim chord_scale_type As Byte
Dim i As Byte
Dim j As Byte
Dim k As Byte
Dim h As Word
initialise:
state = 0
req_pattern_type = 0
notes_pattern = 0
current_key = 0 '(0=C, 1=C#, 2=D, 3=Eb, 4=E, 5=F, 6=F#, 7=G, 8=G#, 9=A, 10=Bb, 11=B)
last_pulse = rotary_pulse
Lcdinit
INTCON2.RBPU = 0 'enable pullups on PORTB
PORTE.7 = 1 'enable pullups on PORTD
ConfigPin PORTB = Input
ConfigPin PORTD = Input
ConfigPin PORTE = Input 'portE has external pull-ups on E0-E2
loop:
Select Case state
Case 0
Lcdcmdout LcdClear
Lcdout "Keyboard"
Lcdcmdout LcdLine2Home
Lcdout "Controller v1.0"
WaitMs 1500
mode = 0
state = 1
Case 1
Lcdcmdout LcdClear
Lcdout "Select mode:"
Lcdcmdout LcdLine2Home
Select Case mode
Case 0
Lcdout "Single chord "
Case 1
Lcdout "All chord notes "
Case 2
Lcdout "Full scale "
Case 3
Lcdout "Walking bassline"
Case 4
Lcdout "MIDI input mode "
EndSelect
state = 2
Case 2
'wait for the rotary dial
curr_direction = 0
curr_button = 0
Gosub read_rotary
If curr_direction = 1 Then
If mode > 0 Then mode = mode - 1 Else mode = 4
state = 1
Endif
If curr_direction = 2 Then
mode = mode + 1
If mode > 4 Then mode = 0
state = 1
Endif
If curr_button = 1 Then
state = 3
Endif
Case 3
Lcdcmdout LcdClear
If mode = 0 Then
Lcdout "Chord type:"
chord_scale_type = 0
state = 4
Endif
If mode = 1 Then
Lcdout "Chord type:"
chord_scale_type = 0
state = 4
Endif
If mode = 2 Then
Lcdout "Scale type:"
chord_scale_type = 100
state = 10
Endif
If mode = 3 Then
Lcdout "Walking bassline"
chord_scale_type = 120
state = 20
Endif
If mode = 4 Then
Lcdout "MIDI mode"
state = 200
Endif
Case 4
Lcdcmdout LcdLine2Home
Select Case chord_scale_type
Case 0
Lcdout "Major chord "
Case 1
Lcdout "Minor chord "
Case 2
Lcdout "Dominant 7th "
Case 3
Lcdout "Major 7th chord "
Case 4
Lcdout "Minor 7th chord "
EndSelect
state = 5
Case 5
'wait for the rotary dial
curr_direction = 0
curr_button = 0
Gosub read_rotary
If curr_direction = 1 Then
If chord_scale_type > 0 Then chord_scale_type = chord_scale_type - 1 Else chord_scale_type = 4
state = 4
Endif
If curr_direction = 2 Then
chord_scale_type = chord_scale_type + 1
If chord_scale_type > 4 Then chord_scale_type = 0
state = 4
Endif
If curr_button = 1 Then
Lcdcmdout LcdClear
Lcdout "Select chord:"
state = 6
Endif
Gosub read_from_keys
Case 6
Lcdcmdout LcdLine2Home
Gosub display_key
If chord_scale_type = 0 Then Lcdout "major "
If chord_scale_type = 1 Then Lcdout "minor "
If chord_scale_type = 1 Then Lcdout "dominant 7th "
If chord_scale_type = 3 Then Lcdout "major 7th "
If chord_scale_type = 4 Then Lcdout "minor 7th "
Gosub display_output
state = 7
Case 7
'wait for the rotary dial
curr_direction = 0
curr_button = 0
Gosub read_rotary
If curr_direction = 1 Then
If current_key > 0 Then current_key = current_key - 1 Else current_key = 11
state = 6
Endif
If curr_direction = 2 Then
current_key = current_key + 1
If current_key > 11 Then current_key = 0
state = 6
Endif
If curr_button = 1 Then
state = 1
Endif
Gosub read_from_keys
Case 10
Lcdcmdout LcdLine2Home
Select Case chord_scale_type
Case 100
Lcdout "Major scale "
Case 101
Lcdout "Minor scale "
Case 102
Lcdout "Penatonic scale "
Case 103
Lcdout "Blues scale "
EndSelect
state = 11
Case 11
'wait for the rotary dial
curr_direction = 0
curr_button = 0
Gosub read_rotary
If curr_direction = 1 Then
If chord_scale_type > 100 Then chord_scale_type = chord_scale_type - 1 Else chord_scale_type = 103
state = 10
Endif
If curr_direction = 2 Then
chord_scale_type = chord_scale_type + 1
If chord_scale_type > 103 Then chord_scale_type = 100
state = 10
Endif
If curr_button = 1 Then
Lcdcmdout LcdClear
Lcdout "Select scale:"
state = 12
Endif
Case 12
Lcdcmdout LcdLine2Home
Gosub display_key
If chord_scale_type = 100 Then Lcdout "major scale "
If chord_scale_type = 101 Then Lcdout "minor scale "
If chord_scale_type = 102 Then Lcdout "pentatonic "
If chord_scale_type = 103 Then Lcdout "blues scale "
Gosub display_output
state = 13
Case 13
'wait for the rotary dial
curr_direction = 0
curr_button = 0
Gosub read_rotary
If curr_direction = 1 Then
If current_key > 0 Then current_key = current_key - 1 Else current_key = 11
state = 12
Endif
If curr_direction = 2 Then
current_key = current_key + 1
If current_key > 11 Then current_key = 0
state = 12
Endif
If curr_button = 1 Then
state = 1
Endif
Case 20
Lcdcmdout LcdLine2Home
Lcdout "Walking bass: "
Gosub display_key
Gosub display_output
state = 21
Case 21
'wait for the rotary dial
curr_direction = 0
curr_button = 0
Gosub read_rotary
If curr_direction = 1 Then
If current_key > 0 Then current_key = current_key - 1 Else current_key = 11
state = 20
Endif
If curr_direction = 2 Then
current_key = current_key + 1
If current_key > 11 Then current_key = 0
state = 20
Endif
If curr_button = 1 Then
state = 1
Endif
Gosub read_from_keys
EndSelect
'now if the output buffers have changed since last time, update the shift register(s)
Goto loop
End
set_scale_pattern:
Select Case req_pattern_type
Case 0 'major chord (10001001 00001000 10010000)
scale_pattern(0) = 10001001b
scale_pattern(1) = 00001000b
scale_pattern(2) = 10010000b
Case 1 'minor chord (10010001 00001001 00010000)
scale_pattern(0) = 10010001b
scale_pattern(1) = 00001001b
scale_pattern(2) = 00010000b
Case 2 'dominant 7th chord (10001001 00101000 10010010)
scale_pattern(0) = 10001001b
scale_pattern(1) = 00101000b
scale_pattern(2) = 10010010b
Case 3 'major 7th chord (10001001 00011000 10010001)
scale_pattern(0) = 10001001b
scale_pattern(1) = 00011000b
scale_pattern(2) = 10010001b
Case 4 'minor 7th chord (10010001 00011001 00010001)
scale_pattern(0) = 10010001b
scale_pattern(1) = 00011001b
scale_pattern(2) = 00010001b
Case 5 'major scale (10101101 01011010 11010101)
scale_pattern(0) = 10101101b
scale_pattern(1) = 01011010b
scale_pattern(2) = 11010101b
Case 6 'minor scale (10110101 10101011 01011010)
scale_pattern(0) = 10110101b
scale_pattern(1) = 10101011b
scale_pattern(2) = 01011010b
Case 7 'minor pentatonic scale (10010101 00101001 01010010)
scale_pattern(0) = 10010101b
scale_pattern(1) = 00101001b
scale_pattern(2) = 01010010b
Case 8 'minor blues scale (10010111 00101001 01110010)
scale_pattern(0) = 10010111b
scale_pattern(1) = 00101001b
scale_pattern(2) = 01110010b
Case 10 'walking bass line (10001001 01101000 10010110)
scale_pattern(0) = 10001001b
scale_pattern(1) = 01101000b
scale_pattern(2) = 10010110b
EndSelect
Return
read_rotary:
If rotary_pulse = 0 And last_pulse <> 0 Then
'on any edge (rising or falling) check to see
'which way the rotary is being turned
If rotary_direction = 0 Then
curr_direction = 2
Else
curr_direction = 1
Endif
WaitMs 25
Endif
last_pulse = rotary_pulse
If rotary_button = 0 Then
'debounce:
WaitMs 10
If rotary_button = 0 Then
While rotary_button = 0
'wait for release
Wend
curr_button = 1
Endif
Endif
Return
display_key:
If current_key = 0 Then Lcdout "C "
If current_key = 1 Then Lcdout "C# "
If current_key = 2 Then Lcdout "D "
If current_key = 3 Then Lcdout "Eb "
If current_key = 4 Then Lcdout "E "
If current_key = 5 Then Lcdout "F "
If current_key = 6 Then Lcdout "F# "
If current_key = 7 Then Lcdout "G "
If current_key = 8 Then Lcdout "G# "
If current_key = 9 Then Lcdout "A "
If current_key = 10 Then Lcdout "Bb "
If current_key = 11 Then Lcdout "B "
Return
display_output:
'this is where we actually light up the LEDs
If chord_scale_type >= 0 And chord_scale_type <= 4 Then req_pattern_type = chord_scale_type
If chord_scale_type >= 100 And chord_scale_type <= 103 Then req_pattern_type = chord_scale_type - 95
If chord_scale_type = 120 Then req_pattern_type = 10
Gosub set_scale_pattern
'load the pattern into a 4-byte Long, repeating the first byte at the fourth (reading from right to left)
notes_pattern.4B = scale_pattern(0)
notes_pattern.3B = scale_pattern(1)
notes_pattern.HB = scale_pattern(2)
notes_pattern.LB = scale_pattern(0)
'now shift the pattern into the appropriate key
If current_key <= 8 Then
'bit-shift the entire pattern to the right
If current_key > 0 Then notes_pattern = ShiftRight(notes_pattern, current_key)
Else
'to raise by 9 or more steps, we need to "flatten" by shifting left
'so a raise of 9 steps is the same as a lowering by 3, raising 10 is the same as lowering by 2,
'raising by 11 is the same a lowering by one (raising by 12 is just an octave higher)
k = 12 - current_key
notes_pattern = ShiftLeft(notes_pattern, k)
'but now we could have blanks in the lowest (fourth) byte, but since this is always
'just a copy of the highest (first) byte, simply copy it over
k = notes_pattern.4B
notes_pattern.LB = k
Endif
'if we've shifted left, this following function won't do anything
'but if we've shifted right, we could potentially have some leading blanks/zeros,
'so we need to OR the fourth byte with the first, to fill in any missing notes
k = notes_pattern.4B
j = notes_pattern.LB
k = k Or j
notes_pattern.4B = k
'if we only want to display a single chord, we only want to display 11 intervals,
'starting at the root note of the key we're in (maybe do the same for walking bass line?)
If mode = 0 Or mode = 3 Then
pattern_mask = 0
pattern_mask.4B = 11111111b
pattern_mask.3B = 11110000b
If current_key > 0 Then pattern_mask = ShiftRight(pattern_mask, current_key)
notes_pattern = notes_pattern And pattern_mask
Endif
'now put the pattern out onto the LEDs
'(for now we'll write it out to the LCD)
Lcdcmdout LcdLine1Home
k = notes_pattern.4B
Gosub show_k_as_hex
Lcdout " "
k = notes_pattern.3B
Gosub show_k_as_hex
Lcdout " "
k = notes_pattern.HB
Gosub show_k_as_hex
Lcdout " "
Return
read_from_keys:
'here we do some multiplexing to see which keys (if any) have been pressed/released
'since the last scan. The keyboard hardware already has pushbutton type pads in groups
'of eight, so multiplexing seems the obvious way to go.
Return
show_k_as_hex:
j = k And 11110000b
j = ShiftRight(j, 4)
Gosub show_j_as_hex
j = k And 00001111b
Gosub show_j_as_hex
Return
show_j_as_hex:
If j < 10 Then Lcdout #j
If j = 10 Then Lcdout "A"
If j = 11 Then Lcdout "B"
If j = 12 Then Lcdout "C"
If j = 13 Then Lcdout "D"
If j = 14 Then Lcdout "E"
If j = 15 Then Lcdout "F"
Return
Define CONFIG1H = 0x0c
Define CONFIG2L = 0x18
Define CONFIG2H = 0x1e
Define CONFIG3L = 0x00
Define CONFIG3H = 0x01
Define CONFIG4L = 0x80
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40
Define CLOCK_FREQUENCY = 20
AllDigital
declarations:
Define LCD_BITS = 4 'allowed values are 4 and 8 - the number of data interface lines
Define LCD_DREG = PORTA
Define LCD_DBIT = 0 '0 or 4 for 4-bit interface, ignored for 8-bit interface
Define LCD_RSREG = PORTA
Define LCD_RSBIT = 4
Define LCD_EREG = PORTA
Define LCD_EBIT = 5
Define LCD_RWREG = PORTA 'set to 0 if not used, 0 is default
Define LCD_RWBIT = 0 'set to 0 if not used, 0 is default
Define LCD_COMMANDUS = 2000 'delay after LCDCMDOUT, default value is 5000
Define LCD_DATAUS = 50 'delay after LCDOUT, default value is 100
Define LCD_INITMS = 2 'delay used by LCDINIT, default value is 100
'the last three Define directives set the values suitable for simulation; they should be omitted for a real device
Dim state As Byte
Dim mode As Byte
Dim output_buffer(8) As Byte 'we can display up to 64 leds
Dim scale_notes(8) As Byte 'we can store up to 64 notes
Dim scale_pattern(3) As Byte 'each 24 note (two octave) pattern repeats over 3 bytes
Dim req_pattern_type As Byte
Symbol rotary_pulse = PORTE.1
Symbol rotary_direction = PORTE.0
Symbol rotary_button = PORTE.2
Dim last_pulse As Bit
Dim curr_direction As Byte
Dim curr_button As Bit
Dim current_key As Byte
Dim notes_pattern As Long '(4 byte value, 3 bytes + 1st byte repeated)
Dim pattern_mask As Long
Dim chord_scale_type As Byte
Dim i As Byte
Dim j As Byte
Dim k As Byte
Dim h As Word
initialise:
state = 0
req_pattern_type = 0
notes_pattern = 0
current_key = 0 '(0=C, 1=C#, 2=D, 3=Eb, 4=E, 5=F, 6=F#, 7=G, 8=G#, 9=A, 10=Bb, 11=B)
last_pulse = rotary_pulse
Lcdinit
INTCON2.RBPU = 0 'enable pullups on PORTB
PORTE.7 = 1 'enable pullups on PORTD
ConfigPin PORTB = Input
ConfigPin PORTD = Input
ConfigPin PORTE = Input 'portE has external pull-ups on E0-E2
loop:
Select Case state
Case 0
Lcdcmdout LcdClear
Lcdout "Keyboard"
Lcdcmdout LcdLine2Home
Lcdout "Controller v1.0"
WaitMs 1500
mode = 0
state = 1
Case 1
Lcdcmdout LcdClear
Lcdout "Select mode:"
Lcdcmdout LcdLine2Home
Select Case mode
Case 0
Lcdout "Single chord "
Case 1
Lcdout "All chord notes "
Case 2
Lcdout "Full scale "
Case 3
Lcdout "Walking bassline"
Case 4
Lcdout "MIDI input mode "
EndSelect
state = 2
Case 2
'wait for the rotary dial
curr_direction = 0
curr_button = 0
Gosub read_rotary
If curr_direction = 1 Then
If mode > 0 Then mode = mode - 1 Else mode = 4
state = 1
Endif
If curr_direction = 2 Then
mode = mode + 1
If mode > 4 Then mode = 0
state = 1
Endif
If curr_button = 1 Then
state = 3
Endif
Case 3
Lcdcmdout LcdClear
If mode = 0 Then
Lcdout "Chord type:"
chord_scale_type = 0
state = 4
Endif
If mode = 1 Then
Lcdout "Chord type:"
chord_scale_type = 0
state = 4
Endif
If mode = 2 Then
Lcdout "Scale type:"
chord_scale_type = 100
state = 10
Endif
If mode = 3 Then
Lcdout "Walking bassline"
chord_scale_type = 120
state = 20
Endif
If mode = 4 Then
Lcdout "MIDI mode"
state = 200
Endif
Case 4
Lcdcmdout LcdLine2Home
Select Case chord_scale_type
Case 0
Lcdout "Major chord "
Case 1
Lcdout "Minor chord "
Case 2
Lcdout "Dominant 7th "
Case 3
Lcdout "Major 7th chord "
Case 4
Lcdout "Minor 7th chord "
EndSelect
state = 5
Case 5
'wait for the rotary dial
curr_direction = 0
curr_button = 0
Gosub read_rotary
If curr_direction = 1 Then
If chord_scale_type > 0 Then chord_scale_type = chord_scale_type - 1 Else chord_scale_type = 4
state = 4
Endif
If curr_direction = 2 Then
chord_scale_type = chord_scale_type + 1
If chord_scale_type > 4 Then chord_scale_type = 0
state = 4
Endif
If curr_button = 1 Then
Lcdcmdout LcdClear
Lcdout "Select chord:"
state = 6
Endif
Gosub read_from_keys
Case 6
Lcdcmdout LcdLine2Home
Gosub display_key
If chord_scale_type = 0 Then Lcdout "major "
If chord_scale_type = 1 Then Lcdout "minor "
If chord_scale_type = 1 Then Lcdout "dominant 7th "
If chord_scale_type = 3 Then Lcdout "major 7th "
If chord_scale_type = 4 Then Lcdout "minor 7th "
Gosub display_output
state = 7
Case 7
'wait for the rotary dial
curr_direction = 0
curr_button = 0
Gosub read_rotary
If curr_direction = 1 Then
If current_key > 0 Then current_key = current_key - 1 Else current_key = 11
state = 6
Endif
If curr_direction = 2 Then
current_key = current_key + 1
If current_key > 11 Then current_key = 0
state = 6
Endif
If curr_button = 1 Then
state = 1
Endif
Gosub read_from_keys
Case 10
Lcdcmdout LcdLine2Home
Select Case chord_scale_type
Case 100
Lcdout "Major scale "
Case 101
Lcdout "Minor scale "
Case 102
Lcdout "Penatonic scale "
Case 103
Lcdout "Blues scale "
EndSelect
state = 11
Case 11
'wait for the rotary dial
curr_direction = 0
curr_button = 0
Gosub read_rotary
If curr_direction = 1 Then
If chord_scale_type > 100 Then chord_scale_type = chord_scale_type - 1 Else chord_scale_type = 103
state = 10
Endif
If curr_direction = 2 Then
chord_scale_type = chord_scale_type + 1
If chord_scale_type > 103 Then chord_scale_type = 100
state = 10
Endif
If curr_button = 1 Then
Lcdcmdout LcdClear
Lcdout "Select scale:"
state = 12
Endif
Case 12
Lcdcmdout LcdLine2Home
Gosub display_key
If chord_scale_type = 100 Then Lcdout "major scale "
If chord_scale_type = 101 Then Lcdout "minor scale "
If chord_scale_type = 102 Then Lcdout "pentatonic "
If chord_scale_type = 103 Then Lcdout "blues scale "
Gosub display_output
state = 13
Case 13
'wait for the rotary dial
curr_direction = 0
curr_button = 0
Gosub read_rotary
If curr_direction = 1 Then
If current_key > 0 Then current_key = current_key - 1 Else current_key = 11
state = 12
Endif
If curr_direction = 2 Then
current_key = current_key + 1
If current_key > 11 Then current_key = 0
state = 12
Endif
If curr_button = 1 Then
state = 1
Endif
Case 20
Lcdcmdout LcdLine2Home
Lcdout "Walking bass: "
Gosub display_key
Gosub display_output
state = 21
Case 21
'wait for the rotary dial
curr_direction = 0
curr_button = 0
Gosub read_rotary
If curr_direction = 1 Then
If current_key > 0 Then current_key = current_key - 1 Else current_key = 11
state = 20
Endif
If curr_direction = 2 Then
current_key = current_key + 1
If current_key > 11 Then current_key = 0
state = 20
Endif
If curr_button = 1 Then
state = 1
Endif
Gosub read_from_keys
EndSelect
'now if the output buffers have changed since last time, update the shift register(s)
Goto loop
End
set_scale_pattern:
Select Case req_pattern_type
Case 0 'major chord (10001001 00001000 10010000)
scale_pattern(0) = 10001001b
scale_pattern(1) = 00001000b
scale_pattern(2) = 10010000b
Case 1 'minor chord (10010001 00001001 00010000)
scale_pattern(0) = 10010001b
scale_pattern(1) = 00001001b
scale_pattern(2) = 00010000b
Case 2 'dominant 7th chord (10001001 00101000 10010010)
scale_pattern(0) = 10001001b
scale_pattern(1) = 00101000b
scale_pattern(2) = 10010010b
Case 3 'major 7th chord (10001001 00011000 10010001)
scale_pattern(0) = 10001001b
scale_pattern(1) = 00011000b
scale_pattern(2) = 10010001b
Case 4 'minor 7th chord (10010001 00011001 00010001)
scale_pattern(0) = 10010001b
scale_pattern(1) = 00011001b
scale_pattern(2) = 00010001b
Case 5 'major scale (10101101 01011010 11010101)
scale_pattern(0) = 10101101b
scale_pattern(1) = 01011010b
scale_pattern(2) = 11010101b
Case 6 'minor scale (10110101 10101011 01011010)
scale_pattern(0) = 10110101b
scale_pattern(1) = 10101011b
scale_pattern(2) = 01011010b
Case 7 'minor pentatonic scale (10010101 00101001 01010010)
scale_pattern(0) = 10010101b
scale_pattern(1) = 00101001b
scale_pattern(2) = 01010010b
Case 8 'minor blues scale (10010111 00101001 01110010)
scale_pattern(0) = 10010111b
scale_pattern(1) = 00101001b
scale_pattern(2) = 01110010b
Case 10 'walking bass line (10001001 01101000 10010110)
scale_pattern(0) = 10001001b
scale_pattern(1) = 01101000b
scale_pattern(2) = 10010110b
EndSelect
Return
read_rotary:
If rotary_pulse = 0 And last_pulse <> 0 Then
'on any edge (rising or falling) check to see
'which way the rotary is being turned
If rotary_direction = 0 Then
curr_direction = 2
Else
curr_direction = 1
Endif
WaitMs 25
Endif
last_pulse = rotary_pulse
If rotary_button = 0 Then
'debounce:
WaitMs 10
If rotary_button = 0 Then
While rotary_button = 0
'wait for release
Wend
curr_button = 1
Endif
Endif
Return
display_key:
If current_key = 0 Then Lcdout "C "
If current_key = 1 Then Lcdout "C# "
If current_key = 2 Then Lcdout "D "
If current_key = 3 Then Lcdout "Eb "
If current_key = 4 Then Lcdout "E "
If current_key = 5 Then Lcdout "F "
If current_key = 6 Then Lcdout "F# "
If current_key = 7 Then Lcdout "G "
If current_key = 8 Then Lcdout "G# "
If current_key = 9 Then Lcdout "A "
If current_key = 10 Then Lcdout "Bb "
If current_key = 11 Then Lcdout "B "
Return
display_output:
'this is where we actually light up the LEDs
If chord_scale_type >= 0 And chord_scale_type <= 4 Then req_pattern_type = chord_scale_type
If chord_scale_type >= 100 And chord_scale_type <= 103 Then req_pattern_type = chord_scale_type - 95
If chord_scale_type = 120 Then req_pattern_type = 10
Gosub set_scale_pattern
'load the pattern into a 4-byte Long, repeating the first byte at the fourth (reading from right to left)
notes_pattern.4B = scale_pattern(0)
notes_pattern.3B = scale_pattern(1)
notes_pattern.HB = scale_pattern(2)
notes_pattern.LB = scale_pattern(0)
'now shift the pattern into the appropriate key
If current_key <= 8 Then
'bit-shift the entire pattern to the right
If current_key > 0 Then notes_pattern = ShiftRight(notes_pattern, current_key)
Else
'to raise by 9 or more steps, we need to "flatten" by shifting left
'so a raise of 9 steps is the same as a lowering by 3, raising 10 is the same as lowering by 2,
'raising by 11 is the same a lowering by one (raising by 12 is just an octave higher)
k = 12 - current_key
notes_pattern = ShiftLeft(notes_pattern, k)
'but now we could have blanks in the lowest (fourth) byte, but since this is always
'just a copy of the highest (first) byte, simply copy it over
k = notes_pattern.4B
notes_pattern.LB = k
Endif
'if we've shifted left, this following function won't do anything
'but if we've shifted right, we could potentially have some leading blanks/zeros,
'so we need to OR the fourth byte with the first, to fill in any missing notes
k = notes_pattern.4B
j = notes_pattern.LB
k = k Or j
notes_pattern.4B = k
'if we only want to display a single chord, we only want to display 11 intervals,
'starting at the root note of the key we're in (maybe do the same for walking bass line?)
If mode = 0 Or mode = 3 Then
pattern_mask = 0
pattern_mask.4B = 11111111b
pattern_mask.3B = 11110000b
If current_key > 0 Then pattern_mask = ShiftRight(pattern_mask, current_key)
notes_pattern = notes_pattern And pattern_mask
Endif
'now put the pattern out onto the LEDs
'(for now we'll write it out to the LCD)
Lcdcmdout LcdLine1Home
k = notes_pattern.4B
Gosub show_k_as_hex
Lcdout " "
k = notes_pattern.3B
Gosub show_k_as_hex
Lcdout " "
k = notes_pattern.HB
Gosub show_k_as_hex
Lcdout " "
Return
read_from_keys:
'here we do some multiplexing to see which keys (if any) have been pressed/released
'since the last scan. The keyboard hardware already has pushbutton type pads in groups
'of eight, so multiplexing seems the obvious way to go.
Return
show_k_as_hex:
j = k And 11110000b
j = ShiftRight(j, 4)
Gosub show_j_as_hex
j = k And 00001111b
Gosub show_j_as_hex
Return
show_j_as_hex:
If j < 10 Then Lcdout #j
If j = 10 Then Lcdout "A"
If j = 11 Then Lcdout "B"
If j = 12 Then Lcdout "C"
If j = 13 Then Lcdout "D"
If j = 14 Then Lcdout "E"
If j = 15 Then Lcdout "F"
Return
While it's very much a work in progress, this should be enough to get you started with the basic chord and scale types (major/minor/pentatonic etc). Other scales and modes can easily be added in future, as they are required.
Once we've got the hardware wired up, we may even add in some way of reading which chord is being played on the lower deck, and have the appropriate notes for the corresponding scale appear on the upper deck. That's a way off yet, but this code is at least a start....
No comments:
Post a Comment