lunes, 5 de enero de 2015

Entrenamiento - Talleres de .NET HTE para Enero

Talleres de .NET HTE para Enero

En este mes de Enero tenemos programado 2 Talleres de .NET sobre Creación de Controles.

A todos los programadores y desarrolladores de .NET que quieran crear Librerías de Controles para facilitar y agilizar el desarrollo mediante la reusabilidad se les recomienda asistir a ambas charlas donde usaremos intensivamente Reflection para crear Controles Enlazados a Datos.

Aquí les dejo la información del evento y ya se pueden ir inscribiendo de cualquiera de las 2 formas:
- Reservación por Correo
- Pago y Confirmación por Correo (envío del voucher)

El correo sigue siendo Luis.duenash@gmail.com e informes@hte.com.pe

La inversión por cada charla de 3 horas es de 40 soles y el que desea Certificado serán 20 soles adicionales.

Nota: El Certificado es opcional, solo para los que lo soliciten.

El horario es de 7:00 a 10:00 pm, pero el ingreso para el registro es a partir de las 6:30 pm.




Los esperamos.

El Demo del Día: Leer y Escribir la Metadata de un Archivo MP3

Leer y Escribir la Metadata de un Archivo MP3

Primer Demo del año, después de un largo periodo sin publicar ejemplos en el Blog. En esta ocasión vamos a ver como podemos leer y escribir la información (metadata) de un archivo MP3.

La especificación que define la metadata de un archivo MP3 se llama ID3 y están disponibles 2 versiones: ID3V1 y ID3V2. En este demo veremos como crear una aplicación que permita leer y escribir el ID3V1.

Existen Librerías en C# que permiten manejar el ID3, tales como:
TagLib
ID3Net
C#ID3Lib

Pero como el lema de este Blog es "Hazlo tu mismo", veremos como crear nuestra propia aplicación WinForms en C#, para lo cual debemos saber que los últimos 128 bytes de un archivo MP3 se usan para el ID3V1, es decir, para guardar información del archivo (Metadata).

La estructura seria la siguiente, para los últimos 128 bytes de un archivo MP3:
- Cabecera: 3 bytes (por ejemplo para el ID3V1 la palabra: TAG)
- Titulo: 30 bytes
- Artista: 30 bytes
- Album: 30 bytes
- Año: 4 bytes
- Comentario: 30 bytes que se dividen en 3 partes:
  -) Comentario: 28 primeros bytes
  -) Tiene Pista: 1 byte (0 si tiene numero de pista)
  -) Numero de Pista: 1 byte (numero de pista o track)
- Genero: 1 byte (Entero de 0 a 255 con los géneros, los cuales enumero en el código)

Teniendo estos conceptos claros ahora crearemos una aplicación que permita seleccionar un archivo MP3 y leer la información de la metadata y poder grabarla si se realiza cambios, para lo cual trabajaremos con archivos.

Crear una Aplicación WinForms en C#

Crear una Aplicación WinForms en C# llamada "Leer_Escribir_ID3_MP3" y al formulario cambiarle de nombre a "frmInfoMP3" y diseñarlo como se muestra en la siguiente figura:



Crear una Clase con la estructura de la MetaData del MP3

Agregar una clase a la aplicación llamada: "MP3ID3Tag" para almacenar la metadata y escribir el siguiente código:

namespace Leer_Escribir_ID3_MP3
{
    public class MP3ID3Tag
    {
        public byte[] Id = new byte[3];
        public byte[] Titulo = new byte[30];
        public byte[] Artista = new byte[30];
        public byte[] Album = new byte[30];
        public byte[] Año = new byte[4];
        public byte[] Comentario = new byte[30];
        public byte[] Genero = new byte[1];

