Afinador de Guitarra – Online Guitar Tuner – v3

Como novedad, para esta tercera versión del afinador, he añadido un selector de guitarra para cambiar entre eléctrica y clásica, no solo visualmente sino también acústicamente con sonidos diferentes para ambas guitarras. Además he puesto un deslizador para controlar el volumen de las cuerdas y separar entre el audio del afinador de guitarra y el audio general de tu dispositivo.

He usado CSS para dibujar todo el diseño, eliminando todas las imágenes (excepto el avatar) y sustituyéndolas todas por código CSS.

Quería haber depurado más el Javascript, pero me lie tanto con el CSS que al final lo he cambiado poco, aunque si he conseguido arreglar un error del otro afinador que me traía de cabeza desde hace tiempo.

Ver Demo

HTML

El HTML es muy parecido al del último afinador y se puede dividir en cuatro partes:

header , section , footer y audio

header

Aquí ponemos los botones para cambiar el tipo de guitarra, eléctrica o clásica. Ambos botones llaman a la función Javascript changeGuitar() en el evento onclick, pasándole como argumento el id del propio botón. Además a uno de los botones (el que queramos seleccionado por defecto) le añadimos la clase active y el parámetro disabled.

<button id="e-classic"  onclick="changeGuitar(this.id)" class="change-guitar"></button>
<button id="e-electric" onclick="changeGuitar(this.id)" class="change-guitar active" disabled></button>

section

En esta sección ponemos las cuerdas que serán elementos button con la clase string y un id para cada uno de ellos, también le añadimos dos eventos a cada cuerda:

  • el evento onmouseenter que llama a la función Javascript pickString() (para cuando usemos la púa)
  • y el evento onclick que llama a la función clickString() (para cuando hagamos clic sobre la cuerda)

Ambas funciones pasan como argumento el id del propio botón. Cada button (cada cuerda) a su vez contiene un elemento span que usaremos para crear un efecto interesante con CSS que imitará la vibración de la cuerda al ser pulsada.

A continuación hemos puesto las notas (por duplicado para inglés y español) que se iluminarán al tocar cada cuerda, cada una de ellas con su id específico y a la que añadiremos la clase lightOn cuando la cuerda esté sonando.

Y finalmente un div con el atributo id move-pick, que será para la púa y que se activará con el evento onmouseenter usando Javascript más adelante..

<button onmouseenter="pickString(this.id)" onclick="clickString(this.id)" class="string" id="s6">
  <span></span>
</button>
<!-- un elemento <button> para cada cuerda (6 en total) -->

<div class="notes">
  <span class="" id="s6Note">E</span>
  <!-- un elemento <span> para cada nota (6 en total) -->
</div>
<div class="notes">
  <span class="" id="s6Nota">MI</span>
  <!-- un elemento <span> para cada nota (6 en total) -->
</div>

<div id="move-pick"></div>

Gracias a Jesus Maria por recomendarme cambiar el antiguo evento onmouseover por onmouseenter, solucionando así un pequeño fallo que hacía que la cuerdas sonaran varias veces al pasar el ratón lentamente sobre las cuerdas usando la púa. Una solución lógica, rápida y efectiva. ¡Gracias!

footer

En la parte de abajo vamos a poner los controles del afinador, hay tres partes bien diferenciadas:

Un control deslizante para el volumen con un input de tipo range que llama a la función setVolume() pasando el value como argumento, esta llamada la hacemos en los eventos oninput y onchange para que el valor cambie al mover el deslizador y no solo al soltar el clic. A continuación ponemos un div con la clase slider-value para mostrar (y actualizar con Javascript ) el valor que tengamos seleccionado en el volumen.

Después van dos botones, uno para detener el sonido y otro para mantener el sonido, cada uno llamando a su función: stopStrings() para detenerlo, y holdSound() para mantenerlo, y cada uno con su propio id.

Y un último botón para activar o desactivar la púa que hará que suenen las cuerdas onmouseenter cuando la púa esté activada, llamará a la función usePick() en el evento onclick, y también le ponemos un id único.

<input id="volume" type="range" min="0" max="1" value="0.5" step="0.1" oninput="setVolume(this.value)" onchange="setVolume(this.value)" autocomplete="off">
<div class="slider-value">5</div>		

