Skip to content

Commit

Permalink
send raw MIDI messages via UI
Browse files Browse the repository at this point in the history
  • Loading branch information
YeonV committed Oct 10, 2024
1 parent 8196f53 commit e33beb7
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 18 deletions.
39 changes: 29 additions & 10 deletions src/components/Midi/LaunchpadButtonMap.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { ArrowForwardIos, BrightnessHigh, Collections, Pause, PlayArrow, ViewSidebar, Menu as MenuIcon, Save, Delete, DeleteForever, Visibility, Autorenew, Fullscreen, FullscreenExit, BugReport } from '@mui/icons-material'
import { Box, Button, Divider, ListItemIcon, ListItemText, Menu, MenuItem, Stack, Typography, useTheme } from '@mui/material'
import { ArrowForwardIos, BrightnessHigh, Collections, Pause, PlayArrow, ViewSidebar, Menu as MenuIcon, Save, Delete, DeleteForever, Visibility, Autorenew, Fullscreen, FullscreenExit, BugReport, Send } from '@mui/icons-material'
import { Box, Button, Divider, ListItemIcon, ListItemText, Menu, MenuItem, Select, SelectChangeEvent, Stack, TextField, TextFieldProps, Typography, useTheme } from '@mui/material'
import BladeIcon from '../Icons/BladeIcon/BladeIcon'
import useStore from '../../store/useStore'
import Assign from '../Gamepad/Assign'
import { useEffect, useRef, useState } from 'react'
import { WebMidi } from 'webmidi'
import LaunchpadButton from './LaunchpadButton'
import { getColorFromValue } from './lpColors'
import { defaultMapping, IMapping, LpMapping } from '../../store/ui/storeMidi'
import { defaultMapping, IMapping, Launchpad, LpMapping } from '../../store/ui/storeMidi'
import LaunchpadColors from './LaunchpadColors'
import { download } from '../../utils/helpers'