        public enum Generos
        {
            Blues =0,
            Classic_Rock =1,
            Country=2,
            Dance=3,
            Disco=4,
            Funk=5,
            Grunge=6,
            HipHop=7,
            Jazz=8,
            Metal=9,
            New_Age=10,
            Oldies=11,
            Other=12,
            Pop=13,
            Rhythm_And_Blues=14,
            Rap=15,
            Reggae=16,
            Rock=17,
            Techno=18,
            Industrial=19,
            Alternative=20,
            Ska=21,
            Death_Metal=22,
            Pranks=23,
            Soundtrack=24,
            Euro_Techno=25,
            Ambient=26,
            Trip_Hop=27,
            Vocal=28,
            Jazz_Funk=29,
            Fusion=30,
            Trance=31,
            Classical=32,
            Instrumental=33,
            Acid=34,
            House=35,
            Game=36,
            Sound_Clip = 37,
            Gospel=38,
            Noise=39,          
            Alternative_Rock = 40,
            Bass=41,
            Soul=42,
            Punk_Rock=43,
            Space=44,
            Meditative=45,
            Instrumental_Pop=46,
            Instrumental_Rock = 47,
            Ethnic=48,
            Gothic=49,
            Darkwave=50,
            Techno_Industrial=51,
            Electronic=52,
            Pop_Folk=53,
            Eurodance=54,
            Dream=55,
            Southern_Rock=56,
            Comedy=57,
            Cult=58,
            Gangsta=59,
            Top_40=60,
            Christian_Rap=61,
            Pop_Funk=62,
            Jungle=63,
            Native_American=64,
            Cabaret=65,
            New_Wave=66,
            Psychedelic=67,
            Rave=68,
            Showtunes=69,
            Trailer=70,
            Lo_Fi=71,
            Tribal=72,
            Acid_Punk=73,
            Acid_Jazz = 74,
            Polka=75,
            Retro=76,
            Musical=77,
            Rock_And_Roll=78,
            Hard_Rock=79,
            Folk=80,
            Folk_Rock=81,
            National_Folk=82,
            Swing=83,
            Fast_Fusion=84,
            Bebop=85,
            Latin=86,
            Revival=87,
            Celtic=88,
            Bluegrass=89,
            Avantgarde=90,
            Gothic_Rock=91,
            Progresive_Rock=92,
            Psychedelic_Rock = 93,
            Symphonic_Rock = 94,
            Slow_Rock=95,
            Big_Band=96,
            Chorus=97,
            Easy_Listening=98,
            Acoustic=99,
            Humour=100,
            Speech=101,
            Chanson=102,
            Opera=103,
            Chamber_Music=104,
            Sonata=105,
            Symphony=106,
            Booty_Bass=107,
            Primus=108,
            Porn_Groove=109,
            Satire=110,
            Slow_Jam=111,
            Club=112,
            Tango=113,
            Samba=114,
            Folklore=115,
            Ballad=116,
            Power_Ballad=117,
            Rhythmic_Soul=118,
            Freestyle=119,
            Duet=120,
            PunkRock=121,
            Drum_Solo=122,
            Acapella=123,
            Euro_House=124,
            Dance_Hall=125,
            Goa_Trance=126,
            Drum_Bass=127,
            Club_House=128,
            Hardcore_Techno=129,
            Terror=130,
            Indie=131,
            Britpop=132,
            Afro_Punk=133,
            Polsk_Punk=134,
            Beat=135,
            Christian_Gangsta_Rap=136,
            Heavy_Metal=137,
            Black_Metal=138,
            Crossover=139,
            Contemporary_Christian=140,
            Christian_Rock=141,
            Merengue=142,
            Salsa=143,
            Thrash_Metal=144,
            Anime=145,
            Jpop=146,
            Synthpop=147,
            Abstract=148,
            Art_Rock=149,
            Baroque=150,
            Bhangra=151,
            Big_Beat=152,
            Breakbeat=153,
            Chillout=154,
            Downtempo=155,
            Dub=156,
            EBM=157,
            Eclectic=158,
            Electro=159,
            Electroclash=160,
            Emo=161,
            Experimental=162,
            Garage=163,
            Global = 164,
            IDM=165,
            Illbient=166,
            Industro_Goth=167,
            Jam_Band=168,
            Krautrock=169,
            Leftfield=170,
            Lounge=171,
            Math_Rock=172,
            New_Romantic=173,
            Nu_Breakz=174,
            Post_Punk=175,
            Post_Rock=176,
            Psytrance=177,
            Shoegaze=178,
            Space_Rock=179,
            Trop_Rock=180,
            World_Music=181,
            Neoclassical=182,
            Audiobook=183,
            Audio_Theatre=184,
            Neue_Deutsche_Welle=185,
            Podcast=186,
            Indie_Rock=187,
            G_Funk=188,
            Dubstep=189,
            Garage_Rock=190,
            Psybient=191
        }
    }
}

