Implement Mod FX, Delay and EQ

This commit is contained in:
Aoife
2020-11-21 00:02:19 -05:00
parent c08fb8ea50
commit 67744f59c7
9 changed files with 1027 additions and 734 deletions
+37 -33
View File
@@ -6,48 +6,52 @@ import './rcSelectTheme.css';
const SliderWithToolTip = createSliderWithTooltip(RCSlider); const SliderWithToolTip = createSliderWithTooltip(RCSlider);
const SelectStyle = { const SelectStyle = {
control: (provided) => ({ control: (provided) => ({
...provided, ...provided,
width: '100%', width: '100%',
}), }),
}; };
const Slider = (props) => { const Slider = (props) => {
return ( return (
<SliderWithToolTip <SliderWithToolTip
tipFormatter={(v) => `${v}`} tipFormatter={(v) => `${v}`}
min={props.min} min={props.min}
max={props.max} max={props.max}
value={props.parameter} value={props.parameter}
onChange={(v) => props.onChange(v)} onChange={(v) => props.onChange(v)}
/> />
); );
}; };
const SelectList = (props) => { const SelectList = (props) => {
return ( return (
<Select <Select
value={{ value: props.value }} value={{ value: props.value }}
options={props.list} options={props.list}
getOptionLabel={(option) => `${option.value}`} getOptionLabel={
onChange={(e) => props.onChange(e.value)} props.labelFunction
styles={SelectStyle} ? props.labelFunction
/> : (option) => `${option.value}`
); }
onChange={(e) => props.onChange(e.value)}
styles={SelectStyle}
/>
);
}; };
const Checkbox = (props) => { const Checkbox = (props) => {
return ( return (
<div> <div>
<span>{`${props.name}:`}</span> <span>{`${props.name}:`}</span>
<input <input
type="checkbox" type="checkbox"
value={props.parameter} value={props.parameter}
defaultChecked={props.parameter} defaultChecked={props.parameter}
onChange={(e) => props.onChange(e.target.checked)} onChange={(e) => props.onChange(e.target.checked)}
/> />
</div> </div>
); );
}; };
export { Slider, SelectList, Checkbox }; export { Slider, SelectList, Checkbox };
+16
View File
@@ -0,0 +1,16 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { ModFX, Delay, EQ } from './parameters/ModFX';
import { selectById } from './timbreSlice.js';
import styles from './Timbre.module.css';
export default function Effects(props) {
const ids = useSelector((state) => selectById(state, props.id));
return (
<div className={styles.timbreStyle}>
<ModFX id={ids.modfx} />
<Delay id={ids.delay} />
<EQ id={ids.eq} />
</div>
);
}
+130 -130
View File
@@ -12,134 +12,134 @@ import { selectById } from './timbreSlice.js';
import styles from './Timbre.module.css'; import styles from './Timbre.module.css';
export default function Timbre(props) { export default function Timbre(props) {
const ids = useSelector((state) => selectById(state, props.id)); const ids = useSelector((state) => selectById(state, props.id));
return ( return (
<div className={styles.timbreStyle}> <div className={styles.timbreStyle}>
<VCO <VCO
name="VCO 1" name="VCO 1"
id={ids.vco1} id={ids.vco1}
waveforms={[ waveforms={[
{ value: 'Saw' }, { value: 'Saw' },
{ value: 'Square' }, { value: 'Square' },
{ value: 'Triangle' }, { value: 'Triangle' },
{ value: 'Sine' }, { value: 'Sine' },
{ value: 'Vox Wave' }, { value: 'Vox Wave' },
{ value: 'DWGS' }, { value: 'DWGS' },
{ value: 'Noise' }, { value: 'Noise' },
{ value: 'Audio In' }, { value: 'Audio In' },
]} ]}
dwgsOrModTypeName="DWGS" dwgsOrModTypeName="DWGS"
dwgsOrModType={[ dwgsOrModType={[
{ value: 'SynSine1' }, { value: 'SynSine1' },
{ value: 'SynSine2' }, { value: 'SynSine2' },
{ value: 'SynSine3' }, { value: 'SynSine3' },
{ value: 'SynSine4' }, { value: 'SynSine4' },
{ value: 'SynSine5' }, { value: 'SynSine5' },
{ value: 'SynSine6' }, { value: 'SynSine6' },
{ value: 'SynSine7' }, { value: 'SynSine7' },
{ value: 'SynBass1' }, { value: 'SynBass1' },
{ value: 'SynBass2' }, { value: 'SynBass2' },
{ value: 'SynBass3' }, { value: 'SynBass3' },
{ value: 'SynBass4' }, { value: 'SynBass4' },
{ value: 'SynBass5' }, { value: 'SynBass5' },
{ value: 'SynBass6' }, { value: 'SynBass6' },
{ value: 'SynBass7' }, { value: 'SynBass7' },
{ value: 'SynWave1' }, { value: 'SynWave1' },
{ value: 'SynWave2' }, { value: 'SynWave2' },
{ value: 'SynWave3' }, { value: 'SynWave3' },
{ value: 'SynWave4' }, { value: 'SynWave4' },
{ value: 'SynWave5' }, { value: 'SynWave5' },
{ value: 'SynWave6' }, { value: 'SynWave6' },
{ value: 'SynWave7' }, { value: 'SynWave7' },
{ value: 'SynWave8' }, { value: 'SynWave8' },
{ value: 'SynWave9' }, { value: 'SynWave9' },
{ value: '5thWave1' }, { value: '5thWave1' },
{ value: '5thWave2' }, { value: '5thWave2' },
{ value: '5thWave3' }, { value: '5thWave3' },
{ value: 'Digi1' }, { value: 'Digi1' },
{ value: 'Digi2' }, { value: 'Digi2' },
{ value: 'Digi3' }, { value: 'Digi3' },
{ value: 'Digi4' }, { value: 'Digi4' },
{ value: 'Digi5' }, { value: 'Digi5' },
{ value: 'Digi6' }, { value: 'Digi6' },
{ value: 'Digi7' }, { value: 'Digi7' },
{ value: 'Digi8' }, { value: 'Digi8' },
{ value: 'Endless' }, { value: 'Endless' },
{ value: 'E.Piano1' }, { value: 'E.Piano1' },
{ value: 'E.Piano2' }, { value: 'E.Piano2' },
{ value: 'E.Piano3' }, { value: 'E.Piano3' },
{ value: 'E.Piano4' }, { value: 'E.Piano4' },
{ value: 'Organ1' }, { value: 'Organ1' },
{ value: 'Organ2' }, { value: 'Organ2' },
{ value: 'Organ3' }, { value: 'Organ3' },
{ value: 'Organ4' }, { value: 'Organ4' },
{ value: 'Organ5' }, { value: 'Organ5' },
{ value: 'Organ6' }, { value: 'Organ6' },
{ value: 'Organ7' }, { value: 'Organ7' },
{ value: 'Clav1' }, { value: 'Clav1' },
{ value: 'Clav2' }, { value: 'Clav2' },
{ value: 'Guitar1' }, { value: 'Guitar1' },
{ value: 'Guitar2' }, { value: 'Guitar2' },
{ value: 'Guitar3' }, { value: 'Guitar3' },
{ value: 'Bass1' }, { value: 'Bass1' },
{ value: 'Bass2' }, { value: 'Bass2' },
{ value: 'Bass3' }, { value: 'Bass3' },
{ value: 'Bass4' }, { value: 'Bass4' },
{ value: 'Bass5' }, { value: 'Bass5' },
{ value: 'Bell1' }, { value: 'Bell1' },
{ value: 'Bell2' }, { value: 'Bell2' },
{ value: 'Bell3' }, { value: 'Bell3' },
{ value: 'Bell4' }, { value: 'Bell4' },
{ value: 'Voice1' }, { value: 'Voice1' },
{ value: 'Voice2' }, { value: 'Voice2' },
{ value: 'Voice3' }, { value: 'Voice3' },
{ value: 'Voice4' }, { value: 'Voice4' },
]} ]}
/> />
<VCO <VCO
name="VCO 2" name="VCO 2"
id={ids.vco2} id={ids.vco2}
waveforms={[ waveforms={[
{ value: 'Saw' }, { value: 'Saw' },
{ value: 'Square' }, { value: 'Square' },
{ value: 'Triangle' }, { value: 'Triangle' },
]} ]}
dwgsOrModTypeName="Mod Type" dwgsOrModTypeName="Mod Type"
dwgsOrModType={[ dwgsOrModType={[
{ value: 'Off' }, { value: 'Off' },
{ value: 'Ring' }, { value: 'Ring' },
{ value: 'Sync' }, { value: 'Sync' },
{ value: 'RingSync' }, { value: 'RingSync' },
]} ]}
/> />
<Mixer name="Mixer" id={ids.mixer} /> <Mixer name="Mixer" id={ids.mixer} />
<Pitch name="Pitch" id={ids.pitch} /> <Pitch name="Pitch" id={ids.pitch} />
<Filter name="Filter" id={ids.filter} /> <Filter name="Filter" id={ids.filter} />
<Amp name="Amp"id={ids.amp} /> <Amp name="Amp" id={ids.amp} />
<div className={styles.lineBreak} /> <div className={styles.lineBreak} />
<EG name="EG 1" id={ids.eg1} /> <EG name="EG 1" id={ids.eg1} />
<EG name="EG 2" id={ids.eg2} /> <EG name="EG 2" id={ids.eg2} />
<LFO <LFO
name="LFO 1" name="LFO 1"
id={ids.lfo1} id={ids.lfo1}
waveforms={[ waveforms={[
{ value: 'Saw' }, { value: 'Saw' },
{ value: 'Square 1' }, { value: 'Square 1' },
{ value: 'Triangle' }, { value: 'Triangle' },
{ value: 'Sample & Hold' }, { value: 'Sample & Hold' },
]} ]}
/> />
<LFO <LFO
name="LFO 2" name="LFO 2"
id={ids.lfo2} id={ids.lfo2}
waveforms={[ waveforms={[
{ value: 'Saw' }, { value: 'Saw' },
{ value: 'Square 2' }, { value: 'Square 2' },
{ value: 'Sine' }, { value: 'Sine' },
{ value: 'Sample & Hold' }, { value: 'Sample & Hold' },
]} ]}
/> />
<Patches name="Patches" id={ids.patches} /> <Patches name="Patches" id={ids.patches} />
</div> </div>
); );
} }
+72 -74
View File
@@ -1,112 +1,110 @@
.timbreStyle { .timbreStyle {
display: inline-flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: center;
} }
@media screen and (min-width: 1824) { @media screen and (min-width: 1824) {
.lineBreak { .lineBreak {
width: 100%; width: 100%;
} }
} }
.buttonContainer { .buttonContainer {
position: fixed; position: fixed;
top: 0; top: 0;
left: 25%; left: 25%;
} }
.buttonContainer > button:hover { .buttonContainer > button:hover {
background: white; background: white;
color: slateblue; color: slateblue;
border: 2px solid slateblue; border: 2px solid slateblue;
} }
.buttonContainer > button:focus { .buttonContainer > button:focus {
background: slateblue; background: slateblue;
color: white; color: white;
border: 2px solid slateblue; border: 2px solid slateblue;
} }
.tabs { .tabs {
height: 100vh; height: 100vh;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.tabList { .tabList {
border-bottom: 1px solid black; border-bottom: 1px solid black;
display: inline-flex; display: inline-flex;
flex-direction: row; flex-direction: row;
list-style-type: none; list-style-type: none;
justify-content: center; justify-content: center;
top: 0; top: 0;
padding: 0; padding: 0;
margin: 0; margin: 0;
width: 100vw; width: 100vw;
background: white; background: white;
} }
.tab { .tab {
width: 78px; width: 78px;
background: white; background: white;
color: slategrey; color: slategrey;
font-size: 0.75em; font-size: 0.75em;
margin: 0.75em 1em; margin: 0.75em 1em;
padding: 0.25em 1em; padding: 0.25em 1em;
border: 2px solid slategrey; border: 2px solid slategrey;
border-radius: 3px; border-radius: 3px;
outline: none; outline: none;
-webkit-touch-callout: none; /* iOS Safari */ -webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */ -webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */ -khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */ -moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */ -ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; user-select: none;
} }
.tab:hover { .tab:hover {
background: white; background: white;
color: slateblue; color: slateblue;
border: 2px solid slateblue; border: 2px solid slateblue;
} }
.selected, .selected,
.selected:hover { .selected:hover {
background: slateblue; background: slateblue;
color: white; color: white;
border: 2px solid slateblue; border: 2px solid slateblue;
transition: 0.2s ease-in-out; transition: 0.2s ease-in-out;
} }
@keyframes slideeffect { @keyframes slideeffect {
0% { 0% {
opacity: 0.5; opacity: 0.5;
} }
100% { 100% {
opacity: 1; opacity: 1;
} }
} }
.tabPanel { .tabPanel {
padding: 1em 0;
padding: 1em 0; height: 100%;
height: 100%; animation: slideeffect 0.6s ease-in-out;
animation: slideeffect 0.6s ease-in-out; opacity: 1;
opacity: 1; overflow-y: scroll;
overflow-y: scroll;
} }
.tabPanel::-webkit-scrollbar { .tabPanel::-webkit-scrollbar {
width: 0.25em; width: 0.25em;
} }
.tabPanel::-webkit-scrollbar-track, .tabPanel::-webkit-scrollbar-thumb { .tabPanel::-webkit-scrollbar-track,
background-color: transparent; .tabPanel::-webkit-scrollbar-thumb {
background-color: transparent;
} }
.tabPanel:hover::-webkit-scrollbar-track { .tabPanel:hover::-webkit-scrollbar-track {
background-color: lightgray; background-color: lightgray;
} }
.tabPanel:hover::-webkit-scrollbar-thumb { .tabPanel:hover::-webkit-scrollbar-thumb {
background-color: slateblue; background-color: slateblue;
border-radius: 6px; border-radius: 6px;
} }
+249 -10
View File
@@ -1,8 +1,8 @@
import React from "react"; import React from 'react';
import { useSelector, useDispatch } from "react-redux"; import { useSelector, useDispatch } from 'react-redux';
import { selectById, parameterUpdated } from "./parameterSlice.js"; import { selectById, parameterUpdated } from './parameterSlice.js';
import { Slider, SelectList } from "../../helpers/Helpers"; import { Slider, SelectList, Checkbox } from '../../helpers/Helpers';
import styles from "./Parameters.module.css"; import styles from './Parameters.module.css';
const ModFX = (props) => { const ModFX = (props) => {
const parameters = useSelector((state) => selectById(state, props.id)); const parameters = useSelector((state) => selectById(state, props.id));
@@ -10,13 +10,15 @@ const ModFX = (props) => {
return ( return (
<div className={styles.container}> <div className={styles.container}>
<span className={styles.header}>Mod FX</span>
Mod Type
<SelectList <SelectList
value={parameters.type} value={parameters.type}
list={ list={[
({ value: "Flanger/Chorus" }, { value: 'Flanger/Chorus' },
{ value: "Ensemble" }, { value: 'Ensemble' },
{ value: "Phaser" }) { value: 'Phaser' },
} ]}
onChange={(value) => onChange={(value) =>
dispatch( dispatch(
parameterUpdated({ parameterUpdated({
@@ -26,6 +28,7 @@ const ModFX = (props) => {
) )
} }
/> />
LFO Speed
<Slider <Slider
min={0} min={0}
max={127} max={127}
@@ -39,6 +42,7 @@ const ModFX = (props) => {
) )
} }
/> />
Mod FX Depth
<Slider <Slider
min={0} min={0}
max={127} max={127}
@@ -55,3 +59,238 @@ const ModFX = (props) => {
</div> </div>
); );
}; };
const Delay = (props) => {
const parameters = useSelector((state) => selectById(state, props.id));
const dispatch = useDispatch();
return (
<div className={styles.container}>
<span className={styles.header}>Delay</span>
Delay Type
<SelectList
value={parameters.type}
list={[
{ value: 'Stereo Delay' },
{ value: 'Cross Delay' },
{ value: 'L/R Delay' },
]}
onChange={(value) =>
dispatch(
parameterUpdated({
id: props.id,
changes: { type: value },
})
)
}
/>
<Checkbox
name="Tempo Sync"
parameter={parameters.tempoSync}
onChange={(value) =>
dispatch(
parameterUpdated({
id: props.id,
changes: { tempoSync: value },
})
)
}
/>
{parameters.tempoSync ? (
<div>
Sync Note
<SelectList
value={parameters.syncNote}
list={[
{ value: '1/32' },
{ value: '1/24' },
{ value: '1/16' },
{ value: '1/12' },
{ value: '3/32' },
{ value: '1/8' },
{ value: '1/6' },
{ value: '3/16' },
{ value: '1/4' },
{ value: '1/3' },
{ value: '3/8' },
{ value: '1/2' },
{ value: '2/3' },
{ value: '3/4' },
{ value: '1/1' },
]}
onChange={(value) =>
dispatch(
parameterUpdated({
id: props.id,
changes: { syncNote: value },
})
)
}
/>
</div>
) : (
<div>
Delay Time
<Slider
min={0}
max={127}
parameter={parameters.delayTime}
onChange={(value) =>
dispatch(
parameterUpdated({
id: props.id,
changes: { delayTime: value },
})
)
}
/>
</div>
)}
Delay Depth
<Slider
min={0}
max={127}
parameter={parameters.delayDepth}
onChange={(value) =>
dispatch(
parameterUpdated({
id: props.id,
changes: { delayDepth: value },
})
)
}
/>
</div>
);
};
const EQ = (props) => {
const parameters = useSelector((state) => selectById(state, props.id));
const dispatch = useDispatch();
return (
<div className={styles.container}>
<span className={styles.header}>EQ</span>
Low EQ Frequency
<SelectList
labelFunction={(e) => `${e.value}kHz`}
value={parameters.lowFrequency}
list={[
{ value: 40 },
{ value: 50 },
{ value: 60 },
{ value: 80 },
{ value: 100 },
{ value: 120 },
{ value: 140 },
{ value: 160 },
{ value: 180 },
{ value: 200 },
{ value: 220 },
{ value: 240 },
{ value: 260 },
{ value: 280 },
{ value: 300 },
{ value: 320 },
{ value: 340 },
{ value: 360 },
{ value: 380 },
{ value: 400 },
{ value: 420 },
{ value: 440 },
{ value: 460 },
{ value: 480 },
{ value: 500 },
{ value: 600 },
{ value: 700 },
{ value: 800 },
{ value: 900 },
{ value: 1000 },
]}
onChange={(value) =>
dispatch(
parameterUpdated({
id: props.id,
changes: { lowFrequency: value },
})
)
}
/>
Low EQ Gain
<Slider
min={-12}
max={12}
parameter={parameters.lowGain}
onChange={(value) =>
dispatch(
parameterUpdated({
id: props.id,
changes: { lowGain: value },
})
)
}
/>
High EQ Frequency
<SelectList
labelFunction={(e) => `${e.value}kHz`}
value={parameters.highFrequency}
list={[
{ value: 1.0 },
{ value: 1.25 },
{ value: 1.5 },
{ value: 1.75 },
{ value: 2.0 },
{ value: 2.25 },
{ value: 2.5 },
{ value: 2.75 },
{ value: 3.0 },
{ value: 3.25 },
{ value: 3.5 },
{ value: 3.75 },
{ value: 4.0 },
{ value: 4.25 },
{ value: 4.5 },
{ value: 4.75 },
{ value: 5.0 },
{ value: 5.25 },
{ value: 5.5 },
{ value: 5.75 },
{ value: 6.0 },
{ value: 7.0 },
{ value: 8.0 },
{ value: 9.0 },
{ value: 10.0 },
{ value: 11.0 },
{ value: 12.0 },
{ value: 14.0 },
{ value: 16.0 },
{ value: 18.0 },
]}
onChange={(value) =>
dispatch(
parameterUpdated({
id: props.id,
changes: { highFrequency: value },
})
)
}
/>
High EQ Gain
<Slider
min={-12}
max={12}
parameter={parameters.highGain}
onChange={(value) =>
dispatch(
parameterUpdated({
id: props.id,
changes: { highGain: value },
})
)
}
/>
</div>
);
};
export { ModFX, Delay, EQ };
@@ -1,88 +1,89 @@
.container, .horizontalContainer, .patchesContainer { .container,
border: solid 1pt slategrey; .horizontalContainer,
border-radius: 6px; .patchesContainer {
border: solid 1pt slategrey;
border-radius: 6px;
} }
.container { .container {
position: relative; position: relative;
font-size: small; font-size: small;
display: inline-flex; display: inline-flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
padding: 16pt; padding: 16pt;
margin: 10pt; margin: 10pt;
width: 15%; min-width: 15%;
height: 214px; height: 214px;
line-height: 1.5em; line-height: 1.5em;
} }
.container > * { .container > * {
margin: 3pt 0; margin: 3pt 0;
} }
.header { .header {
font-size: 1.5em; font-size: 1.5em;
line-height: 1.25em; line-height: 1.25em;
text-align: center; text-align: center;
background-color: white; background-color: white;
padding: 0 .25em 0.075em; padding: 0 0.25em 0.075em;
border-left: 1px solid slategrey; border-left: 1px solid slategrey;
border-right: 1px solid slategrey; border-right: 1px solid slategrey;
box-sizing: border-box; box-sizing: border-box;
} }
.container > .header { .container > .header {
position: absolute; position: absolute;
top: -7.5%; top: -7.5%;
left: 12%; left: 12%;
} }
.horizontalContainer > .header, .patchesContainer > .header { .horizontalContainer > .header,
position: absolute; .patchesContainer > .header {
top: -5.25%; position: absolute;
left: 6%; top: -5.25%;
left: 6%;
} }
.horizontalContainer { .horizontalContainer {
position: relative; position: relative;
font-size: small; font-size: small;
display: inline-flex; display: inline-flex;
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
padding: 16pt 8pt 16pt 8pt; padding: 16pt 8pt 16pt 8pt;
margin: 10pt; margin: 10pt;
width: 448px; width: 448px;
height: 214px; height: 214px;
} }
.patchesContainer { .patchesContainer {
position: relative; position: relative;
font-size: small; font-size: small;
display: inline-flex; display: inline-flex;
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
padding: 16pt 8pt 16pt 8pt; padding: 16pt 8pt 16pt 8pt;
margin: 10pt; margin: 10pt;
width: 680px; width: 680px;
height: 214px; height: 214px;
} }
.horizontalContainer > .container, .horizontalContainer > .container,
.patchesContainer > .container { .patchesContainer > .container {
padding: 0 16pt; padding: 0 16pt;
width: 100%; width: 100%;
margin: 10pt 0; margin: 10pt 0;
border: none; border: none;
} }
.divider { .divider {
height: 214px; height: 214px;
width: 2px; width: 2px;
background-color:slategrey; background-color: slategrey;
margin: 0 8pt; margin: 0 8pt;
} }
.patchesContainer > .divider { .patchesContainer > .divider {
width: 4px; width: 4px;
} }
+362 -338
View File
@@ -3,349 +3,373 @@ import { createSlice, createEntityAdapter } from '@reduxjs/toolkit';
const parametersAdapter = createEntityAdapter({}); const parametersAdapter = createEntityAdapter({});
const parametersSlice = createSlice({ const parametersSlice = createSlice({
name: 'parameters', name: 'parameters',
initialState: parametersAdapter.getInitialState({ initialState: parametersAdapter.getInitialState({
ids: [ ids: [
'vco1', 'vco1',
'vco2', 'vco2',
'mixer1', 'mixer1',
'pitch1', 'pitch1',
'filter1', 'filter1',
'eg1', 'eg1',
'amp1', 'amp1',
'eg2', 'eg2',
'lfo1', 'lfo1',
'lfo2', 'lfo2',
'patches1', 'patches1',
'vco3', 'vco3',
'vco4', 'vco4',
'mixer2', 'mixer2',
'pitch2', 'pitch2',
'filter2', 'filter2',
'eg3', 'eg3',
'amp2', 'amp2',
'eg4', 'eg4',
'lfo3', 'lfo3',
'lfo4', 'lfo4',
'patches2', 'patches2',
'vco5', 'vco5',
'audioIn', 'audioIn',
'mixer3', 'mixer3',
'pitch3', 'pitch3',
'filter3', 'filter3',
'fcMod', 'fcMod',
'eg4', 'eg4',
'amp3', 'amp3',
'lfo5', 'lfo5',
'lfo6', 'lfo6',
'levels', 'levels',
'pans', 'pans',
], 'modfx',
entities: { 'delay',
'vco1': { 'eq',
id: 'vco1', ],
waveform: 'Saw', entities: {
dwgsOrModType: 'SynWave1', vco1: {
waveMod: 0, id: 'vco1',
lfoMod: 0, waveform: 'Saw',
}, dwgsOrModType: 'SynWave1',
'vco2': { waveMod: 0,
id: 'vco2', lfoMod: 0,
waveform: 'Saw', },
dwgsOrModType: 'Off', vco2: {
waveMod: 0, id: 'vco2',
lfoMod: 0, waveform: 'Saw',
}, dwgsOrModType: 'Off',
'vco3': { waveMod: 0,
id: 'vco3', lfoMod: 0,
waveform: 'Saw', },
dwgsOrModType: 'SynWave1', vco3: {
waveMod: 0, id: 'vco3',
lfoMod: 0, waveform: 'Saw',
}, dwgsOrModType: 'SynWave1',
'vco4': { waveMod: 0,
id: 'vco4', lfoMod: 0,
waveform: 'Saw', },
dwgsOrModType: 'Off', vco4: {
waveMod: 0, id: 'vco4',
lfoMod: 0, waveform: 'Saw',
}, dwgsOrModType: 'Off',
'vco5': { waveMod: 0,
id: 'vco5', lfoMod: 0,
waveform: 'Saw', },
dwgsOrModType: 'SynWave1', vco5: {
waveMod: 0, id: 'vco5',
lfoMod: 0, waveform: 'Saw',
}, dwgsOrModType: 'SynWave1',
'audioIn': { waveMod: 0,
id: 'audioIn', lfoMod: 0,
gate: 0, },
threshold: 0, audioIn: {
hpfLevel: 0, id: 'audioIn',
hpfGate: false, gate: 0,
}, threshold: 0,
'mixer1': { hpfLevel: 0,
id: 'mixer1', hpfGate: false,
vol1: 127, },
vol2: 0, mixer1: {
vol3: 0, id: 'mixer1',
}, vol1: 127,
'mixer2': { vol2: 0,
id: 'mixer2', vol3: 0,
vol1: 127, },
vol2: 0, mixer2: {
vol3: 0, id: 'mixer2',
}, vol1: 127,
'mixer3': { vol2: 0,
id: 'mixer3', vol3: 0,
vol1: 127, },
vol2: 0, mixer3: {
vol3: 0, id: 'mixer3',
}, vol1: 127,
'pitch1': { vol2: 0,
id: 'pitch1', vol3: 0,
voiceAssign: 'Mono', },
triggerMode: 'Single', pitch1: {
transpose: 0, id: 'pitch1',
tune: 0, voiceAssign: 'Mono',
unisonDetune: 0, triggerMode: 'Single',
portamento: 0, transpose: 0,
bendRange: 0, tune: 0,
vibratoIntensity: 0, unisonDetune: 0,
}, portamento: 0,
'pitch2': { bendRange: 0,
id: 'pitch2', vibratoIntensity: 0,
voiceAssign: 'Mono', },
triggerMode: 'Single', pitch2: {
transpose: 0, id: 'pitch2',
tune: 0, voiceAssign: 'Mono',
unisonDetune: 0, triggerMode: 'Single',
portamento: 0, transpose: 0,
bendRange: 0, tune: 0,
vibratoIntensity: 0, unisonDetune: 0,
}, portamento: 0,
'pitch3': { bendRange: 0,
id: 'pitch3', vibratoIntensity: 0,
voiceAssign: 'Mono', },
triggerMode: 'Single', pitch3: {
transpose: 0, id: 'pitch3',
tune: 0, voiceAssign: 'Mono',
unisonDetune: 0, triggerMode: 'Single',
portamento: 0, transpose: 0,
bendRange: 0, tune: 0,
vibratoIntensity: 0, unisonDetune: 0,
}, portamento: 0,
'filter1': { bendRange: 0,
id: 'filter1', vibratoIntensity: 0,
filterType: '-24db Low Pass', },
cutoff: 0, filter1: {
resonance: 0, id: 'filter1',
egIntensity: 0, filterType: '-24db Low Pass',
keyboardTrack: 0, cutoff: 0,
}, resonance: 0,
'filter2': { egIntensity: 0,
id: 'filter2', keyboardTrack: 0,
filterType: '-24db Low Pass', },
cutoff: 0, filter2: {
resonance: 0, id: 'filter2',
egIntensity: 0, filterType: '-24db Low Pass',
keyboardTrack: 0, cutoff: 0,
}, resonance: 0,
'filter3': { egIntensity: 0,
id: 'filter3', keyboardTrack: 0,
cutoff: 0, },
resonance: 0, filter3: {
efSense: 0, id: 'filter3',
}, cutoff: 0,
'fcMod': { resonance: 0,
id: 'fcMod', efSense: 0,
source: 'Amp EG', },
intensity: 0, fcMod: {
}, id: 'fcMod',
'eg1': { source: 'Amp EG',
id: 'eg1', intensity: 0,
attack: 0, },
decay: 0, eg1: {
sustain: 127, id: 'eg1',
release: 0, attack: 0,
egReset: false, decay: 0,
}, sustain: 127,
'amp1': { release: 0,
id: 'amp1', egReset: false,
ampLevel: 127, },
panpot: 0, amp1: {
ampTrack: 0, id: 'amp1',
distortion: false, ampLevel: 127,
}, panpot: 0,
'eg2': { ampTrack: 0,
id: 'eg2', distortion: false,
attack: 0, },
decay: 0, eg2: {
sustain: 127, id: 'eg2',
release: 0, attack: 0,
egReset: false, decay: 0,
}, sustain: 127,
'eg3': { release: 0,
id: 'eg3', egReset: false,
attack: 0, },
decay: 0, eg3: {
sustain: 127, id: 'eg3',
release: 0, attack: 0,
egReset: false, decay: 0,
}, sustain: 127,
'amp2': { release: 0,
id: 'amp2', egReset: false,
ampLevel: 127, },
panpot: 0, amp2: {
ampTrack: 0, id: 'amp2',
distortion: false, ampLevel: 127,
}, panpot: 0,
'eg4': { ampTrack: 0,
id: 'eg4', distortion: false,
attack: 0, },
decay: 0, eg4: {
sustain: 127, id: 'eg4',
release: 0, attack: 0,
egReset: false, decay: 0,
}, sustain: 127,
'eg5': { release: 0,
id: 'eg5', egReset: false,
attack: 0, },
decay: 0, eg5: {
sustain: 127, id: 'eg5',
release: 0, attack: 0,
egReset: false, decay: 0,
}, sustain: 127,
'amp3': { release: 0,
id: 'amp3', egReset: false,
ampLevel: 127, },
directLevel: 0, amp3: {
ampTrack: 0, id: 'amp3',
distortion: false, ampLevel: 127,
}, directLevel: 0,
'lfo1': { ampTrack: 0,
id: 'lfo1', distortion: false,
waveform: 'Saw', },
keySync: 'Off', lfo1: {
tempoSync: false, id: 'lfo1',
frequency: 0, waveform: 'Saw',
}, keySync: 'Off',
'lfo2': { tempoSync: false,
id: 'lfo2', frequency: 0,
waveform: 'Saw', },
keySync: 'Off', lfo2: {
tempoSync: false, id: 'lfo2',
frequency: 0, waveform: 'Saw',
}, keySync: 'Off',
'lfo3': { tempoSync: false,
id: 'lfo3', frequency: 0,
waveform: 'Saw', },
keySync: 'Off', lfo3: {
tempoSync: false, id: 'lfo3',
frequency: 0, waveform: 'Saw',
}, keySync: 'Off',
'lfo4': { tempoSync: false,
id: 'lfo4', frequency: 0,
waveform: 'Saw', },
keySync: 'Off', lfo4: {
tempoSync: false, id: 'lfo4',
frequency: 0, waveform: 'Saw',
}, keySync: 'Off',
'lfo5': { tempoSync: false,
id: 'lfo5', frequency: 0,
waveform: 'Saw', },
keySync: 'Off', lfo5: {
tempoSync: false, id: 'lfo5',
frequency: 0, waveform: 'Saw',
}, keySync: 'Off',
'lfo6': { tempoSync: false,
id: 'lfo6', frequency: 0,
waveform: 'Saw', },
keySync: 'Off', lfo6: {
tempoSync: false, id: 'lfo6',
frequency: 0, waveform: 'Saw',
}, keySync: 'Off',
'patches1': { tempoSync: false,
id: 'patches1', frequency: 0,
patch1: { },
source: 'Filter EG', patches1: {
destination: 'Pitch', id: 'patches1',
modIntensity: 0, patch1: {
}, source: 'Filter EG',
patch2: { destination: 'Pitch',
source: 'Filter EG', modIntensity: 0,
destination: 'Pitch',
modIntensity: 0,
},
patch3: {
source: 'LFO 1',
destination: 'Pitch',
modIntensity: 0,
},
patch4: {
source: 'LFO 2',
destination: 'Pitch',
modIntensity: 0,
},
},
'patches2': {
id: 'patches2',
patch1: {
source: 'Filter EG',
destination: 'Pitch',
modIntensity: 0,
},
patch2: {
source: 'Filter EG',
destination: 'Pitch',
modIntensity: 0,
},
patch3: {
source: 'LFO 1',
destination: 'Pitch',
modIntensity: 0,
},
patch4: {
source: 'LFO 2',
destination: 'Pitch',
modIntensity: 0,
},
},
'levels': {
id: 'levels',
level1: 0,
level2: 0,
level3: 0,
level4: 0,
level5: 0,
level6: 0,
level7: 0,
level8: 0
},
'pans': {
id: 'pans',
pan1: 0,
pan2: 0,
pan3: 0,
pan4: 0,
pan5: 0,
pan6: 0,
pan7: 0,
pan8: 0
}
}, },
}), patch2: {
reducers: { source: 'Filter EG',
parameterAdded: parametersAdapter.addOne, destination: 'Pitch',
parameterUpdated: parametersAdapter.updateOne, modIntensity: 0,
},
patch3: {
source: 'LFO 1',
destination: 'Pitch',
modIntensity: 0,
},
patch4: {
source: 'LFO 2',
destination: 'Pitch',
modIntensity: 0,
},
},
patches2: {
id: 'patches2',
patch1: {
source: 'Filter EG',
destination: 'Pitch',
modIntensity: 0,
},
patch2: {
source: 'Filter EG',
destination: 'Pitch',
modIntensity: 0,
},
patch3: {
source: 'LFO 1',
destination: 'Pitch',
modIntensity: 0,
},
patch4: {
source: 'LFO 2',
destination: 'Pitch',
modIntensity: 0,
},
},
levels: {
id: 'levels',
level1: 0,
level2: 0,
level3: 0,
level4: 0,
level5: 0,
level6: 0,
level7: 0,
level8: 0,
},
pans: {
id: 'pans',
pan1: 0,
pan2: 0,
pan3: 0,
pan4: 0,
pan5: 0,
pan6: 0,
pan7: 0,
pan8: 0,
},
modfx: {
id: 'modfx',
type: 'Flanger/Chorus',
lfoSpeed: 0,
effectDepth: 0,
},
delay: {
id: 'delay',
type: 'Stereo Delay',
tempoSync: false,
syncNote: '1/32',
delayTime: 0,
delayDepth: 0,
},
eq: {
id: 'eq',
lowFrequency: 40,
lowGain: 0,
highFrequency: 1.0,
highGain: 0,
},
}, },
}),
reducers: {
parameterAdded: parametersAdapter.addOne,
parameterUpdated: parametersAdapter.updateOne,
},
}); });
export const { export const {
selectById, selectById,
selectAll, selectAll,
selectEntities, selectEntities,
selectIds, selectIds,
} = parametersAdapter.getSelectors((state) => state.parameters); } = parametersAdapter.getSelectors((state) => state.parameters);
export const { parameterAdded, parameterUpdated } = parametersSlice.actions; export const { parameterAdded, parameterUpdated } = parametersSlice.actions;
+69 -63
View File
@@ -3,76 +3,82 @@ import { createSlice, createEntityAdapter } from '@reduxjs/toolkit';
const timbreAdapter = createEntityAdapter({}); const timbreAdapter = createEntityAdapter({});
const timbreSlice = createSlice({ const timbreSlice = createSlice({
name: 'timbre', name: 'timbre',
initialState: timbreAdapter.getInitialState({ initialState: timbreAdapter.getInitialState({
ids: ['timbre1', 'timbre2', 'vocoder', 'effects', 'arpeggiator'], ids: ['timbre1', 'timbre2', 'vocoder', 'effects', 'arpeggiator'],
entities: { entities: {
'timbre1': { timbre1: {
id: 'timbre1', id: 'timbre1',
vco1: 'vco1', vco1: 'vco1',
vco2: 'vco2', vco2: 'vco2',
mixer: 'mixer1', mixer: 'mixer1',
pitch: 'pitch1', pitch: 'pitch1',
filter: 'filter1', filter: 'filter1',
eg1: 'eg1', eg1: 'eg1',
amp: 'amp1', amp: 'amp1',
eg2: 'eg2', eg2: 'eg2',
lfo1: 'lfo1', lfo1: 'lfo1',
lfo2: 'lfo2', lfo2: 'lfo2',
patches: 'patches1', patches: 'patches1',
}, },
'timbre2': { timbre2: {
id: 'timbre2', id: 'timbre2',
vco1: 'vco3', vco1: 'vco3',
vco2: 'vco4', vco2: 'vco4',
mixer: 'mixer2', mixer: 'mixer2',
pitch: 'pitch2', pitch: 'pitch2',
filter: 'filter2', filter: 'filter2',
eg1: 'eg3', eg1: 'eg3',
amp: 'amp2', amp: 'amp2',
eg2: 'eg4', eg2: 'eg4',
lfo1: 'lfo3', lfo1: 'lfo3',
lfo2: 'lfo4', lfo2: 'lfo4',
patches: 'patches2', patches: 'patches2',
}, },
'vocoder': { vocoder: {
id: 'vocoder', id: 'vocoder',
vco: 'vco5', vco: 'vco5',
audioIn: 'audioIn', audioIn: 'audioIn',
mixer: 'mixer3', mixer: 'mixer3',
pitch: 'pitch3', pitch: 'pitch3',
filter: 'filter3', filter: 'filter3',
fcMod: 'fcMod', fcMod: 'fcMod',
eg: 'eg5', eg: 'eg5',
amp: 'amp3', amp: 'amp3',
lfo1: 'lfo5', lfo1: 'lfo5',
lfo2: 'lfo6', lfo2: 'lfo6',
levels: 'levels', levels: 'levels',
pans: 'pans' pans: 'pans',
}, },
}, effects: {
currentTimbre: 'timbre1', id: 'effects',
}), modfx: 'modfx',
reducers: { delay: 'delay',
timbreCurrentUpdate(state, action) { eq: 'eq',
state.currentTimbre = action.payload; },
},
timbreAdded: timbreAdapter.addOne,
timbreUpdated: timbreAdapter.updateOne,
}, },
currentTimbre: 'timbre1',
}),
reducers: {
timbreCurrentUpdate(state, action) {
state.currentTimbre = action.payload;
},
timbreAdded: timbreAdapter.addOne,
timbreUpdated: timbreAdapter.updateOne,
},
}); });
export const { export const {
selectById, selectById,
selectAll, selectAll,
selectEntities, selectEntities,
selectIds, selectIds,
} = timbreAdapter.getSelectors((state) => state.timbres); } = timbreAdapter.getSelectors((state) => state.timbres);
export const { export const {
timbreCurrentUpdate, timbreCurrentUpdate,
timbreAdded, timbreAdded,
timbreUpdated, timbreUpdated,
} = timbreSlice.actions; } = timbreSlice.actions;
export default timbreSlice.reducer; export default timbreSlice.reducer;
+31 -26
View File
@@ -1,35 +1,40 @@
import React from 'react'; import React from 'react';
import Timbre from './Timbre'; import Timbre from './Timbre';
import Vocoder from './Vocoder'; import Vocoder from './Vocoder';
import Effects from './Effects';
import { Tab, Tabs, TabList, TabPanel } from 'react-tabs'; import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
import styles from './Timbre.module.css'; import styles from './Timbre.module.css';
export default function TimbreSwitcher(props) { export default function TimbreSwitcher(props) {
return ( return (
<div className={styles.tabs}> <div className={styles.tabs}>
<Tabs <Tabs
className={styles.tabs} className={styles.tabs}
defaultIndex="0" defaultIndex="0"
selectedTabClassName={styles.selected} selectedTabClassName={styles.selected}
selectedTabPanelClassName={styles.tabPanel}> selectedTabPanelClassName={styles.tabPanel}
<TabList className={styles.tabList}> >
<Tab className={styles.tab}>Timbre 1</Tab> <TabList className={styles.tabList}>
<Tab className={styles.tab}>Timbre 2</Tab> <Tab className={styles.tab}>Timbre 1</Tab>
<Tab className={styles.tab}>Vocoder</Tab> <Tab className={styles.tab}>Timbre 2</Tab>
<Tab className={styles.tab}>Effects</Tab> <Tab className={styles.tab}>Vocoder</Tab>
<Tab className={styles.tab}>Arpeggio</Tab> <Tab className={styles.tab}>Effects</Tab>
</TabList> <Tab className={styles.tab}>Arpeggio</Tab>
</TabList>
<TabPanel> <TabPanel>
<Timbre id="timbre1" /> <Timbre id="timbre1" />
</TabPanel> </TabPanel>
<TabPanel> <TabPanel>
<Timbre id="timbre2" /> <Timbre id="timbre2" />
</TabPanel> </TabPanel>
<TabPanel> <TabPanel>
<Vocoder id="vocoder" /> <Vocoder id="vocoder" />
</TabPanel> </TabPanel>
</Tabs> <TabPanel>
</div> <Effects id="effects" />
); </TabPanel>
</Tabs>
</div>
);
} }