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

 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.