Convierte tu teclado en un teclado

10

Tarea

Debe escribir un programa que, cuando se presiona un botón, emita un sonido diferente para cada tecla.

Las teclas que usará son:

1!2"34$5%6^78*9(0qQwWeErtTyYuiIoOpPasSdDfgGhHjJklLzZxcCvVbBnm

Las notas comienzan en Cy cada tecla de arriba agrega un semitono.

Sin embargo, vamos a hacerlo un poco más fácil. Puedes elegir entre 2 tareas similares,

1) Produce una nota diferente cuando se presiona una tecla que continúa hasta que se presiona otra tecla. Este programa se ejecuta indefinidamente

2) Tome una cadena como entrada que solo contenga los caracteres anteriores que generarán cada nota durante exactamente 1 segundo (se permite una variación de 0.05 segundos)

Entrada

  1. Una tecla presionada
  2. Una sola cadena que contiene solo los símbolos de arriba

Salida

  1. Una sola nota musical que suena hasta que se presiona otra tecla
  2. Una serie de notas, cada una de 1 segundo de duración

Notas

Letter | Note
-------+-------
   1   |  C
   !   |  C#
   2   |  D
   "   |  D#
   3   |  E
   4   |  F
   $   |  F#
   5   |  G
   %   |  G#
   6   |  A
   ^   |  A#
   7   |  B
   8   |  C
   *   |  C#
   9   |  D
   (   |  D#
   0   |  E
   q   |  F
   Q   |  F#
   w   |  G
   W   |  G#
   e   |  A
   E   |  A#
   r   |  B
   t   |  C    <-- middle C
   T   |  C#
   y   |  D
   Y   |  D#
   u   |  E
   i   |  F
   I   |  F#
   o   |  G
   O   |  G#
   p   |  A
   P   |  A#
   a   |  B
   s   |  C
   S   |  C#
   d   |  D
   D   |  D#
   f   |  E
   g   |  F
   G   |  F#
   h   |  G
   H   |  G#
   j   |  A
   J   |  A#
   k   |  B
   l   |  C
   L   |  C#
   z   |  D
   Z   |  D#
   x   |  E
   c   |  F
   C   |  F#
   v   |  G
   V   |  G#
   b   |  A
   B   |  A#
   n   |  B
   m   |  C

Reglas

  • Puede elegir entre las tareas, pero indique cuál en su respuesta
  • Se le da una variación de ± 0.05 segundos en la tarea 2
  • Cada símbolo incrementa el tono en 1 semitono.
  • Las notas individuales se muestran arriba
  • Este es un por lo que el código más corto gana

Esto fue tomado originalmente de aquí con el consentimiento de caird coinheringaahing

Jonathan Allan
fuente
Para abrir esto a idiomas que no tienen bibliotecas de audio, recomiendo un tercer formato de salida: un archivo WAV que contiene la salida de la opción 2, escrito en stdout. Eso permitiría entradas en cualquier idioma que pueda imprimir datos binarios.
Ray

Respuestas:

6

Python 3, 154 140 bytes

from winsound import*
for i in input():Beep(int(65.406*2**('1!2"34$5%6^78*9(0qQwWeErtTyYuiIoOpPasSdDfgGhHjJklLzZxcCvVbBnm'.find(i)/12)),999)

Elegí el segundo tipo de tarea.

El bucle pasa a través de cada carácter y busca el índice de este elemento en la cadena. Este índice es el número de semitonos arriba de Low C ('1'). El cálculo de la frecuencia deseada se realiza mediante esta fórmula .

PD: esta biblioteca solo funciona en Windows.

-13 bytes gracias a los ovs.

-1 byte gracias a Jonathan Allan.

Кирилл Малышев
fuente
1
Probablemente debería mencionar que esto solo funciona en Windows.
Totalmente humano
1
Golfed a 141 bytes:from winsound import* for i in input():Beep(int(65.406*2**('1!2"34$5%6^78*9(0qQwWeErtTyYuiIoOpPasSdDfgGhHjJklLzZxcCvVbBnm'.find(i)/12)),1000)
ovs
Pero la pregunta pedía un programa ...
Neil A.
La 0.05tolerancia debería permitirte usar 999.
Jonathan Allan
3

JavaScript (ES6), 247 o 230 bytes

Decidí probar ambas opciones.

Ahorré algunos bytes gracias a @darrylyeo por sugerir la withdeclaración.
Gracias a @ Кирилл Малышев por señalar un problema con .search().

Opción 1 - Entrada de teclado, 252 246 247 bytes

_=>{c=new AudioContext;q=1;with(c.createOscillator())connect(c.destination),I.oninput=_=>(~(i='1!2"34$5%6^78*9(0qQwWeErtTyYuiIoOpPasSdDfgGhHjJklLzZxcCvVbBnm'.indexOf(I.value,I.value=""))&&(frequency.value=65.4*2**(i/12),q&&start(q=0)))}
<input id=I

Se basa en el elemento de entrada que recibe la letra real escrita, en lugar de los códigos de caracteres. El foco debe estar en el cuadro de entrada.

Opción 2: entrada de cadena, 234 229 230 bytes

s=>{c=new AudioContext;with(c.createOscillator())connect(c.destination),[...s].map((c,i)=>frequency.setValueAtTime(65.4*2**('1!2"34$5%6^78*9(0qQwWeErtTyYuiIoOpPasSdDfgGhHjJklLzZxcCvVbBnm'.indexOf(c)/12),i)),start(),stop(s.length)}

Simplemente toma la cadena como parámetro de función.

Fragmento combinado

Sugiero bajar el volumen mientras se ejecuta esto, puede ser ruidoso. Para detener la reproducción, el fragmento requiere agregar o=dentro de cada uno with(c.createOscillator()).

f= // keyboard input
_=>{c=new AudioContext;q=1;with(o=c.createOscillator())connect(c.destination),I.oninput=_=>(~(i='1!2"34$5%6^78*9(0qQwWeErtTyYuiIoOpPasSdDfgGhHjJklLzZxcCvVbBnm'.indexOf(I.value,I.value=""))&&(frequency.value=65.4*2**(i/12),q&&start(q=0)))}

g= // string input
s=>{c=new AudioContext;with(o=c.createOscillator())connect(c.destination),[...s].map((c,i)=>frequency.setValueAtTime(65.4*2**('1!2"34$5%6^78*9(0qQwWeErtTyYuiIoOpPasSdDfgGhHjJklLzZxcCvVbBnm'.indexOf(c)/12),i)),start(),stop(s.length)}

swap=_=>{keyboard=!keyboard;A.innerHTML=keyboard?"Keyboard":"String";S.style.display=keyboard?"none":"inline";window.c&&c.close();window.o&&o.stop();keyboard?f():I.oninput=null;I.value="";}
keyboard=0;
swap();
<span id="A"></span> Input:<br>
<input id="I">
<button id="S" onclick="g(I.value)">Run</button><br>
<button onclick="swap()">Swap</button>

Justin Mariner
fuente
Puede poner el objeto del oscilador en una withdeclaración para o._=>{c=new AudioContext;with(c.createOscillator())connect(c.destination),I.oninput=_=>(~(i='1!2"34$5%6^78*9(0qQwWeErtTyYuiIoOpPasSdDfgGhHjJklLzZxcCvVbBnm'.search(I.value,I.value=""))&&(frequency.value=65.4*2**(i/12),r||(start(),r=1)))}
aprovechar
1
@darrylyeo Gracias, implementará la withdeclaración, pero rompe el último bit ( o.r||(o.start(),o.r=1)) ya que estaba usando el hecho que o.rno está definido hasta ese momento, pero ahora se equivoca ya que rno se ha declarado. Resulta que fue más corto declarar esa variable separada de cualquier objeto, así que lo hice.
Justin Mariner
Cuando ingresa el símbolo '$', se produce una frecuencia muy alta.
Кирилл Малышев
@ КириллМалышев Buena captura, eso es porque .search()trata la entrada como expresión regular. Al cambiar a .indexOf().
Justin Mariner
1

AHK , 130 bytes

s=1!2"34$5`%6^78*9(0qQwWeErtTyYuiIoOpPasSdDfgGhHjJklLzZxcCvVbBnm
Loop,Parse,1
SoundBeep,55*2**((InStr(s,A_LoopField,1)-10)/12),999

Elegí la opción 2.

Explicación:

Almacenar la cadena de búsqueda como la variable sera más corta que escapar de ese desorden directamente en la SoundBeepfunción. Tuve que escapar del signo de porcentaje, ya que es un carácter de escape para nombres de variables, pero el resto de la cadena está bien como está.

Por defecto, la variable 1es el primer parámetro de entrada. Introducir eso en un bucle de análisis sin especificar un delimitador dará como resultado que cada carácter en la cadena de entrada se analice individualmente.

SoundBeep toma una frecuencia en Hz y una duración en milisegundos y toca esa nota durante ese tiempo.

La parte divertida fue descubrir las frecuencias correctas. Haciendo referencia a la tabla de frecuencias de teclas de piano de Wikipedia y la fórmula en la misma página, encontré que la codificación más corta fue usar A 1 como nota de referencia porque su frecuencia es la ronda agradable de 55 Hz. Como queremos comenzar en C 1 , tenemos que ajustar desde A 1 (la nota 13) a C 1 (la nota 4). Eso, más el hecho de que InStrestá un índice, es la razón por la que restamos 10 del resultado de la InStrfunción.

Tostadas de ingeniero
fuente