<button onfocus="stopStrings()" id="btnStop"></button>
<button onclick="holdSound()" id="btnHold"></button>

<button onclick="usePick()" id="btnPick"></button>

audio

En la última parte vamos a poner los archivos de audio , cada uno con su id, con los sonidos de cada cuerda de la guitarra, de esta manera se cargarán al principio y ya no tendríamos que cargarlos desde Javascript, aunque habrá que cambiarlos por otros archivos cuando cambiemos de guitarra y eso si lo haremos en la parte de Javascript.

<audio id="as1" src="https://cdn.josetxu.com/audio/egs-1.mp3"></audio>
<audio id="as2" src="https://cdn.josetxu.com/audio/egs-2.mp3"></audio>
<audio id="as3" src="https://cdn.josetxu.com/audio/egs-3.mp3"></audio>
<audio id="as4" src="https://cdn.josetxu.com/audio/egs-4.mp3"></audio>
<audio id="as5" src="https://cdn.josetxu.com/audio/egs-5.mp3"></audio>
<audio id="as6" src="https://cdn.josetxu.com/audio/egs-6.mp3"></audio>

Esto es solo una parte del código HTML final. En la demo encontrarás el código completo.

CSS

Como decía al principio he usado CSS para dibujar todo: las guitarras, las pastillas de la eléctrica, la boca de la clásica, las cuerdas, los iconos, los botones, el volumen, la púa

No voy a poner todo el código aquí porque sería demasiado, así que me centraré solo en algunas partes, las que me parecen más interesantes.


cuerdas

Las cuerdas las hacemos de una manera muy simple usando la función repeating-linear-gradient para crear el efecto de cuerda metálica. A las tres primeras (que son realmente la sexta, la quinta y la cuarta) les cambiamos el alto para hacer cada una más pequeña que la anterior.

button.string:before {
  background: repeating-linear-gradient(90deg, #ddd 1px 2px, #bbb 0px 3px, #000c 4px);
  box-shadow: 0px 10px 5px -1px #0004, 0 0 2px 0 #0008;
  border-top: 1px solid #000;
  border-bottom: 1px solid #000;
}
button.string#s5:before {
  height: 8px;
}
button.string#s4:before {
  height: 6px;
}

A las tres cuerdas de abajo, que en guitarra clásica suelen ser de nylon, les damos un color de fondo blanco transparente y también las hacemos cada una más pequeña que la anterior para que parezcan más finas.

button.string:nth-child(n+4):before {
    background: #fff8;
}
button.string#s3:before {
  height: 6px;
}
button.string#s2:before {
  height: 4px;
}
button.string#s1:before {
  height: 2px;
}

La animación de las cuerdas, aunque se usa Javascript para añadir o quitar clases, realmente se hace con CSS. En el siguiente ejemplo añadiré la animación en el :active , por lo que tendrás que pulsar y mantener pulsada la cuerda para ver la animación, aunque realmente se añade de otra manera en la demo final. También he añadido un efecto de partículas vibrando debajo de la cuerda, que ha quedado muy chulo.

/*** Efecto Vibracion ***/
button.string:active:before {
    animation: vibrate 0.1s ease-in-out 0s infinite;
}

@keyframes vibrate {
  25% { margin-top: -1px; }
  75% { margin-top: 1px; }
  0%, 100% { margin-top: 0; }
}

/*** Efecto particulas ***/
@property --bgp1 {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 50%;
}

