04 – Javascript – Web Audio API – Construindo um Sintetizador Web
04 – Javascript – Web Audio API – Construindo um Sintetizador Web
Página principal
Se gostarem do conteúdo dêem um joinha 👍 na página do Código Fluente no
Facebook
Esse é o link do código fluente no Pinterest
Meus links de afiliados:
Hostinger
Digital Ocean
One.com
WEB AUDIO API
Vamos construir um Sintetizador Web pra rodar no browser?
É um teclado sintetizador simples, a cara dele é essa.
Clique na imagem do teclado abaixo para testar o sintetizador no seu browser.
A estrutura do projeto é:
Usaremos o arquivo javascript qwerty-hancock.min.js já pronto, acesse o link abaixo para mais detalhes:
http://stuartmemo.com/qwerty-hancock
No meu github você pode baixar o código completo, com o arquivo qwerty-hancock.min.js com algumas pequenas alterações que fiz e com os comentários em português.
Os códigos são esses:
3-Criando-um-Sintetizador-Web/scripts/qwerty-hancock.min.js
/*
* Qwerty Hancock keyboard library v0.6.0
* The web keyboard for now people.
* Copyright 2012-18, Stuart Memo
*
* Licensed under the MIT License
* http://opensource.org/licenses/mit-license.php
*
* http://stuartmemo.com/qwerty-hancock
*/
(function () {
const root = this;
/* No contexto do script, `this` é a janela.
* No contexto do nó (browserify), `this` é o nó global.
*/
const globalWindow = typeof global === 'undefined' ? root : root.window;
let version = '0.6.0',
settings = {},
mouse_is_down = false,
keysDown = {},
//Mapeia os números ASCII das teclas do teclado do computador para as notas.
key_map = {
// 65 é o 'A' na tabela ASCII
65: 'Cl',
// 87 é o 'W'
87: 'C#l',
// 83 é o 'S'
83: 'Dl',
// 69 o 'E'
69: 'D#l',
// 68 o 'D'
68: 'El',
// 70 o 'F'
70: 'Fl',
// 84 o 'T'
84: 'F#l',
// 71 o 'G'
71: 'Gl',
// 89 o 'Y'
89: 'G#l',
// 90 o 'Z', tá comentado, porque não quero habilitar a tecla 'Z'
//90: 'G#l',
// 72 o 'H'
72: 'Al',
// 85 o 'U'
85: 'A#l',
// 74 o 'J'
74: 'Bl',
// 75 o 'K'
75: 'Cu',
// 79 o 'O'
79: 'C#u',
// 76 o 'L'
76: 'Du',
// 80 o 'P'
80: 'D#u',
// 59 o ';' obs: não funciona em teclado pt-br, por isso tá comentado.
//59: 'Eu',
// 186 o '║' ou 'Ç' no teclado em português pt-br
186: 'Eu',
// 222 o '~' no teclado em português pt-br
222: 'Fu',
// 221 o '[' no teclado em português pt-br
221: 'F#u',
// 220 o ']' no teclado em português pt-br
220: 'Gu'
},
keyDownCallback,
keyUpCallback;
/**
* Calcula a largura da tecla branca.
* @return {number} Largura de uma única tecla branca em pixel.
*/
const getWhiteKeyWidth = function (number_of_white_keys) {
return Math.floor((settings.width - number_of_white_keys) / number_of_white_keys);
};
/**
* Mesclar configurações de usuário com padrões.
* @param {object} user_settings
*/
const init = function (us) {
let container;
user_settings = us || {};
settings = {
// atribui a chave id a string keyboard, caso não seja passado nada pelo user_settings.id
id: user_settings.id || 'keyboard',
// define que o teclado terá 3 oitavas, caso não seja passado nada pelo user_settings.octaves
octaves: user_settings.octaves || 3,
// pega o valor da largura pelo user_settings.width
width: user_settings.width,
// Mesma coisa para o height
height: user_settings.height,
// Define que o teclado vai começar pela nota A3 (Lá 3)
startNote: user_settings.startNote || 'A3',
// Define a cor das teclas brancas do teclado em hexa
whiteKeyColour: user_settings.whiteKeyColour || '#fff',
// Define a cor das teclas pretas do teclado em hexa
blackKeyColour: user_settings.blackKeyColour || '#000',
// Define a cor da tecla ativa, isto é, que tá sendo pressionada, para a cor azul.
activeColour: user_settings.activeColour || '#428bca',
// Define a cor da borda das teclas como preto
borderColour: user_settings.borderColour || '#000'
};
// Pega o id do elemento no html, no nosso caso, o id é keyboard
container = document.getElementById(settings.id);
// Se a largura(width) não for definido no settings, ele pega a largura
// através do container, que é o elemento keyboard, com o offsetWidth
if (typeof settings.width === 'undefined') {
settings.width = container.offsetWidth;
}
// Mesma coisa para a altura(height)
if (typeof settings.height === 'undefined') {
settings.height = container.offsetHeight;
}
// define a oitava inicial, pegando o 3 da string A3, que é a nota inicial.
// "A3".charAt(1), 10) retorna só o "3", que passa no parseInt e vira 3.
settings.startOctave = parseInt(settings.startNote.charAt(1), 10);
// Define a oitava inicial com 3, pego no comando anterior, caso não seja passado
// um valor para user_settings.keyOctave no synth.js como parâmetro octaves.
settings.keyOctave = user_settings.keyOctave || settings.startOctave;
// Adiciona getters e setters
this.setKeyOctave = function(octave){
settings.keyOctave = octave;
return settings.keyOctave;
}
this.getKeyOctave = function(){
return settings.keyOctave;
}
this.keyOctaveUp = function(){
settings.keyOctave++;
return settings.keyOctave;
}
this.keyOctaveDown = function(){
settings.keyOctave--;
return settings.keyOctave;
}
this.getKeyMap = function(){
return key_map;
}
this.setKeyMap = function(newKeyMap){
key_map = newKeyMap;
return key_map;
}
createKeyboard();
addListeners.call(this, container);
};
/**
* Obtém frequência de uma determinada nota.
* @param {string} note Nota musical para converter em hertz.
* @return {number} Frequência de nota em hertz.
*/
const getFrequencyOfNote = function (note) {
let notes = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#'],
key_number,
octave;
if (note.length === 3) {
octave = note.charAt(2);
} else {
octave = note.charAt(1);
}
key_number = notes.indexOf(note.slice(0, -1));
if (key_number < 3) {
key_number = key_number + 12 + ((octave - 1) * 12) + 1;
} else {
key_number = key_number + ((octave - 1) * 12) + 1;
}
return 440 * Math.pow(2, (key_number - 49) / 12);
};
/**
* Alterar a cor de uma tecla.
* @param {element} el Elemento DOM para mudar a cor.
*/
const lightenUp = function lightenUp (el) {
if (el !== null || typeof el === undefined) {
el.style.backgroundColor = settings.activeColour;
}
};
/**
* Reverte a tecla para a cor original.
* @param {element} el Elemento DOM para mudar a cor.
*/
const darkenDown = function darkenDown (el) {
if (el !== null) {
if (el.getAttribute('data-note-type') === 'white') {
el.style.backgroundColor = settings.whiteKeyColour;
} else {
el.style.backgroundColor = settings.blackKeyColour;
}
}
};
/**
* Ordena as notas na ordem definida pela tecla inicial nas configurações.
* @param {array} notes_to_order Notas a serem ordenadas.
* @return {array{ ordered_notes Notas ordenadas.
*/
const orderNotes = function (notes_to_order) {
let i,
keyOffset = 0,
number_of_notes_to_order = notes_to_order.length,
ordered_notes = [];
for (i = 0; i < number_of_notes_to_order; i++) {
if (settings.startNote.charAt(0) === notes_to_order[i]) {
keyOffset = i;
break;
}
}
for (i = 0; i < number_of_notes_to_order; i++) { if (i + keyOffset > number_of_notes_to_order - 1) {
ordered_notes[i] = notes_to_order[i + keyOffset - number_of_notes_to_order];
} else {
ordered_notes[i] = notes_to_order[i + keyOffset];
}
}
return ordered_notes;
};
/**
* Adiciona estilo a uma tecla branca individual.
* @param {element} el Elemento DOM tecla branca.
*/
const styleWhiteKey = function (key) {
key.el.style.backgroundColor = settings.whiteKeyColour;
key.el.style.border = '1px solid ' + settings.borderColour;
key.el.style.borderRight = 0;
key.el.style.height = settings.height + 'px';
key.el.style.width = key.width + 'px';
key.el.style.borderRadius = '0 0 5px 5px';
if (key.noteNumber === getTotalWhiteKeys() - 1) {
key.el.style.border = '1px solid ' + settings.borderColour;
}
};
/**
* Adiciona estilo a uma tecla preta individual.
* @param {element} el Elemento DOM tecla preta.
*/
const styleBlackKey = function (key) {
const white_key_width = getWhiteKeyWidth(getTotalWhiteKeys()),
black_key_width = Math.floor(white_key_width / 2);
key.el.style.backgroundColor = settings.blackKeyColour;
key.el.style.border = '1px solid ' + settings.borderColour;
key.el.style.position = 'absolute';
key.el.style.left = Math.floor(((white_key_width + 1) * (key.noteNumber + 1)) - (black_key_width / 2)) + 'px';
key.el.style.width = black_key_width + 'px';
key.el.style.height = (settings.height / 1.5) + 'px';
key.el.style.borderRadius = '0 0 3px 3px';
};
/**
* Adiciona um estilo a uma tecla individual no teclado.
* @param {object} key Elemento tecla.
*/
const styleKey = function (key) {
key.el.style.display = 'inline-block';
key.el.style['-webkit-user-select'] = 'none';
if (key.colour === 'white') {
styleWhiteKey(key);
} else {
styleBlackKey(key);
}
};
/**
* Redefine estilos no container do teclado e no elemento da lista.
* @param {element} keyboard container do elemento DOM teclado.
*/
const styleKeyboard = function (keyboard) {
const styleElement = function (el) {
el.style.cursor = 'default';
el.style.fontSize = '0px';
el.style.height = settings.height + 'px';
el.style.padding = 0;
el.style.position = 'relative';
el.style.listStyle = 'none';
el.style.margin = 0;
el.style.width = settings.width + 'px';
el.style['-webkit-user-select'] = 'none';
};
styleElement(keyboard.container);
styleElement(keyboard.el);
};
/**
* Chama o evento mouseDown do usuário.
*/
const mouseDown = function (element, callback) {
if (element.tagName.toLowerCase() == 'li') {
mouse_is_down = true;
lightenUp(element);
callback(element.title, getFrequencyOfNote(element.title));
}
};
/**
* Chama o evento mouseUp do usuário.
*/
const mouseUp = function (element, callback) {
if (element.tagName.toLowerCase() == 'li') {
mouse_is_down = false;
darkenDown(element);
callback(element.title, getFrequencyOfNote(element.title));
}
};
/**
* Chama mouseOver do usuário, se necessário, então, podemos até comentar se quiser,
* pois no caso do nosso synth, ela não tá sendo usada.
*/
const mouseOver = function (element, callback) {
if (mouse_is_down) {
lightenUp(element);
callback(element.title, getFrequencyOfNote(element.title));
}
};
/**
* Chama o mouseUp do usuário.
*/
const mouseOut = function (element, callback) {
if (mouse_is_down) {
darkenDown(element);
callback(element.title, getFrequencyOfNote(element.title));
}
};
/**
* Cria o elemento DOM tecla e seus atributos HTML.
* @return {object} Key DOM element.
*/
const createKey = function (key) {
key.el = document.createElement('li');
key.el.id = key.id;
key.el.title = key.id;
key.el.setAttribute('data-note-type', key.colour);
styleKey(key);
return key;
};
// Retorna o total de teclas brancas fazendo uma conta simples,
// cada oitava tem 7 notas brancas, então multiplica-se o 7 pelo
// número de oitavas que queremos no teclado
const getTotalWhiteKeys = function () {
return settings.octaves * 7;
};
// Cria a quantidade certa de teclas do teclado
const createKeys = function () {
let that = this,
i,
key,
keys = [],
note_counter = 0,
octave_counter = settings.startOctave,
total_white_keys = getTotalWhiteKeys();
// total_white_keys é igual a 28 (Teclado com 4 oitavas)
for (i = 0; i < total_white_keys; i++) { // whiteNotes.length é igual a 5 ==> ['C', 'D', 'E', 'F', 'G', 'A', 'B']
// então se i % 5 for ==> 0 atribui zero a note_counter
// só vai entrar no if quando i for igual a 0 ou a 5
if (i % this.whiteNotes.length === 0) {
note_counter = 0;
}
// bizarre_note_counter recebe o valor de whiteNotes ['C', 'D', 'E', 'F', 'G', 'A', 'B']
// na posição note_counter
bizarre_note_counter = this.whiteNotes[note_counter];
// Se bizarre_note_counter for Dó(C) e i for diferente de zero,
// soma uma unidade em octave_counter
if ((bizarre_note_counter === 'C') && (i !== 0)) {
octave_counter++;
}
// Cria uma tecla branca pra ser adicionada as teclas do teclado
key = createKey({
colour: 'white',
octave: octave_counter,
width: getWhiteKeyWidth(total_white_keys),
id: this.whiteNotes[note_counter] + octave_counter,
noteNumber: i
});
// Insere no HTML o elemento(el) DOM tecla
keys.push(key.el);
if (i !== total_white_keys - 1) {
this.notesWithSharps.forEach(function (note, index) {
if (note === that.whiteNotes[note_counter]) {
key = createKey({
colour: 'black',
octave: octave_counter,
width: getWhiteKeyWidth(total_white_keys) / 2,
id: that.whiteNotes[note_counter] + '#' + octave_counter,
noteNumber: i
});
keys.push(key.el);
}
});
}
note_counter++;
}
return keys;
};
// Insere as teclas DOM dentro do HTML
const addKeysToKeyboard = function (keyboard) {
keyboard.keys.forEach(function (key) {
keyboard.el.appendChild(key);
});
};
// Trata da entrada de notas via teclado do computador
const setKeyPressOffset = function (sorted_white_notes) {
settings.keyPressOffset = sorted_white_notes[0] === 'C' ? 0 : 1;
};
// Definição do dicionário keyboard
// Note o el, através dele as teclas são mostradas no HTML como uma lista('ul')
const createKeyboard = function () {
const keyboard = {
container: document.getElementById(settings.id),
el: document.createElement('ul'),
whiteNotes: orderNotes(['C', 'D', 'E', 'F', 'G', 'A', 'B']),
notesWithSharps: orderNotes(['C', 'D', 'F', 'G', 'A']),
};
// Com call(), um objeto pode usar um método pertencente a outro objeto.
// Aqui chamamos o createKeys do próprio objeto teclado instanciado, através do call().
keyboard.keys = createKeys.call(keyboard);
// Chama setKeyPressOffset para tratar as notas via teclado do computador
setKeyPressOffset(keyboard.whiteNotes);
// Chama a styleKeyboard para dá o estilo do teclado(CSS via função javascript)
styleKeyboard(keyboard);
// Adiciona as teclas ao teclado e o teclado ao contêiner.
addKeysToKeyboard(keyboard);
keyboard.container.appendChild(keyboard.el);
// Retorna o teclado formatado, já todo certinho
return keyboard;
};
const getKeyPressed = function (keyCode) {
return key_map[keyCode]
.replace('l', parseInt(settings.keyOctave, 10) + settings.keyPressOffset)
.replace('u', (parseInt(settings.keyOctave, 10) + settings.keyPressOffset + 1)
.toString());
};
/**
* Manipular uma tecla do teclado sendo pressionada.
* @param {object} key Evento de teclado - tecla atualmente pressionada.
* @param {callback} callback A função noteDown do usuário.
* @return {boolean} true se foi uma tecla (combo) usada por qwerty-hancock
*/
const keyboardDown = function (key, callback) {
let key_pressed;
if (key.keyCode in keysDown) {
return false;
}
keysDown[key.keyCode] = true;
if (typeof key_map[key.keyCode] !== 'undefined') {
key_pressed = getKeyPressed(key.keyCode);
// Chama a função noteDown do usuário.
callback(key_pressed, getFrequencyOfNote(key_pressed));
lightenUp(document.getElementById(key_pressed));
return true;
}
return false;
};
/**
* Lida com uma tecla do teclado sendo liberada.
* @param {element} key O elemento DOM da tecla que foi liberada.
* @param {callback} callback A função noteDown do usuário.
* @return {boolean} true se foi uma tecla (combo) usada por qwerty-hancock
*/
const keyboardUp = function (key, callback) {
let key_pressed;
delete keysDown[key.keyCode];
if (typeof key_map[key.keyCode] !== 'undefined') {
key_pressed = getKeyPressed(key.keyCode);
// Chama a função noteDown do usuário.
callback(key_pressed, getFrequencyOfNote(key_pressed));
darkenDown(document.getElementById(key_pressed));
return true;
}
return false;
};
/**
* Determine se a tecla pressionada é uma tecla modificadora ou não
* exemplo de teclas modificadoras: Control, Shift, Alt / Option (Apple),
* AltGr, Meta, Command (Apple) / Windows (Microsoft), Super, Hyper, Fn.
* @param {KeyboardEvent} O evento keydown de uma tecla pressionada.
*/
const isModifierKey = function (key) {
return key.ctrlKey || key.metaKey || key.altKey;
};
/**
* Adiciona event listeners ao teclado.
* @param {element} keyboard_element
*/
const addListeners = function (keyboard_element) {
const that = this;
// A tecla é pressionada no teclado.
//verifica se a tecla pressionada foi um alt, ou Shift, etc.
globalWindow.addEventListener('keydown', function (key) {
if (isModifierKey(key)) {
return;
}
//através da instância do keyboard(this)
if (keyboardDown(key, that.keyDown)) {
key.preventDefault();
}
});
// A tecla é liberada no teclado.
// O método preventDefault ()
//cancela o evento se for cancelável,
//o que significa que a ação padrão que pertence ao evento não ocorrerá.
globalWindow.addEventListener('keyup', function (key) {
if (isModifierKey(key)) {
return;
}
if (keyboardUp(key, that.keyUp)) {
key.preventDefault();
}
});
keyboard_element.addEventListener('mousedown', function (event) {
mouseDown(event.target, that.keyDown);
});
// Mouse é liberado do elemento de teclado.
keyboard_element.addEventListener('mouseup', function (event) {
mouseUp(event.target, that.keyUp);
});
// Mouse é movido sobre o elemento do teclado.
keyboard_element.addEventListener('mouseover', function (event) {
mouseOver(event.target, that.keyDown);
});
// Mouse é movido para fora do elemento do teclado.
keyboard_element.addEventListener('mouseout', function (event) {
mouseOut(event.target, that.keyUp);
});
// O dispositivo suporta eventos de toque.
if ('ontouchstart' in document.documentElement) {
keyboard_element.addEventListener('touchstart', function (event) {
mouseDown(event.target, that.keyDown);
});
keyboard_element.addEventListener('touchend', function (event) {
mouseUp(event.target, that.keyUp);
});
keyboard_element.addEventListener('touchleave', function (event) {
mouseOut(event.target, that.keyUp);
});
keyboard_element.addEventListener('touchcancel', function (event) {
mouseOut(event.target, that.keyUp);
});
}
};
/**
* Construtor do Qwerty Hancock.
* @param {object} settings Configurações do usuário opcionais.
*/
const QwertyHancock = function (settings) {
this.version = version;
init.call(this, settings);
};
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = QwertyHancock;
}
exports.QwertyHancock = QwertyHancock;
} else {
root.QwertyHancock = QwertyHancock;
}
})(this);
3-Criando-um-Sintetizador-Web/scripts/synth.js
// Cria uma instância do QwertyHancock
const keyboard = new QwertyHancock({
id: 'keyboard',
width: 800,
height: 150,
octaves: 4
});
// Cria o contexto de audio
const context = new AudioContext(),
masterVolume = context.createGain(),
oscillators = {};
masterVolume.gain.value = 0.2;
masterVolume.connect(context.destination);
keyboard.keyDown = function (note, frequency) {
const osc = context.createOscillator(),
osc2 = context.createOscillator();
osc.frequency.value = frequency;
osc.type = 'sawtooth';
osc.detune.value = -10;
osc2.frequency.value = frequency;
osc2.type = 'triangle';
osc2.detune.value = 10;
osc.connect(masterVolume);
osc2.connect(masterVolume);
masterVolume.connect(context.destination);
oscillators[frequency] = [osc, osc2];
osc.start(context.currentTime);
osc2.start(context.currentTime);
};
keyboard.keyUp = function (note, frequency) {
oscillators[frequency].forEach(function (oscillator) {
oscillator.stop(context.currentTime);
});
};
3-Criando-um-Sintetizador-Web/styles/main.css
body {
font-family: sans-serif;
}
.container {
margin: auto;
width: 800px;
}
.container h1 {
text-align: center;
}
3-Criando-um-Sintetizador-Web/index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Sintetizador Web</title>
<link rel="stylesheet" href="styles/main.css">
</head>
<body>
<div class="container">
<h1>Construindo um sintetizador com a Web Audio API</h1>
<div id="keyboard"></div>
</div>
<script src="scripts/qwerty-hancock.min.js"></script>
<script src="scripts/synth.js"></script>
</body>
</html>
O Criando-um-Sintetizador-Web/index.html e o Criando-um-Sintetizador-Web/styles/main.css são arquivos bem simples, por isso, vou pular a explicação, qualquer dúvida deixe nos comentários.
No vídeo, como sempre, vou passar rapidamente por eles, mas na parte textual vou falar apenas dos dois pricipais arquivos: o Criando-um-Sintetizador-Web/scripts/synth.js e o 3-Criando-um-Sintetizador-Web/scripts/qwerty-hancock.min.js.
Criando-um-Sintetizador-Web/scripts/synth.js
No Criando-um-Sintetizador-Web/scripts/synth.js é criada uma instância do QwertyHancock (nosso teclado) logo na linha 2.
São passados alguns parâmetros para o construtor do QwertyHancock:
id, width, height e octaves.
Um contexto de áudio é criado(context) e por meio dele, é criado o masterVolume, que é conectado ao context.destination.
Através da instância do QwertyHancock que tá na variável keyboard, é definido o que é feito quando determinada tecla é pressionada (keyboard.keyDown) ou liberada (keyboard.keyUp).
keyboard.keyDown
Quando a tecla é pressionada, são criados dois osciladores osc e osc2, logo depois são definidos os tipos de onda e um valor para o detune.
O detune é uma propriedade da interface AudioBufferSourceNode, que é um AudioParam de taxa k que representa a desafinação do oscilador em cent.
O cent é uma unidade de medida logarítmica usada para intervalos musicais.
Por exemplo, valores de detune de +100 e -100 alteram a afinação da fonte para cima ou para baixo em um semitom:
Enquanto valores de detune de +1200 e -1200 muda a afinação em uma oitava para cima ou para baixo.
O valor atribuído ao detune foi de -10 em um oscilador e 10 no outro, esse valor é ínfimo, ele serve só pra dá uma levíssima desafinada entre a frequência de um oscilador e do outro, para dá uma enriquecida no timbre final, que é a soma dos dois.
O tipo de onda do osc é sawtooth e do osc2 é triangle.
Depois vem a conexão dos dois osciladores ao masterVolume e o masterVolume ao context.destination.
No dicionário vazio chamado oscillators, criado no início do arquivo na linha 10, na chave frequency é atribuída a lista [osc, osc2] com os dois osciladores criados.
Em seguida os dois osciladores são iniciados, linhas 35 e 36.
keyboard.keyUp
Quando a tecla é liberada, é dado um stop em cada oscilador na lista frequency.
3-Criando-um-Sintetizador-Web/scripts/qwerty-hancock.min.js
O 3-Criando-um-Sintetizador-Web/scripts/qwerty-hancock.min.js é mais complexo, vou tentar dá uma pincelada.
Na linha 600, onde temos var QwertyHancock = function (settings) … é onde o teclado é construído, por isso chamamos de construtor, isso é um conceito de orientação a objetos.
Em seguida é definida a versão com: this.version = version; pegando o valor atribuído na linha 18 com var version = ‘0.6.0’,
Em seguida chama o método init dele mesmo, passando ele mesmo e o resto dos parâmetros: id, width, height e octaves para terminar de construir o objeto QwertyHancock .
O trecho de código abaixo expõe o QwertyHancock( nosso teclado ), como um módulo.
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = QwertyHancock;
}
exports.QwertyHancock = QwertyHancock;
} else {
root.QwertyHancock = QwertyHancock;
}
O Javascript utiliza módulo para imitar o conceito de classes, já que JavaScript não suporta nativamente esse conceito.
Com isso, podemos ter variáveis e métodos públicos e privados semelhante ao conceito de classes de outras linguagens de programação como Java, Python, C#, etc.
Módulos em geral, são altamente auto-suficientes, com funcionalidades distintas, o que lhes permite ser reutilizado em vários projetos.
Então podemos pensar em módulo como uma peça de código reutilizável.
No caso do QwertyHancock, ele é uma peça de software, já pronto, que estamos utilizando para criar nosso sintetizador web.
Ele pode ser utilizado em vários outros projetos.
Em 3-Criando-um-Sintetizador-Web/scripts/qwerty-hancock.min.js foi usado função anônima.
Justamente por isso, precisamos expor nosso módulo QwertyHancock com module.exports para acessar seus métodos e propriedades fora da função anônima em que ele está encapsulado.
No código do teclado, primeiro é verificado se o exports e o módulo estão definidos (linha 605 e 606): typeof exports !== ‘undefined’ e typeof module !== ‘undefined’ && module.exports, e através do exports.QwertyHancock expomos o QwertyHancock construído.
Se o export estiver indefinido(undefined) ainda, definimos ele com: root.QwertyHancock = QwertyHancock;
O (this) é a instância do teclado construído.
Na linha 13 root recebe a instância do próprio teclado (this): var root = this;
Quando não está no contexto do navegador, geralmente o contexto raiz é chamado global, então você pode usar isso (linha 17).
var globalWindow = typeof global === ‘undefined’ ? root : root.window;
Se global não estiver definido, definimos globalWindow como root, a janela raiz.
Se já estiver definida, atribuímos root.window à globalWindow.
Vou ficando por aqui.
Os códigos estão comentados e qualquer dúvida deixe nos comentários.
Para entender melhor assista o vídeo da aula.
Para baixar os códigos é só acessar meu github.
Se gostarem do conteúdo dêem um joinha 👍 na página do Código Fluente no
Facebook
Esse é o link do código fluente no Pinterest
Meus links de afiliados:
Hostinger
Digital Ocean
One.com
Obrigado, até e bons estudos. 🙂