Xwork's Blog

The lord is waiting to take your hand.

Vamos a programar #104 - Leyendo metadatos de archivos FLAC (Pt. 3 Ver. C#)

No hay comentarios.

 Hola de nuevo a todos, el día de hoy vamos a continuar con la última parte de FlacTagReader.


En el post anterior vimos cómo es que funcionan algunas funciones (valga la redundancia) y hoy veremos las faltantes.

La siguiente función es: "NumberToBlockType()". Esta función sirve para convertir un número en su equivalente al de la numeración "BlockTypes". Recibe un parámetro del tipo "uint" que es el número que queremos convertir. Regresa un valor del tipo enumeración "BlockTypes" equivalente. Hay que recordar que nos basamos en la de los tipos de bloques de la documentación.

La siguiente función es: "ReadVorbisData()". Cómo su nombre lo podría sugerir, esta función sirve para leer los datos de tipo vorbis ¿Qué es esto? te preguntaras, este bloque en particular es el que contiene los metadatos tales cómo: álbum, artista, año, etc. Siguen la estructura para los comentarios en archivos ogg vorbis.

La estructura de los comentarios es cómo la que sigue:

  • Tamaño de la descripción del proveedor (32 bits).
  • Cadena de texto para describir al proveedor.
  • Tamaño de la lista de comentarios del usuario (32 bits).
  • Tamaño de la lista de comentarios.
    • Tamaño del elemento actual.
    • Cadena de texto en formato UTF-8
  • Marcador de final del bloque (si es verdadero o no hay se marca error o fin del bloque).
Cada elemento de la lista anterior consta de 3 partes:
  • Nombre del campo.
  • = (símbolo de igual o símbolo ASCII 0x3D).
  • Descripción del campo.

Aunque no es mandatorio seguir una estructura particular para cada nombre de campo, si se recomiendan los siguientes:
  • Los nombres de cada campo no deben de contener símbolos que escapen del estándar ASCII de caracteres imprimibles, es decir: de 0x20 a 0x7D (excluyendo el símbolo de igual "=" o 0x3D) y de 0x41 a 0x5A.
  • Se pueden usar los siguientes nombres de campo:
    • TITLE
    • VERSION
    • ALBUM
    • TRACKNUMBER
    • ARTIST
    • PERFORMER
    • COPYRIGHT
    • LICENSE
    • ORGANIZATION
    • DESCRIPTION
    • GENRE
    • DATE
    • LOCATION
    • CONTACT
    • ISRC
  • Aunque los campos anteriores son sugeridos, podemos usar los propios (sin abusar de ello) y por ejemplo, un campo llamado BEATPERMINUTE, es totalmente válido.
Una vez que hemos visto cómo esta estructurado los comentarios para los archivos OGG Vorbis, analicemos la función "ReadVorbisData()". La función "ReadVorbisData()" sirve para leer un bloque que contenga los datos para los comentarios de los archivos ogg (y FLAC). Recibe un arreglo del tipo "byte" que contiene el bloque completo con los datos.
Primero creamos las variables del tipo "uint" llamadas: "NumberOfFields", "CurrentField" y "CurrentPosition"; las inicializamos con los valores de cero, uno y cero respectivamente. La variable "NumberOfFields" servirá para almacenar la cantidad de comentarios contenidos en el bloque; la variable "CurrentField" llevará la cuenta de cual es el número de comentario que se procesa al momento; la variable "CurrentPosition" llevará la posición en la que nos ubicamos dentro de la secuencia.
Luego procedemos a leer los datos, si recordamos la descripción, lo primero que debemos de buscar es la secuencia que contiene el tamaño de la descripción del proveedor y deberían de ser los primeros cuatro bytes de la secuencia. Creamos una variable del tipo "uint" llamada "CurrentSize" y tal cómo su nombre los indica, nos servirá para ir almacenando el tamaño del comentario actual, procedemos a hacer la lectura y tendremos el tamaño de la cadena de texto siguiente, por lo que podemos desplazarnos en el bloque cuatro bytes, por lo que a la variable "CurrentPosition" la aumentaremos en cuatro. Para almacenar la cadena de texto que vamos a leer, creamos una nueva variable llamada "CurrentChunk" del tipo "byte[]" y reservaremos espacio de acuerdo al tamaño actual del comentario por lo que la asignamos el tamaño de "CurrentSize". Después copiamos del arreglo "TheData" (que es parámetro que se paso a la función) al arreglo "CurrentChunk" la cantidad de bytes marcada por "CurrentSize", creamos una nueva variable del tipo "string" llamada "CurrentText" y la asignaremos con el resultado de la llamada a la función "Encoding.UTF8.GetString()" con el parámetro "CurrentChunk".


Nuevamente nos desplazamos la cantidad de bytes que nos diga "CurrentSize" y nos encontraremos en la posición que contiene la cantidad de campos por la cual está compuesto el bloque por lo que asignamos la variable "CurrentText" con el resultado de mandar a llamar a la función "BitConverter.ToUInt32()". Ahora que tenemos este dato, crearemos un arreglo del tipo "string" y reservaremos tantos espacios cómo "NumberOfFields" nos diga.
Para leer los campos, simplemente crearemos un bucle que haga mas o menos lo mismo que hicimos ahorita: leeremos el tamaño, leemos la cadena de texto, desplazamos el marcador posición y repetimos hasta que leamos todos los campos. 
La función recibe un parámetro del tipo arreglo de "byte" y devuelve una un arreglo del tipo "string" que contiene todos los campos encontrados.

La siguiente función es "GetBlockType". Esta función lo que hace es "convertir" el valor de un solo byte a su equivalente a la descripción del tipo de bloque. Para hacerlo, simplemente desplazamos los bits del byte tres lugares a la izquierda y luego a la derecha, hay que recordad que el primer byte contiene el marcador por si es el ultimo bloque, pero además el tipo de bloque por lo que podríamos encontrar algo cómo sigue:10000110 , si lo desplazamos tres lugares a la izquierda, tendríamos: 00110000, y si lo desplazamos tres lugares a la derecha tendríamos 00000110 o seis decimal que marcaria un bloque del tipo "PICTURE". La función recibe un valor del tipo "byte" que es el byte que se va a convertir y regresa el resultado del desplazamiento.

La siguiente función es "IsLastFrame". Esta sirve para determinar si el bloque actual es el último (de acuerdo a la descripción), esta función es similar a la anterior, cómo queremos aislar solo el primer bit (de izquierda a derecha), simplemente desplazamos los bits siete lugares a la derecha y comprobamos, si el resultado del desplazamiento es uno, la función devuelve "true" en caso contrario devuelve false.

