Skip to content

Commit 6ebdfd5

Browse files
authored
Merge pull request #14 from gallegretti/volume-mixer
Simple audio mixer
2 parents f17a49f + 8e5b270 commit 6ebdfd5

File tree

8 files changed

+143
-4
lines changed

8 files changed

+143
-4
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { Slider } from "@mui/material";
2+
import { Track } from "../../alphatab-types/alphatab-types";
3+
import styled from "@emotion/styled";
4+
import { useEffect, useState } from "react";
5+
6+
interface AudioMixerTrack {
7+
track: Track;
8+
onVolumeChange: (track: Track, volume: number) => void;
9+
}
10+
11+
const AudioMixerLayout = styled('div')({
12+
display: 'flex',
13+
flexDirection: 'column',
14+
alignItems: 'center',
15+
height: '300px',
16+
width: '200px'
17+
});
18+
19+
const AudioMixerTrackName = styled('p')({
20+
height: '120px',
21+
textAlign: 'center'
22+
});
23+
24+
const VerticalVolumeSlider = styled(Slider)({
25+
'& .MuiSlider-thumb': {
26+
borderRadius: '2px',
27+
height: '10px'
28+
},
29+
})
30+
31+
export function AudioMixerTrack(props: AudioMixerTrack) {
32+
const [volumeState, setVolumeState] = useState(props.track.playbackInfo.volume);
33+
34+
useEffect(() => {
35+
props.track.playbackInfo.volume = volumeState;
36+
props.onVolumeChange(props.track, volumeState);
37+
}, [volumeState]);
38+
39+
return (
40+
<AudioMixerLayout>
41+
<AudioMixerTrackName>{props.track.name}</AudioMixerTrackName>
42+
<VerticalVolumeSlider
43+
min={0}
44+
max={16}
45+
marks
46+
value={volumeState}
47+
onChange={(_, volume) => setVolumeState(volume as number)}
48+
orientation="vertical"
49+
/>
50+
</AudioMixerLayout>
51+
);
52+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { Dialog } from "@mui/material";
2+
import { Score, Track } from "../../alphatab-types/alphatab-types";
3+
import styled from "@emotion/styled";
4+
import { AudioMixerTrack } from "./audio-mixer-track";
5+
6+
interface AudioMixerProps {
7+
isOpen: boolean;
8+
onClose: () => void;
9+
onVolumeChange: (track: Track, volume: number) => void;
10+
score: Score;
11+
}
12+
13+
const TrackLayout = styled('div')({
14+
display: 'flex',
15+
height: '360px'
16+
});
17+
18+
export function DialogAudioMixer(props: AudioMixerProps) {
19+
return (
20+
<Dialog
21+
open={props.isOpen}
22+
onClose={props.onClose}
23+
>
24+
<TrackLayout>
25+
{props.score.tracks.map((track) => (
26+
<AudioMixerTrack key={track.index} track={track} onVolumeChange={props.onVolumeChange} />
27+
))}
28+
</TrackLayout>
29+
</Dialog>
30+
);
31+
}

src/editor-skeleton/alphatab-viewport/alphatab-viewport.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const AlphaTabContainer = styled('div')`
1616
overflow-y: auto;
1717
position: absolute;
1818
top: 96px;
19-
left: 120px;
19+
left: 140px;
2020
right: 0;
2121
bottom: 0;
2222
padding-right: 20px;

src/editor-skeleton/editor-left-menu.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const SideMenuDiv = styled('div')(({ theme }) => ({
1111
top: 0,
1212
left: 0,
1313
bottom: 0,
14-
width: '120px',
14+
width: '140px',
1515
display: 'flex',
1616
alignContent: 'stretch',
1717
zIndex: '1001',

src/editor-skeleton/editor-player-controls/editor-player-controls.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ import MetronomeGlyph from '@glyphs/player-controls/metronome';
66
import RepeatGlyph from '@glyphs/player-controls/repeat';
77
import VolumeControlComponent from './volume-control';
88
import EditorPlayerSpeedComponent from './editor-player-speed';
9+
import AudioMixerGlyph from '@glyphs/player-controls/audio-mixer';
910

1011
interface EditorPlayerControlsProps {
1112
playPause: () => void;
1213
isPlaying: boolean;
1314
isCountIn: boolean;
1415
isMetronome: boolean;
1516
isLooping: boolean;
17+
onOpenVolumeMixer: () => void;
1618
onLoopingChange: (isLooping: boolean) => void;
1719
onCountInChange: (countIn: boolean) => void;
1820
onMetronomeChange: (metronome: boolean) => void;
@@ -65,7 +67,9 @@ export default function EditorPlayerControls(props: EditorPlayerControlsProps) {
6567

6668
return (
6769
<EditorPlayerControlsDiv>
68-
<EditorPlayerControlsLeft />
70+
<EditorPlayerControlsLeft>
71+
<AudioMixerGlyph onClick={props.onOpenVolumeMixer} selected={false} disabled={false} />
72+
</EditorPlayerControlsLeft>
6973
<EditorPlayerControlsMid>
7074
<PlayPauseGlyph selected={props.isPlaying} onClick={props.playPause} disabled={false} />
7175
</EditorPlayerControlsMid>

src/editor-skeleton/editor.tsx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import EditorActionDispatcher from '../editor/editor-action-dispatcher';
2424
import EditorScoreState from '../editor/editor-score-state';
2525
import exportGuitarPro from './editor-export/export-guitar-pro';
2626
import exportMidi from './editor-export/export-midi';
27+
import { DialogAudioMixer } from '@dialogs/dialog-audio-mixer/dialog-audio-mixer';
28+
import useDialog from '@hooks/use-dialog';
2729

2830
function useForceUpdate() {
2931
const [_, setValue] = useState(0); // integer state
@@ -56,7 +58,7 @@ const AppContent = styled('div')({
5658

5759
const AppEditorControls = styled('div')({
5860
position: 'absolute',
59-
left: '120px',
61+
left: '140px',
6062
right: 0,
6163
zIndex: 999,
6264
})
@@ -202,6 +204,12 @@ export default function Editor({ hasDialog }: { hasDialog: boolean }) {
202204

203205
const score = (): Score | null => api?.score ?? null;
204206

207+
const setTrackVolume = (track: Track, volume: number) => {
208+
if (api) {
209+
api.changeTrackVolume([track], volume);
210+
}
211+
}
212+
205213
const setVolume = (volume: number) => {
206214
if (api) {
207215
api.masterVolume = volume;
@@ -243,8 +251,22 @@ export default function Editor({ hasDialog }: { hasDialog: boolean }) {
243251
editorActions.clearUndoAndRedoHistory();
244252
};
245253

254+
const {
255+
openDialog: openAudioMixerDialog,
256+
closeDialog: closeAudioMixerDialog,
257+
isDialogOpen: isAudioMixerDialogOpen
258+
} = useDialog();
259+
246260
return (
247261
<AppContainer>
262+
{api?.score && (
263+
<DialogAudioMixer
264+
isOpen={isAudioMixerDialogOpen}
265+
onClose={closeAudioMixerDialog}
266+
score={api.score}
267+
onVolumeChange={setTrackVolume}
268+
/>
269+
)}
248270
<AppContent>
249271
<EditorLeftMenu
250272
tracks={api?.score?.tracks ?? null}
@@ -290,6 +312,7 @@ export default function Editor({ hasDialog }: { hasDialog: boolean }) {
290312
onCountInChange={setCountIn}
291313
onMetronomeChange={setMetronome}
292314
onLoopingChange={setIsLooping}
315+
onOpenVolumeMixer={openAudioMixerDialog}
293316
isCountIn={api?.countInVolume !== 0}
294317
isMetronome={api?.metronomeVolume !== 0}
295318
isPlaying={api?.playerState === 1}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* eslint-disable max-len */
2+
import React from 'react';
3+
import { Tooltip } from '@mui/material';
4+
import { useTranslation } from 'react-i18next';
5+
import { DynamicGlyphProps } from '../dynamics/dynamic';
6+
import { useGlyphColor } from '../glyphColor';
7+
import baseSvgStyle from '../glyphBaseSvgStyle';
8+
9+
export default function AudioMixerGlyph(props: DynamicGlyphProps) {
10+
const color = useGlyphColor(props);
11+
const { t } = useTranslation();
12+
return (
13+
<Tooltip title={t('Audio Mixer')}>
14+
<svg onClick={props.onClick} style={baseSvgStyle(props)} height="28px" width="28px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink"
15+
viewBox="0 0 64 64" xmlSpace="preserve">
16+
<line fill="none" stroke={color} stroke-width="2" stroke-miterlimit="10" x1="12" y1="19" x2="12" y2="64" />
17+
<line fill="none" stroke={color} stroke-width="2" stroke-miterlimit="10" x1="52" y1="0" x2="52" y2="45" />
18+
<line fill="none" stroke={color} stroke-width="2" stroke-miterlimit="10" x1="32" y1="38" x2="32" y2="64" />
19+
<line fill="none" stroke={color} stroke-width="2" stroke-miterlimit="10" x1="32" y1="0" x2="32" y2="26" />
20+
<circle fill="none" stroke={color} stroke-width="2" stroke-miterlimit="10" cx="12" cy="13" r="6" />
21+
<circle fill="none" stroke={color} stroke-width="2" stroke-miterlimit="10" cx="52" cy="51" r="6" />
22+
<circle fill="none" stroke={color} stroke-width="2" stroke-miterlimit="10" cx="32" cy="32" r="6" />
23+
<line fill="none" stroke={color} stroke-width="2" stroke-miterlimit="10" x1="12" y1="0" x2="12" y2="7" />
24+
<line fill="none" stroke={color} stroke-width="2" stroke-miterlimit="10" x1="52" y1="57" x2="52" y2="64" />
25+
</svg>
26+
</Tooltip>
27+
);
28+
}

src/i18n.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ const resources: Resource = {
190190
'move_cursor_previous_bar': 'Mover cursor para a barra anterior',
191191
'move_cursor_previous_bar_shortcut': 'Ctrl + Seta para esquerda',
192192
},
193+
'Audio Mixer': 'Mixer de Áudio',
193194
'How long the note should be played': 'Por quanto tempo a nota deve ser tocada',
194195
'How strong the note should be played': 'Quão forte a nota deve ser tocada',
195196
'Getting started': 'Básico',

0 commit comments

Comments
 (0)