11. Playing audio
Rustam Apay
Posted on August 18, 2022
- 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.
-
main
andshifted
{
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 mainName
s 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.
Posted on August 18, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024