Las siguiente función es "GetBlockSize()" + 1 sobrecarga. Esta función se encarga de obtener el tamaño de un bloque. la primera recibe un parámetro y es un arreglo del tipo "byte" que contiene los datos. Para hacerlo, simplemente invertimos los datos del arreglo y regresamos el valor de mandar a llamar a la función "BitConverter.ToUInt32()". La sobrecarga recibe dos parámetros mas, el primero, un valor del tipo "int" que sirve cómo marcador de posición de donde se empezará a leer la secuencia de bytes, esta también se diferencia de la otra porque esta espera una secuencia de bytes "completa" o donde el primer grupo de cuatro bytes no es la secuencia que esperamos, por lo que es importante saber "donde empezar a leer", el tercer parámetro sirve para indica la longitud de bytes a leer. Ambas funciones devuelven un valor del tipo "uint" que representa el tamaño del bloque.

El último procedimiento es "GetBlock()" este sirve para ejecutar la funciones encargadas de buscar los bloques. recibe dos parámetros, el primero un valor del tipo "string" que es la ruta del archivo del cual se quiere obtener información. El segundo es un valor de la enumeración "BlockTypes" que sirve para indicar el tipo de bloque que se va a buscar. Esta función fue la primera que hice y al principio solo la hice para buscar la secuencia "fLaC" por lo que puede parecer repetitiva, pero igual lo deje para dar mayor claridad a lo hicimos.

Y bien, por ahora es todo, cómo de costumbre puedes descargar el proyecto completo de mi dropbox para que lo pruebes por ti mismo. Cabe resaltar que al igual cómo paso con los archivos MP3, aun falta mucho, pero algo que si haré en el corto plazo será crear un programa que agregue la caratulas de los discos.

Los leo luego.

No hay comentarios. :

Publicar un comentario

Vamos a programar #103 - Leyendo metadatos de archivos FLAC (pt 2. Ver c#)

No hay comentarios.

Hola de nuevo a todos. El día de hoy vamos a continuar con mas de los archivos FLAC y sus metadatos.

En el post anterior vimos cómo es que está estructurado cada bloque de metadatos, incluso vimos cómo es que se hace la lectura de cada uno (y leímos el bloque "STREAMINFO"). Ahora que sabemos cómo, solo nos queda automatizarlo y para eso vamos a usar el lenguaje de programación C#.
Para empezar, veamos el código (sin ningún orden particular en las funciones):


using System; using System.Drawing; using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace FLACTagReader { public partial class Form1 : Form { // 0 : STREAMINFO 0000000 // 1 : PADDING 0000001 // 2 : APPLICATION 0000010 // 3 : SEEKTABLE 0000011 // 4 : VORBIS_COMMENT 0000100 // 5 : CUESHEET 0000101 // 6 : PICTURE 0000110 // 7-126 : reserved 1111000 - Invalid // 127 : invalid, to avoid confusion with a frame sync code /// <summary> /// Enumeración con los posibles bloques contenidos en un archivo FLAC /// </summary> private enum BlocksTypes { /// <summary> /// Bloque mandatorio con la información del Stream /// </summary> Block_Type_StreamInfo = 0, /// <summary> /// Bloque de Padding /// </summary> Block_Type_Padding = 1, /// <summary> /// Bloque con la informacion de la aplicación /// </summary> Block_Type_Application = 2, /// <summary> /// Bloque Seektable /// </summary> Block_Type_SeekTable = 3, /// <summary> /// Bloque con metadatos /// </summary> Block_Type_VorbisComment = 4, /// <summary> /// Bloque con cuesheet /// </summary> Block_Type_CueSheet = 5, /// <summary> /// Bloque con imagen /// </summary> Block_Type_Picture = 6, /// <summary> /// Bloque no válido /// </summary> Block_Type_NoValid = 7 } public Form1() { InitializeComponent(); } /// <summary> /// Crea una imagen a partir de una secuencia de bytes /// </summary> /// <param name="bytesArr">Matriz de bytes que contiene los datos de la imagen</param> /// <returns>Regresa una imagen</returns> public Image ByteArrayToImage(byte[] bytesArr) { using (MemoryStream memstr = new MemoryStream(bytesArr)) { Image img = Image.FromStream(memstr); return img; } } // 4 4 n*4 4 n*4 4 4 4 4 !4 !n*4 //<32>,<32>,<n*8>,<32>,<n*8>,<32>,<32>,<32>,<32>,<32>,<n*8> // 1 2 3 4 5 6 7 8 9 10 11 /// <summary> /// Lee todo los datos del bloque PICTURE y extrae la imagen contenida /// </summary> /// <param name="TheData">Arreglos bytes que contiene todo el bloque PICTURE</param> /// <returns>Regresa una imagen</returns> private Image ReadPictureData(byte[] TheData) { uint CurrentPos = 4;//1 uint CurrentSize = GetBlockSize(TheData, (int)CurrentPos, 4); CurrentPos += 4;//2 string MimeType = Encoding.ASCII.GetString(TheData, (int)CurrentPos, (int)CurrentSize); CurrentPos += CurrentSize;//3 CurrentSize = GetBlockSize(TheData, (int)CurrentPos, 4); CurrentPos += (CurrentSize + (4 * 5));//4-9 CurrentSize = GetBlockSize(TheData, (int)CurrentPos, 4); CurrentPos += 4; byte[] TempImage = new byte[CurrentSize]; Array.Copy(TheData, CurrentPos, TempImage, 0, CurrentSize); return ByteArrayToImage(TempImage); } /// <summary> /// Convierte un número en su valor equivalente al tipo de bloque /// </summary> /// <param name="Data"> /// Entero sin signo con la representacion del bloque</param> /// <returns>Regresa un valor de la enumeración <typeparamref name="BlockTypes"/>BlockTypes</returns> private BlocksTypes NumberToBlockType(uint Data) { switch (Data) { case 0: return BlocksTypes.Block_Type_StreamInfo; case 1: return BlocksTypes.Block_Type_Padding; case 2: return BlocksTypes.Block_Type_Application; case 3: return BlocksTypes.Block_Type_SeekTable; case 4: return BlocksTypes.Block_Type_VorbisComment; case 5: return BlocksTypes.Block_Type_CueSheet; case 6: return BlocksTypes.Block_Type_Picture; default: return BlocksTypes.Block_Type_NoValid; } } /// <summary> /// Lee el bloque con la informacion estructurada /// </summary> /// <param name="TheData">Arreglo de bytes del cual se extraera la información</param> /// <returns>Regresa un arreglo del tipo string con todos los campos que se encontraron</returns> private string[] ReadVorbisData(byte[] TheData) { uint NumberOfFields = 0; uint CurrentField = 1; uint CurrentPosition = 0; //Vendor uint CurrentSize = BitConverter.ToUInt32(TheData, (int)CurrentPosition); CurrentPosition += 4; byte[] CurrentChunk = new byte[CurrentSize]; Array.Copy(TheData, CurrentPosition, CurrentChunk, 0, CurrentSize); string Currenttext = Encoding.UTF8.GetString(CurrentChunk); CurrentPosition += CurrentSize; NumberOfFields = BitConverter.ToUInt32(TheData, (int)CurrentPosition); CurrentPosition += 4; string[] Fields = new string[NumberOfFields]; //CommentField while (CurrentField <= NumberOfFields) { CurrentSize = BitConverter.ToUInt32(TheData, (int)CurrentPosition); CurrentPosition += 4; byte[] CurrenUserCommentList = new byte[CurrentSize]; Array.Copy(TheData, CurrentPosition, CurrenUserCommentList, 0, CurrentSize); Currenttext = Encoding.UTF8.GetString(CurrenUserCommentList); CurrentPosition += CurrentSize; Fields[CurrentField - 1] = Currenttext; CurrentField += 1; } return Fields; } /// <summary> /// Obtiene el valor del bloque desde un byte /// </summary> /// <param name="Data">byte del cual se va a obtener la información</param> /// <returns>Regresa un valor que es equivalente al tipo de bloque</returns> private UInt32 GetBlockType(byte Data) { Data <<= 3; Data >>= 3; return Data; } /// <summary> /// Obtiene si el bloque es el último de la serie /// </summary> /// <param name="Data">byte del cual se obtendra la información</param> /// <returns>true si el bloque es el último, false en caso contrario</returns> private bool IsLastFrame(byte Data) { Data >>= 7; if (Data == 1) return true; else return false; } /// <summary> /// Obtiene el tamaño de un bloque /// </summary> /// <param name="Data">Arreglo de bytes que contiene el tamaño del bloque</param> /// <param name="StartIndex">Indica la posicion en donde se empezará a leer</param> /// <param name="Size">Indica el tamaño en bytes que se van a leer</param> /// <returns>Regresa el tamaño del bloque actual</returns> private UInt32 GetBlockSize(byte[] Data, int StartIndex, int Size) { byte[] CurrentData = new byte[4]; Array.Copy(Data, StartIndex, CurrentData, 0, Size); Array.Reverse(CurrentData); return BitConverter.ToUInt32(CurrentData, 0); } /// <summary> /// Obtiene el tamaño de un bloque /// </summary> /// <param name="Data">Arreglo de bytes que contiene el tamaño del bloque</param> /// <returns>Regresa el tamaño del bloque actual</returns> private UInt32 GetBlockSize(byte[] Data) { byte[] CurrentData = Data; //Ponemos el primer byte en 0 porque se usa para identificar el bloque //a la hora de convertir a UInt32 se esperan 4 bytes, pero este siempre será 0 u otro valor no relevante //para el tamaño del bloque CurrentData[0] = 0; Array.Reverse(CurrentData); return BitConverter.ToUInt32(CurrentData, 0); } /// <summary> /// Obtiene los datos de un bloque /// </summary> /// <param name="FileName">Nombre del archivo del cual se obtendra</param> /// <param name="TypeOfBlock">Tipo de bloque que se va a buscar</param> private void GetBlock(string FileName, BlocksTypes TypeOfBlock) { byte[] DataBuff; bool LastFrame = false; FileStream FS = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.Read); using (BinaryReader BR = new BinaryReader(FS, Encoding.ASCII)) { DataBuff = BR.ReadBytes(4); if (string.Equals(Encoding.ASCII.GetString(DataBuff), "fLaC", StringComparison.Ordinal)) { UInt32 CurrentBlockSize; UInt32 CurrentPosition = (UInt32)FS.Position; BlocksTypes CurrentBlockType = BlocksTypes.Block_Type_NoValid; while (!LastFrame) { //primer bloque siempre será Block_Type_StreamInfo DataBuff = BR.ReadBytes(4); LastFrame = IsLastFrame(DataBuff[0]); CurrentBlockType = NumberToBlockType(GetBlockType(DataBuff[0])); if (CurrentBlockType == TypeOfBlock) { if (TypeOfBlock == BlocksTypes.Block_Type_VorbisComment) { string[] Fields; CurrentBlockSize = GetBlockSize(DataBuff); Fields = ReadVorbisData(BR.ReadBytes((int)CurrentBlockSize)); textBox1.Clear(); for (int i = 0; i < Fields.Length; i++) { textBox1.Text += Fields[i] + " | "; } } else if (TypeOfBlock == BlocksTypes.Block_Type_Picture) { CurrentBlockSize = GetBlockSize(DataBuff); pictureBox1.Image = ReadPictureData(BR.ReadBytes((int)CurrentBlockSize)); } } else { CurrentBlockSize = GetBlockSize(DataBuff); FS.Seek(FS.Position + CurrentBlockSize, SeekOrigin.Begin); } } } else { MessageBox.Show("Archivo Flac no válido"); } } } private void button1_Click(object sender, EventArgs e) { using (OpenFileDialog OpDiag = new OpenFileDialog()) { OpDiag.Filter = "Archivos FLAC|*.flac|Todos los arhivos|*.*"; if (OpDiag.ShowDialog() == DialogResult.OK) { GetBlock(OpDiag.FileName, BlocksTypes.Block_Type_VorbisComment); GetBlock(OpDiag.FileName, BlocksTypes.Block_Type_Picture); pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage; } } } } }
Lo primero que hacemos es crear una enumeración llamada "BlockTypes" que contiene las posibles enumeraciones para cualquier tipo de bloque. Si bien la especificación dice que los valores de 0 hasta 127 son validos (aunque no tienen uso todos, al menos  al momento de escribir esto), decidí declarar cómo no validos a los que superan al 6 y por eso, después de ahí, su nombre es "Block_Type_NoValid". Se podrían usar solo números, pero me pareció mas fácil de identificar cada uno de esta forma.

La primera función es "ByteArrayToImage()" del tipo "Image". Esta función, cómo su nombre lo pudiera indicar, se encarga de convertir una secuencia de bytes en una imagen (si los datos son válidos), recibe cómo parámetro un arreglo del tipo "byte[]" que contiene la secuencia de bytes de la imagen. Regresa un valor del tipo "Image" que es la imagen dentro del archivo (si es que hay).

La siguiente función es "ReadPictureData()". Esta función es la encargada de procesar los datos del bloque  "PICTURE". Recibe cómo parámetro un arreglo del tipo "byte[]" que contiene la secuencia de bytes del bloque "PICTURE" completo. Para procesarlo, se siguen las siguientes:
  • <32> El tipo de imagen de acuerdo a la descripción de la etiqueta ID3 "APIC".
  • <32> El tamaño de la descripción del tipo de archivo o MIME type.
  • <n*8> Cadena de texto con la descripción del tipo de archivo.
  • <32> El tamaño de la descripción de la imagen.
  • <n*8> La descripción de la imagen en UTF8
  • <32> El ancho de la imagen en píxeles
  • <32> El alto de la imagen en pixeles.
  • <32> La profundidad del color de la imagen en bits por pixel.
  • <32> Para las imágenes con índice de color, el número de colores usados, para el resto 0.
  • <32> El tamaño de los datos de la imagen.
  • <n*8> Los datos de la imagen.
Para realizar la lectura de la imagen se asume que solo se pasan los datos del bloque completos, solo omitiendo el tamaño del bloque mismo. Y en este caso, cómo solo nos interesa obtener la imagen "tal cual" solo nos concentraremos en leer las ultimas dos secuencias, pero en el código lo hacemos paso a paso para poder apreciar mejor lo que esta ocurriendo y para simplificarlo, lo podemos apreciar mejor en el siguiente diagrama:


Todo este bloque se representa en 11 partes (parte de abajo de la imagen), cada una de la partes ya tiene su tamaño en bits establecido (parte media), que es lo mismo en bytes (parte superior). Si bien hace un momento mencione que vamos a ignorar todo salvo la última y penúltima parte, no podemos ignorar del todo a los otros datos, sobre todo a los que son variables. Ahora vamos leyendo el código.
Primero creamos una variable del tipo "uint" llamada "CurrentPos", esta la vamos a ir usando para saber en que parte del bloque estamos, si observaste bien, te darás cuenta que esta inicializada con un valor de 4, al hacer esto, estaremos brincando la primer secuencia de 32 bits 

Seguido, creamos una variable llamada "CurrentSize" del tipo "uint" y la asignamos con el valor de la llamada a la función "GetBlockSIze()" (que veremos pronto), con esto tendremos el tamaño de la siguiente secuencia (3) por lo que podemos avanzar 4 bytes mas el tamaño que nos dio con la función anterior 
.
Aunque C# nos da muchas facilidades, a la hora de tratar de hacer lo mismo en otro lenguaje las cosas se pueden complicar, este bloque es una cadena de texto con la descripción del tipo de archivo por lo que es importante tenerlo en cuenta, para eso creamos una variable llamada "MimeType" del tipo "string" y se le asigna el valor de la llamada a la función "Encoding.ASCII.GetString()", esta recibe tres parámetro, el primero, un arreglo del tipo "byte[]" con los datos de la cadena ASCII que esperamos obtener; el segundo es un valor del tipo "int" que sirve cómo indicador de que parte del arreglo es donde se va a empezar a leer; el tercero es un valor del tipo "int" que sirve para indicar cuantos bytes de la secuencia se van a leer. Al realizar la "conversión" de una secuencia de "bytes" a "string", tendremos algo cómo lo de la imagen que sigue:

Luego sumamos la posición actual y el tamaño de la secuencia anterior. Para las dos siguientes partes, repetimos lo mismo: obtenemos el tamaño del bloque, lo sumamos a la posición actual y avanzamos cuatro bytes mas.

Las siguientes 4 secuencias son iguales en tamaño, por lo que podemos brincar 4*4 (en el código es 4*5 porque brinque la secuencia anterior tambien).

Una vez leído las partes anteriores, solo queda leer los datos de la imagen por lo que repetimos nuevamente: obtenemos el tamaño de los datos de la imagen, creamos una nueva variable del tipo "byte[]" llamada "TempImage" y al mismo tiempo le asignamos el tamaño de la secuencia actual, luego copiamos la porción del bloque al arreglo que acabamos de crear y devolvemos el resultado de mandar a llamar la función "ByteArrayToImage()".

Y bien, por ahora es todo, en el siguiente post publicaré el proyecto completo y terminaremos de revisar las funciones que no vimos.

Los leo luego.

No hay comentarios. :

Publicar un comentario

Vamos a programar #102 - Leyendo metadatos de archivos FLAC (pt.1)

No hay comentarios.

 Hola de nuevo a todos. El día de hoy vamos a continuar con más de los archivos FLAC.


En los post mas recientes hemos visto las cualidades de los archivos FLAC, pero además cómo crear los nuestros. Al igual que en MP3, existen metadatos embebidos en ellos, y sirven para describir algunos datos importantes tales cómo: el nombre de la canción, el artista, el nombre del álbum, el genero, etc.


Estructura de un archivo FLAC

La estructura de los archivos FLAC es totalmente diferente a la de un MP3 por lo que vale la pena revisarla por separado. Cada archivo FLAC consiste de cuatro partes principales:

  • Una cadena de cuatro bytes con la secuencia "fLaC" (así tal cual se ve).
  • Un bloque de metadatos con la información del "stream"
  • Cero o mas bloques de metadatos.
  • Uno o mas "frames" de audio.

Para mas detalles se puede revisar la página de xiph.org, donde esta la descripción completa para los archivos FLAC.

De las cuatro partes que se mencionan anteriormente, nos concentraremos en la segunda y tercera (Técnicamente las dos entran en el mismo conjunto, solo que la segunda es obligatoria, mientras que las subsecuentes son opcionales, hablando solamente de los bloques de metadatos), por lo que revisaremos cómo es que está compuesta cada una.

Pero antes una representación de cómo está estructurado el archivo:


Si observamos bien la imagen, veremos que hay dos partes centrales: "STREAM" y "FRAME", por ahora revisaremos la parte de "STREAM" que contiene los datos que nos interesan. 

Metadatos

A partir de ahora nos referiremos a cada parte cómo "bloque". Del lado de METADATA, cada bloque estará constituido por un encabezado (HEADER) y el bloque de datos en si, el encabezado se encarga de describir cómo es que cada parte esta formada. Para poder leer cada bloque, deberemos de seguir los datos de este. Salvo que se indique lo contrario, cada valor N representará un solo bit (OJO: bit, no byte al menos que se indique lo contrario), al igual que en la documentación (que recomiendo encarecidamente leer dos veces), usaremos un número entre los corchetes cuadrados "<" y ">" El valor que se encuentre en medio dirá cuantos bits conforman esa parte. Habiendo aclarado lo anterior, veamos cómo se forma el encabezado de cada bloque:
  • STREAM
  • METADATA_BLOCK
  • METADATA_BLOCK_HEADER (Encabezado)
    • <1>   Indicador de último bloque
    • <7>   Descriptor del tipo de bloque
    • <24> Tamaño del bloque en bytes (BYTES!!!)
Para el indicador del último bloque se usa un solo bit, si es 0 indica que hay mas bloques a continuación, pero si es 1, indica que el bloque es el último y empiezan los "FRAMES" por lo que si solo estamos leyendo los metadatos, deberíamos de dejar de buscar.

La secuencia de los siguientes 7 bits, indican que tipo de bloque es el que sigue a continuación, para ello hay una serie ya predefinida y dependiendo del valor que este nos diga, el bloque del tipo será. Actualmente solo hay siete tipos de bloque ya predefinidos y son los que siguen:
  • 0: STREAMINFO
    • Contiene información acerca de todo el archivo, este bloque es mandatorio y siempre será e primero de la secuencia después de la secuencia 0x66, 0x4c, 0x61, 0x43 (o de manera simple después de  "fLaC" ).
  • 1: PADDING
    • Este tipo de bloque sirve cómo reserva y el contenido no representará nada, normalmente se llena con 0x00. Cuando se crea el archivo sin los metadatos completos, en lugar des escribir un archivo nuevo con los bloques nuevos, simplemente se reemplaza este bloque conservando el archivo original y agilizando la escritura del mismo.
  • 2: APPLICATION
    • Nombre de la aplicación que se uso para codificar el archivo, puede ser cualquiera que el usuario elija, aunque se recomienda el registro de la aplicación para obtener un ID único para cada quien.
  • 3: SEEKTABLE
    • Sirve cómo marcador para desplazarse en el archivo a la hora de la reproducción, aunque se puede omitir, se recomienda incluirlo para agilizar la lectura.
  • 4: VORBIS_COMMENT
    • Este bloque contiene la información relevante a los creadores del contenido multimedia y la descripción del mismo, se usa la especificación de "Vorbis comment"
  • 5: CUESHEET
    • Contiene información que se puede usar en un CD
  • 6: PICTURE
    • Imagen representativa del archivo, similar a la imagen embebida en un archivo MP3.
  • 7-126: Reservado
    • Reservado por ahora, por lo que se podría decir que si un bloque tiene descriptor en este rango, no es valido. Se planea su uso futuro.
  • 127: No válido
    • Bloque no valido, ya que la misma secuencia se usa cómo marcador para sincronización.
Por lo que por ahora solo nos serian relevantes los bloques con descriptores: 0, 4, 6, 7-126 y 127. Especialmente el que tenga descriptor 0, porque es mandatorio; 4, porque seria el equivalente a los TAGS en mp3; y 6, porque es la imagen del álbum (por lo general). Sabiendo los tipos de bloques que vamos a leer, vamos a concéntranos solo en ellos, por lo que primero revisaremos cómo es que está armado el bloque "STREAMINFO".

Bloque "STREAMINFO"

El bloque STREAMINFO, consta de la siguiente secuencia:
  • <16> Tamaño mínimo del bloque.
  • <16> Tamaño máximo del bloque.
  • <24> Tamaño mínimo del "FRAME" en bytes.
  • <24> Tamaño máximo del "FRAME" en bytes.
  • <20> Frecuencia de sampleo.
  • <3> Número de canales.
  • <36> Total de muestras por segundo.
  • <128> MD5 del audio.
Ya que cada una de las secciones tiene un tamaño ya predefinido, podemos asegurar que toda la secuencia siempre tendrá el mismo tamaño y cómo no es necesario que sepamos el contenido de esta, bastará con desplazarnos al siguiente bloque. Antes de continuar, haremos el calculo a mano de la posición en la que empieza y en la que acaba, para eso usaremos XVI32 para ver el contenido de forma hexadecimal, y el archivo de muestra será el que usamos para comparar en el post de "FLAC vs WAV"

Si leemos las cosas en orden, debemos de empezar por buscar la secuencia "fLaC" que serán los primeros 4 bytes.

Ahora que sabemos que el primer bloque debe de ser el bloque STREAMINFO, nos vamos a concentrar en eso, si hacemos memoria, lo primero que debemos de buscar de cada bloque, es su encabezado que serán 32 bits (4 bytes) por lo que inmediatamente después de la secuencia "fLaC" los siguientes bytes corresponden al encabezado de nuestro bloque.

En este caso, el encabezado está representado por la secuencia hexadecimal: 0x00, 0x00, 0x00 y 0x22. ¿Pero cómo la interpretamos? simple, la referencia dice que el primer bit es el indicador del último bloque, solo si es 1, para entender mejor, veamos el número en binario.

Cómo iremos leyendo "de byte en bytes", el mínimo de bits a leer es 8, pero sim problema podemos aislar el primer bit de cada byte y determinar si es o no el último bloque, en este caso, cómo encontramos un 0, indica que hay mas bloques después de este.

Los siguientes 7 bits indicaran el tipo de bloque y para el tipo de bloque debe de ser 0, antes veamos cómo son los números del uno al seis en binario (recuerda que en el blog tenemos DecToAny que sirve para convertir un número decimal a cualquier base hasta 25, puedes descargar la aplicación para Windows, android o usar la versión web).


Pero si no quieres molestarte en revisar, aquí la numeración binaria del cero al seis, que son los valores validos para esta parte de la secuencia.



Cuando leemos la información del bloque encontramos con 0x00 lo que es igual cero decimal o 0 en binario, lo que confirma que el bloque es el bloque STREAMINFO. Los restantes 24 bits indican cual es el tamaño del bloque. Al igual que los hicimos con el primer byte, los siguiente 3, se irán leyendo de uno por uno, pero juntos representan un solo número.

Toda la secuencia anterior representa 34

Si en XVI32 marcamos esos 34 bytes, tendríamos seleccionado todo el bloque.

Y bien, por ahora es todo. para no hacer muy extenso el post, terminaremos por hoy, sirve que da tiempo para leer toda la documentación del los archivos FLAC.
Si bien este post se podría tomar cómo una mala copia de la documentación, no lo es y estoy seguro que a mas de uno le será de ayuda, pero además así es nuestro estilo de trabajo, primero nos ensuciamos las manos descuartizando el archivo con el lector hexadecimal y luego hacemos código que hace lo mismo pero más rápido. Ahora y diferente al caso de ArtView, trataré de hacer versiones para los distintos lenguajes de programación.

Ya es diciembre por lo que publicaré un par de post antes de que acabe el año. Es cierto que la actividad del blog vino en picada, pero para todos aquellos que se quedaron o que regresaron, los post iran saliendo de manera regular.

Los leo luego.

No hay comentarios. :

Publicar un comentario

El Video (AUDIO) Correcto #9 - Convirtiendo CD a FLAC

No hay comentarios.

 Hola de nuevo a todos, el día de hoy vamos a ver cómo extraer nuestros audios de CD's originales y convertirlos a FLAC. Al inicio pensé en hacer alugan clase de programa para hacerlo, pero cómo probablemente solo uno de cada mil personas va a convertir sus discos (incluso a estas alturas, habrá quienes no los conozcan), decidí solo mostrar cual es el método que uso actualmente.


Para poder hacer la copia de los discos, vamos a usar MediaGo de SONY, aunque es un programa relativamente viejo, aun al día de hoy funciona y tiene la virtud de que las funciones que requieren de internet, aun funcionan. Para no adelantarnos, vamos a ir en orden y lo primero que haremos es descargar el instalador de Media Go. Una vez lo descargamos, lo instalamos y lo ejecutamos.

Una vez que el programa está listo, simplemente insertaremos nuestro CD. De lado izquierdo aparecerá en una ficha llamada "CD de audio"; hacemos clic en ella y podremos ver el contenido del CD.


Antes de continuar, haremos clic en el menú "Herramientas>>Preferencias" y se abrirá un dialogo con los ajustes del programa.


Hacemos clic en "Importación de CD" y en la caja de selección de la opción "Usar pistas usando el formato" seleccionaremos la opción FLAC. Hacemos clic en aceptar y los ajustes estarán listos.

Para comenzar la copia, simplemente hacemos clic en el botón "Importar CD". La copia comenzará y al finalizar, podremos escuchar nuestro archivos.


La razón principal para usar "Media Go" es simple: Ya tiene todo lo necesario; cuando importa los archivos, se conecta a la base de datos Gracenote y obtiene todos los datos que puedan ser relevantes a la hora de identificar una canción.

Y bien, por ahora es casi todo...

He hablado de las cosas que son necesarias para poder oír audio en buena calidad (y no hablo de esos "audiofilos mugorosos" que le rebanan los bordes al los CD's para mejorar la calidad del audio), ya mencione los audifonos, los archivos de audio y la última cosa que es importante mencionar; y eso es el dispositivo que se va a encargar de reproducir el archivo.

Muchos de los celulares, simplemente contienen la "placa de audio" mas genérica que se pude encontrar, aun en los dispositivos de gama media, la mayor parte de ellos tendrán dicha placa que solo es capaz de reproducir hasta 32000Hz (si bien nos va); aunque parezca redundante; si conectamos unos audífonos de calidad superior al puerto 3.5mm del teléfono y este solo pude decodificar hasta cierta calidad, estaremos desperdiciando el hardware. Identificar si un teléfono es capaz de reproducir audio en alta calidad no es sencillo, ya que muchas veces es un dato que no es relevante a la hora de vender (siempre se verá primero la RAM y el CPU) pero si es posible, buscar el logotipo "Hi res audio" ayuda.


Aun si el equipo no cuenta con el logotipo, hay otras formas de saber si lo es.

LDAC ayuda a transmitir audio en alta calidad por Bluetooth


Y bien, por ahora es todo, en el siguiente post veremos cómo leer los metadatos de los archivos FLAC en C# y varios lenguajes mas.

Los leo luego.


No hay comentarios. :

Publicar un comentario

El Video (AUDIO) Correcto #8 - WAV VS FLAC

No hay comentarios.

 Hola de nuevo a todos, el día de hoy vamos a continuar con un poco más sobre el audio de buena calidad.



En el post anterior vimos cómo es importante tener un par de audífonos de la calidad adecuada para poder disfrutar de la música cómo es debido. Pero, no solo se trata de los audífonos, hay otros elementos que son importantes a la hora de disfrutar del audio de buena calidad. 

En este post nos concentraremos en el archivo de audio en si. En reiteradas ocasiones he dicho que los archivos FLAC ofrecen una calidad superior al MP3, incluso en alguno de los post anteriores hice el comparativo, en twitter (o ahora X), mucha gente dijo que los archivos FLAC si bien tienen una calidad mejor que el MP3, también se pierde mucha de la información que conforma la música, y esto es cierto o no, dependiendo de cómo se configura la compresión, cual es el origen del cual vamos a crear nuestro FLAC y algunos otros factores. Pero por lo general, si se configura bien, los archivos FLAC no tendrán ninguna perdida y para probarlo, vamos a hacer la misma prueba que hicimos hace tiempo; vamos a comparar FLAC contra WAV. ¿Por qué WAV? te estarás preguntando, simple, es el contenedor que se usa para el audio sin compresión, por lo que su tamaño será significativamente mayor al de los otros.

Archivo WAV copiado desde un CD ORIGINAL

Archivo FLAC creado desde un CD ORIGINAL

Las pruebas.

Al igual que la vez anterior, vamos a usar AUDACITY para comparara los audios. Su interfaz a cambiado un poco, pero si sigues los pasos que te mostraré, todo saldrá igual. En esta ocasión de igual forma subiré dos archivos de audio de la misma canción, pero eso si, recuerda que si no posees un CD original, debes de eliminarlo a las 24 horas máximo (resulta difícil tener una copia original, aun buscando el ID del CD que es: "Fantasía TFF-3838" no se encuentra, ni en la pagina de fonovisa que es la que lo editó).


  1. Descargar audacity.
  2. Descargar el archivo WAV.
  3. Descargar el archivo FLAC.
Una vez instalado audacity, lo abriremos luego arrastraremos los archivos de audio que descargamos,
puede ser uno o los dos a la vez. Una vez abiertos, seleccionaremos una pista de audio (de hecho dos porque son estéreo) e iremos al menú "Efectos>>Especial>>Invertir" con esto crearemos una versión invertida de nuestra canción. Para "sumarlas", bastara con seleccionar las dos pistas (técnicamente cuatro pistas porque ambas son estéreo) para hacerlo, haremos clic en el panel izquierdo y muestras mantenemos presionada la tecla "control" hacemos lo mismo con la otra. Una vez seleccionada las dos pistas, iremos al menú "Pistas>>Mezclar y generar nueva pista" y con esto se generará una nueva que se vera cómo una línea. En esta ocasión no es necesario alinear los inicios de las pistas puesto que eso ya lo hice (nuevamente puedes revisar el post donde comparé MP3 y FLAC).

Cómo el archivo resultante es "silencio" podemos afirmar que ambas pistas son iguales, solo que, la ventaja del archivo FLAC es que pesa casi la mitad que el archivo WAV.

Y bien, por ahora es todo, en el siguiente post ahora si veremos cómo importar nuestros discos al formato FLAC.

Los leo luego.

No hay comentarios. :

Publicar un comentario

El Video (AUDIO) Correcto #7 - Un poco mas sobre el audio.

No hay comentarios.

 Hola de nuevo a todos, el día de hoy vamos a ver un poco mas sobre los archivos FLAC.

imagen tomada de: https://www.revistagadgets.com/2017/04/04/audio-hi-res-la-nueva-linea-audifonos-pioneer/


Cómo muchos de ustedes sabrán, me gusta mucho oír música (música de verdad y no "regeton"), pero siempre había usado equipo de "baja calidad" (y solo por nombrarlo de alguna manera). Pero no hace mucho tiempo, visité un lugar donde se exponían diferente sistemas de audio, desde los mas sencillos; cómo bocina bluetooth; hasta los mas complejos; llámese audio de estudio.


Dentro del mismo lugar había un apartado para los audífonos, de inmediato fui a revisar, y había varios para probar. Cada uno tenia la ficha que describía cuales eran sus características, pero hacían un fuerte énfasis en la frecuencia de respuesta de cada uno.


Primero probé los que ofrecían una respuesta de 20 hasta 20000Hz, justo cómo la mayor parte de audífonos son, la calidad era aceptable, mucho de los audífonos que he tenido cumplían con esa frecuencia y todo parecía aceptable. Los siguientes tenían una respuesta de 20 hasta 32000Hz, la misma calidad que los audífonos que siempre usaba, y justo cómo los anteriores, todo funcionaba bien, y a mi gusto, nada podía superar la calidad. En la siguiente mesa había unos audífonos con una respuesta de 20 hasta 40000Hz... había vivido engañado todo el tiempo, siempre me habían dicho que el oído humano no era capaz de oír frecuencias mas allá de los 32000Hz, pero al momento de probar esos, de inmediato me di cuenta que, si bien es cierto que el oído humano está limitado a ciertas frecuencias, el hecho es que cada persona es diferente y hay quienes alcanzan un rango auditivo mayor al de otros. En mi caso es muy difícil decir hasta "donde puedo escuchar", ya que nunca he hecho un estudio que sirva para eso, pero no había duda de que esos audífonos "sonaban mejor" que los otros, por lo que decidí conseguir unos.


Finalmente cosegui unos audifonos edifier w820nb plus que cuestan poco y tienen la calidad superior a los que ya tenía. 

Pero para poder disfrutar de un buen audio, no solo basta con tener los audífonos, también hay que tener un dispositivo compatible y los archivos de audio adecuados. Por fortuna para mi, aun soy de la vieja escuela y tengo mi colección de discos guardados. Normalmente lo que hacia era utilizar mi reproductor de CD (si, en 2023 aun sigo usándolo), pero el inconveniente que encontré, es que la única salida que tiene, es el plug tradicional de 3.5 mm, mientras que los audífonos soportan bluetooth y USB-C.

Para poder escuchar mis discos decidí crear una copia  de ellos, pero no en mp3, porque ya en ocasiones anteriores he hablado de ciertas desventajas que este tiene con respecto a FLAC, detalles que puedes encontrar en un post que hice hace un buen rato.




 Y bien, por ahora es todo, en los siguientes post veremos detalles de cómo importar la música en FLAC, pero además entraremos en detalles técnicos para poder leer y editar los metadatos de los archivos; para mantener todo mas o menos organizados (al igual que lo hicimos con MP3).

Los leo luego.

No hay comentarios. :

Publicar un comentario

Cumplimos 7 años -_-!!!!

No hay comentarios.

 

Hola de nuevo a todos, el dia de hoy solo escribo para recordar que un dia cómo hoy pero de hace siete años, nació el blog de Xwork. Si bien es que ha habido altas y bajas; sobre todo bajas hablando del blog; solo quiero decir que ya estoy trabajando para continuar con el plan de un post al mes.

En tiempos recientes, he tenido que atender otros asuntos y contrario a lo que se podria pensar, basados en el estado del blog; realmente estoy disfrutando el momento y por eso es que lo he descuidado, pero cómo todo, estoy tratando de encontrar el balance entre haer lo que debo y lo que me gusta (que casí van de la mano).

Por eso nuevamente quiero agradecer a todos los que visitan y recordarles que sigan al pendiente que esto seguirá mientras no haya ningun impedimento.

Hay varios proyectos listos, solo hay que esperar un poco

Saludos y nos seguimos leyendo.


No hay comentarios. :

Publicar un comentario

Vamos a programar #101 - Operaciones a nivel de bits en Python y tablas de verdad.

No hay comentarios.

 Hola de nuevo a todos, el día de hoy vamos a ver mas operaciones a nivel de bits.


Hace algunos días alguien me pregunto que si era posible usar operaciones a nivel de bits en Python, la respuesta sencilla es: si. Pero ¿Cómo es que trabaja cada una y cuales son las que están disponibles? Anteriormente vimos cómo es posible usarlos en C# y si bien son esencialmente lo mismo, vale la pena revisarlas por separado. En este post veremos las operaciones disponibles SOLO para Python.


En Python disponemos de las siguientes operaciones:

  • Or (o) "|"
  • XOr (o exclusivo) "^"
  • And (y) "&"
  • Shift left (desplazamiento a la izquierda) "<<"
  • Shift right (desplazamiento a la derecha) ">>"
  • Not (inverso) "~"

Or "|"

El operador "|" aplica la operación O entre dos números, hay que recordar las tablas de verdad y recordar que que se produce un valor verdadero cuando uno u otro de los valores son verdaderos.

  • Verdadero O Verdadero = Verdadero
  • Verdadero O Falso = Verdadero
  • Falso O Verdadero = Verdadero
  • Falso O Falso = Falso
Que es lo mismo:

  • 1|1 = 1
  • 1|0 = 1
  • 0|1 = 1
  • 0|0 = 0
Si escribimos lo anterior en la consola de Python, comprobamos que es correcto.


XOr "^"

El operador "^" aplica la operación O Exclusiva a dos números, de nueva cuenta, tomado las tablas de verdad tenemos:
  • Verdadero OEx Verdadero = Falso
  • Verdadero OEx Falso = Verdadero
  • Falso OEx Verdadero = Verdadero
  • Falso OEx Falso = Falso
Que es lo mismo:
  • 1^1 = 0
  • 1^0 = 1
  • 0^1 = 1
  • 0^0 = 0


And "&"

El operador "&" aplica la operación Y a dos números y tiene una tabla de verdad como la que sigue:
  • Verdadero Y Verdadero = Verdadero
  • Verdadero Y Falso = Falso
  • Falso Y Verdadero = Falso
  • Falso Y Falso = Falso
Que es lo mismo:
  • 1&1 = 1
  • 1&0 = 0
  • 0&1 = 0
  • 0&0 = 0


Shift Left "<<"

El operador "<<" mueve a la izquierda una secuencia de bits tantas veces como el número del lado derecho del operador lo indique.

Para que quede un poco mas claro, tomemos como ejemplo el número 76 decimal, cuya representación en binario es 1001100 y lo queremos desplazar a la izquierda dos lugares, entonces tenemos:
  • 76 <<  2 = 304
Pero ¿por que? Para tener una visión mas clara de que es lo que sucede, veamos la representación binaria de la misma operación
  • 1001100 << 10 = 100110000
Si observas de manera detenida, veras que la secuencia "1001100" se movió a la izquierda, pero como no había mas números, simplemente se agregaron dos ceros para completar. En Python podemos crear el código siguiente para probar que estamos en lo correcto.

MiNum = 76

print (MiNum)
print("{:b}".format(MiNum))

MiNum <<= 0b10

print(MiNum)
print("{:b}".format(MiNum))

    

Shift Right ">>"

El operador ">>" mueve a la derecha una secuencia de bits tantas veces como el número del lado derecho del operador lo indique.

Retomado número 76 pero ahora supongamos que los queremos desplazar  cuatro lugares a la derecha, entonces tenemos:
  • 76 >> 4 = 4
Nuevamente revisemos los bits para entender que es lo que sucede:
  • 1001100 >> 100 = 100
Si observamos bien vemos que en efecto, todos los bits se desplazaron a la derecha, pero cómo en este caso llegamos al limite derecho, todos los bits sobrantes se descartaron. En Python podemos crear el código siguiente para probar que estamos bien:

MiNum = 76

print (MiNum)
print("{:b}".format(MiNum))

MiNum >>= 0b100

print(MiNum)
print("{:b}".format(MiNum))



Not "~"

El operador "~" simplemente invierte una secuencia de bits, hay que tomar en cuenta que numero estamos usando, y dependiendo del mismo, Python usará mas o menos bits para guardarlo en memoria, pero además hay que tener en cuenta que al aplicar el operador a números con signo (y no digo -1 o algo por el estilo, sino a los números enteros con signo donde un byte se utiliza para indicar si el número es negativo o no) este invertirá toda la secuencia por lo que si esperamos que; por ejemplo; 10 en binario lo invierta en 01 no será así.

Para apreciar un poco más lo que sucede, tomemos el número entero de 8 bits 127, cuya representación en binario es 01111111 y es importante considerar el cero a la izquierda, ya que este nos dice que es un número positivo; al aplicar el operador ~ tenemos la secuencia de bits 10000000 que representa al número decimal -128.

Y bien, por ahora es todo, en el siguiente post veremos algunos ejemplos de la vida real en donde saber usar la operaciones a nivel de bits es de mucha ayuda.

Los leo luego

No hay comentarios. :

Publicar un comentario

Inútil apps #5 - Visualizer V3 (parte 3)

No hay comentarios.
Hola de nuevo a todos, después de tomar el sueño eterno (que en la actualidad es de seis a nueve meses!!) Por fin regresamos a terminar con los asunto pendientes y a tratar de aprender mas en el proceso. En el último post, estábamos fabricando unas luces que prenden y apagan al ritmo de la música.

Para poder comenzar vamos a ver el diagrama, esta disponible para su consulta en el sitio de OSHWLab, el proyecto puede ser visto en línea o puedes descargarlo para poder abrirlo en Eagle o Altium y antes de empezar te recomiendo revisar las primeras dos partes de proyecto, en la primera hablaamos sobre cómo amplificar la señal usando el circuito integrado LM358 y en la segunda parte, vimos cómo se hacen las conexiones para el LM3915.

Una vez dicho lo anterior, veamos todas las partes electricas que necesitaremos para el proyecto.

Una cosa mas antes de continuar con la lista de partes, todos los pines que tengan el prefijo "H" (Por ejemplo H1, H2, etc) Y también los llamados "AUDIOINR" y "AUDIOINL" los omitiré de la lista, ya que en lugar de soldar pines, ahí soldaré directamente los cable y dependiendo de cada quien, se pueden poner los pines o no.

ahora si, veamos la lista de componentes:
MARCAValor
R1,R4,R9,R1010k
R2,R51k
R3,R6200k
R7,R8680
C1,C210uF
D1,D21N4007
U1LM358
U2,U3LM3915
LED1,LED2,LED3,...,LED20 Diodo LED 5mm
POT1Potenciómetro 100k
BUCK1Buck converter

Nuevamente sugiero que revises la parte 1 y la parte 2 de este proyecto para poder entender el "porqué" de cada valor. Los circuitos los pedí por JLCPCB y llegaron en tiempo y en forma (nadie me paga por decir lo anterior), recomiendo ampliamente el ordenarlo, pero si no confías en este tipo de servicios, también es posible hacerlo a mano en placas de prototipo.

Una vez hechas las conexiones del diagrama, es necesario explicar para que sirven todos los pines.
  • AUDIOINR
    • Sirve para conectar el audio, el canal derecho es recomendado, en el pin que tiene forma de cuadrado o PIN1 conectamos la parte positiva del audio, el pin 2 no se conecta y el pin 3 va al negativo del audio.
  • AUDIOINL
    • Igual que el anterior, sirve para conectar el audio de entrada, el canal izquierdo es el recomendado.
  • H1
    • Comparte las conexiones del pin 1 y tres de los pines "AUDIOINR", pero además, en este se encuentra la salida regulada del audio que se conecta a una entrada del LM358.
  • H2
    • Comparte las conexiones del pin 1 y tres de los pines "AUDIOINL", pero además, en este se encuentra la salida regulada del audio que se conecta a una entrada del LM358.
  • H3
    • Es la entrada de 5v
  • H4
    • Es la entrada de 12v
  • U5 y U4
    • Son los jumpers para seleccionar el modo punto o barra del LM3615
Para controlar el nivel del audio, usamos un potenciómetro de 100k, al inicio planee ponerlo en la placa pero debido a que mi visión fue cómo la del prototipo (o la foto de arriba). El potenciómetro, debe de ir en una de las paredes del gabinete, por lo que es necesario usar los cables. Para que la detección funcione, necesitamos hacer las conexiones cómo sigue:

Y la razón por la que están compartidas las conexiones es simple, en mi caso, el las terminales del potenciómetro están conectadas a H1, pero queda libre "AUDIOINR" para poder conectar mi amplificador de audio y poder escuchar, algunos usan un plug de doble salida.

Para alimentar el circuito, se pueden usar fuentes de 5 hasta 24v, y se conectan a H4, pero además es necesario usar una fuente adicional para obtener un voltaje inferior y conectarlo a H3. Seguramente te estás cuestionando ¿para qué?. La respuesta es simple, supongamos que alimentamos a H4 con 5v, este voltaje se va a usar para alimentar el integrado LM358 que hace la amplificación, pero si recordamos, el LM358 no es capaz de sacar un voltaje igual al que se usa para alimentarlo, es decir si amplificamos 0.2v diez veces, tendremos una señal de 2v a la salida, ahora si por ejemplo, tomamos 0.49v y le aplicamos el mismo novel de ganancia, tendríamos a la salida del LM358 4.5v (no exactamente); la idea central de todo esto, es que el voltaje siempre será menor al que usemos de alimentación y a la hora de ingresarlo al LM3915 no seria suficiente para cubrir el rango de este que iría de 0v a 5v. Para solucionarlo, decidí usar un voltaje diferente e inferior para alimentar al LM3915, retomando los 5v de ejemplo, si usamos ese, a H3 lo podemos alimentar con 3.3v usando el buck converter (incluso usar el LM7803) y con eso aseguramos que el rango vaya de 0 3.3v, asegurando que la señal siempre podrá cubrirlo. La configuración que yo uso es 12v para H4 y 5v para H3

Finalmente para U4 y U5, si se hace un puente para cada una, es decir si los pines de U4 los unimos y hacemos lo mismo con U5; activaran el modo barra, si los dejamos abiertos, el LM3915 trabajará en modo punto.



Y bien, por ahora es todo, es cierto que pasaron momento difíciles (se que habrá algunos preocupados) en el blog pero planeo seguir con esto lo mas que se pueda. y por cierto, dejo un video del proyecto en acción.


Cómo de costumbre, los leo luego.

No hay comentarios. :

Publicar un comentario