Skip to content

Commit e848e4c

Browse files
committed
extracted useRotary
1 parent 2ca72bc commit e848e4c

File tree

11 files changed

+193
-92
lines changed

11 files changed

+193
-92
lines changed

src/App/App.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import { SequencerPage } from './Sequencer/Sequencer';
1111
import { ChangeKit } from './Sequencer/MainSection/ChangeKit/ChangeKit';
1212
import { LoadSave } from './Sequencer/LoadSave/LoadSave';
1313
import { LoginPage } from './Login/LoginPage';
14-
import { Mixer } from './Sequencer/MainSection/Mixer/Mixer';
14+
import { GlobalMixer } from './Sequencer/MainSection/Mixer/GlobalMixer';
15+
import { SampleMixer } from './Sequencer/MainSection/Mixer/SampleMixer';
1516
import { PATHS } from 'hooks/useGoTo';
1617

1718
export default function App() {
@@ -33,7 +34,8 @@ const AppContent = () => {
3334
<Route path='/' exact render={() => <Redirect to={PATHS.BASE} />} />
3435
<Route path='/sequencer/:shared' component={SequencerPage} />
3536
<Route path={PATHS.CHANGE_KIT} component={ChangeKit} />
36-
<Route path={PATHS.MIXER} component={Mixer}/>
37+
<Route path={PATHS.GLOBAL_MIXER} component={GlobalMixer}/>
38+
<Route path={PATHS.SAMPLE_MIXER} component={SampleMixer}/>
3739
<Route path={PATHS.LOAD} render={() => <LoadSave tab='load' />} />
3840
<Route path={PATHS.SAVE} render={() => <LoadSave tab='save' />} />
3941
<Route path={PATHS.LOGIN} component={LoginPage} />
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { mainBus } from 'App/Tone';
2+
import { Portal } from 'App/shared/Portal';
3+
import { useEffect, useRef, useState } from 'react';
4+
import { ArrowUpDownIcon } from 'assets/icons';
5+
import { useTouchAndMouse } from 'hooks/useTouchAndMouse';
6+
import { Knob } from './Knob';
7+
8+
export const GlobalMixer = () => {
9+
return null;
10+
// return (
11+
// <Portal targetId='overGridPortal'>
12+
// <div id='mixer' className='mixer'>
13+
// <div className='mixItemWrapper'>
14+
// {Object.entries(mainBus.mixer).map(([property, node], i) => {
15+
// console.log(property, node);
16+
// return <MixItem key={`mixItem${i}`} property={property} node={node} />;
17+
// })}
18+
// </div>
19+
// </div>
20+
// </Portal>
21+
// );
22+
};
23+
24+
// const MixItem = ({ property, node }) => {
25+
26+
// const id = `globalMixItem${property}`;
27+
// const knobId = `${id}Knob`;
28+
// return (
29+
// <div id={id} className='mixItem'>
30+
// <p className='mixItemName'>{property}</p>
31+
// <div className='knobWrapper'>
32+
// <div className='knob' id={knobId} {...touchAndMouse}>
33+
// <label htmlFor={knobId}>
34+
// <ArrowUpDownIcon />
35+
// </label>
36+
// <Knob value={value} />
37+
// </div>
38+
// </div>
39+
// </div>
40+
// );
41+
// };

src/App/Sequencer/MainSection/Mixer/Mixer.js renamed to src/App/Sequencer/MainSection/Mixer/SampleMixer.js

Lines changed: 31 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
import cuid from 'cuid';
21
import React, { useEffect, useRef, useState } from 'react';
32
import { Portal } from 'App/shared/Portal';
43
import { getGrid } from 'utils/getGrid';
54
import { useTouchAndMouse } from 'hooks/useTouchAndMouse';
65
import { Knob } from './Knob';
76
import { Kit, FX } from 'App/Tone';
87
import { ArrowUpDownIcon, ChevronDownIcon } from 'assets/icons';
8+
import { useRotaryKnob } from 'hooks/useRotaryKnob';
99

10-
export const Mixer = () => {
10+
export const SampleMixer = () => {
1111
const grid = getGrid(9);
1212
return (
1313
<Portal targetId='overGridPortal'>
1414
<div id='mixer' className='mixer'>
15-
<div className='mixSamples'>
15+
<div className='mixItemWrapper mixSamples'>
1616
{grid.map((i) => {
17-
return <MixSample key={`mixSample${i}`} i={i} />;
17+
return <MixSample key={`mixItem${i}`} i={i} />;
1818
})}
1919
</div>
2020
</div>
@@ -27,25 +27,21 @@ const MixSample = ({ i }) => {
2727
const sample = Kit.samples[i];
2828

2929
const [property, setProperty] = useState('volume');
30-
const { value, startFunc, moveFunc, endFunc } = useRotaryKnob(sample, property);
31-
const touchAndMouse = useTouchAndMouse(startFunc, moveFunc, endFunc);
32-
useApplyValue(sample, property, value);
30+
const initialVal = getInitialValue(sample, property);
3331

3432
const onChange = ({ target: { value } }) => setProperty(value);
3533

36-
const id = `mixSample${i}`;
34+
const id = `mixItem${i}`;
3735
const knobId = id + property;
3836
return (
39-
<div id={id} className='mixSample'>
40-
<p className='sampleName'>{sample.name}</p>
41-
<div className='knobWrapper'>
42-
<div className='knob' id={knobId} {...touchAndMouse}>
43-
<label htmlFor={knobId}>
44-
<ArrowUpDownIcon />
45-
</label>
46-
<Knob value={value} />
47-
</div>
48-
</div>
37+
<div id={id} className='mixItem'>
38+
<p className='mixItemName'>{sample.name}</p>
39+
<RotaryKnob
40+
property={property}
41+
sample={sample}
42+
initialVal={initialVal}
43+
knobId={knobId}
44+
/>
4945
<div className='customSelectWrapper'>
5046
<select
5147
id='mixerSelect'
@@ -65,67 +61,40 @@ const MixSample = ({ i }) => {
6561
</select>
6662
<ChevronDownIcon />
6763
</div>
68-
<div className={`mixSampleBorder border${i}`} />
64+
<div className={`mixItemBorder border${i}`} />
6965
</div>
7066
);
7167
};
7268

73-
const useApplyValue = (sample, property, value) => {
69+
const RotaryKnob = ({ property, sample, initialVal, knobId }) => {
70+
const { value, startFunc, moveFunc, endFunc } = useRotaryKnob(initialVal);
71+
const touchAndMouse = useTouchAndMouse(startFunc, moveFunc, endFunc);
72+
7473
const prevPropertyRef = useRef(null);
7574
useEffect(() => {
7675
if (prevPropertyRef.current !== property) return (prevPropertyRef.current = property);
7776
if (property === 'volume') {
7877
let newVal = (value - 100) * 0.25;
79-
console.log(newVal);
8078
return (sample.channel.volume.value = newVal);
8179
}
8280
if (property === 'pan') return (sample.channel.pan.value = (value - 50) / 100);
8381
sample[property].set({ gain: value / 100 });
8482
}, [property, sample, value]);
85-
};
86-
87-
const useRotaryKnob = (sample, property) => {
88-
const [value, setValue] = useState(getValue(sample, property));
89-
useEffect(() => {
90-
setValue(getValue(sample, property));
91-
}, [property, sample]);
92-
93-
const prevYRef = useRef(null);
9483

95-
const startFunc = (e) => {
96-
prevYRef.current = getY(e);
97-
};
98-
const moveFunc = (e) => {
99-
const newY = getY(e);
100-
let amount = getKnobAmount(newY, prevYRef.current);
101-
prevYRef.current = newY;
102-
setValue((value) => {
103-
let newVal = value + amount;
104-
if (newVal < 0) newVal = 0;
105-
if (newVal > 100) newVal = 100;
106-
return newVal;
107-
});
108-
};
109-
const endFunc = () => {
110-
prevYRef.current = null;
111-
};
112-
113-
return { value, startFunc, moveFunc, endFunc };
114-
};
115-
116-
const getY = (e) => {
117-
let y;
118-
if (e.touches) y = e.touches[0].clientY;
119-
else y = e.clientY;
120-
return y;
121-
};
122-
123-
const getKnobAmount = (newY, prevY) => {
124-
let amount = prevY - newY;
125-
return amount;
84+
return (
85+
<div className='knobWrapper'>
86+
<div className='knob' id={knobId} {...touchAndMouse}>
87+
<label htmlFor={knobId}>
88+
<ArrowUpDownIcon />
89+
</label>
90+
<Knob value={value} />
91+
</div>
92+
</div>
93+
);
12694
};
12795

128-
const getValue = (sample, property) => {
96+
const getInitialValue = (sample, property) => {
97+
console.log(sample, property);
12998
if (property === 'volume') {
13099
let value = sample.channel.volume.value * 4 + 100;
131100
if (value > 100) value = 100;

src/App/Sequencer/MainSection/Mixer/_mixer.scss

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
@extend %fullAbs;
88
@extend %bg90;
99

10-
.mixSamples {
10+
.mixItemWrapper {
1111
@extend %full;
1212
@include grid(3, 3, 5px);
1313
padding: 0.25rem;
1414

15-
.mixSample {
15+
.mixItem {
1616
padding: 0.5rem;
1717
@extend %full;
1818
@extend %borderHalf;
@@ -23,11 +23,11 @@
2323
// border: 1px solid red;
2424
}
2525

26-
.sampleName {
26+
.mixItemName {
2727
text-transform: capitalize;
2828
}
2929

30-
.mixSampleBorder {
30+
.mixItemBorder {
3131
@extend %noEventsLayerAbs;
3232
top: 0;
3333
left: 0;
@@ -37,7 +37,7 @@
3737

3838
&.flash,
3939
&.pulse {
40-
.mixSampleBorder {
40+
.mixItemBorder {
4141
transition: none;
4242
opacity: 1;
4343
}

src/App/Sequencer/MenuBar/MenuBar.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { TransportPanel } from './MenuItems/Transport/TransportPanel';
33
import { UndoRedoBtn } from './MenuItems/UndoRedoBtn';
44
import { EraseBtn } from './MenuItems/EraseBtn';
55
import { FileBtn } from './MenuItems/FileBtn';
6-
import { KitBtn, MixerBtn } from './MenuItems/OpenPathBtn';
6+
import { KitBtn } from './MenuItems/OpenPathBtn';
7+
import { MixerMenu } from './MenuItems/MixerMenu';
78
import { TapMenu } from './MenuItems/TapMenu';
89
import { DisplayMenu } from './MenuItems/DisplayMenu/DisplayMenu';
910
import { useSelector } from 'react-redux';
@@ -22,7 +23,7 @@ export const MenuBar = () => {
2223
<DisplayMenu />
2324
<FileBtn />
2425
<KitBtn />
25-
<MixerBtn />
26+
<MixerMenu />
2627
</div>
2728
<TransportPanel />
2829
<div className='menuItems'>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { MODES, setMode } from 'App/reducers/editorSlice';
2+
import { MenuItem, PopupMenu } from 'App/shared/PopupMenu/PopupMenu';
3+
import { MixerIcon } from 'assets/icons';
4+
import { useGoTo, useCurrentPath } from 'hooks/useGoTo';
5+
import { useDispatch } from 'react-redux';
6+
7+
export const MixerMenu = () => {
8+
return (
9+
<PopupMenu name='mixer' Icon={MixerIcon}>
10+
<MixerMenuItems />
11+
</PopupMenu>
12+
);
13+
};
14+
15+
export const MixerMenuItems = () => {
16+
const dispatch = useDispatch();
17+
const goTo = useGoTo();
18+
const { mixingGlobal, mixingSamples } = useCurrentPath();
19+
const openPath = (path) => goTo[path](() => dispatch(setMode(MODES.TAP)));
20+
return (
21+
<>
22+
<MenuItem
23+
item={'Global'}
24+
selected={mixingGlobal}
25+
onClick={() => openPath('globalMixer')}
26+
/>
27+
<MenuItem
28+
item={'Samples'}
29+
selected={mixingSamples}
30+
onClick={() => openPath('sampleMixer')}
31+
/>
32+
</>
33+
);
34+
};

src/App/Sequencer/MenuBar/MenuItems/OpenPathBtn.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { useMemo } from 'react';
22
import { useDispatch } from 'react-redux';
33
import { Button } from 'App/shared/Button';
4-
import { KitIcon, MixerIcon } from 'assets/icons';
4+
import { KitIcon } from 'assets/icons';
55
import { MODES, setMode } from 'App/reducers/editorSlice';
66
import { useGoTo, useCurrentPath } from 'hooks/useGoTo';
77
import { useStopPropEventListener } from 'hooks/useStopPropEventListener';
@@ -42,8 +42,3 @@ export const KitBtn = () => {
4242
const { selectingKit } = useCurrentPath();
4343
return <OpenPathBtn active={selectingKit} path='changeKit' label='kit' Icon={KitIcon} />;
4444
};
45-
46-
export const MixerBtn = () => {
47-
const { mixing } = useCurrentPath();
48-
return <OpenPathBtn active={mixing} path='mixer' label='mixer' Icon={MixerIcon} />;
49-
};

src/App/Tone/index.js

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,39 @@ const initialClick = async () => {
1212
document.addEventListener('touchstart', initialClick);
1313
document.addEventListener('mousedown', initialClick);
1414

15+
export const fft = new Tone.FFT({
16+
size: 32,
17+
normalRange: true,
18+
});
19+
1520
const limiter = new Tone.Limiter(-20);
16-
const mainBus = new Tone.Channel({ volume: -6, pan: 0, channelCount: 2 }).chain(
21+
const output = new Tone.Channel({ volume: -6, pan: 0, channelCount: 2 }).chain(
1722
limiter,
1823
Tone.Destination
1924
);
25+
2026
const fxFilter = new Tone.Filter(240, 'highpass', -12);
2127
const fxBus = new Tone.Channel({ volume: 0, pan: 0, channelCount: 2 }).chain(
2228
fxFilter,
23-
mainBus
29+
output
2430
);
2531

26-
export const fft = new Tone.FFT({
27-
size: 32,
28-
normalRange: true,
29-
});
30-
31-
export const filter = new Tone.Filter(20000, 'lowpass', -24);
32-
export const pitchShift = new Tone.PitchShift();
33-
export const envelope = new Tone.AmplitudeEnvelope();
32+
export const mainBus = new Tone.Channel({ volume: -6, pan: 0, channelCount: 2 }).connect(
33+
output
34+
);
35+
mainBus.mixer = { volume: mainBus.volume };
36+
mainBus.mixer.delay = new Tone.Gain(0).chain(
37+
new Tone.PingPongDelay({
38+
delayTime: '.8n',
39+
feedback: 0.2,
40+
wet: 1,
41+
}),
42+
fxBus
43+
);
44+
mainBus.mixer.reverb = new Tone.Gain(0).chain(new Tone.Reverb({ decay: 2, wet: 1 }), fxBus);
45+
mainBus.mixer.filter = new Tone.Filter(20000, 'lowpass', -24).connect(fxBus);
46+
mainBus.mixer['pitch shift'] = new Tone.PitchShift().connect(fxBus);
47+
mainBus.mixer['envelope'] = new Tone.AmplitudeEnvelope().connect(fxBus);
3448

3549
export const FX = {
3650
'delay 1\u204416': new Tone.PingPongDelay({

src/App/shared/PopupMenu/usePopupMenu.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,15 @@ export const usePopupMenu = (keepOpenOnSelect) => {
4141
}
4242
}
4343
document.removeEventListener('click', closeMenu);
44-
document.getElementById('menuBar').removeEventListener('scroll', closeMenu);
44+
document.getElementById('menuBar')?.removeEventListener('scroll', closeMenu);
4545
setShowMenu(false);
4646
};
4747

4848
const onClick = (e) => {
4949
e.stopPropagation();
5050
if (!showMenu) {
5151
document.addEventListener('click', closeMenu);
52-
document.getElementById('menuBar').addEventListener('scroll', closeMenu);
52+
document.getElementById('menuBar')?.addEventListener('scroll', closeMenu);
5353
}
5454
setShowMenu(!showMenu);
5555
};

0 commit comments

Comments
 (0)