|
14 | 14 | from src.note import Note |
15 | 15 | from src.settings import DeviceSettings |
16 | 16 | from src.articulation import Articulation |
| 17 | +from src.gamepad import Gamepad |
17 | 18 |
|
18 | 19 | with open(os.devnull, "w") as devnull: |
19 | 20 | # suppress pygame messages |
@@ -122,12 +123,12 @@ def set_light(self, x, y, col): # col is [1,11], 0 resets |
122 | 123 | self.send_cc(0, 22, col) |
123 | 124 |
|
124 | 125 | if self.launchpad: |
125 | | - lp_col = COLOR_CODES[col] |
| 126 | + lp_col = COLOR_CODES[col] / 4 |
126 | 127 | if 0 <= x < 8 and 0 <= y < 8: |
127 | 128 | if not self.is_macro_button(x, y): |
128 | 129 | self.launchpad.LedCtrlXY(x, y+1, lp_col[0], lp_col[1], lp_col[2]) |
129 | 130 | else: |
130 | | - self.launchpad.LedCtrlXY(x, y+1, 127, 127, 127) |
| 131 | + self.launchpad.LedCtrlXY(x, y+1, 63, 63, 63) |
131 | 132 |
|
132 | 133 | def reset_light(self, x, y, reset_red=True): |
133 | 134 | note = self.get_note_index(x, y) |
@@ -176,16 +177,16 @@ def reset_launchpad_light(self, x, y): |
176 | 177 | def set_red_light(self, x, y, state=True): |
177 | 178 | self.red_lights[y][x] = state |
178 | 179 | if self.launchpad: |
179 | | - lp_col = ivec3(127, 0, 0) |
| 180 | + lp_col = ivec3(63, 0, 0) |
180 | 181 | if state: |
181 | 182 | self.launchpad.LedCtrlXY(x, y, lp_col[0], lp_col[1], lp_col[2]) |
182 | 183 |
|
183 | 184 | def set_launchpad_light(self, x, y, color): |
184 | | - col = COLOR_CODES[color] |
| 185 | + col = COLOR_CODES[color] / 4 |
185 | 186 | if not self.is_macro_button(x, 8 - y - 1): |
186 | 187 | self.launchpad.LedCtrlXY(x, 8-y, col[0], col[1], col[2]) |
187 | 188 | else: |
188 | | - self.launchpad.LedCtrlXY(x, 8-y, 127, 127, 127) |
| 189 | + self.launchpad.LedCtrlXY(x, 8-y, 63, 63, 63) |
189 | 190 |
|
190 | 191 | def setup_lights(self): |
191 | 192 | for y in range(self.board_h): |
@@ -397,6 +398,7 @@ def init_board(self): |
397 | 398 | self.notes[i] = Note() |
398 | 399 |
|
399 | 400 | self.chord_notes = [False] * 127 |
| 401 | + self.note_set = set() |
400 | 402 |
|
401 | 403 | def midi_write(self, dev, msg, ts=0): |
402 | 404 | if dev: |
@@ -514,6 +516,7 @@ def note_on(self, data, timestamp, width=None, curve=True, mpe=None): |
514 | 516 | note.split = split_chan |
515 | 517 |
|
516 | 518 | self.chord_notes[data[1]] = True |
| 519 | + self.note_set.add(data[1]) |
517 | 520 | self.dirty_chord = True |
518 | 521 |
|
519 | 522 | if self.is_split(): |
@@ -610,6 +613,7 @@ def note_off(self, data, timestamp, width=None, mpe=None): |
610 | 613 | data[1] += 7 |
611 | 614 |
|
612 | 615 | self.chord_notes[data[1]] = False |
| 616 | + self.note_set.remove(data[1]) |
613 | 617 | self.dirty_chord = True |
614 | 618 |
|
615 | 619 | if self.is_split(): |
@@ -806,16 +810,14 @@ def macro(self, x, y, val): |
806 | 810 |
|
807 | 811 | # uses button state events (mk3 pro) |
808 | 812 | def cb_launchpad_in(self, event, timestamp=0): |
809 | | - # if (self.launchpad_mode == "pro" or self.launchpad_mode == "promk3") and event[0] == 255: |
810 | | - # if event[0] >= 255: |
811 | | - # # I'm testing the mk3 method on an lpx, so I'll check this here |
812 | | - # vel = event[2] if self.launchpad_mode == 'lpx' else event[1] |
813 | | - # for note in self.notes: |
814 | | - # if note.location: |
815 | | - # print(note.midinote) |
816 | | - # self.note_on([160, note.midinote, vel], timestamp, width=8, mpe=True) |
817 | | - |
818 | | - if self.launchpad_mode == 'lpx' and event[0] >= 255: # pressure |
| 813 | + if (self.launchpad_mode == "pro" or self.launchpad_mode == "promk3") and event[0] >= 255: |
| 814 | + # if event[0] >= 255: # uncomment this for testing pro behavior on launchpad X |
| 815 | + # I'm testing the mk3 method on an lpx, so I'll check this here |
| 816 | + vel = event[2] if self.launchpad_mode == 'lpx' else event[1] |
| 817 | + for note in self.note_set: |
| 818 | + self.midi_write(self.midi_out, [160, note, vel], timestamp) |
| 819 | + self.articulation.pressure(vel / 127) |
| 820 | + elif self.launchpad_mode == 'lpx' and event[0] >= 255: # pressure |
819 | 821 | x = event[0] - 255 |
820 | 822 | y = 8 - (event[1] - 255) |
821 | 823 | vel = event[2] |
@@ -1053,6 +1055,8 @@ def __init__(self): |
1053 | 1055 | # ) or get_option( |
1054 | 1056 | # opts, "no_overlap", DEFAULT_OPTIONS.mpe |
1055 | 1057 | # ) |
| 1058 | + self.options.mpe = True |
| 1059 | + self.options.vibrato = get_option(opts, "vibrato", DEFAULT_OPTIONS.vibrato) |
1056 | 1060 | self.options.midi_out = get_option(opts, "midi_out", DEFAULT_OPTIONS.midi_out) |
1057 | 1061 | self.options.split_out = get_option( |
1058 | 1062 | opts, "split_out", DEFAULT_OPTIONS.split_out |
@@ -1358,6 +1362,13 @@ def __init__(self): |
1358 | 1362 | self.visualizer = None |
1359 | 1363 | self.launchpad = None |
1360 | 1364 | self.launchpad_mode = None |
| 1365 | + |
| 1366 | + self.gamepad = None |
| 1367 | + if self.options.experimental: |
| 1368 | + pygame.joystick.init() |
| 1369 | + if pygame.joystick.get_count() > 0: |
| 1370 | + self.gamepad = Gamepad(self, 0) |
| 1371 | + print('Gamepad initialized') |
1361 | 1372 |
|
1362 | 1373 | innames = rtmidi2.get_in_ports() |
1363 | 1374 | for i in range(len(innames)): |
@@ -1469,13 +1480,35 @@ def rpn(self, num, value): |
1469 | 1480 | self.midi_write(self.linn_out, [176, 38, value_lsb]) |
1470 | 1481 | self.midi_write(self.linn_out, [176, 101, 127]) |
1471 | 1482 | self.midi_write(self.linn_out, [176, 100, 127]) |
1472 | | - time.sleep(0.1) |
| 1483 | + time.sleep(0.05) |
1473 | 1484 |
|
1474 | 1485 | def mpe_rpn(self, on=True): |
1475 | 1486 | if on: |
1476 | 1487 | self.rpn(0, 1) |
1477 | 1488 | self.rpn(100, 1) |
1478 | 1489 | self.rpn(227, 0) |
| 1490 | + |
| 1491 | + if self.options.hardware_split: |
| 1492 | + # left side channels |
| 1493 | + self.rpn(1, 1) |
| 1494 | + self.rpn(2, 0) |
| 1495 | + for x in range(3, 10): |
| 1496 | + self.rpn(x, 1) |
| 1497 | + for x in range(10, 18): |
| 1498 | + self.rpn(x, 0) |
| 1499 | + |
| 1500 | + # right side channels |
| 1501 | + self.rpn(101, 16) # main=16 |
| 1502 | + for x in range(110, 117): |
| 1503 | + self.rpn(x, 1) |
| 1504 | + self.rpn(117, 0) # 16 off |
| 1505 | + else: |
| 1506 | + # left side only |
| 1507 | + self.rpn(1, 1) |
| 1508 | + self.rpn(2, 0) |
| 1509 | + for x in range(3, 18): |
| 1510 | + self.rpn(x, 1) |
| 1511 | + |
1479 | 1512 | else: |
1480 | 1513 | self.rpn(227, 5) |
1481 | 1514 |
|
@@ -1682,6 +1715,16 @@ def logic(self, dt): |
1682 | 1715 | except KeyError: |
1683 | 1716 | pass |
1684 | 1717 |
|
| 1718 | + else: |
| 1719 | + if self.gamepad and ev.type in (\ |
| 1720 | + pygame.JOYAXISMOTION, |
| 1721 | + pygame.JOYBALLMOTION, |
| 1722 | + pygame.JOYBUTTONDOWN, |
| 1723 | + pygame.JOYBUTTONUP, |
| 1724 | + pygame.JOYHATMOTION |
| 1725 | + ): |
| 1726 | + self.gamepad.event(ev) |
| 1727 | + |
1685 | 1728 | if not self.options.lite: |
1686 | 1729 | if ev.type == pygame.MOUSEMOTION: |
1687 | 1730 | x, y = ev.pos |
@@ -1777,6 +1820,9 @@ def logic(self, dt): |
1777 | 1820 | if self.launchpad: |
1778 | 1821 | self.articulation.logic(dt) |
1779 | 1822 |
|
| 1823 | + if self.gamepad: |
| 1824 | + self.gamepad.logic(dt) |
| 1825 | + |
1780 | 1826 | # figure out the lowest note to highlight it |
1781 | 1827 | # if self.options.show_lowest_note: |
1782 | 1828 | # old_lowest_note = self.lowest_note |
@@ -1992,6 +2038,31 @@ def render(self): |
1992 | 2038 | x += 1 |
1993 | 2039 | y += 1 |
1994 | 2040 |
|
| 2041 | + if self.gamepad: |
| 2042 | + pos = self.gamepad.positions() |
| 2043 | + # gp_pos.y = self.board_h - y - 1 |
| 2044 | + |
| 2045 | + circ = [None] * 2 |
| 2046 | + for i in range(2): |
| 2047 | + circ[i] = ivec2( |
| 2048 | + int(pos[i].x * sz + b / 2 + sz / 2), |
| 2049 | + int(self.menu_sz + pos[i].y * sz + b / 2 + sz / 2), |
| 2050 | + ) |
| 2051 | + |
| 2052 | + pygame.gfxdraw.aacircle( |
| 2053 | + self.screen.surface, |
| 2054 | + circ[i].x + 1, |
| 2055 | + circ[i].y - 1, |
| 2056 | + rad, |
| 2057 | + ivec3(0, 255, 0), |
| 2058 | + ) |
| 2059 | + # pygame.gfxdraw.filled_circle( |
| 2060 | + # self.screen.surface, |
| 2061 | + # circ[i].x + 1, |
| 2062 | + # circ[i].y - 1, |
| 2063 | + # rad, |
| 2064 | + # ivec3(0, 255, 0), |
| 2065 | + # ) |
1995 | 2066 |
|
1996 | 2067 | # if self.options.experimental: |
1997 | 2068 | text = self.font.render(self.scale_name, True, ivec3(127)) |
|
0 commit comments