Skip to content

Commit

Permalink
Add sound dropdown and fix a duplicate listener bug
Browse files Browse the repository at this point in the history
  • Loading branch information
ZaneH committed Oct 9, 2022
1 parent b42bbac commit 72315fb
Show file tree
Hide file tree
Showing 13 changed files with 1,478 additions and 1,391 deletions.
3 changes: 1 addition & 2 deletions .taurignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
*

!src/**/*
!src-tauri/**/*
!src/**/*
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ Learn to play the piano at your own pace through various modes of practice. [Wat
## Coming Soon

- [ ] Interactive inversion practice
- [ ] Change audio output (ASIO?)
- [ ] Settings
- [ ] Toggle questions in quiz mode
- [ ] Change keyboard sound
- [x] Change keyboard sound

# Releases

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
]
},
"devDependencies": {
"@tauri-apps/cli": "1.0.5",
"@tauri-apps/cli": "1.1.1",
"@types/prettier": "^2.6.3",
"@types/styled-components": "^5.1.25",
"@types/testing-library__jest-dom": "^5.14.5",
Expand Down
6 changes: 3 additions & 3 deletions src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
},
"package": {
"productName": "Piano Trainer",
"version": "1.0.14"
"version": "1.1.0"
},
"tauri": {
"allowlist": {
Expand Down Expand Up @@ -61,10 +61,10 @@
"windows": [
{
"fullscreen": false,
"height": 600,
"height": 650,
"resizable": true,
"title": "Piano Trainer",
"width": 800
"width": 900
}
]
}
Expand Down
11 changes: 7 additions & 4 deletions src/components/KVProvider/KVProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
useState,
} from 'react'
import { useTranslation } from 'react-i18next'
import { InstrumentName } from 'soundfont-player'
import { Store } from 'tauri-plugin-store-api'
import { AVAILABLE_SETTINGS, MidiDevice, PTSettingsKeyType } from '../../utils'
import {
Expand All @@ -20,15 +21,15 @@ type KVContextType = {
children?: React.ReactNode

isLoading?: boolean
pianoSound?: string
pianoSound?: InstrumentName
showKeyboard?: boolean
muteSound?: boolean
midiDevice?: MidiDevice
language?: SupportedLanguagesType
isSentryOn?: boolean

setIsLoading?: Dispatch<SetStateAction<boolean>>
setPianoSound?: Dispatch<SetStateAction<string>>
setPianoSound?: Dispatch<SetStateAction<InstrumentName>>
setShowKeyboard?: Dispatch<SetStateAction<boolean>>
setMuteSound?: Dispatch<SetStateAction<boolean>>
setMidiDevice?: Dispatch<SetStateAction<MidiDevice>>
Expand All @@ -47,7 +48,9 @@ export const KVContext = createContext({} as KVContextType)
const KVProvider: FC<KVContextType> = ({ children }) => {
const store = useMemo(() => new Store('.settings.dat'), [])
const [isLoading, setIsLoading] = useState(true)
const [pianoSound, setPianoSound] = useState('acoustic_grand_piano')
const [pianoSound, setPianoSound] = useState(
'acoustic_grand_piano' as InstrumentName
)
const [showKeyboard, setShowKeyboard] = useState(true)
const [muteSound, setMuteSound] = useState(false)
const [midiDevice, setMidiDevice] = useState<MidiDevice>({
Expand All @@ -67,7 +70,7 @@ const KVProvider: FC<KVContextType> = ({ children }) => {
if (value === null) return
switch (key) {
case 'piano-sound':
setPianoSound(String(value))
setPianoSound(value as InstrumentName)
break
case 'show-keyboard':
setShowKeyboard(Boolean(value))
Expand Down
7 changes: 4 additions & 3 deletions src/components/Keyboard/Keyboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import 'react-piano/dist/styles.css'
import styled, { css } from 'styled-components'
import {
getFifthFromMidiNumber,
getTriadChordFromMidiNumber,
getSeventhChordFromMidiNumber,
getTriadChordFromMidiNumber,
MidiDevice,
midiNumberToNote,
swapNoteWithSynonym,
Expand All @@ -35,7 +35,8 @@ const Keyboard = () => {
setChordStack,
scale,
} = useContext(TrainerContext)
const { muteSound, showKeyboard, midiDevice, setMidiDevice } =

const { muteSound, showKeyboard, midiDevice, setMidiDevice, pianoSound } =
useContext(KVContext)
const unlistenRef = useRef<UnlistenFn>()
const [activeNotes, setActiveNotes] = useState<{ [note: string]: boolean }>(
Expand Down Expand Up @@ -206,7 +207,7 @@ const Keyboard = () => {

return (
<SoundfontProvider
instrumentName={'acoustic_grand_piano'}
instrumentName={pianoSound || 'acoustic_grand_piano'}
hostname={'https://d1pzp51pvbm36p.cloudfront.net'}
format={'mp3'}
soundfont={'MusyngKite'}
Expand Down
68 changes: 26 additions & 42 deletions src/components/Quiz/Quiz.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const KeyboardContainer = styled.div`
`

const Quiz = () => {
const { showKeyboard, muteSound, midiDevice, setMidiDevice } =
const { showKeyboard, muteSound, midiDevice, setMidiDevice, pianoSound } =
useContext(KVContext)
const { chordStack, setChordStack } = useContext(TrainerContext)
const unlistenRef = useRef<UnlistenFn>()
Expand Down Expand Up @@ -157,10 +157,6 @@ const Quiz = () => {
setMidiDevice?.(foundMidi || { id: 0 })
}, [setListeningIdx, midiDevice, setMidiDevice, listeningIdx, setChordStack])

useEffect(() => {
onLoadCallback()
}, [onLoadCallback])

const gotoNextQuestion = useCallback(() => {
setActiveNotes({})
setCurrentQuestion(() => {
Expand Down Expand Up @@ -334,43 +330,31 @@ const Quiz = () => {
{currentQuestion.type === 'fifth' && fifthAnswers}
</QuizOptionsContainer>
{showKeyboard && currentQuestion.type === 'key' && (
<SoundfontProvider
instrumentName={'acoustic_grand_piano'}
hostname={'https://d1pzp51pvbm36p.cloudfront.net'}
format={'mp3'}
soundfont={'MusyngKite'}
onLoad={() => {}}
render={({ playNote, stopNote }) => (
<KeyboardContainer>
<Piano
noteRange={{ first: firstNote, last: lastNote }}
playNote={(midiNumber: number) => {
setActiveNotes((an) => ({ ...an, [midiNumber]: true }))
setChordStack?.((cs) => [...cs, midiNumber])
!muteSound && playNote(midiNumber)
}}
stopNote={(midiNumber: number) => {
setActiveNotes((an) => ({ ...an, [midiNumber]: false }))

// remove midiNumber from chordStack
setChordStack?.((cs) => {
const removalIdx = cs.indexOf(midiNumber)
if (removalIdx > -1) {
cs.splice(removalIdx, 1)
}

return cs
})

stopNote(midiNumber)
}}
activeNotes={Object.keys(activeNotes)
.filter((v: string) => activeNotes[v])
.map((s: string) => Number(s))}
/>
</KeyboardContainer>
)}
/>
<KeyboardContainer>
<Piano
noteRange={{ first: firstNote, last: lastNote }}
playNote={(midiNumber: number) => {
setActiveNotes((an) => ({ ...an, [midiNumber]: true }))
setChordStack?.((cs) => [...cs, midiNumber])
}}
stopNote={(midiNumber: number) => {
setActiveNotes((an) => ({ ...an, [midiNumber]: false }))

// remove midiNumber from chordStack
setChordStack?.((cs) => {
const removalIdx = cs.indexOf(midiNumber)
if (removalIdx > -1) {
cs.splice(removalIdx, 1)
}

return cs
})
}}
activeNotes={Object.keys(activeNotes)
.filter((v: string) => activeNotes[v])
.map((s: string) => Number(s))}
/>
</KeyboardContainer>
)}
</QuizPage>
)
Expand Down
27 changes: 26 additions & 1 deletion src/components/SettingsSidebar/SettingRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import { useTranslation } from 'react-i18next'
import Select from 'react-select'
import UncheckedIcon from 'remixicon-react/CheckboxBlankCircleLineIcon'
import CheckedIcon from 'remixicon-react/CheckboxCircleFillIcon'
import { InstrumentName } from 'soundfont-player'
import styled from 'styled-components'
import { MidiDevice, PTSettingType } from '../../utils'
import { AVAILABLE_SOUNDS, MidiDevice, PTSettingType } from '../../utils'
import {
AVAILABLE_LANGUAGES,
SupportedLanguagesType,
Expand Down Expand Up @@ -38,6 +39,7 @@ const SettingRow = ({ setting, value }: SettingRowProps) => {
setMidiDevice: setConnectedMidiDevice,
setLanguage,
setIsSentryOn,
setPianoSound,
} = useContext(KVContext)
const { t } = useTranslation()

Expand All @@ -63,6 +65,7 @@ const SettingRow = ({ setting, value }: SettingRowProps) => {
}
}, [setting.key])

// Render Dropdown inputs
if (setting.key === 'midi-input-id') {
if (!Array.isArray(midiDevices)) return null
const connectedMidiDevice = midiDevices[Number(value)]
Expand Down Expand Up @@ -115,8 +118,30 @@ const SettingRow = ({ setting, value }: SettingRowProps) => {
/>
</SettingRowContainer>
)
} else if (setting.key === 'piano-sound') {
return (
<SettingRowContainer>
<span className='settings-row-label'>
{t(`settings.options.${setting.key}`)}
</span>
<Select
options={Object.keys(AVAILABLE_SOUNDS).map((code) => ({
label: AVAILABLE_SOUNDS[code as InstrumentName]?.name || 'N/A',
value: code,
}))}
value={{
label: AVAILABLE_SOUNDS[value as InstrumentName]?.name || 'N/A',
value,
}}
onChange={(e) => {
setPianoSound?.(e?.value as InstrumentName)
}}
/>
</SettingRowContainer>
)
}

// Render boolean options
return (
<SettingRowContainer
onClick={() => {
Expand Down
14 changes: 11 additions & 3 deletions src/components/SettingsSidebar/SettingsSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,14 @@ const Sidebar = styled.div`
`

const SettingsSidebar = () => {
const { showKeyboard, muteSound, midiDevice, language, isSentryOn } =
useContext(KVContext)
const {
showKeyboard,
muteSound,
midiDevice,
language,
isSentryOn,
pianoSound,
} = useContext(KVContext)
const { setIsOpen } = useContext(SidebarContext)
const { t } = useTranslation()

Expand All @@ -56,9 +62,11 @@ const SettingsSidebar = () => {
)
case 'is-sentry-on':
return <SettingRow key={s.key} setting={s} value={isSentryOn} />
case 'piano-sound':
return <SettingRow key={s.key} setting={s} value={pianoSound} />
}
},
[showKeyboard, muteSound, isSentryOn, midiDevice?.id, language]
[showKeyboard, muteSound, isSentryOn, midiDevice?.id, language, pianoSound]
)

return (
Expand Down
1 change: 1 addition & 0 deletions src/i18n/en/translation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ const en = {
'midi-input-id': 'MIDI input',
language: 'Language',
'is-sentry-on': 'Send crash reports',
'piano-sound': 'Piano sound',
},
},
}
Expand Down
1 change: 1 addition & 0 deletions src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,4 @@ export const AVAILABLE_SETTINGS: readonly PTSettingType[] = [
] as const

export * from './midi'
export * from './sounds'
73 changes: 73 additions & 0 deletions src/utils/sounds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { InstrumentName } from 'soundfont-player'

export type SoundOptionType = {
name: string
code: InstrumentName
}

export type AvailableSoundsType = {
[key in InstrumentName]?: SoundOptionType
}

export const AVAILABLE_SOUNDS: AvailableSoundsType = {
acoustic_grand_piano: {
name: 'Grand Piano',
code: 'acoustic_grand_piano',
},
brass_section: {
name: 'Brass Section',
code: 'brass_section',
},
church_organ: {
name: 'Church Organ',
code: 'church_organ',
},
flute: {
name: 'Flute',
code: 'flute',
},
ocarina: {
name: 'Ocarina',
code: 'ocarina',
},
french_horn: {
name: 'French Horn',
code: 'french_horn',
},
acoustic_bass: {
name: 'Acoustic Bass',
code: 'acoustic_bass',
},
electric_bass_finger: {
name: 'Electric Bass',
code: 'electric_bass_finger',
},
synth_strings_2: {
name: 'Synth Strings',
code: 'synth_strings_2',
},
clavinet: {
name: 'Clavinet',
code: 'clavinet',
},
lead_2_sawtooth: {
name: 'Lead Sawtooth',
code: 'lead_2_sawtooth',
},
music_box: {
name: 'Music Box',
code: 'music_box',
},
xylophone: {
name: 'Xylophone',
code: 'xylophone',
},
violin: {
name: 'Violin',
code: 'violin',
},
vibraphone: {
name: 'Vibraphone',
code: 'vibraphone',
},
} as const
Loading

0 comments on commit 72315fb

Please sign in to comment.