Piezoeléctrico y cuerda pulsada

Se trata de convertir la señal de un piezo en una nota midi.
Lo ideal sería que, mientras haya vibración -mientras haya tensión- suene la nota. Y... suena pero durante el tiempo que dura la vibración, Arduino te ha visto muchas veces e interpreta cada pico de la señal como una nota nueva así que se oye una ametralladora.
¿Alguien tiene una solución a esto?
Desde ya muchas gracias.

¿Que piezo y circuio esas usando?,
Saludos.

La señal del piezo y la masa se unen con una resistencia de 1 M
Salida midi desde Arduino a Focusrite y ProTools

Si posteas el código en una foto (que no está permitido) ¿cómo lo copio para probarlo o modificarlo?

Si me obligas a tipearlo (siendo que podría hacer un copia y pega), por más corto que sea el código, me sacas las ganas de siquiera pensar una solución.

#include <MIDI.h>

#define C360 0                 //El Do3 nota midi 60 entra por A0

byte val = 0;

MIDI_CREATE_DEFAULT_INSTANCE();


void setup() 

{
 MIDI.begin (MIDI_CHANNEL_OFF);
}

void loop()

 {
  val = analogRead(C360);
  
  if (val > 100)
  
  MIDI.sendNoteOn (60, val, 1);     
                              
  if (val = 1)
                        
  MIDI.sendNoteOff (60, 0, 1);
                              
 }                     
  
  

