Vamos a programar #54 - ID3 y LUA.
Hola de nuevo a todos, el día de hoy vamos a ver código en LUA que sirve para extraer las imágenes embebidas en un MP3. No es lo lo más optimizado, pero a veces lo que cuenta es conseguir nuestro objetivo.Antes de continuar, es recomendable que leas uno de los post antiguos del blog en cual se explica cómo hacer de manera "artesanal" todo el procedimiento, a veces ayuda un poco saber exactamente que es lo que vamos a hacer para comprender.
Para poder probar el código vamos a necesitar un interprete de LUA para windows (o para PC con cualquier sistema operativo). Si usas windows al igual que yo, recomiendo usar ZeroBrane Studio, es gratuito para todos pero el autor muestra links para donaciones (si puedes apoyarlo hazlo, siempre le cae bien una bebida a cualquier programador independiente). ZeroBrane además de contener el interprete de lua, es un IDE que sirve para depurar código. Es muy importante instalar localmente una copia del interprete para poder abrir los archivos desde nuestro disco duro.
El código.
Con el interprete ya instalado veamos el código.
-----------De la documentación disponible en http://www.id3.org para la versión 2---------------
--[[
Para la version 2.2
Header for 'Attached picture', ID: "APIC">
Text encoding $xx
MIME type <text string> $00
Picture type $xx
Description <text string according to encoding> $00 (00)
Picture data <binary data>
Para la version 2.0
Attached picture "PIC"
Frame size $xx xx xx
Text encoding $xx
Image format $xx xx xx
Picture type $xx
Description <textstring> $00 (00)
Picture data <binary data>
]]
function WriteImage(NombreDeLaCancion,NombreDeLaImagen)
--Abrimos el archivo en modo de lectura binario
local Rdata = io.open(NombreDeLaCancion,"rb")
--Ponemos el puntero al inicio del archivo
Rdata:seek("set")
--Ahora leemos los primeros 1024b del archivo, si no encontramos aquí la etiqueta "APIC" o "PIC" asumimos que el archivo no tiene imagen embebida
local Sdata = Rdata:read(1024)
--En esta variable Guardaremos la ubicación del La etiqueta "APIC"
local GotIt = string.find(Sdata,"APIC")
--Si GotIt es nil en este punto, buscamos la etiqueta PIC
if GotIt == nil then
GotIt = string.find(Sdata,"PIC")
end
--
--Si la variable GotIt tiene cualquier valor diferente de nil; procedemos a buscar el tipo de imagen que este embebida.
if GotIt ~= nil then
local GotPNG =string.find(Sdata,string.char(137)..string.char(80)..string.char(78)..string.char(71))
--Obtenemos la versión
local GetVer = string.find(Sdata,"APIC")
--La comprobación es simple ya llegados a este punto; si uno es falso el otro debe de ser verdadero.
--Regresamos el puntero a la posición en donde se encontró la etiqueta APIC y leemos la longitud de la etiqueta
local b1,b2,b3,b4
local TagSize
if GetVer ~= nil then
Rdata:seek("set",GotIt+3)
b1=string.byte(Rdata:read(1))*256*256*256
b2=string.byte(Rdata:read(1))*256*256
b3=string.byte(Rdata:read(1))*256
b4=string.byte(Rdata:read(1))
TagSize = b1+b2+b3+b4+10
else
Rdata:seek("set",GotIt+2)
b1=string.byte(Rdata:read(1))*256*256
b2=string.byte(Rdata:read(1))*256
b3=string.byte(Rdata:read(1))
TagSize = b1+b2+b3+5
end
--Si los datos dicen que la imagen es JPG
if GotPNG == nil then
local JPicInit = string.find(Sdata,string.char(255)..string.char(216)..string.char(255))
Rdata:seek("set",JPicInit-1)
IMGData = Rdata:read(TagSize-(JPicInit-GotIt))
local MPImg = io.open(NombreDeLaImagen..".jpg","wb")
MPImg:write(IMGData)
MPImg:flush()
MPImg:close()
MPImg=nil
else
local PPicInit = string.find(Sdata,string.char(137).."PNG")
local TagDMP
if GetVer then
TagDMP=8
else
TagDMP=6
end
Rdata:seek("set",PPicInit-1)
local IMGData = Rdata:read(TagSize-(PPicInit-GotIt))
MPImg = io.open(NombreDeLaImagen..".png","wb")
MPImg:write(IMGData)
MPImg:flush()
MPImg:close()
MPImg=nil
end
end
Rdata:close()
Rdata = nil
end
print("Inserta la ubicacion de un mp3")
local FILE = io.read();
print("Inserta un nombre de archivo")
local SavePlace = io.read();
WriteImage(FILE, SavePlace);
Primero que nada, LUA dispone de funciones de lectura y escritura bastante similares a los de C. Para usar un lector, debemos de iniciarlo pasando dos parámetros, uno de ellos es el archivo que queremos leer (o nuestra canción) y el segundo parámetro es el modo en cual se abrirá; en este caso, usamos "rb" que indicará que leeremos el archivo de forma "binaria".
Al igual que en C, disponemos de una función que sirve para desplazarnos en el archivo que tenemos abierto. Antes de continuar, hay que aclarar algo; LUA no es un lenguaje orientado a objetos pero tiene una sintaxis que ayuda a simularlo y para el código anterior es lo mismo "Rdata:seek("set");" que "Rdata = io.seek("set");" y lo mismo para todos los procedimiento provenientes de cualquier "clase" así que una vez que se inicializa una variable del tipo "io", podemos usar el nombre que le dimos seguido de dos puntos para acceder a los sub-métodos. Entonces, usando "seek" sin ningún parámetro adicional a "set", le indicamos que queremos mover el puntero al inicio del archivo (byte cero)
Cuando ya iniciamos todo, leemos los primeros 1024 bytes del archivo y al igual que en C#, vamos a buscar cualquiera de las etiquetas que se usan para indicar una imagen; es decir: "APIC" o "PIC". Algo que probablemente olvide decir en el primer post sobre imágenes en los MP3's es la importancia de buscar primero "APIC" a algunos les resultará obvio cual es la razón pero a otros no. La razón es simple si buscamos PIC (que corresponde a la versión 2), el resultado de la búsqueda sera verdadero si existe "APIC" porque esta contiene toda la cadena de caracteres que buscamos, en cambio si buscamos "APIC" primero, si no se encuentra, eso no significa que necesariamente no exista "PIC".
Para realizar la búsqueda de la etiqueta, una vez que leímos todos los bytes en los cuales podría estar, creamos un flag llamado "GotIt" del tipo "boolean" y a esta le asignamos el resultado de la función "string.find()" usando cómo parámetros "Sdata" que es una copia de "Rdata" (los 1024 bytes leídos) y es en donde buscará la cadena de texto que le pasamos en el segundo parámetro.
Repetimos lo anterior 4 veces, la primera es para buscar "APIC", la segunda para buscar "PIC" luego si la variable "GotIt" resulta "true" en cualquiera de las dos funciones, hacemos una nueva búsqueda pero ahora en lugar de las etiquetas de imagen, buscamos el tipo de imagen; ya sea PNG o JPG, pero para hacerlo, hacemos uso de de los caracteres que sirven de "encabezado" para los archivos PNG, cómo ya estamos dentro de la condición en la cual si se encontró una etiqueta de imagen, solo hacemos una comprobación y si no encontramos al "encabezado" del archivo PNG entonces la imagen es JPG
Para calcular el tamaño de las imágenes, hay que recordar que seguido de la etiqueta, los cuatro bytes siguientes para la versión tres y los tres bytes siguiente en la versión dos, indican cual es el tamaño de total de la etiqueta, para poder saber cual es el valor, bastará con multiplicar cada byte por potencias de 256, empezando de izquierda a derecha por 256^3 para la versión 3 y 256^2 para la versión dos.
Finalmente guardamos la imagen haciendo uso de un escritor de archivos que se usa igual al de C, es decir creamos el archivo e indicamos cual es el modo en el cual se trabajara, cuando usamos "wb" indicamos que abriremos un archivo pra escribir de forma binaria, si el archivo no existe, se creara uno nuevo.
Para poder usar la función, en ZeroBrane presionaremos F6 y en la parte inferior, el programa no preguntará por la ubicación de una canción seguido de la ubicación que usaremos para guardar la imagen, para este ultimo es importante solo indicar la ruta y el nombre del archivo sin extensión, dentro del programa al determinar si la imagen es jpg o png automáticamente agrega la extensión adecuada.
![]() |
| Si observas bien, el archivo de imagen solo tiene la ruta y el nombre, pero no la extensión. |
Y bien por ahora es todo, el código lo puedes copiar y pegar para probarlo.
Los leo luego.
El reto de Xwork #3.
Hola de nuevo a todos, el día de hoy solo vengo a dejar el reto de Xwork.Si llevas tiempo visitando el blog no tardarás tanto en encontrar la respuesta.
Hay que recordar que el primer desafio solo fue resuelto por el usuario Zed0008 (que ya tienen su lugar en el salon de la fama). Y que el reto #2 sigue abierto.
Los leo luego.
¡¡Feliz aniversario!!
![]() |
| Primer imagen representativa del blog. |
Hace exactamente dos años, un día 21 de junio, me di a la tarea de empezar con este blog. Aunque al inicio era un poco escéptico sobre que tanta aceptación podría llegar a tener, al paso del tiempo me di cuenta de la aceptación que poco a poco iba tomando lo que me motivo a continuar con los proyectos.
Durante mucho tiempo acumule software que jamas publiqué y que solo se iba perdiendo entre montañas de CD-Roms y sectores defectuosos de discos duros. Nunca me moleste en "presumir" que hice tal programa o que X programa que subi a MEGA (R.I.P) se descargo tantas veces que pude comprar una cuenta premium por un mes. Nunca pensé que todo el código fuente que escribí le resultara útil a alguien más.
![]() |
| Segunda imagen representativa del blog (Primer aniversario). |
Cómo cualquier cosa, en el transcurso de estos dos años han habido altas y bajas, temporadas en las que fluyen las ideas cómo si de un río se tratara, pero hay ocasiones en las que otras cosas me distraen de hacer algo que valga la pena publicar, pero me he dado cuenta que la gente se sigue dando vueltas por acá y eso ayuda mucho a seguir.
![]() |
| Tercera imagen representativa del blog (Segundo aniversario). |
Los leo luego. ¡¡Gracias Totales!!
Bienvenidos a la cultura de lo desechable.
| La imagen fue tomada de: Revista Quaestionis |
Es bien sabido por todos que en la actualidad se usan los servicios "en la nube" para guardar información. Ahí depositamos toda nuestra vida: la fotos con nuestros amigos, nuestra música favorita, nuestras series favoritas y todo lo relacionado a nuestro teléfono.
Hace 20 años nos resultaba difícil el poder guardar una canción completa en un disquete por la simple y sencilla razón que estos solo pueden almacenar 1.44 MB o 2.88 MB en el mejor de los casos y una canción de cuatro minutos ocupa 8 MB.
Con el tiempo este tipo de problemas se resolvieron y poco a poco se empezaron a ver volúmenes de información bestiales en algo tan pequeño cómo una uña. Hoy en la actualidad es muy común ver unidades USB flash de 16 GB en promedio, tarjetas de memoria micro SD de igual capacidad y ambas por un precio ridículamente bajo o alto; eso si lo comparamos con el almacenamiento tradicional o mejor dicho del disco duro tradicional que en la actualidad pueden ser de 320 GB para el usuario promedio.
Con tantos datos cualquiera pensaría que la gente optaría por tener una copia de su canción favorita, el vídeo más visto de Internet almacenado para verlo un poco después y a la hora que sea; mas no fue asi. Junto al auge del almacenamiento masivo también se dio el auge de los dispositivos móviles, cualquier experto en el 2004 hubiese pronosticado que al ir incrementando los dispositivos móviles, a demanda de almacenamiento también lo haría... Y no fue así, solo por un tiempo se dio esa tendencia pero después Apple presento lo que seria la introducción al almacenamiento masivo en la nube y todo cambio.
El servicio de ICloud sirve para almacenar todos los archivos; <primordialmente> del dispositivo de Apple; llámese Ipod, Ipad o Iphone. El hecho de poder acceder a una foto; por ejemplo; que se tomó desde un IPhone y verla en un IPad que tiene una pantalla mucho más grande y sin hacer nada adicional, significó una revolución.
Poco a poco empezaron a proliferar los servicios que ofrecían almacenamiento en la nube y algunos fueron un poco más allá. Todas las personas que poseen un smartphone no solo lo usaran para llamar por teléfono o enviar e-mail, también lo usaran para otras cosas cómo jugar, oír música o ver videos y aquí es cuando entra el ingenio.
Cómo mencione un poco más arriba, el almacenamiento ha crecido de forma exponencial, los dispositivos multimedia tambien lo hicieron y con esto también lo hizo el contenido y a pesar que 64GB pueda parecer mucho, si lo llenamos con video de alta calidad solo podríamos almacenar de 10 a 30 horas de este. Ahora imaginemos que guardamos nuestra serie favorita en mi caso es Monk y se divide en ocho temporadas de 16 capítulos y cada uno dura 40 minutos, usando la métrica anterior tenemos que dura 64 horas y requeriría 128 GB para poder almacenarla.
Tomando en cuenta que también quiero escuchar música y quiero ver otras series, resulta imposible tenerlo todo a la mano. A alguien se le ocurrió este problema y dijo "usemos la nube" y así fue cómo empezaron a surgir servicios cómo netflix y todos los derivados para el consumo de video; y spotify para el consumo de audio. Anteriormente existían servicios que almacenaban archivos pero solo hacían eso, si querías hacer uso de un archivo mp3 tenías que descargarlo.
Poco a poco estos servicios empezaron a dominar el mercado y ahora resulta difícil de alguien que no haya utilizado en alguna de las ocasiones alguno de estos servicios. Para algunos es una ventaja y resulta en cierta parte razonable, nunca me he preguntado donde están mis discos de soda estéreo de la década de los 90's incluso es más fácil buscar la canción en spotify que buscar el disco, el lector y mis audífonos.
Pero por otro lado y a partir de aquí son solo especulaciones mías. El hecho de tener todo disponible a la mano, hace que la gente se acostumbre a eso. Algo no esta disponible, entonces no debe de ser bueno o tengo todo el mundo por ver pero no se por donde empezar. A lo mejor exagero un poco, pero las nuevas generaciones al nacer inmersos en estás cosas, se dan el lujo de hacer lo mismo con las personas, se reemplazan amigos más rápido que lo que cambian de zapatos, tienen parejas que solo duran dos o tres meses, se casan y el "amor" dura un par de años. Resultaría un tanto injusto decir que es debido a Netflix pero de algo no hay duda, vivimos en la cultura de lo desechable.
P:D: Me invitaron a escribir aquí por los dos años de este blog, no cuenten con volver a leer nada que provenga de mi. Además cualquiera daría por muerto al dueño.
Inutil apps #4 - Visualizador de sonido (pt. 2.)
Hola de nuevo a todos, el día de hoy vamos a continuar con la construcción del visualizador de sonido.
En el post anterior vimos cómo hacer las conexiones en el diagrama, hoy solo veremos cómo ensamblarlo.
Para que se más vistoso decidí hacer una caja de 100 cm x 10 cm x 10 cm con madera de 0.4 cm. para eso corte 2 pedazos de 100 cm x 10cm y once pedazos de 10 cm x 10 cm para usarlos cómo divisores.
Para unir todo simplemente use clavos de 1.27 cm y pedazo de madera de 9 cm x 2 cm x 2 cm. Odio admitirlo, pero de esta parte no gusto tanto el resultado porque se así:
Y se notan más cuando la luz se enciende pero a pesar de todo decidi mantener el diseño cómo simple recordatorio de que hay que planear bien todo desde el principio.
Luego pegue los LED's usando silicón caliente, puesto que esto esta diseñado para no moverse mucho, en lugar de usar clavos o un pegamento más potente, el silicón cumple con su trabajo a la perfección y por eso también lo use en los espaciadores.
Cuando terminé de pegar los LED's use cable "rainbow" de 8 buses (que era la que tenía a la mano) + dos cables 28 AWG para hacer las conexiones hacia el circuito controlador, hay que recordar que el integrado LM3915 /14/16 va a manejar cada LED desde su cátodo por lo que estos deben de ir por separado. Para el anodo, igual use cable 28 AWG, cada modulo LED usa 20 mA por lo que suponiendo que todos estén encendidos a su máxima capacidad, solo circularan 200mA por este cable.
Finalmente solo conecte el circuito ya hecho, todo parecía funcionar de maravilla, pero aqui vuelvo a remarcar la importancia de planear estás cosas. A pesar de que es un proyecto que llevo "haciendo" desde el 2014 (15?) cuando por pura casualidad le dije a una amiga sobre mi adicción a las luces sensibles al sonido y ella me consiguió los primero lm3915 (que todos esos murieron en nombre del progreso). Hasta ahora que en teoría ya debería de tener una idea clara de que y cómo hacerlo. Simplemente no aprendí nada ya que no tome en consideración el espacio para anclar debidamente todo el circuito y simplemente lo deje así; colgando.
Aunque es una mala practica dejar las cosas "cómo queden", por está ocasión la dejare así, ya que el resultado es igual a cómo lo imaginé hace mucho.
Los leo luego.
P.D:
![]() |
| Lo admito. |
¡¡Cumplimos 2 años!!
Hola de nuevo a todos, el día de hoy solo escribo para agradecer a todos los que han hecho crecer al blog y motivarme para continuar con el.
Han pasado muchas cosas y hoy con certeza puedo afirmar que el blog ha llegado tan lejos gracias a los lectores.
Sin más que decir por ahora solo me queda agradecer.
Feliz segundo año. Los leo luego.
Inútil apps #4 -Visualizador de sonido.
Desde que era pequeño, siempre tuve fascinación por las luces audioritmicas, recuerdo que mi papá tenía un Boom-Box (a grabadora) que tenia un visualizdaor de 10 niveles (un LED por nivel). El efecto que lograba era bastante llamativo y tal mosco a la luz, no podía evitar ser atraído por esta.El día de hoy vamos a hacer un visualizador de sonido. usando uno de los integrados más comunes: el LM3915.
Para empezar revisemos el siguiente esquema:
El circuito integrado LM3915 se encarga de medir niveles de voltaje y es capaz de manejar 10 LED's.
Antes de continuar revisemos para que sirve cada una de las entradas del integrado
- Pin 1 - Salida de LED.
- Pin 2 - Tierra.
- Pin 3 - VCC (3 ~ 35V).
- Pin 4 - Divisor bajo
- Pin 5 - Input
- Pin 6 - Divisor alto.
- Pin 7 - Referencia de salida.
- Pin 8 - Ajuste de referencia.
- Pin 9 - Selector de modo.
- Pin 10 ~ Pin 18 - Salida de LED's
- U1 - Circuito integrado LM3915 (14/16).
- D1 - Diodo 1N5819
- R1 - Resistencia 680 Ohms
- R2 - Resistencia 150 Ohms
- R3 - Resistencia 10 KiloOhms
- C1 - Capacitor electrolitico 10 micro Faradios.
- LED1 ~ 10. Diodo LED.
- 12.5/R1
- 12.5/680 = 18.3 mA
Si se quiere hacer uso de 12V podemos usar segementos de LED como los siguientes:
Este tipo de módulos son muy comunes, al hacer la medición cada segmento consume 20mA, para poder calcular la resistencia adecuada podemos re-acomodar la formula de tal forma que si queremos saber que resistencia debemos usar tendremos algo cómo lo que sigue:
- 12.5/I (donde I es la corriente).
- 12.5/0.02 = 625 Ohms
- 12.5/0.025 = 500 Ohms.
Para la entrada de señal, el circuito esta diseñado para ser conectado a la salida de un amplificador con niveles de 0V a 9V, para poder variar la sensibilidad, debemos de cambiar la corriente que circula por el pin8. Por ahora solo dejare esta versión, pero si necesitas saber cual es el valor de las resistencias para los voltaje, puedes leer la hoja de datos del integrado.
Para poder controlar cómo se va a mostrar los niveles, disponemos de dos modos:
- Modo Barra.
- Modo Punto.
![]() |
| El modulo rojo debería de estar totalmente apagado, pero sin la resistencia no lo hacer (aunque pienso que quueda bien) |
Y bien, por ahora es todo, en el siguiente post, veremos cómo armar el circuito y trataremos de hacer un empaque para que se vea un poco mejor.
Los leo luego.
Suscribirse a:
Entradas
(
Atom
)





















No hay comentarios. :
Publicar un comentario