Precached images. ToobTuner. key additions.

This commit is contained in:
Robin Davies
2022-02-23 04:29:21 -05:00
parent ac51296782
commit f677b8b608
24 changed files with 589 additions and 137 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
{
"socket_server_port": 8080,
"socket_server_port": 80,
"socket_server_address": "*",
"max_upload_size": 1048576,
+6 -1
View File
@@ -31,6 +31,8 @@ import ToobToneStackViewFactory from './ToobToneStackView';
import ToobCabSimViewFactory from './ToobCabSimView';
import ToobPowerStage2Factory from './ToobPowerStage2View';
import ToobSpectrumAnalyzerViewFactory from './ToobSpectrumAnalyzerView';
import ToobMLViewFactory from './ToobMLView';
import {ToobTunerViewFactory,GxTunerViewFactory> from './GxTunerView';
let pluginFactories: IControlViewFactory[] = [
@@ -38,7 +40,10 @@ let pluginFactories: IControlViewFactory[] = [
new ToobToneStackViewFactory(),
new ToobCabSimViewFactory(),
new ToobPowerStage2Factory(),
new ToobSpectrumAnalyzerViewFactory()
new ToobSpectrumAnalyzerViewFactory(),
new ToobMLViewFactory(),
new GxTunerViewFactory(),
new ToobTunerViewFactory()
];
+127
View File
@@ -0,0 +1,127 @@
// Copyright (c) 2021 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 from 'react';
import { Theme } from '@mui/material/styles';
import { WithStyles } from '@mui/styles';
import createStyles from '@mui/styles/createStyles';
import withStyles from '@mui/styles/withStyles';
import IControlViewFactory from './IControlViewFactory';
import { PiPedalModelFactory, PiPedalModel } from "./PiPedalModel";
import { PedalBoardItem } from './PedalBoard';
import PluginControlView, { ControlGroup,ControlViewCustomization } from './PluginControlView';
import GxTunerControl from './GxTunerControl';
const GXTUNER_URI = "http://guitarix.sourceforge.net/plugins/gxtuner#tuner";
const TOOBTUNER_URI = "http://two-play.com/plugins/toob-tuner";
const styles = (theme: Theme) => createStyles({
});
interface GxTunerProps extends WithStyles<typeof styles> {
instanceId: number;
item: PedalBoardItem;
}
interface GxTunerState {
}
const GxTunerView =
withStyles(styles, { withTheme: true })(
class extends React.Component<GxTunerProps, GxTunerState>
implements ControlViewCustomization
{
model: PiPedalModel;
customizationId: number = 1;
constructor(props: GxTunerProps) {
super(props);
this.model = PiPedalModelFactory.getInstance();
this.state = {
}
}
getControlIndex(key: string): number {
let item = this.props.item;
for (let i = 0; i < item.controlValues.length; ++i)
{
if (item.controlValues[i].key === key)
{
return i;
}
}
throw new Error("GxTuner: Control '" + key + "' not found.");
}
ModifyControls(controls: (React.ReactNode| ControlGroup)[]): (React.ReactNode| ControlGroup)[]
{
let refFreqIndex = this.getControlIndex("REFFREQ");
let thresholdIndex = this.getControlIndex("THRESHOLD");
let result: (React.ReactNode | ControlGroup)[] = [];
let tunerControl = (<GxTunerControl instanceId={this.props.instanceId} />);
result.push(tunerControl);
result.push(controls[refFreqIndex]);
result.push(controls[thresholdIndex]);
return result;
}
render() {
return (<PluginControlView
instanceId={this.props.instanceId}
item={this.props.item}
customization={this}
customizationId={this.customizationId}
/>);
}
}
);
class GxTunerViewFactory implements IControlViewFactory {
uri: string = GXTUNER_URI;
Create(model: PiPedalModel, pedalBoardItem: PedalBoardItem): React.ReactNode {
return (<GxTunerView instanceId={pedalBoardItem.instanceId} item={pedalBoardItem} />);
}
}
// ToobTuner uses the same controls and control semantics.
class ToobTunerViewFactory implements IControlViewFactory {
uri: string = TOOBTUNER_URI;
Create(model: PiPedalModel, pedalBoardItem: PedalBoardItem): React.ReactNode {
return (<GxTunerView instanceId={pedalBoardItem.instanceId} item={pedalBoardItem} />);
}
}
export ToobTunerViewFactory;
export GxTunerViewFactory;
+1 -1
View File
@@ -332,7 +332,7 @@ const JackServerSettingsDialog = withStyles(styles)(
>
{bufferSizes.map((buffSize) =>
(
<MenuItem value={buffSize}>{buffSize}</MenuItem>
<MenuItem key={"b"+buffSize} value={buffSize}>{buffSize}</MenuItem>
)
)}
+23 -2
View File
@@ -55,6 +55,9 @@ const NARROW_DISPLAY_THRESHOLD = 600;
const FILTER_STORAGE_KEY = "com.twoplay.pipedal.load_dlg.filter";
let lastClickTime: number = 0;
const pluginGridStyles = (theme: Theme) => createStyles({
frame: {
@@ -338,8 +341,26 @@ export const LoadPluginDialog =
}
}
onClick(e: SyntheticEvent, uri: string): void {
e.preventDefault();
let currentTime = Date.now();
let dt = currentTime-lastClickTime;
let DOUBLE_CLICK_TIME = 500;
let isDoubleClick = dt < DOUBLE_CLICK_TIME;
lastClickTime = currentTime;
this.setState({ selected_uri: uri });
// we have to synthesize double clicks because
// DOM rewrites interfere with natural double click.
if (isDoubleClick)
{
this.props.onOk(uri);
}
}
handleMouseEnter(e: SyntheticEvent, uri: string): void {
// this.setHoverUri(uri);
@@ -373,7 +394,7 @@ export const LoadPluginDialog =
for (let i = 0; i < classNode.children.length; ++i) {
let child = classNode.children[i];
let name = "\u00A0".repeat(level * 3 + 1) + child.display_name;
result.push((<MenuItem value={child.plugin_type}>{name}</MenuItem>));
result.push((<MenuItem key={child.plugin_type} value={child.plugin_type}>{name}</MenuItem>));
if (child.children.length !== 0) {
this.createFilterChildren(result, child, level + 1);
}
@@ -383,7 +404,7 @@ export const LoadPluginDialog =
let classes = this.model.plugin_classes.get();
let result: ReactNode[] = [];
result.push((<MenuItem value={PluginType.Plugin}>&nbsp;All</MenuItem>));
result.push((<MenuItem key={PluginType.Plugin} value={PluginType.Plugin}>&nbsp;All</MenuItem>));
this.createFilterChildren(result, classes, 1);
return result;
+2
View File
@@ -42,6 +42,7 @@ export class Port implements Deserializable<Port> {
this.is_atom_port = input.is_atom_port;
this.is_valid = input.is_valid;
this.supports_midi = input.supports_midi;
this.supports_time_position = input.supports_time_position;
this.port_group = input.port_group;
return this;
}
@@ -70,6 +71,7 @@ export class Port implements Deserializable<Port> {
is_atom_port: boolean = false;
is_valid: boolean = false;
supports_midi: boolean = false;
supports_time_position: boolean = false;
port_group: string = "";
}
+48 -50
View File
@@ -311,7 +311,7 @@ export interface PiPedalModel {
presets: ObservableProperty<PresetIndex>;
zoomedUiControl: ObservableProperty< ZoomedControlInfo| undefined >;
zoomedUiControl: ObservableProperty<ZoomedControlInfo | undefined>;
setJackServerSettings(jackServerSettings: JackServerSettings): void;
setMidiBinding(instanceId: number, midiBinding: MidiBinding): void;
@@ -382,7 +382,7 @@ export interface PiPedalModel {
cancelListenForMidiEvent(listenHandle: ListenHandle): void;
addControlValueChangeListener(instanceId: number, onValueChanged: ControlValueChangedHandler): ControlValueChangedHandle
removeControlValueChangeListener(handle: ControlValueChangedHandle): void;
removeControlValueChangeListener(handle: ControlValueChangedHandle): void;
listenForAtomOutput(instanceId: number, onComplete: (instanceId: number, atomOutput: any) => void): ListenHandle;
cancelListenForAtomOutput(listenHandle: ListenHandle): void;
@@ -398,9 +398,9 @@ export interface PiPedalModel {
getWifiChannels(countryIso3661: string): Promise<WifiChannel[]>;
getAlsaDevices() : Promise<AlsaDeviceInfo[]>;
getAlsaDevices(): Promise<AlsaDeviceInfo[]>;
zoomUiControl(sourceElement: HTMLElement,instanceId: number,uiControl: UiControl): void;
zoomUiControl(sourceElement: HTMLElement, instanceId: number, uiControl: UiControl): void;
clearZoomedControl(): void;
};
@@ -438,7 +438,7 @@ class PiPedalModelImpl implements PiPedalModel {
new PresetIndex()
);
zoomedUiControl: ObservableProperty<ZoomedControlInfo | undefined> = new ObservableProperty<ZoomedControlInfo | undefined>(undefined);
zoomedUiControl: ObservableProperty<ZoomedControlInfo | undefined> = new ObservableProperty<ZoomedControlInfo | undefined>(undefined);
svgImgUrl(svgImage: string): string {
//return this.varServerUrl + "img/" + svgImage;
@@ -466,7 +466,7 @@ class PiPedalModelImpl implements PiPedalModel {
onSocketReconnecting(retry: number, maxRetries: number): void {
if (this.visibilityState.get() === VisibilityState.Hidden) return;
//if (retry !== 0) {
this.setState(State.Reconnecting);
this.setState(State.Reconnecting);
//}
}
@@ -536,11 +536,11 @@ class PiPedalModelImpl implements PiPedalModel {
this.handleNotifyMidiListener(clientHandle, isNote, noteOrControl);
} else if (message === "onNotifyAtomOut") {
let clientHandle = body.clientHandle as number;
let instanceId = body.instanceId as number;
let instanceId = body.instanceId as number;
let atomJson = body.atomJson as string;
this.handleNotifyAtomOutput(clientHandle, instanceId,atomJson);
this.handleNotifyAtomOutput(clientHandle, instanceId, atomJson);
if (header.replyTo) {
this.webSocket?.reply(header.replyTo,"onNotifyAtomOut",true);
this.webSocket?.reply(header.replyTo, "onNotifyAtomOut", true);
}
} else if (message === "onControlChanged") {
let controlChangedBody = body as ControlChangedBody;
@@ -733,6 +733,10 @@ class PiPedalModelImpl implements PiPedalModel {
})
.then((clientId) => {
this.clientId = clientId;
return this.getWebSocket().request<string>("imageList");
})
.then((data) => {
this.preloadImages(data);
return true;
})
.catch((error) => {
@@ -842,20 +846,16 @@ class PiPedalModelImpl implements PiPedalModel {
}
exitBackgroundState()
{
if (this.state.get() === State.Background)
{
exitBackgroundState() {
if (this.state.get() === State.Background) {
console.log("Exiting background state.");
this.visibilityState.set(VisibilityState.Visible);
this.webSocket?.exitBackgroundState();
}
}
enterBackgroundState()
{
if (this.state.get() !== State.Background)
{
enterBackgroundState() {
if (this.state.get() !== State.Background) {
console.log("Entering background state.");
this.visibilityState.set(VisibilityState.Hidden);
this.setState(State.Background);
@@ -864,12 +864,10 @@ class PiPedalModelImpl implements PiPedalModel {
}
onVisibilityChanged(doc: Document, event: Event) : any
{
onVisibilityChanged(doc: Document, event: Event): any {
if (document.visibilityState) {
switch (document.visibilityState)
{
switch (document.visibilityState) {
case "visible":
this.visibilityState.set(VisibilityState.Visible);
this.exitBackgroundState();
@@ -898,8 +896,8 @@ class PiPedalModelImpl implements PiPedalModel {
});
let t = this.onVisibilityChanged;
(document as any).addEventListener("visibilitychange",(doc: Document,event: Event) => {
return t(doc,event);
(document as any).addEventListener("visibilitychange", (doc: Document, event: Event) => {
return t(doc, event);
});
}
@@ -958,22 +956,18 @@ class PiPedalModelImpl implements PiPedalModel {
}
}
_controlValueChangeItems: ControlValueChangeItem[] = [];
addControlValueChangeListener(instanceId: number, onValueChanged: ControlValueChangedHandler): ControlValueChangedHandle
{
addControlValueChangeListener(instanceId: number, onValueChanged: ControlValueChangedHandler): ControlValueChangedHandle {
let handle = ++this.nextListenHandle;
this._controlValueChangeItems.push({ handle: handle, instanceId: instanceId,onValueChanged: onValueChanged});
return { _ControlValueChangedHandle: handle};
this._controlValueChangeItems.push({ handle: handle, instanceId: instanceId, onValueChanged: onValueChanged });
return { _ControlValueChangedHandle: handle };
}
removeControlValueChangeListener(handle: ControlValueChangedHandle)
{
for (let i = 0; i < this._controlValueChangeItems.length; ++i)
{
if (this._controlValueChangeItems[i].handle === handle._ControlValueChangedHandle)
{
this._controlValueChangeItems.splice(i,1);
removeControlValueChangeListener(handle: ControlValueChangedHandle) {
for (let i = 0; i < this._controlValueChangeItems.length; ++i) {
if (this._controlValueChangeItems[i].handle === handle._ControlValueChangedHandle) {
this._controlValueChangeItems.splice(i, 1);
return;
}
}
@@ -992,12 +986,10 @@ class PiPedalModelImpl implements PiPedalModel {
if (notifyServer) {
this._setServerControl("setControl", instanceId, key, value);
}
for (let i = 0; i < this._controlValueChangeItems.length; ++i)
{
for (let i = 0; i < this._controlValueChangeItems.length; ++i) {
let item = this._controlValueChangeItems[i];
if (instanceId === item.instanceId)
{
item.onValueChanged(key,value);
if (instanceId === item.instanceId) {
item.onValueChanged(key, value);
}
}
}
@@ -1557,7 +1549,7 @@ class PiPedalModelImpl implements PiPedalModel {
listenForAtomOutput(instanceId: number, onComplete: (instanceId: number, atomOutput: any) => void): ListenHandle {
let handle = this.nextListenHandle++;
this.atomOutputListeners.push(new AtomOutputListener(handle,instanceId, onComplete));
this.atomOutputListeners.push(new AtomOutputListener(handle, instanceId, onComplete));
this.webSocket?.send("listenForAtomOutput", { instanceId: instanceId, handle: handle });
return {
@@ -1570,7 +1562,7 @@ class PiPedalModelImpl implements PiPedalModel {
for (let i = 0; i < this.atomOutputListeners.length; ++i) {
let listener = this.atomOutputListeners[i];
if (listener.handle === clientHandle && listener.instanceId === instanceId) {
listener.callback(instanceId,jsonObject);
listener.callback(instanceId, jsonObject);
}
}
}
@@ -1760,8 +1752,7 @@ class PiPedalModelImpl implements PiPedalModel {
return result;
}
getAlsaDevices() : Promise<AlsaDeviceInfo[]>
{
getAlsaDevices(): Promise<AlsaDeviceInfo[]> {
let result = new Promise<AlsaDeviceInfo[]>((resolve, reject) => {
if (!this.webSocket) {
reject("Connection closed.");
@@ -1776,15 +1767,22 @@ class PiPedalModelImpl implements PiPedalModel {
return result;
}
zoomUiControl(sourceElement: HTMLElement,instanceId: number,uiControl: UiControl): void
{
this.zoomedUiControl.set({source: sourceElement,instanceId: instanceId,uiControl: uiControl});
zoomUiControl(sourceElement: HTMLElement, instanceId: number, uiControl: UiControl): void {
this.zoomedUiControl.set({ source: sourceElement, instanceId: instanceId, uiControl: uiControl });
}
clearZoomedControl(): void
{
clearZoomedControl(): void {
this.zoomedUiControl.set(undefined);
}
preloadImages(imageList: string): void {
let imageNames = imageList.split(';');
for (let i = 0; i < imageNames.length; ++i)
{
let imageName = imageNames[i];
let img = new Image();
img.src = "/img/" + imageName;
}
}
};
+5 -39
View File
@@ -31,7 +31,6 @@ import PluginControl from './PluginControl';
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
import VuMeter from './VuMeter';
import { nullCast } from './Utility'
import GxTunerControl from './GxTunerControl';
import { PiPedalStateError } from './PiPedalError';
import Typography from '@mui/material/Typography';
import FullScreenIME from './FullScreenIME';
@@ -40,7 +39,6 @@ import FullScreenIME from './FullScreenIME';
export const StandardItemSize = { width: 80, height: 110 };
const GXTUNER_URI = "http://guitarix.sourceforge.net/plugins/gxtuner#tuner";
const LANDSCAPE_HEIGHT_BREAK = 500;
@@ -127,7 +125,7 @@ const styles = (theme: Theme) => createStyles({
paddingTop: 0,
paddingBottom: 0,
border: "2pt #AAA solid",
borderRadius: 4,
borderRadius: 8,
elevation: 12,
display: "flex",
flexDirection: "row", flexWrap: "wrap",
@@ -144,7 +142,7 @@ const styles = (theme: Theme) => createStyles({
paddingTop: 0,
paddingBottom: 0,
border: "2pt #AAA solid",
borderRadius: 10,
borderRadius: 8,
elevation: 12,
display: "flex",
flexDirection: "row", flexWrap: "nowrap",
@@ -152,7 +150,7 @@ const styles = (theme: Theme) => createStyles({
},
portGroupTitle: {
position: "absolute",
top: -10,
top: -15,
background: "white",
marginLeft: 20,
paddingLeft: 8,
@@ -344,35 +342,6 @@ const PluginControlView =
throw new Error("Not found.");
}
getTunerControls(plugin: UiPlugin, controlValues: ControlValue[]): ControlNodes {
// display standard version of just a few controls.
let shortList: ControlValue[] = [];
// for (let i = 0; i < controlValues.length; ++i)
// {
// shortList.push(controlValues[i]);
// }
shortList.push(this.getControl(controlValues, "REFFREQ"));
shortList.push(this.getControl(controlValues, "THRESHOLD"));
let controls = shortList.map((controlValue) => (
<PluginControl instanceId={this.props.instanceId} uiControl={plugin.getControl(controlValue.key)} value={controlValue.value}
onChange={(value: number) => { this.onValueChanged(controlValue.key, value) }}
onPreviewChange={(value: number) => { this.onPreviewChange(controlValue.key, value) }}
requestIMEEdit={(uiControl, value) => this.requestImeEdit(uiControl, value)}
/>
));
let tunerControl = (<GxTunerControl instanceId={this.props.instanceId} />);
let result: ControlNodes = [];
result.push(tunerControl);
for (let i = 0; i < controls.length; ++i)
{
result.push(controls[i]);
}
return result;
}
onImeValueChange(key: string, value: number) {
this.model.setPedalBoardControlValue(this.props.instanceId, key, value);
this.onImeClose();
@@ -464,11 +433,8 @@ const PluginControlView =
let vuMeterRClass = this.state.landscapeGrid ? classes.vuMeterRLandscape : classes.vuMeterR;
let controlNodes: ControlNodes;
if (plugin.uri === GXTUNER_URI) {
controlNodes = this.getTunerControls(plugin, controlValues);
} else {
controlNodes = this.getStandardControlNodes(plugin, controlValues);
}
controlNodes = this.getStandardControlNodes(plugin, controlValues);
if (this.props.customization)
{
// allow wrapper class to insert/remove/rebuild controls.
+1 -1
View File
@@ -138,7 +138,7 @@ function makeControls(controls: UiControl[]) {
<Grid container direction="row" justifyContent="flex-start" alignItems="flex-start" spacing={1} style={{ paddingLeft: "24px" }}>
{
controls.map((control) => (
<Grid item spacing={2} xs={6} sm={4} key={control.symbol} >
<Grid xs={6} sm={4} key={control.symbol} >
<Typography variant="body2">
{control.name}
</Typography>
+2 -1
View File
@@ -279,7 +279,8 @@ const PluginPresetSelector =
<Typography variant="caption" color="textSecondary" style={{marginLeft: 16,marginTop:4,marginBottom: 4}}>Plugin presets</Typography>
{
this.state.presets.map((preset) => {
return (<MenuItem onClick={(e) => this.handleLoadPluginPreset(preset.presetUri)}>{preset.name}</MenuItem>);
return (<MenuItem key={preset.presetUri}
onClick={(e) => this.handleLoadPluginPreset(preset.presetUri)}>{preset.name}</MenuItem>);
})
}
{/*
+42 -9
View File
@@ -46,6 +46,10 @@ const styles = (theme: Theme) => createStyles({
interface ToobFrequencyResponseProps extends WithStyles<typeof styles> {
instanceId: number;
maxDb?: number;
minDb?: number;
minFrequency?: number;
maxFrequency?: number;
}
interface ToobFrequencyResponseState {
@@ -104,8 +108,8 @@ const ToobFrequencyResponseView =
requestOutstanding: boolean = false;
requestDeferred: boolean = false;
dbMinOpt: number = -35;
dbMaxOpt: number = 5;
dbMinDefault: number = -35;
dbMaxDefault: number = 5;
dbTickSpacingOpt: number = 10;
@@ -120,8 +124,6 @@ const ToobFrequencyResponseView =
xMax: number = PLOT_WIDTH+4;
yMin: number = 0;
yMax: number = PLOT_HEIGHT;
dbMin: number = this.dbMaxOpt; // deliberately reversed to flip up and down.
dbMax: number = this.dbMinOpt;
dbTickSpacing: number = this.dbTickSpacingOpt;
toX(frequency: number): number
@@ -189,6 +191,10 @@ const ToobFrequencyResponseView =
currentPath: string = "";
majorGridLine(x0: number, y0: number, x1: number, y1: number): React.ReactNode {
return (<line x1={x0} y1={y0} x2={x1} y2={y1} fill='none' stroke="#FFF" strokeWidth="0.75" opacity="1" />);
}
gridLine(x0: number, y0: number, x1: number, y1: number): React.ReactNode {
return (<line x1={x0} y1={y0} x2={x1} y2={y1} fill='none' stroke="#FFF" strokeWidth="0.25" opacity="1" />);
}
@@ -199,27 +205,54 @@ const ToobFrequencyResponseView =
for (var db = Math.ceil(this.dbMax/this.dbTickSpacing)*this.dbTickSpacing; db < this.dbMin; db += this.dbTickSpacing )
{
var y = (db-this.dbMin)/(this.dbMax-this.dbMin)*(this.yMax-this.yMin);
result.push(
this.gridLine(this.xMin,y,this.xMax,y)
);
if (db === 0)
{
result.push(
this.majorGridLine(this.xMin,y,this.xMax,y)
);
} else {
result.push(
this.gridLine(this.xMin,y,this.xMax,y)
);
}
}
let decade0 = Math.pow(10,Math.floor(Math.log10(this.fMin)));
for (var decade = decade0; decade < this.fMax; decade *= 10)
{
for (var i = 0; i < 10; ++i)
for (var i = 1; i <= 10; ++i)
{
var f = decade*i;
if (f > this.fMin && f < this.fMax)
{
var x = this.toX(f);
result.push(this.gridLine(x,this.yMin,x,this.yMax));
if (i === 10)
{
result.push(this.majorGridLine(x,this.yMin,x,this.yMax));
} else {
result.push(this.gridLine(x,this.yMin,x,this.yMax));
}
}
}
}
return result;
}
dbMin: number = 5;
dbMax: number = -35;
render() {
// deliberately reversed to flip up and down.
this.dbMax = this.props.minDb ?? this.dbMinDefault;
this.dbMin = this.props.maxDb ?? this.dbMaxDefault;
this.fMin = this.props.minFrequency ?? 30;
this.fMax = this.props.maxFrequency ?? 20000;
this.logMin = Math.log(this.fMin);
this.logMax = Math.log(this.fMax);
let classes = this.props.classes;
return (
<div className={classes.frame} >
+93
View File
@@ -0,0 +1,93 @@
// Copyright (c) 2021 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 from 'react';
import { Theme } from '@mui/material/styles';
import { WithStyles } from '@mui/styles';
import createStyles from '@mui/styles/createStyles';
import withStyles from '@mui/styles/withStyles';
import IControlViewFactory from './IControlViewFactory';
import { PiPedalModelFactory, PiPedalModel } from "./PiPedalModel";
import { PedalBoardItem } from './PedalBoard';
import PluginControlView, { ControlGroup,ControlViewCustomization } from './PluginControlView';
import ToobFrequencyResponseView from './ToobFrequencyResponseView';
const styles = (theme: Theme) => createStyles({
});
interface ToobMLProps extends WithStyles<typeof styles> {
instanceId: number;
item: PedalBoardItem;
}
interface ToobMLState {
}
const ToobMLView =
withStyles(styles, { withTheme: true })(
class extends React.Component<ToobMLProps, ToobMLState>
implements ControlViewCustomization
{
model: PiPedalModel;
customizationId: number = 1;
constructor(props: ToobMLProps) {
super(props);
this.model = PiPedalModelFactory.getInstance();
this.state = {
}
}
ModifyControls(controls: (React.ReactNode| ControlGroup)[]): (React.ReactNode| ControlGroup)[]
{
let group = controls[1] as ControlGroup;
group.controls.splice(0,0,
( <ToobFrequencyResponseView instanceId={this.props.instanceId} minDb={-20} maxDb={20} />)
);
return controls;
}
render() {
return (<PluginControlView
instanceId={this.props.instanceId}
item={this.props.item}
customization={this}
customizationId={this.customizationId}
/>);
}
}
);
class ToobMLViewFactory implements IControlViewFactory {
uri: string = "http://two-play.com/plugins/toob-ml";
Create(model: PiPedalModel, pedalBoardItem: PedalBoardItem): React.ReactNode {
return (<ToobMLView instanceId={pedalBoardItem.instanceId} item={pedalBoardItem} />);
}
}
export default ToobMLViewFactory;
+39 -5
View File
@@ -25,7 +25,7 @@ import createStyles from '@mui/styles/createStyles';
import withStyles from '@mui/styles/withStyles';
import IControlViewFactory from './IControlViewFactory';
import { PiPedalModelFactory, PiPedalModel } from "./PiPedalModel";
import { PiPedalModelFactory, PiPedalModel,ControlValueChangedHandle } from "./PiPedalModel";
import { PedalBoardItem } from './PedalBoard';
import PluginControlView, { ControlGroup,ControlViewCustomization } from './PluginControlView';
import ToobFrequencyResponseView from './ToobFrequencyResponseView';
@@ -41,7 +41,7 @@ interface ToobToneStackProps extends WithStyles<typeof styles> {
}
interface ToobToneStackState {
isBaxandall: boolean;
}
const ToobToneStackView =
@@ -57,14 +57,48 @@ const ToobToneStackView =
super(props);
this.model = PiPedalModelFactory.getInstance();
this.state = {
isBaxandall: this.IsBaxandall()
}
}
IsBaxandall() : boolean {
return this.props.item.getControl("ampmodel").value === 2.0;
}
controlValueChangedHandle?: ControlValueChangedHandle;
componentDidMount()
{
this.controlValueChangedHandle = this.model.addControlValueChangeListener(
this.props.instanceId,
(key,value) => {
if (key === "ampmodel")
{
this.setState({isBaxandall: value === 2.0});
}
}
);
}
componentWillUnmount() {
if (this.controlValueChangedHandle)
{
this.model.removeControlValueChangeListener(this.controlValueChangedHandle);
this.controlValueChangedHandle = undefined;
}
}
ModifyControls(controls: (React.ReactNode| ControlGroup)[]): (React.ReactNode| ControlGroup)[]
{
controls.splice(0,0,
( <ToobFrequencyResponseView instanceId={this.props.instanceId} />)
);
if (this.state.isBaxandall)
{
controls.splice(0,0,
( <ToobFrequencyResponseView instanceId={this.props.instanceId}
minDb={-20} maxDb={20} />)
);
} else {
controls.splice(0,0,
( <ToobFrequencyResponseView instanceId={this.props.instanceId} />)
);
}
return controls;
}
render() {