// Copyright (c) 2022 Robin Davies // // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of // the Software, and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import React, { SyntheticEvent } from 'react'; import DialogEx from './DialogEx'; import ResizeResponsiveComponent from './ResizeResponsiveComponent'; import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; import Typography from '@mui/material/Typography'; import { Theme } from '@mui/material/styles'; import WithStyles from './WithStyles'; import { createStyles } from './WithStyles'; import { withStyles } from "tss-react/mui"; import AppBar from '@mui/material/AppBar'; import Toolbar from '@mui/material/Toolbar'; import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import IconButtonEx from './IconButtonEx'; import MidiBinding from './MidiBinding'; import MidiBindingView, { getMidiControlType } from './MidiBindingView'; import { PortGroup, UiPlugin, makeSplitUiPlugin } from './Lv2Plugin'; import { css } from '@emotion/react'; const styles = (theme: Theme) => createStyles({ dialogAppBar: css({ position: 'relative', top: 0, left: 0 }), dialogTitle: css({ marginLeft: theme.spacing(2), flex: "1 1 auto", }), pluginTable: css({ border: "collapse", width: "100%", }), pluginHead: css({ borderTop: "1pt #DDD solid", paddingLeft: 22, paddingRight: 22 }), groupHead: css({ borderBottom: "1px solid " + theme.palette.divider, marginLeft: 0, marginBottom: 0 }), bindingTd: css({ verticalAlign: "top", paddingLeft: 12, paddingBottom: 8 }), nameTd: css({ paddingLeft: 48, verticalAlign: "top", paddingTop: 12 }), }); function canDoTapTempo(uiPlugin: UiPlugin | undefined, symbol: string): boolean { if (!uiPlugin) return false; let port = uiPlugin.getControl(symbol); if (!port) return false; if (port.canDoTapTempo()) { return true; } return false; } function not_null(value: T | null) { if (!value) throw Error("Unexpected null value"); return value; } export interface MidiBindingDialogProps extends WithStyles { open: boolean, onClose: () => void } export interface MidiBindingDialogState { } export const MidiBindingDialog = withStyles( class extends ResizeResponsiveComponent { model: PiPedalModel; constructor(props: MidiBindingDialogProps) { super(props); this.state = { listenInstanceId: -2, listenSymbol: "", listenForRangeSymbol: "", listenSnackbarOpen: false, listenForRangeMin: 127, listenForRangeMax: 0 }; this.model = PiPedalModelFactory.getInstance(); this.handleClose = this.handleClose.bind(this); } mounted: boolean = false; hasHooks: boolean = false; handleClose() { this.props.onClose(); } onWindowSizeChanged(width: number, height: number): void { } componentDidMount() { super.componentDidMount(); this.mounted = true; } componentWillUnmount() { this.mounted = false; super.componentWillUnmount(); } componentDidUpdate() { } handleItemChanged(instanceId: number, newBinding: MidiBinding) { this.model.setMidiBinding(instanceId, newBinding); } generateTable(): React.ReactNode[] { const classes = withStyles.getClasses(this.props); let result: React.ReactNode[] = []; let pedalboard = this.model.pedalboard.get(); let iter = pedalboard.itemsGenerator(); let keyIx = 1; while (true) { let v = iter.next(); if (v.done) break; let item = v.value; let isSplit = item.uri === "uri://two-play/pipedal/pedalboard#Split"; let plugin: UiPlugin | null = this.model.getUiPlugin(item.uri); if (plugin === null && isSplit) { plugin = makeSplitUiPlugin(); let splitType = item.getControlValue("splitType"); not_null(plugin.getControl("splitType")).not_on_gui = true; switch (splitType) { case 0: // A/B not_null(plugin.getControl("select")).not_on_gui = false; not_null(plugin.getControl("mix")).not_on_gui = true; not_null(plugin.getControl("volL")).not_on_gui = true; not_null(plugin.getControl("panL")).not_on_gui = true; not_null(plugin.getControl("volR")).not_on_gui = true; not_null(plugin.getControl("panR")).not_on_gui = true; break; case 1: //mixer not_null(plugin.getControl("select")).not_on_gui = true; not_null(plugin.getControl("mix")).not_on_gui = false; not_null(plugin.getControl("volL")).not_on_gui = true; not_null(plugin.getControl("panL")).not_on_gui = true; not_null(plugin.getControl("volR")).not_on_gui = true; not_null(plugin.getControl("panR")).not_on_gui = true; break; case 2: // L/R not_null(plugin.getControl("select")).not_on_gui = true; not_null(plugin.getControl("mix")).not_on_gui = true; not_null(plugin.getControl("volL")).not_on_gui = false; not_null(plugin.getControl("panL")).not_on_gui = false; not_null(plugin.getControl("volR")).not_on_gui = false; not_null(plugin.getControl("panR")).not_on_gui = false; break; } // xxx } if (plugin) { result.push( {item.title ? item.title : plugin.name} ); if (!isSplit) { result.push( Bypass this.handleItemChanged(instanceId, newItem)} /> ); } let lastPortGroup: PortGroup | null = null; for (let i = 0; i < plugin.controls.length; ++i) { let control = plugin.controls[i]; if (!control.is_input) { continue; } let portGroup = plugin.getPortGroupBySymbol(control.port_group); if (portGroup != lastPortGroup) { lastPortGroup = portGroup; if (portGroup != null) { result.push(
{portGroup?.name}
); } } let symbol = control.symbol; result.push( {control.name} this.handleItemChanged(instanceId, newItem)} /> ); } } } return result; } supressDefault(e: SyntheticEvent) { //e.preventDefault(); //e.stopPropagation(); } render() { let props = this.props; let { open } = props; const classes = withStyles.getClasses(props); if (!open) { return (
); } return ( { }} >
Preset MIDI Bindings
{this.generateTable()}
); } }, styles); export default MidiBindingDialog;