Skip to content

Commit

Permalink
Fix MIDI-Scenes. Add custom midi button mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
YeonV committed Oct 4, 2024
1 parent bb96dd5 commit 86a09a9
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 165 deletions.
43 changes: 5 additions & 38 deletions src/components/Dialogs/SceneDialogs/EditSceneDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import {
Autocomplete
} from '@mui/material'
import { Clear, Undo, NavigateBefore, MusicNote } from '@mui/icons-material'
import { WebMidi, Input, NoteMessageEvent } from 'webmidi'
import { useDropzone } from 'react-dropzone'
import isElectron from 'is-electron'
import { filterKeys, ordered } from '../../../utils/helpers'
Expand Down Expand Up @@ -76,7 +75,7 @@ const EditSceneDialog = () => {
const getUserPresets = useStore((state) => state.getUserPresets)
const getImage = useStore((state) => state.getImage)
const [imageData, setImageData] = useState(null)
const midiInput = useStore((state) => state.midiInput)
const midiEvent = useStore((state) => state.midiEvent)

const getFullConfig = useStore((state) => state.getFullConfig)

Expand Down Expand Up @@ -227,34 +226,12 @@ const EditSceneDialog = () => {
}, [open])

useEffect(() => {
if (features.scenemidi) {
const handleMidiEvent = (input: Input, event: NoteMessageEvent) => {
if (features.scenemidi && midiEvent.button > -1) {
setMIDIActivate(
`${input.name} Note: ${event.note.identifier} buttonNumber: ${event.note.number}`
`${midiEvent.name} Note: ${midiEvent.note} buttonNumber: ${midiEvent.button}`
)
}
WebMidi.enable({
callback(err: Error) {
if (err) {
console.error('WebMidi could not be enabled:', err)
} else {
const { inputs } = WebMidi
if (inputs.length > 0) {
inputs.forEach((input: Input) => {
if (midiInput === input.name) {
return input.addListener('noteon', (event: NoteMessageEvent) => {
handleMidiEvent(input, event)
})
}
}
)
}
}
}
})
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
}, [midiEvent])

const renderPresets = (
current_ledfx_presets: any,
Expand Down Expand Up @@ -665,7 +642,7 @@ const EditSceneDialog = () => {
) : (
<></>
)}
{features && features.scenemidi && WebMidi.inputs.length > 0 ? (
{features && features.scenemidi ? (
<>
<Stack direction={small ? 'column' : 'row'} gap={1}>
<FormControl sx={{ mt: 1, width: small ? '100%' : '130px' }}>
Expand Down Expand Up @@ -771,15 +748,6 @@ const EditSceneDialog = () => {
</Avatar>
}
/>
{/* <Chip
label={/\((.*?)\)/.exec(midiActivate)?.[1]}
onDelete={() => setMIDIActivate('')}
avatar={
<Avatar>
{/\((.*?)\)/.exec(midiActivate)?.[1]}
</Avatar>
}
/> */}
<Chip
label={
midiActivate
Expand All @@ -793,7 +761,6 @@ const EditSceneDialog = () => {
}
/>
<Chip
// onDelete={() => setMIDIActivate('')}
label={
midiActivate
?.split('buttonNumber: ')[1]
Expand Down
54 changes: 38 additions & 16 deletions src/components/Midi/LaunchpadButton.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import Button from '@mui/material/Button'
import DialogTitle from '@mui/material/DialogTitle'
import Dialog from '@mui/material/Dialog'
import { darken, DialogContent, Divider, MenuItem, Select, Stack, Typography } from '@mui/material'
import { useState } from 'react'
import { darken, DialogContent, Divider, IconButton, MenuItem, Select, Stack, TextField, Typography } from '@mui/material'
import { useEffect, useState } from 'react'
import LpColorPicker from './LpColorPicker'
import Assign from '../Gamepad/Assign'
import useStore from '../../store/useStore'
import { getColorFromValue } from './lpColors'
import { Autorenew, Save } from '@mui/icons-material'

const LaunchpadButton = ({
buttonNumber,
Expand All @@ -23,8 +24,8 @@ const LaunchpadButton = ({
bgColor?: string
}) => {
const [open, setOpen] = useState(false)

const midiMapping = useStore((state) => state.midiMapping)
const midiEvent = useStore((state) => state.midiEvent)
const setMidiMapping = useStore((state) => state.setMidiMapping)
const midiSceneInactiveColor = useStore((state) => state.midiColors.sceneInactiveColor)
const midiSceneActiveColor = useStore((state) => state.midiColors.sceneActiveColor)
Expand All @@ -41,6 +42,17 @@ const LaunchpadButton = ({
setOpen(false)
}

const currentMapping = midiMapping[0][buttonNumber] || {};

const [midiButtonNumber, setMidiButtonNumber] = useState(currentMapping.buttonNumber || 0)
const [midiRecord, setMidiRecord] = useState(false)

useEffect(() => {
if (midiRecord && midiEvent.button > -1) {
setMidiButtonNumber(midiEvent.button)
}
}, [midiEvent.button])

return (
<div>
<Button
Expand Down Expand Up @@ -77,6 +89,16 @@ const LaunchpadButton = ({
}}>
<DialogTitle>Edit Launchpad Button {buttonNumber}</DialogTitle>
<DialogContent>
<Stack direction={'row'} spacing={2} justifyContent={'space-between'} alignItems={'center'}>
<Typography>MIDI Button</Typography>
<Stack direction={'row'}>
<IconButton onClick={() => {
setMidiMapping({...midiMapping, 0: {...midiMapping[0], [buttonNumber]: {...currentMapping, buttonNumber: midiButtonNumber}}})
setMidiRecord(!midiRecord)
}}>{midiRecord ? <Save /> : <Autorenew />}</IconButton>
<TextField disabled value={midiButtonNumber} sx={{ width: 70 }} size='small' />
</Stack>
</Stack>
<Assign
type={'midi'}
compact={false}
Expand All @@ -90,48 +112,48 @@ const LaunchpadButton = ({
<Divider sx={{ mb: 2.5, mt: 1.5}} />
<Stack direction={'column'} spacing={1} mt={1}>
<Typography variant='h6'>Button Color</Typography>
{midiMapping[0][buttonNumber]?.command === 'scene' ? <>
{currentMapping.command === 'scene' ? <>
<Stack direction={'row'} spacing={2} justifyContent={'space-between'} alignItems={'center'}>
<Typography>Scene inactive</Typography>
<Stack direction={'row'} spacing={2} justifyContent={'space-between'} alignItems={'center'}>
<Select disableUnderline value={midiMapping[0][buttonNumber]?.typeSceneInactive || midiSceneInactiveType || '90'} onChange={(e) => {
setMidiMapping({...midiMapping, 0: {...midiMapping[0], [buttonNumber]: {...midiMapping[0][buttonNumber], typeSceneInactive: e.target.value}}})
<Select disableUnderline value={currentMapping.typeSceneInactive || midiSceneInactiveType || '90'} onChange={(e) => {
setMidiMapping({...midiMapping, 0: {...midiMapping[0], [buttonNumber]: {...currentMapping, typeSceneInactive: e.target.value}}})
}}>
<MenuItem value={'90'}>Solid</MenuItem>
<MenuItem value={'91'}>Flash</MenuItem>
<MenuItem value={'92'}>Pulse</MenuItem>
</Select>
<LpColorPicker defaultColor={getColorFromValue(midiMapping[0][buttonNumber]?.colorSceneInactive || midiSceneInactiveColor)} onColorSelect={(color: string) => {
setMidiMapping({...midiMapping, 0: {...midiMapping[0], [buttonNumber]: {...midiMapping[0][buttonNumber], colorSceneInactive: color}}})
<LpColorPicker defaultColor={getColorFromValue(currentMapping.colorSceneInactive || midiSceneInactiveColor)} onColorSelect={(color: string) => {
setMidiMapping({...midiMapping, 0: {...midiMapping[0], [buttonNumber]: {...currentMapping, colorSceneInactive: color}}})
}} />
</Stack>
</Stack>
<Stack direction={'row'} spacing={2} justifyContent={'space-between'} alignItems={'center'}>
<Typography>Scene active</Typography>
<Stack direction={'row'} spacing={2} justifyContent={'space-between'} alignItems={'center'}>
<Select disableUnderline value={midiMapping[0][buttonNumber]?.typeSceneActive || midiSceneActiveType || '90'} onChange={(e) => {
setMidiMapping({...midiMapping, 0: {...midiMapping[0], [buttonNumber]: {...midiMapping[0][buttonNumber], typeSceneActive: e.target.value}}})
<Select disableUnderline value={currentMapping.typeSceneActive || midiSceneActiveType || '90'} onChange={(e) => {
setMidiMapping({...midiMapping, 0: {...midiMapping[0], [buttonNumber]: {...currentMapping, typeSceneActive: e.target.value}}})
}}>
<MenuItem value={'90'}>Solid</MenuItem>
<MenuItem value={'91'}>Flash</MenuItem>
<MenuItem value={'92'}>Pulse</MenuItem>
</Select>
<LpColorPicker defaultColor={getColorFromValue(midiMapping[0][buttonNumber]?.colorSceneActive || midiSceneActiveColor)} onColorSelect={(color: string) => {
setMidiMapping({...midiMapping, 0: {...midiMapping[0], [buttonNumber]: {...midiMapping[0][buttonNumber], colorSceneActive: color}}})
<LpColorPicker defaultColor={getColorFromValue(currentMapping.colorSceneActive || midiSceneActiveColor)} onColorSelect={(color: string) => {
setMidiMapping({...midiMapping, 0: {...midiMapping[0], [buttonNumber]: {...currentMapping, colorSceneActive: color}}})
}} />
</Stack>
</Stack>
</> :
<Stack direction={'row'} spacing={2} justifyContent={'space-between'} alignItems={'center'}>
<Select disableUnderline value={midiMapping[0][buttonNumber]?.typeCommand || midiCommandType || '90'} onChange={(e) => {
setMidiMapping({...midiMapping, 0: {...midiMapping[0], [buttonNumber]: {...midiMapping[0][buttonNumber], typeCommand: e.target.value}}})
<Select disableUnderline value={currentMapping.typeCommand || midiCommandType || '90'} onChange={(e) => {
setMidiMapping({...midiMapping, 0: {...midiMapping[0], [buttonNumber]: {...currentMapping, typeCommand: e.target.value}}})
}}>
<MenuItem value={'90'}>Solid</MenuItem>
<MenuItem value={'91'}>Flash</MenuItem>
<MenuItem value={'92'}>Pulse</MenuItem>
</Select>
<LpColorPicker defaultColor={getColorFromValue(midiMapping[0][buttonNumber]?.colorCommand || midiCommandColor)} onColorSelect={(color: string) => {
setMidiMapping({...midiMapping, 0: {...midiMapping[0], [buttonNumber]: {...midiMapping[0][buttonNumber], colorCommand: color}}})
<LpColorPicker defaultColor={getColorFromValue(currentMapping.colorCommand || midiCommandColor)} onColorSelect={(color: string) => {
setMidiMapping({...midiMapping, 0: {...midiMapping[0], [buttonNumber]: {...currentMapping, colorCommand: color}}})
}} />
</Stack>}
</Stack>
Expand Down
87 changes: 46 additions & 41 deletions src/components/Midi/LaunchpadButtonMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -205,48 +205,53 @@ const LaunchpadButtonMap = ({toggleSidebar, sideBarOpen}:{toggleSidebar: () => v
</Stack>
</Stack>
<Stack direction={'row'} spacing={2} mb={2}>
<Stack direction={'column'} spacing={1}>
{matrix.map((row, rowIndex) => {
return (
<Stack key={'row' + rowIndex} direction={'row'} spacing={1}>
{row.map((_button, buttonIndex) => {
const row = 9 - rowIndex
const column = buttonIndex + 1
const buttonNumber = `${(row)}${column}`
const btnNumberInt = parseInt(buttonNumber)
const btn = midiMapping[0][btnNumberInt]

const bgColor = midiEvent.button === btnNumberInt
? theme.palette.primary.main
: btn?.command &&
btn?.command === 'scene' &&
btn?.payload.scene === recentScenes[0]
? getColorFromValue(btn?.colorSceneActive || '1E') || '#0f0'
: btn?.command &&
btn?.command === 'scene'
? getColorFromValue(btn?.colorSceneInactive || '07') || '#f00'
: btn?.command &&
btn?.command !== 'none' && rowIndex !== 0
? getColorFromValue(btn?.colorCommand || '63') || '#ff0'
: rowIndex === 0 || buttonIndex === 8
? '#000'
: '#ccc'
return (
<LaunchpadButton
buttonNumber={btnNumberInt}
active={!!(rowIndex === 0 && btn?.command && btn?.command !== 'none')}
bgColor={bgColor}
key={'button' + buttonIndex}
borderless={rowIndex === 0 && buttonIndex === 8}
>
{labels(rowIndex, buttonIndex)}
</LaunchpadButton>
)
})}
</Stack>
)
})}
<Stack direction={'column'} spacing={1}>
{matrix.map((row, rowIndex) => {
return (
<Stack key={'row' + rowIndex} direction={'row'} spacing={1}>
{row.map((_button, buttonIndex) => {
const row = 9 - rowIndex
const column = buttonIndex + 1
const buttonNumber = `${row}${column}`
const btnNumberInt = parseInt(buttonNumber)
const btn = midiMapping[0][btnNumberInt]

// Use the buttonNumber from the mapping for functional logic
const functionalButtonNumber = btn?.buttonNumber

const bgColor = midiEvent.button === (functionalButtonNumber || btnNumberInt)
? theme.palette.primary.main
: btn?.command &&
btn?.command === 'scene' &&
btn?.payload.scene === recentScenes[0]
? getColorFromValue(btn?.colorSceneActive || '1E') || '#0f0'
: btn?.command &&
btn?.command === 'scene'
? getColorFromValue(btn?.colorSceneInactive || '07') || '#f00'
: btn?.command &&
btn?.command !== 'none' && rowIndex !== 0
? getColorFromValue(btn?.colorCommand || '63') || '#ff0'
: rowIndex === 0 || buttonIndex === 8
? '#000'
: '#ccc'

return (
<LaunchpadButton
buttonNumber={btnNumberInt}
active={!!(rowIndex === 0 && btn?.command && btn?.command !== 'none')}
bgColor={bgColor}
key={'button' + buttonIndex}
borderless={rowIndex === 0 && buttonIndex === 8}
>
{labels(rowIndex, buttonIndex)}
</LaunchpadButton>
)
})}
</Stack>
)
})}
</Stack>

{sideBarOpen && <Stack direction={'column'} spacing={1} maxHeight={694} width={300} sx={{ overflowY: 'scroll'}}>
{matrix.map((row, rowIndex) => row.map((button, buttonIndex) => {
return (
Expand Down
Loading

0 comments on commit 86a09a9

Please sign in to comment.