button#s7:active span {
  --bgp1: 50%;
  background-image: 
    repeating-radial-gradient(#fff 0.0001%, #fff0 .0025%, #fff0 .065%, #fff0 0.091%), 
    repeating-radial-gradient(#fff 0.0001%, #fff0 .0025%, #fff0 .0675%, #fff0 0.0875%);
  background-size: 100% var(--bgp1), 100% var(--bgp1);
  background-repeat: no-repeat;
  background-position: 50% 50%, 50% 50%;
  position: absolute;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
  z-index: 1;
  animation: particles 4s ease 0s infinite;
  animation-fill-mode: forwards;
  filter: drop-shadow(0 0 1px #fff) drop-shadow(0 0 2px #fff) blur(1px);
  transition-property: all;
  opacity: 0;
}

@keyframes particles {
  0% { --bgp1: 50%; opacity: 0; }
  1% { opacity: 0.9; }
  100% { --bgp1: 100%; opacity: 0; }
}

Para la animación de partículas he usado la regla @property de CSS, hasta hace poco solo soportada por Chrome y Safari, pero (según he visto en caniuse) parece que la última versión de Firefox, la 117, ha añadido por fin soporte para esta regla. Quisiera escribir algo más sobre @property pero lo haré en un próximo artículo para explicar bien todo lo que ofrece, básicamente permite animar gradientes CSS pero realmente da mucho más juego…

Para las cuerdas de la eléctrica lo único que hacemos es girar el ángulo de inicio en la función CSS repeating-linear-gradient para darle un efecto mas bruto. Y para las dos cuerdas más finas (la primera y la segunda empezando por abajo) cambiaremos también el ángulo de inicio pero más exagerado, hasta 0deg para darle un efecto de alambre, además a estas dos cuerdas les alargaremos 1px el color gris.

.e-electric button.string:before {
    background: repeating-linear-gradient(120deg, #ababab 1px 2px, #000c 3px);
}

.e-electric #s1:before,
.e-electric #s2:before {
    background: repeating-linear-gradient(0deg, #ababab 1px 3px, #000c 4px);
}

fondos

Me he esmerado bastante en los fondos para conseguir unos cuerpos de guitarra realistas y en general estoy bastante contento con el resultado, aunque siempre hay margen de mejora.

Guitarra Eléctrica

El cuerpo de la guitarra eléctrica lleva un color de fondo azul con degradado a negro y además las pastillas dobles que están creadas en los pseudo-elementos de cuerpo de la propia guitarra. En la demo final he cambiado el orden de los colores de una de las pastillas para darle más realismo.

.electric-body {
  background: linear-gradient(180deg, #000 5%, #0566c2, #000 95%);
}
.electric-body:before, .electric-body:after {
  --p-inner: #080808;
  --p-outer: #fffeee;
  --p-side: #141414;
  --dot: radial-gradient(circle, #ebebeb 3px, #adadad 8px, #000 9px, #fff0 10px 100%);
  background: var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), radial-gradient(circle at 120px 41px, var(--p-outer) 38px, #fff0 calc(38px + 1.5px) 100%), radial-gradient(circle at 120px calc(100% - 41px), var(--p-outer) 38px, #fff0 calc(38px + 1.5px) 100%), radial-gradient(circle at 41px calc(100% - 41px), var(--p-inner) 37px, #fff0 calc(37px + 1.5px) 100%), radial-gradient(circle at 41px 41px, var(--p-inner) 37px, #fff0 calc(37px + 1.5px) 100%), radial-gradient(circle at 119px 39px, #686868 37px, #fff0 calc(37px + 1.5px) 100%), radial-gradient(circle at 119px calc(100% - 37px), #686868 37px, #fff0 calc(37px + 1.5px) 100%), radial-gradient(circle at 41px calc(100% - 37px), #686868 37px, #fff0 calc(37px + 1.5px) 100%), radial-gradient(circle at 40px 39px, #686868 36px, #fff0 calc(36px + 1.5px) 100%), linear-gradient(180deg, #121212 40px, #fff0 0 calc(100% - 40px), #121212 0 100%), linear-gradient(90deg, #111 3px, var(--p-inner) 4px calc(50% - 3px), #111 50%, var(--p-outer) calc(50% + 3px) calc(100% - 3px), #fff0 100%), linear-gradient(45deg, #242424 2px, #fff0 3px 100%), linear-gradient(-45deg, #242424 2px, #fff0 3px 100%), linear-gradient(135deg, #242424 2px, #fff0 3px 100%), linear-gradient(225deg, #242424 2px, #fff0 3px 100%), #121212;
  width: 180px;
  left: calc(50% - 25px);
  height: 380px;
  top: calc(50% - 190px);
  border-radius: 10px;
  border: 10px solid #181818;
  border-width: 25px 10px;
  box-sizing: border-box;
  background-repeat: no-repeat;
  margin-left: 50px;
  filter: none;
  background-size: 22px 22px, 22px 22px, 22px 22px, 22px 22px, 22px 22px, 22px 22px, 22px 22px, 22px 22px, 22px 22px, 22px 22px, 22px 22px, 22px 22px, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 100% 100%;
  background-position: 109px 20px, 109px 74px, 109px 128px, 109px 182px, 109px 236px, 109px 290px, 29px 20px, 29px 74px, 29px 128px, 29px 182px, 29px 236px, 29px 290px, 0 0, 0 0, 0 0, 0 0, 0 0, 0 0, 0 0, 0 0, 0 0, 0 0, 0 0, 0 0;
  box-shadow: 0 0 3px 1px #262626, -1px 1px 0px 0px var(--p-side), -2px 1px 0px 0px var(--p-side), -3px 2px 0px 0px var(--p-side), -4px 2px 0px 0px var(--p-side), -5px 3px 0px 0px var(--p-side), -6px 3px 0px 0px var(--p-side), -7px 4px 0px 0px var(--p-side), -8px 4px 0px 0px var(--p-side), -9px 5px 0px 0px #20202080, -9px 5px 0px 0px #101010, -15px 10px 10px 0px #0008, 0 0 3px 1px #262626 inset;
}

.electric-body:before {
    margin-left: -200px !important;
    margin-top: 5px !important;
}

Guitarra Clásica

El cuerpo de la guitarra clásica es más simple. Con radial-gradient creamos el vacío de la boca central, el borde de la boca y los adornos de bordes rojos acabando con color naranja, y ponemos encima un linear-gradient negro-transparente-negro, para darle volumen. Con los pseudo-elementos esta vez hacemos el sombreado del interior de la boca y los adornos de círculos rojos.

.classic-body {
  --c-mouth: #7c1d1c;
  background: linear-gradient(180deg, var(--c-mouth) 0%, #fff0 10% 90%, var(--c-mouth) 100%), linear-gradient(180deg, #0008 0%, #fff0 40% 60%, #0008 95%), radial-gradient(circle at 50% 50%, #c5a05e 0 135px, #bb8d3c 173px, #ff5e00 178px 185px, var(--c-mouth) 186px 195px, #ff5e00 196px 235px, var(--c-mouth) 236px 245px, #ff5e00 246px 100% );
}

.classic-body:after {
  content: "";
  position: absolute;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
  --dot: radial-gradient(circle, var(--c-mouth) calc(68% - 1px), #fff0 68% 100%);
  background: var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot), var(--dot);
  background-position: calc(50% - 216px) 50%, calc(50% - 204px) calc(50% + 70px), calc(50% - 175px) calc(50% + 125px), calc(50% - 125px) calc(50% + 175px), calc(50% - 70px) calc(50% + 204px), 50% calc(50% + 215px), calc(50% + 70px) calc(50% + 204px), calc(50% + 125px) calc(50% + 175px), calc(50% + 175px) calc(50% + 125px), calc(50% + 204px) calc(50% + 70px), calc(50% + 215px) 50%, calc(50% + 204px) calc(50% - 70px), calc(50% + 175px) calc(50% - 125px ), calc(50% + 125px) calc(50% - 175px), calc(50% + 70px) calc(50% - 204px), 50% calc(50% - 216px), calc(50% - 70px) calc(50% - 204px), calc(50% - 125px) calc(50% - 175px), calc(50% - 175px) calc(50% - 125px), calc(50% - 204px) calc(50% - 70px);
  background-size: 10px 10px, 15px 15px, 20px 20px, 25px 25px, 30px 30px, 40px 40px, 30px 30px, 25px 25px, 20px 20px, 15px 15px, 10px 10px, 15px 15px, 20px 20px, 25px 25px, 30px 30px, 40px 40px, 30px 30px, 20px 20px, 15px 15px, 10px 10px;
  background-repeat: no-repeat;
}

.classic-body:before {
  content: "";
  position: absolute;
  background: radial-gradient(circle at calc(50% + 5px) calc(50% + 2.5px), #fff0 175px, var(--c-mouth) 185px), radial-gradient(circle at 40% 55%, #fff0 175px, #0004 195px, #000c 220px);
  border-radius: 100%;
  left: calc(50% - 176px);
  top: calc(50% - 178px);
  width: 350px;
  height: 350px;
}

Hay mucho mas CSS interesante, los iconos de guitarras, los botones, el control de volumen, el icono de la púa… podéis revisarlo todo en la demo final.


Esto es solo una parte del código CSS final. En la demo encontrarás el código completo.

Javascript

El Javascript es bastante simple y muy parecido al del último afinador, básicamente lo que hacen casi todas las funciones es poner o quitar clases dependiendo de donde se pulse. Lo más destacable sería la función clickString() que he modificado para eliminar un error muy obvio del último afinador:

Antes, cuando pulsabas una cuerda, se añadía la clase playingSound a la cuerda y se activaba un setTimeout que eliminaba esa clase a los 4 segundos (la duración del archivo de audio), pero si volvías a pulsar la cuerda antes de esos 4 segundos la clase no se volvía a añadir porque la cuerda aún la tenía, la animación de vibración seguía funcionando pero el primer setTimeout eliminaba la clase playingSound a los 4 segundos con lo que la cuerda «dejaba de vibrar» antes de tiempo, aunque el audio seguía sonando. Puedes probarlo aquí, pulsa varias veces en la misma cuerda con dos o tres segundos de diferencia y verás como se detiene la animación y se apaga la iluminación antes de que la cuerda deje de sonar.

Después de probar un par de veces con resultados insatisfactorios encontré una solución válida usando el método setInterval y una función que detecta si un audio está reproduciéndose. Si es así y el audio se está reproduciendo se limpia el setInterval usando el método clearInterval y se reinicia la función de nuevo desde cero. No es una solución muy elegante pero funciona y creo que bastante mejor que el último afinador, que tenia ese pequeño fallo y bien visible.

Que suenen las cuerdas

En la función clickString() se usan un par de funciones que debo mostraros antes, una es para acortar el document.getElementById y la otra para detectar si un audio está sonando:

// Acortar document.getElementById  
function elem(id){ return document.getElementById(id); }

// Detectar si un audio esta sonando
function isPlaying(aId) { return !aId.paused; }

Y finalmente así queda la función clickString():

function clickString(thisString) {
  // reset
  if (isPlaying(window[thisString])) clearInterval(soundTimer); 
  window[thisString].pause();
  window[thisString].currentTime = 0;
  elem(thisString).className = "string ";
  elem(thisString).offsetHeight; 
  elem(thisString).style.animation = null; 
  // play
  window[thisString].play();
  elem('tuner-title').className='imgTitle';
  elem(thisString).className = "string playing-sound";
  elem(thisString+'Note').className = "lightOn";
  elem(thisString+'Nota').className = "lightOn";
  // stop
  var soundTimer = setInterval(function() {
    if (!isPlaying(window[thisString])) {
      if(window[thisString].loop != true){
        elem(thisString).className = "string";
        elem(thisString+'Note').className = "";
        elem(thisString+'Nota').className = "";
        if(document.querySelectorAll('.playing-sound').length==0){
          elem('tuner-title').classList.remove('imgTitle');
        }
      }
      clearInterval(soundTimer);
    }
  }, 200);
}

La función, explicada línea a línea, funciona de la siguiente manera:

  1. Nombre de la función clickString y el argumento que será el id cada cuerda, thisString.
  2. Comentario que indica que empieza el reseteo de la cuerda pulsada.
  3. Condicional if: comprobamos si el audio está sonando con la función isPlaying() y si es así se limpia el intervalo que hace que se detenga cuando ha dejado de sonar (este intervalo lo crearemos mas abajo).
  4. Pausamos el sonido.
  5. Rebobinamos el sonido.
  6. Añadimos a la cuerda solo la clase string.
  7. Reiniciamos el elemento (la cuerda).
  8. Reiniciamos la animación de partículas.
  9. Comentario que indica que empieza a sonar la cuerda.
  10. Reproducimos el sonido de la cuerda.
  11. Añadimos una clase al titulo para encenderlo.
  12. Añadimos la clase playing-sound a la cuerda pulsada.
  13. Añadimos una clase a la nota (en inglés) de esa cuerda para encenderla.
  14. Añadimos una clase a la nota (en español) de esa cuerda para encenderla.
  15. Comentario que indica que empieza el pausado de la cuerda.
  16. Almacenamos un setInterval en la variable soundTimer. Este intervalo se ejecutara cada 200 milisegundos ver línea 28.
  17. Condicional if: si no está sonando la cuerda (si ya terminó el audio…).
  18. – Condicional if: si no esta activado el botón hold (mantener)
  19. – – Quitamos la clase playing-sound.
  20. – – Quitamos las clases lightOn que iluminan las notas en inglés.
  21. – – Quitamos las clases lightOn que iluminan las notas en español.
  22. – – Condicional if: si no hay ninguna otra cuerda sonando.
  23. – – – Quitamos la clase imgTitle que ilumina el título.
  24. – – Cierre de if linea 22
  25. – Cierre de if linea 18
  26. Limpiamos el intervalo almacenado en la variable setTimer con clearInterval() para que deje de ejecutarse.
  27. Cierre de if linea 17
  28. Cierre del método setInterval linea 16. Aquí definimos también la duración del intervalo em milisegundos, o cada cuanto tiempo queremos que se ejecute.
  29. Cierre de la función clickString linea 1

La verdad es que ahora describiendo aquí la función he visto un par de cosas mejorables, no te sorprendas si en la demo final esta función aparece algo cambiada…

Cambio de cuerdas

Poco más en cuanto al Javascript, si acaso el cambio de los archivos de sonido en las cuerdas cuando se cambia de guitarra, que se hace con la función changeStrings() . Esta función será llamada desde la función changeGuitar() que no hace nada raro y que no mostraré aquí, básicamente detiene todas las cuerdas, cambia el cuerpo de la guitarra modificando unas clases y llama a la función changeStrings() que es la que cambia los archivos de audio de clásica por los audios de eléctrica (o viceversa), y que si muestro y describo a continuación.

function changeStrings() {
  // si antes del cambio estaba seleccionada la clasica
  if(elem('guitar-body').classList.contains('e-classic')) {
    // ponemos los audios de electrica
    s1.src="https://cdn.josetxu.com/audio/cgs-1.mp3";
    s2.src="https://cdn.josetxu.com/audio/cgs-2.mp3";
    s3.src="https://cdn.josetxu.com/audio/cgs-3.mp3";
    s4.src="https://cdn.josetxu.com/audio/cgs-4.mp3";
    s5.src="https://cdn.josetxu.com/audio/cgs-5.mp3";
    s6.src="https://cdn.josetxu.com/audio/cgs-6.mp3";
  } else { // si no
    // ponemos los audios de clasica
    s1.src="https://cdn.josetxu.com/audio/egs-1.mp3";
    s2.src="https://cdn.josetxu.com/audio/egs-2.mp3";
    s3.src="https://cdn.josetxu.com/audio/egs-3.mp3";
    s4.src="https://cdn.josetxu.com/audio/egs-4.mp3";
    s5.src="https://cdn.josetxu.com/audio/egs-5.mp3";
    s6.src="https://cdn.josetxu.com/audio/egs-6.mp3";
  }
}

Si, es muy cutre, pero funciona perfectamente y eso es lo que buscaba. Tampoco descarto modificar esta función por algo más limpio, en un futuro…

Y como decía poco más, el resto de funciones son muy básicas, como mucho tienen algún bucle para modificar grupos de elementos, como por ejemplo todas las cuerdas, o todas las notas. Algunas de estas funciones las veremos en próximos artículos, como la del control de volumen, o la que hace que la púa siga el movimiento del ratón… eso si, adaptadas a otros menesteres.


Esto es solo una parte del código Javascript final. En la demo encontrarás el código completo.

Demo

Aquí tenéis la demo en un tamaño… intermedio tirando a pequeño, el que nos permite el ancho del blog, aún así parece que se comporta bastante bien…

See the Pen Online Guitar Tuner – v3 by Josetxu (@josetxu) on CodePen.

Como siempre, recomiendo ver la demo a tamaño completo en Codepen.

Espero que el nuevo afinador os sea de ayuda…

¡ Larga vida al Rock & Roll !

9 Comentarios en “Afinador de Guitarra – Online Guitar Tuner – v3

  1. Me gustaría saber si puedes solucionar el hecho que con los estilos (efectos) de las cuerdas suenen 3 veces al pasar la pua. Pienso que es un problema de los :before y :after, con un movimiento rápido y ágil no hay problema, pero bueno ya se que es mas un ejemplo de lo que se puede hacer en HTML5 y CSS3 con javascript puro y duro (vinilla o canelita).

    Gracias

    1. Hola Jesus Maria!

      La púa funciona con el evento onmouseover y se activa cuando pasas por encima de una de las cuerdas. Los botones de las cuerdas no son solo el espacio que ocupa la cuerda, es un botón de 40px de alto con la cuerda en medio, lo hice así para que no fuera muy complicado pulsar las cuerdas más finas, ya que la más fina solo mide 4px de alto. Como la púa se activa al hacer onmouseover, cada vez que lo haces sobre el boton de 40px de alto se reproduce el sonido. Lo cierto es que en la version anterior ese problema no pasaba pero al arreglar otro problema que tenía ese afinador (lo explico en el comienzo de la parte de Javascript de este artículo) ahora aparece este problema en esta última versión. Realmente la púa no está hecha para afinar cada cuerda por separado, solo está para hacer un rasgueo y comprobar el sonido final de todas las cuerdas, ya sea hacia abajo o hacia arriba.

      Se me ocurre que se podría usar la nueva función solo sin la púa seleccionada y la función de la anterior versión cuando la púa sí esté seleccionada. Lo investigaré para ver si se puede mejorar…

      Gracias por tu comentario Jesus Mari!
      Un saludo!

      1. Realmente vi el problema si se usa el evento hover junto al mousedown para poder levantar digamos la púa o sea sólo arrastrar o pasar por algunas cuerdas.
        Ya me contarás es un trabajo muy bueno con el que demuestras tu capacidad técnica y artística, pensé que para esas definiciones de css3 se usaban herramientas de diseño gráfico. Yo sigo en el puro javascript sin a penas nada más y del estilo moderno poco sólo me defiendo algo con los promise y asyncr muy necesarios para el javascript realmente.
        Gracias de nuevo

        Ah! por cierto vi una linea de codigo ya en codepen al pulsar una cuerda que era esa que dices de la altura pero no probe a cambiar, en clickString( … ) la linea: elem(thisString).offsetHeight; – que sin parte izquierda ni derecha no la entendia, debe de ser donde esta el alto que decias

        1. Es todo con el evento onmouseover de Javascript, el evento hover solo afecta a los estilos CSS coloreando la cuerda al pasar por encima, pero si mantienes el puntero encima de la cuerda con el evento onmouseover de Javascript se reinicia el sonido de la cuerda.

          CSS es cada vez más potente y se puede hacer casi cualquier cosa ya, desde dar unos estilos básicos hasta animaciones o elementos tridimensionales flipantes.

          La línea que comentas: elem(thisString).offsetHeight; es una triquiñuela para eliminar ese elemento del DOM y volverlo a cargar, de esta forma se reinicia la animación CSS (el efecto de vibración) al pulsar la cuerda repetidamente. De no hacerlo así el sonido y la animación no estarían compenetrados. El alto del botón (40px) se define en el CSS, en la sentencia: .tuner-body button.string

          Gracias a ti, por encontrar ese fallo y tomarte la molestia de contármelo, de esta manera puedo mejorar el afinador y a la vez seguir aprendiendo.

          Un saludo!

          1. Es cierto, en Codepen donde vi tu Tuner encuentras verdaderas maravillas sobre todo esas visuales, hoy vi otra con bolitas en un Reel que está hecho con puro css3 seguro, bolitas que cada una atraviesa un circulo, ida y vuelta, como radios, sincronizadas de tal forma que el efecto visual es muy curioso.

            Esa triquiñuela es importante, lo malo que esas cosas a mi luego se me olvidan cuando debiera usarlas, jajaja.

  2. Se me olvido decirte y no he visto si solucionaste aquellos del repique al pasar la pua. La solución es tan sencilla como usar el evento onmouseenter en vez de onmouseover para pick

    Saludos

    1. Pues lo tenía en mente, pero creí que iba a tener que volver a modificar la función clickString() de Javascript y lo dejé para cuando tuviera más tiempo libre. No creo que se me hubiera ocurrido una solución tan fácil como la que propones; lógica, rápida y efectiva. Lo he cambiado en Codepen en menos de un minuto y funciona genial.

      Muchas gracias por la aportación Jesus Maria!
      Un saludo!

      1. Kaixo

        No estaba seguro si te lo había dicho después de mirar lo que dijiste del height para facilitar el click y luego ver como el problema como te dije era los efectos me di cuenta que podía hacerse algo con el hover y ya caí en la cuenta que siendo una función separada… para el evento…

        Bueno, me encantan tus diseños aunque la verdad que tampoco he mirado cosas mas que algo por encima.

        Muchos saludos

Deja un Comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *