/*

  This is an example program that shows how to extract MP3 ID3v1 tags.
  It is written in standard ANSI C and can be compiled with any working
  C compiler.

  Usage: "id3tag file1.mp3 [file2.mp3 [...]]"

  Author: Henrik Herranen, VLSI Solution, 2000-07-21

 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>



/*

  Different genres are described below. If it is felt that these take
  too much space from a microcontroller, the whole list may be thrown
  away since the genre information is used wrong most of the time anyway.

 */
#define GENRES 148

char *genres[GENRES] = {
  "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", "Ambient", "Trip-Hop",
  "Vocal", "Jazz+Funk", "Fusion", "Trance",
  "Classical", "Instrumental", "Acid", "House",
  "Game", "Sound Clip", "Gospel", "Noise",
  "AlternRock", "Bass", "Soul", "Punk",
  "Space", "Meditative", "Instrumental Pop", "Instrumental Rock",
  "Ethnic", "Gothic", "Darkwave", "Techno-Industrial",
  "Electronic", "Pop-Folk", "Eurodance", "Dream",
  "Southern Rock", "Comedy", "Cult", "Gangsta",
  "Top 40", "Christian Rap", "Pop/Funk", "Jungle",
  "Native American", "Cabaret", "New Wave", "Psychadelic",
  "Rave", "Showtunes", "Trailer", "Lo-Fi",
  "Tribal", "Acid Punk", "Acid Jazz", "Polka",
  "Retro", "Musical", "Rock & Roll", "Hard Rock",
  "Folk", "Folk/Rock", "National folk", "Swing",
  "Fast-fusion", "Bebob", "Latin", "Revival",
  "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock",
  "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock",
  "Big Band", "Chorus", "Easy Listening", "Acoustic",
  "Humour", "Speech", "Chanson", "Opera",
  "Chamber Music", "Sonata", "Symphony", "Booty Bass",
  "Primus", "Porn Groove", "Satire", "Slow Jam",
  "Club", "Tango", "Samba", "Folklore",
  "Ballad", "Powder Ballad", "Rhythmic Soul", "Freestyle",
  "Duet", "Punk Rock", "Drum Solo", "A Capella",
  "Euro-House", "Dance Hall", "Goa", "Drum & Bass",
  "Club House", "Hardcore", "Terror", "Indie",
  "BritPop", "NegerPunk", "Polsk Punk", "Beat",
  "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
  "Contemporary C", "Christian Rock", "Merengue", "Salsa",
  "Thrash Metal", "Anime", "JPop", "SynthPop"
};



/*

  Here is the main program. The program is called by giving 1 or more
  MP3 files as command line arguments.

  Example:
  mp3tag mysong.mp3 othersong.mp3

 */


int main(int argc, char **argv) {
  int i;
  /* 128 bytes needed for raw ID3 data */
  char id3[128];

  for (i=1; i<argc; i++) {
    if (!strcmp(argv[i], "-h")) {
      printf("Usage: %s file1.mp3 [file2.mp3 [...]]\n", argv[0]);
      exit(EXIT_SUCCESS);
    } else {
      FILE *fp = fopen(argv[i], "rb");

      if (!fp) {
	printf("Couldn't open file %s\n", argv[i]);
	exit(EXIT_FAILURE);
      }

      /* Read last 128 bytes of the file, if we can */

      if (fseek(fp, -128, SEEK_END) || fread(id3, 128, 1, fp) != 1) {
	printf("Couldn't jump/read in file %s\n", argv[i]);
	exit(EXIT_FAILURE);
      }
      fclose(fp);

      /* Now we have read the last 128 bytes and it's time to see if we
	 have some ID3 there or not. A valid ID3 tag has the characters
	 'T', 'A', and 'G' as its 3 identifying characters. */

      if (strncmp(id3, "TAG", 3)) {
	printf("File \"%s\" doesn't have an ID3 tag\n\n", argv[i]);
      } else {
	unsigned char *s = id3+3;
	char title[31];
	char artist[31];
	char album[31];
	char year[5];
	char comment[31];
	char genre[31];

	/* Id3 tag elements don't necessarily end in a '\0' if they
	   occupy the full 30 character space. Thus, we'll have to
	   nul-terminate all strings just to be sure. */
	strncpy(title, s, 30);
	title[30] = '\0';
	s += 30;

	strncpy(artist, s, 30);
	artist[30] = '\0';
	s += 30;

	strncpy(album, s, 30);
	album[30] = '\0';
	s += 30;

	strncpy(year, s, 4);
	year[4] = '\0';
	s += 4;

	strncpy(comment, s, 30);
	comment[30] = '\0';
	s += 30;

	/* The genre field is not encoded as a string, but just one byte
	   that indexes the decoding table. If memory is too expensive,
	   the whole field may be ignored or just shown as a number. */
	if (*s >= GENRES)
	  strcpy(genre, "Unknown");
	else
	  strcpy(genre, genres[*s]);

	/* And now the final printing */
	printf("File \"%s\":\n", argv[i]);
	printf("Title  : %-30s  Artist: %s\n", title, artist);
	printf("Album  : %-30s  Year  : %4s\n", album, year);
	printf("Comment: %-30s  Genre : %s\n\n", comment, genre);
      }
    }
  }

  return EXIT_SUCCESS;
}