const LaunchpadButtonMap = ({toggleSidebar, sideBarOpen, fullScreen, setFullScreen}:{toggleSidebar: () => void, sideBarOpen: boolean, fullScreen?: boolean, setFullScreen: (f:boolean) => void}) => {
const theme = useTheme()
const parentRef = useRef<HTMLDivElement>(null);
const childRef = useRef<HTMLDivElement>(null);
const [midiMessageToSend, setMidiMessageToSend] = useState<string>('')
const [scale, setScale] = useState(1);
const [midiLogs, setMidiLogs] = useState<{
name: string;
Expand Down Expand Up @@ -365,13 +366,31 @@ const LaunchpadButtonMap = ({toggleSidebar, sideBarOpen, fullScreen, setFullScre
<Typography variant='caption' sx={{ cursor: 'pointer'}} onClick={() => setMidiLogs([])}>Clear Logs</Typography>
</Stack>
<Divider sx={{ mb: 0.5 }} />
<Box sx={{overflowY: 'auto', height: 120}}>
{midiLogs.map((log, index) => <Stack key={index} direction={'row'}>
<Typography width={200} variant='caption'>{log.name}</Typography>
<Typography width={50} variant='caption'>{log.note}</Typography>
<Typography width={50} variant='caption'>{log.button}</Typography>
</Stack>)}
</Box>
<Stack>
<Box sx={{overflowY: 'auto', height: 120}}>
{midiLogs.map((log, index) => <Stack key={index} direction={'row'}>
<Typography width={200} variant='caption'>{log.name}</Typography>
<Typography width={50} variant='caption'>{log.note}</Typography>
<Typography width={50} variant='caption'>{log.button}</Typography>
</Stack>)}
</Box>
<Stack direction={'row'}>
{Object.keys(Launchpad.X.command).length && <Select variant='outlined' size='small' sx={{ width: 200 }} onChange={(e: SelectChangeEvent) => {
setMidiMessageToSend(Launchpad.X.command[e.target.value as keyof typeof Launchpad.X.command].map((v: any) => `0x${v.toString(16)}`).join(', '))
}}>
{Object.entries(Launchpad.X.command).map(([key, value]) => <MenuItem key={key} value={key}>{key}</MenuItem>)}
</Select>}
<TextField label='Send raw MIDI message' variant='outlined' size='small' fullWidth value={midiMessageToSend} onChange={(e) => setMidiMessageToSend(e.target.value)} />
<Button onClick={()=>{
const output = midiOutput !== '' ? WebMidi.getOutputByName(midiOutput) : WebMidi.outputs[1]
if (!output) return
console.log(midiMessageToSend)
output.send(midiMessageToSend.replaceAll(', ',' ').split(' ').map((v: any) => parseInt(v)) || [])
}}>
<Send />
</Button>
</Stack>
</Stack>
</Box>}

</>)
Expand Down
32 changes: 24 additions & 8 deletions src/components/Midi/lpColors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,32 @@ export const sortColorsByHSL = (colors: IColor[]) => {
}

export const lpsColors = {
'#FF0000': 0x0F, // full red
'#FFA500': 0x2F, // full orange
'#00FF00': 0x3C, // full green
'#8B0000': 0x0D, // dim red
'#526F50': 0x1C, // dim green
'#FFFF00': 0x3E, // full yellow
'#000000': 0x0C, // off
'#FF7F00': 0x3F, // full amber
// 'red': 0x0F,
// 'orange': 0x2F,
// 'lime': 0x3C,
// 'darkred': 0x0D,
// 'darkolivegreen': 0x1C,
// 'yellow': 0x3E,
// 'black': 0x0C,
// 'darkorange': 0x3F,
'#FF0000': 0x0F,
'#FFA500': 0x2F,
'#00FF00': 0x3C,
'#8B0000': 0x0D,
'#526F50': 0x1C,
'#FFFF00': 0x3E,
'#000000': 0x0C,
'#FF7F00': 0x3F,
}
export const lpColors = {
// 'red': 0x05,
// 'orange': 0x09,
// 'lime': 0x15,
// 'darkred': 0x07,
// 'darkolivegreen': 0x17,
// 'yellow': 0x0d,
// 'black': 0x00,
// 'darkorange': 0x3c,
'#616161': 0x00,
'#b3b3b3': 0x01,
'#dddddd': 0x02,
Expand Down
49 changes: 49 additions & 0 deletions src/store/ui/storeMidi.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { produce } from 'immer'
import type { IStore } from '../useStore'
import { lpColors, lpsColors } from '../../components/Midi/lpColors'

export interface IMidiMapping {
command?: string
Expand Down Expand Up @@ -70,6 +71,54 @@ export const LpMapping = {
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
]
}
export const Launchpad = {
X: {
buttonNumbers: [
[11, 12, 13, 14, 15, 16, 17, 18, 19],
[21, 22, 23, 24, 25, 26, 27, 28, 29],
[31, 32, 33, 34, 35, 36, 37, 38, 39],
[41, 42, 43, 44, 45, 46, 47, 48, 49],
[51, 52, 53, 54, 55, 56, 57, 58, 59],
[61, 62, 63, 64, 65, 66, 67, 68, 69],
[71, 72, 73, 74, 75, 76, 77, 78, 79],
[81, 82, 83, 84, 85, 86, 87, 88, 89],
[91, 92, 93, 94, 95, 96, 97, 98, 99],
],
colors: lpColors,
command: {
'programmer': [0xF0, 0x00, 0x20, 0x29, 0x02, 0x0C, 0x0E, 0x01, 0xF7],
'live': [0xF0, 0x00, 0x20, 0x29, 0x02, 0x0C, 0x0E, 0x00, 0xF7],
'standalone': [0xF0, 0x00, 0x20, 0x29, 0x02, 0x0C, 0x10, 0x00, 0xF7],
'daw': [0xF0, 0x00, 0x20, 0x29, 0x02, 0x0C, 0x10, 0x01, 0xF7],
'ledOn': [0x90, "buttonNumber", "color"],
'ledFlash': [0x91, "buttonNumber", "color"],
'ledPulse': [0x92, "buttonNumber", "color"],
},
sendCommand: {
'ledOff': (buttonNumber: number) => [0x90, buttonNumber, 0x00],
'ledOn': (buttonNumber: number, color: keyof typeof lpColors | number ) => [0x90, buttonNumber, typeof color === 'number' ? color : lpColors[color]],
'ledFlash': (buttonNumber: number, color: keyof typeof lpColors | number ) => [0x91, buttonNumber, typeof color === 'number' ? color : lpColors[color]],
'ledPulse': (buttonNumber: number, color: keyof typeof lpColors | number ) => [0x92, buttonNumber, typeof color === 'number' ? color : lpColors[color]],
}
},
S: {
buttonNumbers: [
[112, 113, 114, 115, 116, 117, 118, 119, 120],
[96, 97, 98, 99, 100, 101, 102, 103, 104],
[80, 81, 82, 83, 84, 85, 86, 87, 88],
[64, 65, 66, 67, 68, 69, 70, 71, 72],
[48, 49, 50, 51, 52, 53, 54, 55, 56],
[32, 33, 34, 35, 36, 37, 38, 39, 40],
[16, 17, 18, 19, 20, 21, 22, 23, 24],
[0, 1, 2, 3, 4, 5, 6, 7, 8],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
],
colors: lpsColors,
sendCommand: {
'ledOff': (buttonNumber: number) => [0x90, buttonNumber, 0x0C],
}
}
}

export function getUiBtnNo(inputInt: number): number | null {
for (let i = 0; i < LpMapping.LaunchpadS.length; i++) {
Expand Down

0 comments on commit e33beb7

Please sign in to comment.