Having Trouble reading last byte in mp3 file

Hello there

I'm working on a program that reads the last 128 bytes of an mp3 file and gathers its ID3v1.1 information to show the user and allow him or her to make modifications to it. I have yet to start working on the second part of that as I am a little stuck over a problem I have with displaying the initial data of the mp3 file, specifically the last byte or the genre byte.

Whenever I try to read in the last byte of the file, I always get -2 regardless of the mp3 file I choose to open. I know this number is not supposed to be negative and it should be between 0-80 or so depending on the genre of music.

Here is the code I have written:

[CODE]
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main()
{
//variable declaration (C style strings for first 125 bytes)
//+1 in each index for the null character
char tag[4]; //the 3 character (byte) portion of the mp3 file
char songTitle[31]; //30 characters (bytes)
char artist[31]; //30 characters (bytes)
char album[31]; //30 characters (bytes)
char year[5]; //4 characters (bytes)
char comment[29]; //28 characters (bytes)

//variable declaration (binary portion of file)
char zero; //this is always 0
char track; //track number for mp3 file
char genre; //number telling which genre the song belongs to

//variable declaration (string)
string mp3Name; //name of mp3 file

//variable declaration (read input from a file)
ifstream mp3In; //read information from mp3 file
ofstream mp3Out; //write information out to an mp3 file

//Description of program
cout << "This program allows for modifying the ID3v1.1 tag of an mp3 file. " << endl
<< "It reads in the information from an mp3 file. " << endl
<< "The user can then write over any field within the ID3v1.1 tag. " << endl << endl;

//Prompt the user for the name of an mp3 file to be read and processed
//Or let the user terminate the program
cout << "Enter the name of an mp3 file to open or enter 'exit' to end program: ";
cin >> mp3Name;
cout << endl;

//If user entered 'exit', then exit the program
if (mp3Name == "exit" || mp3Name == "EXIT" || mp3Name == "Exit")
{
cout << "Ending program. Goodbye" << endl;
system("pause");
return 1;
}

//Open the file, converting the mp3 file name to a c string
mp3In.open(mp3Name.c_str(), ios::binary);

//Check to make sure that the file can be opened
//If not, display an ERROR message and end the program
if (!mp3In.is_open())
{
cerr << "ERROR! Couldn't open mp3 file. Ending program" << endl;
system("pause");
return 2;
}
else
{
//set ifstream pointer to the beginning of the last 128 bytes in the file
mp3In.seekg(-128, ios::end);

//read in the bytes and store them in appropriate variables
//At the end of each unformatted variable (or variable without a \0), add a terminating character to parse the
//byte sequence
mp3In.read(tag, 3);
tag[3] = '\0';
mp3In.read(songTitle, 30);
songTitle[30] = '\0';
mp3In.read(artist, 30);
artist[30] = '\0';
mp3In.read(album, 30);
album[30] = '\0';
mp3In.read(year, 4);
year[4] = '\0';
mp3In.read(comment, 28);
comment[28] = '\0';
mp3In >> zero;
mp3In >> track;
mp3In >> genre;

//display current ID3v1.1 information to the user
cout << "Tag: " << tag << endl
<< "Song Title: " << songTitle << endl
<< "Artist: " << artist << endl
<< "Album: " << album << endl
<< "Year: " << year << endl
<< "Comment: " << comment << endl
<< "Zero byte: " << (int)zero << endl
<< "Track byte: " << (int)track << endl
<< "Genre byte: " << (int)genre << endl;

}
mp3In.close();
system("pause");
return 0;
}

This was coded in Dev-C++ in case anyone is wondering.

I've been messing around with shifting the get pointer for the input stream around, declaring the variable in question as a c string and adding a terminating character at the end, but it hasn't helped me.

Any help regarding this is greatly appreciated.

Code looks fine to me (except for the fact that genre and track should be unsigned char types -- but that isn't causing a problem.)

Inspect the last byte of the file in a hex editor if you're not confident the code is correct. Then you'll know for sure whether it's the file you're dealing with or your code.
Ok so I ran a few mp3's (all of which are different genres of music) through a hex editor and in all of them the last byte was 0C (which should be 12). The genre of music in these mp3 files are classical, game, and jazz. I should be getting 32, 36, and 8 as results.

Something interesting happened when I declared genre as an unsigned char however. Instead of getting -2, I'm now getting 254 instead. It's a positive number now, but still not the right kind of output I expected.

I guess maybe there might be something wrong with the mp3 files I have (I got them off of amazon mp3). I'll take your word for it that my code works fine and just keep on going ahead. I can always just overwrite that pesky genre byte :)
You may want to check to see if you're dealing with a different version of tags in the MP3 files. You're assuming id3v1.

http://www.id3.org/Home
> Whenever I try to read in the last byte of the file, I always get -2 regardless of the mp3 file I choose to open.

You get incorrect results when you use formatted input on binary data.
Change the code to perform unformatted input and you would be ok.

1
2
3
4
5
6
7
8
9
// ...
mp3In.read( comment, 28 );
comment[28] = '\0';
mp3In.read( &zero, 1 ); // mp3In >> zero; // ****
mp3In.read( &track, 1 ); // mp3In >> track; // ****
mp3In.read( &genre, 1 ); // mp3In >> genre; // ****

//display current ID3v1.1 information to the user
// ... 
Now, why didn't I see that? Totally makes sense with the value of the last byte. You should still check to see the format of the tags you're dealing with, though!
I think that did the trick. I'm now getting the value of 12 which is the last byte for each mp3 in the hex editor. Finally, it matches up!

Is this how it is in future versions of ID3? Does the last byte always come out to 12? To my understanding, if the first three bytes in the 128 byte sequence come out to TAG, then I have an mp3 with ID3v1 format. That's how it is with the mp3 files I've used.

http://www.vbaccelerator.com/home/VB/Code/vbMedia/Audio/Reading_and_Writing_MP3_ID3v1_and_v2_Tags/article.asp

Thanks for the help you've provided so far.
I know this thread is pretty much solved, but in general I've found it easier to declare unsigned chars while dealing with a binary file.
Topic archived. No new replies allowed.