- Prepare audio files
- HTML5 audio element
- Data model extension
- getAudioFileName
- Testing
- Dynamic audio playing
Prepare audio files
We will use a short mp3 files for each key value. In the folder keyboardData create folders: en, ru, ar. Move audio files with numbers (for 3 langs) to the folders.
GITHUB
Note:
If you need to make many files from one, I highly recommend free audio editor Audacity. There you can select parts of an audio and attach text labels to them (ctrl+b). Then in menu: File --> Export --> Export Multiple --> Split based on: Label.
For example, you have 1 audio file with numbers from 0 to 9.
You will get files: 0.mp3, 1.mp3, ... 9.mp3.
HTML5 audio element
In App.js methods, at the beginning of setActiveKey add 2 lines:
App.js methods
setActiveKey(keyContent) {
const audio = new Audio(`./keyboardData/en/1.mp3`);
audio.play();
...
}
That's how audio element works.
Now when you click on any button, will be played one file en/1.mp3. You guess that we need to play different files. But there is a problem to identify them in our data model. If you remember, each key is represented by object:
const key = {
code,
label,
main,
shifted
}
Data model extension
Key data aren't filled in the same way. Keys have such different set of props:
file naming
- Only
code
{
code: 'F1'
}
File name F1.mp3 is good for such keys.
-
mainandshifted
{
code: 'Digit1',
main: '1',
shifted: '!',
// should add:
shiftedName: 'exclamation mark'
},
Here we cannot use code as before. Because there is only 1 code, but we need 2 audio files for main and shifted values.
Furthermore, ! is forbidden symbol for file names. So it would be good to have an additional field shiftedName: 'exclamation mark', that we'll use in a file name.
Value of main is good for filename 1.mp3, but sometimes we will need an additional field mainName.
1.mp3 or exclamation mark.mp3 would be good filenames for keyContent above.
- lower and upper case letters
{
code: 'KeyQ',
main: 'q',
shifted: 'Q',
// add:
shiftedName: 'q'
},
Here it is enough to have only 1 file q.mp3 for both values q and Q.
How do we fill our data now? We add to every main and shifted values that we can't or don't want to use as a file name, additional values: mainName and/or shiftedName.
The idea behind this different approach to each key type, instead of writing filename for every key value, is that we are trying to avoid overloading of our keyboardData/lang.js files. So we will add a minimum info do keyboard data file, and then calculate filenames from that minimum.
getAudioFileName
const getAudioFileName = (keyContent, shiftKey) => {
const { main, mainName, shifted, shiftedName, code } = keyContent
let fileName
if (shiftKey) {
// will be returned 1 of 3 values (if it exist). priority to the first one
fileName = shiftedName || shifted || code
} else {
fileName = mainName || main || code
}
// to have a guarantee, that everything is written in the same (lower) case
return fileName.toLowerCase()
}
Notice, that we call any audio file by its lower case name. So we don't need to change keyboard data for values like q-Q. When you name files make sure they are in lowercase.
Testing
When you wrote a function, and you're not sure if it works or not, you should test it.
The simplest way: copy/paste the function to console (Chrome --> DevTools --> Console). (code above without word const)
Also copy to the console keyContent examples that we wrote before. Put them to the array input:
const input = [
{ code: 'F1' },
{
code: 'Digit1',
main: '1',
shifted: '!',
shiftedName: 'exclamation mark'
},
{
code: 'KeyH',
main: 'h',
shifted: 'H'
}
]
Then call getAudioFileName with these data entities and different shiftKey values, in the console.
getAudioFileName(input[0], false) // f1
getAudioFileName(input[0], true) // f1
getAudioFileName(input[1], false) // 1
getAudioFileName(input[1], true) // exclamation mark
getAudioFileName(input[2], false) // h
getAudioFileName(input[2], true) // h
That is called testing. Programmers save such a code with:
-
input, -
call(input), correct output
to special files -- called tests. Then, after codebase has changed, we run the tests to check that we haven't broken anything.
Dynamic audio playing
Add that function definition at the top of Keyboard.js, just after imports:
Keyboard.js
import Keyboard from './components/Keyboard.js'
import LangSwitcher from './components/LangSwitcher.js'
const getAudioFileName = (keyContent, shiftKey) => {
...
}
And call it where we played static audio before.
Keyboard.js methods
setActiveKey(keyContent) {
const fileName = getAudioFileName(keyContent, this.shiftKey)
const audio = new Audio(
`./keyboardData/${this.currentLang}/${fileName}.mp3`
)
audio.play()
...
}
Now when you click on different buttons, you hear a particular key sound, even when you switch languages. Don't forget, that for now we have files only for numbers 0, 1, ..., 9 -- they are correct for en and ru. But for playing Arabic numbers you should add their mainNames to keyboardData/ar.js.
keyboardData/ar.js
{
code: 'Digit1',
main: '١',
// add:
mainName: '1',
shifted: '!'
},
...
Or you should rename files to ١.mp3, ٢.mp3 e.t.c.
As you can see, our approach of file naming and data filling is flexible.

Top comments (0)