Programar con Archivos en el Formulario WinForms en C#

Escribir el siguiente código en el formulario "frmInfoMP3":

using System;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace Leer_Escribir_ID3_MP3
{
    public partial class frmInfoMP3 : Form
    {
        public frmInfoMP3()
        {
            InitializeComponent();
        }

        private void cargarGeneros(object sender, EventArgs e)
        {
            Type tipo = typeof(MP3ID3Tag.Generos);
            cboGenero.DataSource = Enum.GetNames(tipo);
            cboGenero.SelectedIndex = -1;
        }

        private void abrirArchivoMp3(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Title = "Abrir archivos mp3";
            ofd.Filter = "Archivos mp3|*.mp3";
            ofd.InitialDirectory = @"C:\Musica\The Best";
            if (ofd.ShowDialog().Equals(DialogResult.OK))
            {
                btnGrabar.Enabled = true;
                txtArchivoMp3.Text = ofd.FileName;
                leerInfoMP3();
            }
        }

        private void leerInfoMP3()
        {
            using (FileStream fs = File.OpenRead(txtArchivoMp3.Text))
            {
                if (fs.Length >= 128)
                {
                    MP3ID3Tag tag = new MP3ID3Tag();
                    fs.Seek(-128, SeekOrigin.End);
                    fs.Read(tag.Id, 0, tag.Id.Length);
                    fs.Read(tag.Titulo, 0, tag.Titulo.Length);
                    fs.Read(tag.Artista, 0, tag.Artista.Length);
                    fs.Read(tag.Album, 0, tag.Album.Length);
                    fs.Read(tag.Año, 0, tag.Año.Length);
                    fs.Read(tag.Comentario, 0, tag.Comentario.Length);
                    fs.Read(tag.Genero, 0, tag.Genero.Length);
                    string tagId = Encoding.Default.GetString(tag.Id);
                    if (tagId.Equals("TAG"))
                    {
                        txtTitulo.Text = Encoding.Default.GetString(tag.Titulo).Trim();
                        txtArtista.Text = Encoding.Default.GetString(tag.Artista).Trim();
                        txtAlbum.Text = Encoding.Default.GetString(tag.Album).Trim();
                        txtAño.Text = Encoding.Default.GetString(tag.Año);
                        byte[] comentario = new byte[28];
                        Buffer.BlockCopy(tag.Comentario, 0, comentario, 0, 28);
                        txtComentario.Text = Encoding.Default.GetString(comentario).Trim();
                        Type tipo = typeof(MP3ID3Tag.Generos);
                        byte n = (byte)tag.Genero[0];
                        string genero = Enum.GetName(tipo, n);
                        int pos = cboGenero.Items.IndexOf(genero);
                        if (pos > -1) cboGenero.SelectedIndex = pos;
                        if (tag.Comentario[28].Equals(0))
                        {
                            txtPista.Text = tag.Comentario[29].ToString();
                        }
                    }
                }
            }
        }

        private void escribirInfoMP3()
        {
            using (FileStream fs = File.OpenWrite(txtArchivoMp3.Text))
            {
                if (fs.Length >= 128)
                {
                    MP3ID3Tag tag = new MP3ID3Tag();
                    tag.Id = Encoding.Default.GetBytes("TAG");
                    tag.Titulo = Encoding.Default.GetBytes(txtTitulo.Text.PadRight(30, ' '));
                    tag.Artista = Encoding.Default.GetBytes(txtArtista.Text.PadRight(30, ' '));
                    tag.Album = Encoding.Default.GetBytes(txtAlbum.Text.PadRight(30, ' '));
                    tag.Año = Encoding.Default.GetBytes(txtAño.Text);
                    byte[] comentario = new byte[28];
                    comentario = Encoding.Default.GetBytes(txtComentario.Text.PadRight(28, ' '));
                    byte[] tienePista = new byte[] { 0 };
                    byte pista = byte.Parse(txtPista.Text);
                    byte[] numeroPista = new byte[] { pista };                  
                    Buffer.BlockCopy(comentario, 0, tag.Comentario, 0, 28);
                    Buffer.BlockCopy(tienePista, 0, tag.Comentario, 28, 1);
                    Buffer.BlockCopy(numeroPista, 0, tag.Comentario,29, 1);
                    Type tipo = typeof(MP3ID3Tag.Generos);
                    MP3ID3Tag.Generos genero = (MP3ID3Tag.Generos)
                    Enum.Parse(tipo, cboGenero.SelectedItem.ToString());
                    byte n = (byte)genero;
                    tag.Genero = new byte[] {n};
                    fs.Seek(-128, SeekOrigin.End);
                    fs.Write(tag.Id, 0, tag.Id.Length);
                    fs.Write(tag.Titulo, 0, tag.Titulo.Length);
                    fs.Write(tag.Artista, 0, tag.Artista.Length);
                    fs.Write(tag.Album, 0, tag.Album.Length);
                    fs.Write(tag.Año, 0, tag.Año.Length);
                    fs.Write(tag.Comentario, 0, tag.Comentario.Length);
                    fs.Write(tag.Genero, 0, tag.Genero.Length);
                    MessageBox.Show("ID Tag V1 del archivo mp3 fue cambiado");
                }
            }
        }

        private void grabarArchivoMP3(object sender, EventArgs e)
        {
            escribirInfoMP3();
        }
    }
}

