MP3 Reader - C# Programming Exercise

This C# exercise is about the ID3 specifications, which apply to any file or audiovisual container, but are primarily used with audio containers. There are three compatible versions of the specification, meaning a file may contain both version 1.1 and version 2.0 tags simultaneously, and in this case, the media player must determine which tags are relevant.

ID3 version 1 is a very simple specification that involves appending a fixed 128-byte block to the end of the file. This block contains several tags that provide information about the audio file. The tags are as follows:

- A header that identifies the presence of the ID3 block and its version. This header consists of the characters "TAG". - Title: 30 characters. - Artist: 30 characters. - Album: 30 characters. - Year: 4 characters. - Comment: 30 characters. - Genre (music): 1 character.

All tags use ASCII characters, except for the genre, which is an integer stored in a single byte. The musical genre associated with each byte is predefined in the standard definitions and includes 80 genres numbered from 0 to 79. Some tagging programs have expanded the predefined genres beyond 79. This exercise will allow you to work with this structure to read and manipulate audio files using the ID3 version 1 specification.

 Category

File Management

 Exercise

MP3 Reader

 Objective

ID3 specifications apply to any file or audiovisual container, but they are primarily used with audio containers. There are three compatible versions of the specification. For example, a file may contain both version 1.1 and version 2.0 tags simultaneously, and in this case, the media player must determine which tags are relevant.

ID3 version 1 is a very simple specification. It involves appending a fixed block size of 128 bytes to the end of the file in question. This block contains the following tags:

A header that identifies the presence of the ID3 block and its version. Specifically, this header comprises the characters "TAG".
Title: 30 characters.
Artist: 30 characters.
Album: 30 characters.
Year: 4 characters.
Comment: 30 characters.
Genre (music): 1 character.
All tags use ASCII characters, except for genre, which is an integer stored within a single byte. The musical genre associated with each byte is predefined in the standard definitions and includes 80 genres numbered from 0 to 79. Some tagging programs have expanded the predefined genres beyond 79.

 Write Your C# Exercise

// Import the necessary namespaces for file handling
using System;
using System.IO;
using System.Text;

class MP3Reader
{
    // Main method where the program starts
    static void Main(string[] args)
    {
        // Ensure the user provided the correct number of arguments
        if (args.Length != 1)
        {
            Console.WriteLine("Usage: MP3Reader ");
            return;
        }

        string mp3File = args[0];

        // Check if the file exists
        if (!File.Exists(mp3File))
        {
            Console.WriteLine("Error: The file does not exist.");
            return;
        }

        try
        {
            // Open the MP3 file in read-only mode
            using (FileStream fs = new FileStream(mp3File, FileMode.Open, FileAccess.Read))
            {
                // Move to the last 128 bytes where the ID3v1 tag is located
                fs.Seek(-128, SeekOrigin.End);

                // Read the last 128 bytes into a buffer
                byte[] tagBuffer = new byte[128];
                fs.Read(tagBuffer, 0, 128);

                // Check if the tag header is "TAG" (ID3v1 header identifier)
                string tagHeader = Encoding.ASCII.GetString(tagBuffer, 0, 3);
                if (tagHeader != "TAG")
                {
                    Console.WriteLine("No ID3v1 tag found in this MP3 file.");
                    return;
                }

                // Extract the information from the ID3v1 tag
                string title = TrimString(Encoding.ASCII.GetString(tagBuffer, 3, 30));
                string artist = TrimString(Encoding.ASCII.GetString(tagBuffer, 33, 30));
                string album = TrimString(Encoding.ASCII.GetString(tagBuffer, 63, 30));
                string year = TrimString(Encoding.ASCII.GetString(tagBuffer, 93, 4));
                string comment = TrimString(Encoding.ASCII.GetString(tagBuffer, 97, 30));

                // Genre is stored as a byte, so we read it and map it to a genre
                byte genreByte = tagBuffer[127];
                string genre = GetGenreName(genreByte);

                // Display the extracted information
                Console.WriteLine("ID3v1 Tag Information:");
                Console.WriteLine($"Title: {title}");
                Console.WriteLine($"Artist: {artist}");
                Console.WriteLine($"Album: {album}");
                Console.WriteLine($"Year: {year}");
                Console.WriteLine($"Comment: {comment}");
                Console.WriteLine($"Genre: {genre}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"An error occurred: {ex.Message}");
        }
    }

    // Helper function to trim trailing spaces from strings
    static string TrimString(string input)
    {
        return input.TrimEnd('\0', ' ');
    }

    // Helper function to map genre byte to genre name
    static string GetGenreName(byte genreByte)
    {
        // 80 predefined genres from the ID3v1 specification
        string[] genres = new string[]
        {
            "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", 
            "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", 
            "Rock", "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", 
            "Soundtrack", "Euro-Techno", "Pop-Folk", "Pop-Funk", "Fusion", "Trance", "Video", 
            "Rock & Roll", "Hard Rock", "Alternative Rock", "Christian", "Country Rock", 
            "Dance Hall", "Death Metal", "Disco House", "Eurodance", "Groove", "House", 
            "Indie", "Minimal", "Reggaeton", "Techno Trance", "Hardcore", "Dubstep", "Trap", 
            "Ambient", "Chill-out", "House Techno", "Synthwave", "Nu Disco", "Electro", 
            "Future Bass", "Deep House", "Indie Dance", "Funk", "Folk", "Reggae Dub", "Jazz Funk",
            "K-Pop", "J-Pop", "Blues Rock", "Soul", "Acoustic", "Folk Rock", "Gospel", "Pop Rock", 
            "Soul", "Folk", "Punk", "Post Punk", "Ska Punk", "Riot Grrl", "Country Blues", "Blues Rock", 
            "Latin Jazz", "Experimental", "Avant-garde", "Jazzy Funk", "Electropop", "Acid Jazz", 
            "Post-Rock", "Noise", "Jazz Rock", "Math Rock", "Psychedelic Rock", "Pop Punk", 
            "Southern Rock", "Folk Punk", "Indie Pop", "Jazz Blues", "Folk Soul", "Indie R&B", 
            "Blues Soul", "Electro-Rock", "Garage Rock"
        };

        // Return the genre name based on the genre byte
        if (genreByte >= 0 && genreByte < genres.Length)
        {
            return genres[genreByte];
        }
        else
        {
            return "Unknown";
        }
    }
}

 Share this C# exercise

 More C# Programming Exercises of File Management

Explore our set of C# programming exercises! Specifically designed for beginners, these exercises will help you develop a solid understanding of the basics of C#. From variables and data types to control structures and simple functions, each exercise is crafted to challenge you incrementally as you build confidence in coding in C#.

  •  C to C# converter

    This exercise consists of creating a program that converts simple C programs, such as the following one, into C#, ensuring that the resulting program compiles ...

  •  File splitter

    This exercise involves creating a program that splits a file (of any kind) into pieces of a certain size. The program should receive the file name and the desired size of th...

  •  Encrypt a BMP file

    This exercise involves creating a program to encrypt and decrypt a BMP image file by changing the "BM" mark in the first two bytes to "MB" and vice versa. The program should...

  •  CSV converter

    This exercise involves creating a program that reads a CSV file with four data blocks (three text fields and one numeric) separated by commas, and generates a text file wher...

  •  File comparer

    This exercise involves creating a C# program that determines if two files (of any kind) are identical, meaning they have the same content. The program should c...

  •  Display BPM on console

    This exercise involves creating a C# program to decode an image file in the Netpbm format (specifically, the P1 format, which is for black and white ima...