Esto va de un proyecto que he hecho para que unos LEDs bailen según la música que le pongo en el PC.
Uso el Arduino, que podeis ver de que va en el link de la derecha (y si os interesa la electrónica, os recomiendo haceros con uno). Con 6 LEDs y resistencias, y el arduino, sobra para hacer esto.
Antes tenía un problema de sincronismo (los LEDs se volvian majaras y se intercambiaban posiciones), pero ya lo he arreglado. La parte alta del byte que envia el PC indica para que LED es la información, y la parte baja la intensidad del sonido en esa banda de frecuencias.
Si no os interesa todo el rollo ese, mirad el video siguiente que es lo bonito:
Fijaros cuando silba K.K Slider
Primero comento un poco por encima el programa, y al final os pondre el código. Los que os interese el Arduino echadle un vistazo, así os podeis hacer una idea de lo fácil que es programar para esto (aunque si quieres hacer cosas complicadas, también puedes programar en C).
La parte que está en el Arduino es muy simple, y de hecho esta casi fusilada de un ejemplo que viene con el compilador del Arduino (Dimmer, se llama). Simplemente se indica que los pines capaces de regular voltaje son salida, y luego se espera que lleguen los bytes del PC. Se separa la parte alta y la parte baja, con la alta se elige el LED correspondiente (mediante un vector), y la parte baja lleva la intensidad del volumen ya tratada. Como la luminosidad de los LEDs no es lineal con el voltaje, hay otro vector para esto, entramos como índice con el volumen y ya nos devuelve cual sería el voltaje (que va de 0 a 255, es decir, de 0 a 5 V).
Esto de la luminosidad suena raro, pero realmente lo hice a voleo probando valores. Primero lo puse a tope (255) y luego busque lo que para mí sería un valor medio de luminosidad. El resto de valores esta medio extrapolando medio interpolación lineal.
La parte que lleva el PC (mediante Processing) es un poco más complicada. Utiliza la libreria minim, que la verdad es que me resolvió la peor parte de todo, poder obtener el espectro de frecuencias de la señal de salida de la tarjeta de sonido.
Esto esta hecho muy a voleo, con poca base de utilización de señal y demás. Lo podría haber hecho mejor, pero quería algo molón, no exacto.
Lo que hago primero es obtener la transformada de fourier de la señal de sonido, gracias a la libreria. Una vez obtenido, la separo en 240 barras equidistantes de forma lineal, para agrupar bandas de frecuencias. Y luego lo que hago es escoger para cada LED varias barras de estas, y coger el valor máximo de cualquiera de ellas.
¿Por que lo hago así? Como sólo tengo 6 LEDs si cojo el espectro, lo divido en 6 y que haga la media de amplitud, no se ve casi nada. Si lo hago en plan logarítmico (que es como van la mayoría de estos ecualizadores o analizadores de frecuencia) pues no va mal del todo, pero pasa lo mismo que antes, los LEDs se encienden casi todo el rato y no se llega a distinguir mucho a la vista.
Pero con esto del máximo, si hay un instrumento tocando en la banda de frecuencias de un LED, al tener mucha amplitud pero poco ancho de frecuencia, se notara muchisimo en un led en particular, vamos, lo que pasa en ese video con el silbido, o en el de la entrada anterior con la ocarina.
Aparte de eso, cada rango de frecuencias suele tener una amplitud más baja a medida que la frecuencia es mayor. Para compensarlo tienen coeficientes distintos, y en el ultimo LED que es para detectar ruido o percusiones multiplico la amplitud por la frecuencia.
Luego otra cosa que tiene es lo de "volumen" esto es una variable que intenta detectar el volumen general que tiene la canción o lo que sea, ya que dependiendo de como pongas tu el volumen manualmente, como sea el PC, o si la canción esta más bajita que otra o lo que sea los LEDs se iluminarian más o menos, y no queremos eso. Esto mide el volumen actual (que es in.mix.level, si es muy bajo es que no suena nada en ese preciso instante) y lo va actualizando, porque si lo cogiera de forma instantanea saldrian igual los sonidos fuertes o debiles dentro de una misma canción y eso tampoco lo queremos.
Despues separa la información en LEDs y la intensidad (que lo hace dividiendo por 10, para que sea un valor entre 0 y 30) y se la envia al arduino. Además lo dibuja, que es lo que usaba yo para ajustarlo fino, ya que lo último que hice fue enviar los datos al Arduino.
Y creo que eso es todo. Pongo el código a continuación (lleva muchos comentarios de como va cada cosa, eso sí, en inglés porque quiero ponerlo en los foros del arduino), y si alguno quereis saber más pues me lo preguntais aquí mismo.
Código para el Arduino: Secreto: (Pincha para leerlo)
/*You'll need 6 LEDS to make it work, connected to the PWM pins on the arduino duemilanove. If you have the arduino mega, you could put more LEDs, feel free to change the code.
I used a 100 ohm resistor, you can watch the LEDs I used (and a demo) on this video:
http://www.youtube.com/watch?v=pH9U5miKfcc
*/
const int vectledPin[]={3,5,6,9,10,11};
/*These are the values that will be given to the PWM ports on the arduino. The arduino will receive values between 0 and 30, that measures the "volume" linearlly. However, the LED's don't bright linearlly, so I tested it a bit and put these values as my own testing. I used the DIMMER sketch example on the arduino program to know what values to use. Feel free to change them. One small change would be to make two vectors, as I used two different types of LEDs.*/
const int vectbright[]={0,1,2,3,4,6,8,19,14,18,22,27,32,38,47,56,66,76,86,96,105,114,122,130,138,148,162,190,222,255,255}; int i=0;
void setup() { // initialize the serial communication: Serial.begin(9600); // initialize the ledPin as an output: for (i=0;i<6;i++) pinMode(vectledPin, OUTPUT); i=0; }
void loop() { byte brightness; byte led;
// check if data has been sent from the computer: if (Serial.available()) { // read the most recent byte (which will be from 0 to 255): brightness = Serial.read(); led=(brightness>>5); //This reads what LED it is (it is stored on the 3 high bits)
brightness=((brightness)&0x1F); //and this reads the 5 lower bits only. It puts a 0 in the higher ones.
analogWrite(vectledPin[led], vectbright[brightness]); //and finally, using both vectors and the brightness index, the PWM value is sent } }
Código para el Processing: Secreto: (Pincha para leerlo)
/*A very important note. You have first to compile and upload the arduino code, otherwise it will give you a serial error.
Also, if you want the stereo mix as an input (the sound that is going through your speakers), you have to change it in windows (or mac and linux as well, i'm not sure) as the main input for recording. This is easily done in windows vista and 7 right clicking the general volume button, choosing recording options, and selecting stereo mix as the main one. You'll probably have to switch off (software) the microphone input, too. If you don't see this options, right click your microphone, and check all options to make sure stereo mix (or something like that) is shown. You'll have to restart this Processing sketch in order to make it work.
The things you need to make it work are told in the arduino code. */ import processing.serial.*; import ddf.minim.analysis.*; import ddf.minim.*;
Serial port;
AudioInput in; Minim minim; FFT fftLin; //I used an example of FFT as a base, and tweaked it a bit.
float vectormedias[]=new float[6]; // this keeps the averages of the 6 bands of frequency. float magnitud=4; //general setting, it multiplies all volume signal. float volumen; // this measures the general volume, but it changes slowly (like a P control) to avoid noise int volcaptado; // this is the final volume sent to arduino for a certain led. It gives the index to the brightness vector.
void setup() { println(Serial.list()); if (port==null) port = new Serial(this, Serial.list()[1], 9600); //perhaps in your case is Serial.list()[0] size(512, 300, P3D); volumen=1;
minim = new Minim(this); in = minim.getLineIn(Minim.STEREO, 2048); fftLin = new FFT(in.bufferSize(), in.sampleRate()); fftLin.linAverages(240); //It takes 240 bands of frequency (linear). This is to avoid noise or strange sounds. (perhaps not needed) // Later, the maximum of a certain range of this bars will be taken. rectMode(CORNERS); }
void draw() { background(0); // perform a forward FFT on the samples in jingle's mix buffer // note that if jingle were a MONO file, this would be the same as using jingle.left or jingle.right fftLin.forward(in.mix);
noStroke(); fill(255); int w = int(width/6); //next follows a for that gets the maximum of certain ranges of bars, for 6 LEDs for(int i = 0; i < 120; i++) { if (i<=1) { if (vectormedias[0]<2*fftLin.getAvg(i)) vectormedias[0]=2*fftLin.getAvg(i); // Each range has a multiplier, to adjust the visual response. This is based on tests, feel free to change it. // I changed them a lot, feel free to change what bars are included too. Some will be OK for certain music, or not. } else if (i<=5) { if (vectormedias[1]<1.2*fftLin.getAvg(i)) vectormedias[1]=1.2*fftLin.getAvg(i); } else if (i<=12) { if (vectormedias[2]<1.6*fftLin.getAvg(i)) vectormedias[2]=1.6*fftLin.getAvg(i); } else if (i<=22) { if (vectormedias[3]<1.75*fftLin.getAvg(i)) vectormedias[3]=1.75*fftLin.getAvg(i); } else if (i<=55) { if (vectormedias[4]<2*fftLin.getAvg(i)) vectormedias[4]=2*fftLin.getAvg(i); } if (i<=160) { //This is the last one. It is multiplied by the bar index, to give more weight to the final frequencies (that tend to be lower always). //This gives good feedback for noise, high pitch sounds, or percusion instruments. vectormedias[5]=i*fftLin.getAvg(i)/300+vectormedias[5]; } if (i==119) { for (byte k=0;k<6;k++) { delay(10); fill(255); //The following number is important. It is the level that is taken as real input, if you catch noise //you will have to make it a bit bigger. If you don't have any noise, perhaps a lower number is better if (in.mix.level()>0.001) { /*This keeps the volume changing with the in.mix level. However, we don't want it to change very fast, because in.mix.level is very variable. Otherwise, you'll see low sounds as big as high sounds. And we don't want it to be constant, otherwise when the volume is low you won¡t see anything. Feel free to change the values to change faster or slower though (keeping the sum as 1.00, don't mind the *10)*/ volumen=volumen*0.998+in.mix.level()*0.002*10; // the *10 is cause the in.mix.level is usually 0.1. I wanted it to be closer to 1. //println(in.mix.level()); //uncomment this if you want to try to change the volume control volcaptado=int(magnitud*vectormedias[k]/volumen); //This is the last step. It gives the amount of volume to the graphic bars and the arduino. if (volcaptado>300) volcaptado=300; //we don't want it to be VERY big. volcaptado=volcaptado/10; //the arduino will get a value between 0 and 30 as the volume input. A same, but it is necessary as we'll need 3 bits to select the LED, //and we have 5 more (up to 31). I could have used 0 to 31, but I was lazy.
port.write((k<<5)|byte(volcaptado)); //This gives the arduino wich led it is with K, and the value of volcaptado. // it works like this: XXX | XXXXX // first the number of the LED, and last the amount of volume. The serial port only send one byte (eight bits) so it has to be like that. // Another option would be giving a certain number to sync arduino and processing, like 0, v1, v2, v3, v4, v5, v6 , (and repeat). // However, the LED's change so fast that with 30 values I found it enough. Feel free to change it, though. rect(k*w, height, k*w + w, height - magnitud*vectormedias[k]/volumen); //and this draws the rectangles in your processing window If you don't want this feedback, just comment the line above. } else{ //We get here if the in.mix.level is very low. So no sound is received. You'll receive noise only. volumen=0.4; //We put a low volume as a base (so when a sound comes in, the LED will bright more than usual) port.write((k<<5)); // We tell the arduino to put all LED's with a volume of 0. delay(100); // change the delay if you want, or even delete it. }
vectormedias[k]=0; // we delete the previous maximums, to make new ones in the next iteration.
} }
}
}
void stop() { // always close Minim audio classes when you are done with them in.close(); // always stop Minim before exiting minim.stop();
super.stop(); // send led=0 before exiting port.write(0); }
Bueno, hace unos días os enseñaba el aparatito que me he comprado . Uno de los proyectos "sencillos" a nivel de electrónica que se me ocurrieron es usar varios LEDs como salida de sonido del ordenador.
Cuando lo pensé imaginé que me costaría gran parte del verano, pero gracias a Processing y la libreria Minim , lo he hecho en apenas dos días. Aún no esta acabado al 100% (me falta arreglar unas cosillas, a veces los LEDs se desincronizan y "cambian de sitio"), pero cuando esté el codigo arreglado y bonito lo pondré aquí y en los foros del arduino , además de poner una entrada más explicando cosillas.
Basicamente son 6 LEDs, el primero (izq) va con los graves, el segundo un poco más agudo... y así, hasta el 6º que en vez de ir con eso mide el volumen en general (en teoría va bien para ver ritmos).
Donde mejor se ve es con música clásica o instrumental, ya que el contenido en frecuencias esta más concentrado. Por eso os lo muestro con una de las canciones que mejor se ve:
Y que además, mola mil. No esta entera por mi cutremovil.
Creo que me ha quedado bastante bien, ya explicaré más como va el asunto cuando cuelgue el código. Tardaré unos dias, que me ha de llegar una placa de pruebas nueva y hasta entonces no creo que lo vuelva a probar.
Hoy vengo a hablaros de Arduino, se trata de una plaquita electrónica de "codigo libre". ¿Que significa esto? Que el esquematico del circuito es descargable, te la puedes fabricar tu mismo adquiriendo el microchip y modificarlo a tu gusto, dispone de un compilador basado en Java de código libre genial (con muchas librerias y sencillo de usar)...
Yo creo que es el cacharro más adecuado si quereis empezar a trastear con la electrónica con posibilidad de programación.
Al margen de eso, si os decidis a comprarlo, tendreís una plaquita la mar de interesante. El Arduino Duemilanove (la versión más típica y barata, sobre los 25€) tiene 14 salidas/entradas digitales (6 de ellas configurables como PWM), 6 entradas análogicas, conexión I2C, alimentable (y programable con el PC) por cable USB B (creo que el B, el de la impresora vamos), también se puede alimentar luego con alimentación externa si lo preferis... tiene un sinfín de posibilidades, y es una gran placa si quereis empezar a trastear con esto (como es mí caso).
El lenguaje con el que se programa, basado en Java (es de nivel más alto), es sencillisimo de usar aunque no por ello tiene pocas posibilidades, y viene con muchos ejemplos para los circuitos típicos que se os pueden ocurrir, de forma que podeis aprender con ellos y hacer los vuestros propios. Por si fuera poco, tiene una comunidad muy fuerte detrás, sobretodo en inglés pero tambien tiene página y foros en español.
Comentar también que hay otro lenguaje de programación muy util para crear interfaces de modo rápido, y hacer toda clase de cosas, llamado Processing , desarrollado por los mismos que han hecho el lenguaje de compilación para el arduino (un par de profesores del MIT, creo). Este último lenguaje y compilador ha ganado muchos premios, y se puede hacer de todo con él, desde interfaces gráficas en el ordenador, videos, que capte video y trate imagenes, hacer pdfs... Tiene muchas librerias. Pero ya hablaré en otra entrada de él, supongo.
Si os choca todo lo que he dicho pero aún así os interesa, una tienda de las cuales las vende en España, tiene un videotutorial-presentación que aclara bastante las cosas:
Si os decidis a trastear tendreís que comprar cosas típicas de resistencias, leds, una plaquita de pruebas... En muchas páginas viene con un starter kit. Para que os hagais una idea, yo hice el pedido con mi novia y decidimos comprar todo lo demás aparte, y al final nos gastamos unos 32€ cada uno en componentes (compramos un kit basto de resistencias, muchos condensadores, un pack de 20 leds distintos, dos packs de switches, receptores de infrarrojos y emisor de infrarrojos, cable, plaquita de pruebas donde enganchar los cables, alimentación externa)
Lo digo para que tengais una idea del precio, aunque quizá lo mejor si no teneis mucha idea sería que anotarais con lo que suelen venir esos starter pack, y acudais a alguna tienda de electrónica que tengais cerca a ver por cuanto os puede salir comprarlo todo (seguramente mucho más barato).
Si teneis dudas, aquí me teneis. Proximamente comentaré una cosilla que estoy haciendo con el Processing, una especie de ecualizador de sonido, pero que lo único que hace es mostrar la amplitud de las frecuencias para que quede molón. Lo he hecho en 2-3 horas, en las librerias de sonido de Processing ya había cosas similares. El proyecto es luego enchufarlo al Arduino, y que muestre eso por 6 leds, de forma que cuando este jugando, escuchando música pero a mi aire, vea el ecualizador por los leds del Arduino.