Moderador:
Realmente si un forero te advierte que te estas manejando mal, porque no te tomas el trabajo de mirar otros hilos o mejor aún las normas del foro!!
Ahora te pido dos cosas.

  1. Edita el post#5 usando etiquetas de código como ya @gatul te había pedido.
  2. el sensor al que le has puesto una foto es muy lindo pero sabes que nosotros no podemos leer de cual se trata, asi que postea un link (usando la etiqueta (eslabón).
    No es muy dificil y será de ayuda para ti asi podremos darte una mejor respuesta.

Normas del foro Arduino en Español

La verdad es que he leído decenas de hilos y he leído las normas del foro que entiendo se refieren al trato personal. No sé lo que es "etiquetas de código". Eso es lo único que tengo y lo escribí yo leyendo y leyendo y más leyendo.
Si tuviera alguna característica del piezo la hubiera puesto pero no tengo nada de nada. Sé que está hecho en Francia por encargo de un Luthier y el fabricante del piezo no me va a dar a mi sus características. Ese producto no está en Internet en ninguna parte y he buscado mucho. Es un piezo apropiado para recoger la vibración de una cuerda.

Hola.
Prueba este otro código y cuentame las diferencias con el anterior

#include <MIDI.h>
#define LED 13
#define HARP1 0

byte val = 0;
MIDI_CREATE_DEFAULT_INSTANCE();

void setup() {
  pinMode (LED, OUTPUT);
  MIDI.begin (MIDI_CHANNEL_OFF);
}
void loop() {
  val = analogRead(HARP1);
  if (val > 100) {
    MIDI.sendNoteOn (60, val, 1);
    delay (val);
  }
  else {
    MIDI.sendNoteOff (60, 0, 1);
  }
}

Saludos

Para mí tendría que usar un filtrado tipo debouncer, disparar la nota cuando la cuerda empieza a vibrar, dejarla sonando mientras la cuerda vibre y solo cortar la nota cuando la cuerda ya no vibra.

Se me ocurre que lo apropiado sería tomar como fin de vibración x cantidad de lecturas por debajo de cierto umbral. Entonces cada lectura por encima del umbral reiniciará el contador (o sea que la cuerda está vibrando), hasta que llegado al umbral el contador avanzará con cada lectura porque ya no se reiniciará, hasta que se cumpla la cuenta y se "apague" la nota.

Voy a intentar pasarlo a código.

Saludos

Algo así

#include <MIDI.h>
#define LED 13
#define HARP1 A0

byte umbral_sup = 100;  // ajustar según sea conveniente
byte umbral_inf = 1;  // ajustar según sea conveniente
unsigned long contador = 0;
unsigned long fin_cuenta = 1000;  // ajustar al valor más adecuado
bool vibrando = false;

MIDI_CREATE_DEFAULT_INSTANCE();

void setup() {
  pinMode (LED, OUTPUT);
  MIDI.begin (MIDI_CHANNEL_OFF);
}

void loop() {
  byte val = analogRead(HARP1) / 8;
  
  if (val > umbral_sup) {
    if(vibrando == false) {
      MIDI.sendNoteOn (60, val, 1);
      vibrando = true;
    }
    contador = 0;
  }

  if(val < umbral_inf) {
    if(vibrando == true) {
      contador++;
    }
    if(contador == fin_cuenta) {
      MIDI.sendNoteOff (60, 0, 1);
      vibrando = false;
    }
  }
}

Lo explico:
Inicia el loop() con la lectura del piezo.
Si la lectura supera umbral_sup y la cuerda ya no estaba vibrando, dispara la nota y pone en verdadero la variable vibrando que indica el estado de la cuerda. Por otro lado, siempre que se supere umbral_sup se resetea contador.
En caso que no se supera umbral_inf y mientras vibrando es verdadera, se incrementa contador.
En próximas pasadas del loop(), si contador llega a fin_cuenta lecturas por debajo de umbral_inf, apaga la nota y pone vibrando en false para indicar que la cuerda está en reposo. Eso es todo.

Ver de ajustar umbral_sup si la nota no se dispara (disminuir su valor).
Modificar umbral_inf si el apagado de la nota no se realiza como debe (aumentar su valor).
Principalmente ajustar el valor de fin_cuenta hasta que deje de "ametrallar" (yo puse un valor arbitrario, puede ser necesario aumentar o diminuir su valor).

Saludos

Nota: Perdón por tantas ediciones, corregí algunos errores que me marcó @gonpezzi , hice algunas modificaciones y amplié contenido.

Saludos

De "10" @gatul , solo un par de preguntas:

  • ¿No habria que cambiar #define HARP1 0 por #define HARP1 A0?. Lo mismo estamos leyendo las transmisiones del puerto serie con el equipo midi
  • val es de tipo byte yo pondria : val = map((analogRead(HARP1)),0,1023,0,127);
    El 127 no me preguntes el por que, en todos los ejemplos que he visto solo llegan a esa cantidad, debe ser alguna especificación del protocolo MIDI. Y si este valor que digo es el correcto un limite de100 para activar me parece un poco alto.
    Saludos.

Uh! Tenés razón! Me olvidé de corregirlo.

Si, tenés razón también en lo del 2do. parámetro de sendNote..().
Tiene como valor máximo 127 porque así fue definido el protocolo, de cada byte solo se usan 7 bits para datos y el bit 7 se usa como señalización.
Por eso el valor máximo que se puede enviar es 127.

Lo voy a solucionar sin map().
Ahora entiendo por qué originalmente usaron byte y no int... ( y sale oootra corrección).

Respecto al pin, es válido acceder a A0 como 0, yo lo descubrí hace poco, claramente el compilador se encarga de asignar el pin correcto al hacer un analogRead().

Por cuestión de claridad, también lo corrijo.

Aviso, corrijo los códigos, pero resalto la ayuda del amigo @gonpezzi. Que conste en actas. :grin:

Respecto a los umbrales traté de ajustarme al código que subió @DANIELJORDAN y que le funciona, solo trato de evitar la "ametralladora".

Gracias!

@DANIELJORDAN si pruebas el código y el disparo se efectúa con valores demasiado bajos de umbral o el apagado es muy abrupto, hay que hacer una modificación del código, simplemente avisa y lo vemos.

Ocurre que al desconocer los niveles de tensión que genera el piezoeléctrico estoy usando valores de umbral que pueden no ser los adecuados, lo mismo con la división que hago del valor leído en el ADC.

Eventualmente se podría limitar la lectura para que no exceda el máximo permitido por MIDI de la siguiente manera

void loop() {

  int val = analogRead(HARP1);
  if(val > 127) val = 127;

// lo que sigue...

Por supuesto el código se puede mejorar mucho, por ej. tu código no varía el volumen por debajo de 100, suena en nivel 101 hasta que se apaga, es muy "artificial" (si acaso un instrumento MIDI pudiera no serlo...), se podría modificar fácilmente para que "acompañe" a la cuerda.

Saludos

Muchas gracias. Ya se nota que está mejor redactado el código. Así aprendo.
Repite notas igual pero suena mucho mejor: mi código da una señal audio más sucia y la tuya suena con mucho más nitidez.

Wow !!! Vaya profesionales !!
Felicitaciones !! Pensé en todo momento que me orientaríais hacia el hardware; nunca pensé que el problema se pudiera arreglar con el código. Bien.
Imposible llegar al final de este proyecto sin vuestra ayuda. Mil, mil gracias.
Necesito un par de días o tres para probar cosas con un amigo y ahí podré decir qué manda exactamente el piezo.
El ajuste de "umbral" no puede ser muy bajo (10 originalmente): las cuerdas son siempre ruidosas y se dispara con cualquier roce. Por lo menos 100
Tampoco el "fin de la cuenta" puede ser 1000, con 250 va mejor aunque -muy de vez en cuando- repite una nota. Hay que ajustarlo mejor y quedo encargado.
El problema de ese "1000" es que, si quieres dar un par de notas o tres seguiditas, no las ve, no suenan.
Anecdóticamente digo que hay un récord que creo que está en 16 notas en 1 segundo sobre la misma tecla... Yo ya estoy mayor para tantas pero qué menos que 3 ó 4, no... ?
Bajando esta variable a 250-300 (sigo probando) sí se pueden dar notas seguidas.
También apaga bien el sonido: paras la vibración... para el sonido (eso está perfecto)
Ahora pregunto: si mejoro la calidad de la señal del piezo, se podrá seguir usando el mismo código o habrá que pensar en otro ??
Otra cosa, otro tema relacionado:
El proyecto tiene 2 cosas más que debo consultar (hoy adelanto una)
Sobre el mismo código debo implementar un interruptor de 3 posiciones (-1, 0, 1)
Cuando arranca Arduino estaría en "0". No hace nada.
Al interruptor lo llamamos "semitonos" y le asignamos la entrada digital 4 (por ejemplo)
Esta práctica está hecha enviando la nota midi 60 que corresponde a un Do - C3
Bien: if "semitono" está en 0, no hace nada / if "semitono" está en "1" en vez de mandar la midi note 60 manda la 61 / if "semitono" -por último, está en la posición "-1" mandará la nota 59.
Reitero mi agradecimiento y que, a medida vaya teniendo más datos y práctica, iré subiendo los resultados.
Saludos cordiales a todos.

Daniel, es un gusto dar una mano.

Supuse que habría que ajustar cosas, sobre todo la cantidad de lecturas, 1000 es un valor absolutamente arbitrario porque obviamente no tengo como probarlo, o sea, hay que calibrarlo como lo estás haciendo.

El código, si se mejora la señal, se puede mejorar pero como está funcionaría igual.
De hecho hay un par de cosas que se pueden hacer al circuito que pueden venir bien (ya planteo mejoras y no tengo ni idea de como es el circuito, ja).
Si no es molestia, más tarde te envío los detalles por privado para no sobrecargar el tema.

Respecto al interruptor, al ser de 3 posiciones vas a tener que usar 2 pines digitales. Si ambos pines están en HIGH (el interruptor está en el centro) se interpreta como 0, cuando solo uno lo está entonces será 1 ó -1 según corresponda.
Otra solución puede ser con el interruptor conmutar resistencias que formen un divisor de tensión y leerlo con un pin analógico. No es nada complicado.

Saludos