Nota: La función "cargarGeneros" esta asociada al evento "Load" del formulario, la función "abrirArchivoMp3" esta asociada al evento "Click" del botón "btnAbrirMp3" y la función "grabarArchivoMP3" esta asociada al evento "Click" del botón "btnGrabar".

Probar la Aplicación Windows Forms

Grabar la aplicación y ejecutarla con F5. Se mostrará la siguiente ventana:


Nota: Ver como se ha llenado la lista con los géneros disponibles en la enumeración.

Clic al botón de la parte superior derecha y seleccionar un archivo MP3 en el diálogo de abrir, luego se mostrará la información de dicho archivo, similar a la siguiente figura:


Cambiar la información del archivo, por ejemplo el Album, cambiar el Genero, agregar un Comentario y luego "Grabar".


Cerrar la aplicación y volverla a ejecutar nuevamente para verificar si la información del archivo se guardó o también abrir el Winamp, reproducir la canción y pulsar Alt + 3 para ver la información del archivo y verificar que los cambios se han realizado satisfactoriamente.

Comentario Final

En este post hemos aprendido a leer y escribir la metadata de un archivo MP3 manejando los 128 últimos bytes del archivo usando el método "Seek" de la clase "FileStream" para ubicarnos en los últimos 128 bytes y a partir de esa posición usar "Read" para leer y "Write" para escribir.

Espero que les guste este primer post y tratare de que sean mas seguidos, ya que es lo que mas interesa a los visitantes del Blog.

Descarga como rar
Demo28_Leer_Escribir_ID3_MP3

Descarga sin extension (luego renombrar a rar y descomprimir)
Leer_Escribir_ID3_MP3

El Libro del Día: RaphaëlJS

El Libro del Día: 2015-01-05

Titulo: RaphaëlJS
Autor: Chris Wilson
Editorial: O'Reilly
Nro Paginas: 121

Capítulos:
1. Introduction: Why Raphael is Great
2. Shapes
3. Interaction
4. Paths: How to Make Custom Shapes and Curves
5. Animations, Part One
6. Maps, Illustrations, and Other Artifacts
7. Animations, Part Two
8. Mobile, Global Variables, and Other Things That Hurt Less Than You Think

Descarga:
RaphaelJS