I'm having a bit o a problem with inheritance. The context is this assignment i have in which we have to read from an mp3 file, extacting the informations within it as well as provide other informations not explicitly contained in it (for instance the total audio time of the file, which result from a calculation involving some explicit parameter of the file).

Said that, i organized my implementation in 2 classes: The Mp3 class, that will be responsible for opening the stream and fill a list of valid frames (frames with actual audio content aka "non-garbage frames"). Problem is when i try to compile, the compiler says Frame is not a recognizable type. That gets me confused. I cannot use instances of derived classes within the respective base class? I was kinda of used to do that in java :S

I could make Mp3 as an interface, but the .cpp with the main (which has been given by the professor) contains instanciation of this type. What should i do? here's the code:

Mp3.h:

#ifndef MP3_H
#define MP3_H

#include <fstream>
#include <list>

using namespace std;

class Mp3 {

	list<Frame> frames;
	fstream myfile;
	unsigned long length;

public:

	char * name;

	Mp3(){}
	Mp3(const char * n);
	const char * Getname();
	unsigned long getLen(const char * path);
	bool isOk();
	bool getFirstFrame(Frame& f);
	list<Frame> getFrames(const char * path);
	int visitFrames(FrameVistior fv);
	void WriteFrame(Frame fr, FILE * dst);
	
};

#endif

#ifndef FRAME_H
#define FRAME_H
//
#define MASK_EMPH 3
#define MASK_ORIG 4
#define MASK_COPY 8
#define MASK_EXT 48
#define MASK_MODE 192

#define MASK_PRIV 1
#define MASK_PAD 2
#define MASK_FREQ 12
#define MASK_BITR_IDX 240

#define MASK_PROT 1
#define MASK_LAYER 6
#define MASK_VERS 24

#define OFFSET_ORIG 2
#define OFFSET_COPY 3
#define OFFSET_EXT 4
#define OFFSET_MODE 6

#define OFFSET_PAD 1
#define OFFSET_FREQ 2
#define OFFSET_BIDX 4

#define OFFSET_LAYER 1
#define OFFSET_VERS 3

#include <fstream>

using namespace std;
//
class Frame : public Mp3{

	unsigned long position;
	unsigned long length;
	unsigned long numelems;
	unsigned char * bitmap; 

public:

	Frame();
	unsigned long getLength(){ return length; }
	void addByte(char ch);
	void clear();
	void getFrame(const char * path);
	int fastValidation();
	long getTimeMilis();
	int getVersion();
	int getLayer();
	int getBitrate();
	int getFrequency();
};

#endif

Mp3.cpp:

#include "Mp3.h"
//#include "cmd.h"
#include<stdio.h>
#include<string.h>

	Mp3::Mp3(const char * n)
	{
		name = new char [strlen(n)+1];
		strcpy(name,n);
		myfile.open (name,fstream::in|fstream::out|fstream::binary);//pointer aponta para o inicio do file
		length = getLen(myfile);
		frames = get_frames(n);

	}

	const char * Mp3::Getname(){ return name; }
	
	unsigned long Mp3::getLen(const char * path)
	{
		ifstream file;
		file.open(path,fstream::in | fstream::binary);
		file.seekg(0,ios::end);

		return file.tellg();
	}

	bool Mp3::isOk()
	{
		if (!myfile.is_open()) return false;
		return true;
	}

		bool Mp3::getFirstFrame(Frame& f)
	{
		if(!frames.empty())
		{
		f = frames.front();
		return true;
		}
		return false;
	}

	list<Frame> Mp3::get_frames(const char* myfilePath)
	{

	fstream file(myfilePath, ios::in | ios::binary);

		char * memblock = new char [4]; //1º 4 bytes da frame...header.
		char * start = memblock;
		int i = 0;
		char c;
		list<Frame> lst;
		Frame f;

			while(!file.eof()){

				while(i<4){

				c=file.get();
				f.addByte(c);
				memblock[i++]=c;
			
				}
				file.seekg(-4,ios::cur);
				i = 0;

				if((memblock[0] == 0xFF) && ((memblock[1])& 0xE0) == 0xE0) 
				{
					f.getFrame(myfilePath);//Pedaço do ficheiro ate encontrar prox header.
					
					//Construir uma frame para meter na lista.
					if(f.fastValidation() == 0)
					{ 
						
					lst.push_back((f));
					memblock = start;
				}
					else
					{
						f.clear();
						memblock = start;
						file.seekg(1,ios::cur);
					}
					f.clear();
					memblock = start;
					file.seekg(1,ios::cur);
		}
			}
	return lst;
}

		void Mp3::WriteFrame(Frame& f, FILE * dst)
	{
		size_t num_bytes = f.getLength(); 
		memcpy(dst,f.frame,num_bytes);

	}

Frame.cpp

Frame::Frame()
	{
		Mp3();
		numelems = 0;
		length = 4;
		bitmap= NULL;
	}

void Frame::addByte(char byte)
{

	if(numelems == length)
	{
		length *=2;
		bitmap[numelems] = byte;
		numelems++;
	}
	else
	{
		bitmap[numelems] = byte;
		numelems++;
	}	
}

void Frame::clear()
{
	bitmap= NULL;
	numelems = 0;
}

void Frame::getFrame(fstream& file)
{

	while(!file.eof())
	{
		if(file.get() == 0xFF && ((file.get() & 0xE0) == 0xE0))
			return;
		else	
			file.seekg(-2, ios_base::cur);
			addByte(file.get());
			
	}
	return;
}

int Frame::getVersion()
{
	return (bitmap[1] & MASK_VERS);

}

int Frame::getLayer()
{
	return ((bitmap[1] & MASK_LAYER) >> OFFSET_LAYER);
}

int Frame::getBitrate()
{

	return ((bitmap[2] & MASK_BITR_IDX) >> OFFSET_BIDX);

}

int Frame::getFrequency()
{
	return ((bitmap[2] & MASK_FREQ) >> OFFSET_FREQ);
}


	int Frame::fastValidation(Frame f)
	{
		
	if((f.getVersion() ==1) || (f.getLayer() == 0) || (f.getBitrate() == 0 || f.getBitrate() == 15) || (f.getFrequency() == 3))
	return -1;
	return 0;

	}

I'm a bit unexperienced in coding with c++. So i apologize for some stupid mistakes u may encounter in this.

Cheers

Can you explain your design? A Frame is an Mp3, but an Mp3 has a list of Frames, so an Mp3 has a list of Mp3s? Why does Frame need to inherit from Mp3? That does not make sense to me, but I admit that I only know enough about Mp3s to play them. ;)

The error you are getting means that Frame is not defined when Mp3 is defined, but Mp3 uses Frame in the class definition. Problems like that can usually be solved by forward declaring the class being used:

class Frame;

class Mp3 {
	list<Frame> frames;
	fstream myfile;
	unsigned long length;
public:
	char * name;

	Mp3(){}
	Mp3(const char * n);
	const char * Getname();
	unsigned long getLen(const char * path);
	bool isOk();
	bool getFirstFrame(Frame& f);
	list<Frame> getFrames(const char * path);
	int visitFrames(FrameVistior fv);
	void WriteFrame(Frame fr, FILE * dst);
};

But I am not sure that fixing the actual error makes as much sense as solving what might be a design problem.

This concept seems really strange to me...
You've created a class called Mp3 and a class derived from Mp3 called Frame, but the Mp3 class has members which are instances of Frames???

I could be wrong, but I don't think it's possible to do that in C++. In all my years, I've certainly never seen or heard of it being done before!

This sounds like a paradox kinda like the chicken and egg scenario... Which came first, Mp3 or Frame? Mp3 is a class which uses Frame, and Frame is derived from Mp3 (where Mp3 is a class which uses Frame, which is derived from Mp3, which uses Frame.....etc ad nauseum.). It all seems a little incestuous and ultimately unnecessary!

You could declare two classes Mp3 and Frame and you could get Mp3 to use instances of Frame in it. But I don't think that there's any need to derive Frame from Mp3.

Personally, I think you need to rethink your design!
Cheers for now,
Jas.

The idea is that an Mp3 file consists on a set of frames. However, an instance of Frame doesnt have any direct relation with an instance of Mp3.
In retrospective it was kinda dumb to put Frame inheriting from Mp3 :S

I'll keep this thread open should more doubts emerge from this

Thanks

I have a new issue. I did this same assignment in C a few months ago, and i used the FILE * to read every byte on the mp3 file. every time i called a function passing it the pointer as a parameter, the called function would retain the state of the pointer at the time the function was called and would carry on reading from that point.

Now with c++ i opened the file in read+write mode using fstream, and im getting the bytes out of the file with the get function. Thing is, when i want to call a function to do some operation at that point (or even ahead) on the file, i dont know if the get() pointer (associated with the seekg operation) is passed to the function with the reference to the open file, aka, does the called function know where to start reading when we pass it the reference to the fstream??

I'll illustrate with some code:

list<Frame> Mp3::get_frames(fstream& file) {

		char * header = new char [4]; 
		char * start = header;
		long offset;
		list<Frame> lst;
		Frame f;

	while(!(file.eof())){
	
				file.get(header,4);			
				file.seekg(-4,ios::cur);

		if((header[0] == 0xFF) && ((header[1])& 0xE0) == 0xE0) 
				{
					offset = f.getFrame(file);//CALL FUNCTION
					
					if(f.fastValidation() == 0)
					{ 

					lst.push_back((f));
					header = start;
					}
					else
					{
						f.clear();
						header = start;
						file.seekg(-(offset),ios::cur);
					}
				}
					f.clear();
					header = start;
					file.seekg(1,ios::cur);
		
			}
	return lst;
}

The function i want to call is f.getFrame(file), being file: fstream file(name,fstream::in|fstream::out|fstream::binary);

Likewise, when i return from this function, the get "pointer" is affected too?

Thanks

The get and set pointers will not revert to their value before the function was called when the function returns because the stream object needs to be passed as a reference. Try passing by value and you will get an error. ;)

The behavior is easy to test:

#include <iostream>

void GetNext(std::istream& is)
{
    std::cout << (char)is.get() << '\n';
}

int main()
{
    GetNext(std::cin);
    GetNext(std::cin);
    GetNext(std::cin);
}

Plus,

Doing

file.get(header,4);
file.seekg(-4,ios::cur);

gets the get pointer back in its original point? I'm kinda confused with this :S

Plus,

Doing

file.get(header,4);
file.seekg(-4,ios::cur);

gets the get pointer back in its original point? I'm kinda confused with this :S

Stand up and take 4 steps forward, then take 4 steps back. Now you are right where you started. This is the same principle expressed as C++ code. :)

Last thing...

file.get(header,4);		
				f.setHeader(header);

		if((header[0] == 0xFF) && ((header[1])& 0xE0) == 0xE0) 
				{
					offset = f.getFrame(file);

When i make the call to the getFrame function, this function will start to operate 4 bytes from the start of the file right?

Well i tested...and it didnt even compile :S

#include <stdio.h>
#include <iostream>

using namespace std;

int main()
{

fstream file("test.txt", ios::in | ios::out | ios::binary);

GetNext(file);
GetNext(file);
GetNext(file);

}


void GetNext(fstream& is)

{

cout << (char)is.get() << '\n';

}

Error C2079 : 'file' uses undefined class 'std::basic_fstream<_Elem,_Traits>...' :S

This is just a grain of sand in this project...and i cant even get this simple sh** to work...wtf is wrong?

Plus, the debugger on my Visual Studio 2005 went beserk. I have to debug this sh** in command line...

The fstream class is declared in the <fstream> header, not <iostream> or <stdio.h>. And a function needs to be declared before it can be used. You can declare it by moving the definition before main like my last example, or by adding a prototype before main and leaving the definition in the same place as your code:

#include <iostream>
#include <fstream>

using namespace std;

void GetNext(fstream& is);

int main()
{
    fstream file("test.txt", ios::in | ios::out | ios::binary);

    GetNext(file);
    GetNext(file);
    GetNext(file);
}

void GetNext(fstream& is)
{
    cout << (char)is.get() << '\n';
}

New problem:

while(file.good()){
			   file.read(header,4);								
			f.setHeader(header);

		if(((header[0]) == 0xFF) && ((header[1])&0xE0) == 0xE0) {

header is a local variable of type char *

setHeader function just adds the 4 bytes that we read from the file into a vector...Thing is the vector is being correctly filled with the bytes. But when i read the sequence of bytes that would normally send us "inside" the if, the expression is evaluated as false, and the code inside the if is not executed.

I've debugged this using prints, printing header[0,1,2,3] and the chars are correctly printed onto the console...but the if expression isnt being correctly evaluated. Any thoughts?

0xFFFBB464

the first 11 bits have to be 1 to pass the test. but it seems that the test isnt being done at all cos i've tried just if(header[0] == 0xFF) and it didnt pass as well :S

I was able to do a watch on the header variable...and all the positions are 0x00...does that mean that the read method isnt writing on the char array? but if it isnt writing on the array, how on earth can the method set header read the bytes from the file correctly?

Check the header variable between the file.get() and f.setHeader(). Are the bytes the right value and in the right order? Then check it again after f.setHeader() is called and make sure that the bytes have not changed.

The values are 0x00...but when i pass the array to the next function, the values are correct. and when im back to this function, the values seem to disappear again. Its strange. Maybe i should encapsulate the test in a function, passing it the array. That should solve it, if we follow this train of thought. But its still very strange that the values disappear like this :S

One stupid question: Maybe that this is related with the fact that im compiling and debugging in release mode?

Add a cout statement to print the bytes right after reading them. Debuggers sometimes lie, and it could be telling you they are 0x00 when they really are not.

I did that already (the cout hing) and the values are correct.

Yeah but even if the debugger is lying...how come the expression is not evaluated? It always assumes that all the values are 0x00 :S

Did you print the result of the expression to see what happens? :)

cout << hex << header[0] << '\t' 
     << boolalpha << (header[0] == 0xFF) << '\n';
cout << hex << header[1] << '\t'
     << hex << (header[1] & 0xE0) << '\t'
     << boolalpha << ((header[1] & 0xE0) == 0xE0) << '\n';

Correctly in that you get two true results? Do you get the same result if you print everything just before the if statement?

I've tried everything...like i said before this is just a grain of sand...and i spent all day stuck in this :S

I'll send you this part of the project so u can help me, ok?

Thanks :)

Attachments
#ifndef MP3_H
#define MP3_H

#include <sstream>
#include <fstream>
#include <list>

using namespace std;
class Frame;

class Mp3 {

	list<Frame> frames;
	fstream myfile;
	unsigned long length;

public:

	char * name;

	Mp3(const char * n);
	// const char * Getname();
	// unsigned long getLen(const char * path);
	// bool isOk();
	// bool getFirstFrame(Frame& f);
	list<Frame> get_frames(fstream& file);
	bool first_validation(char * header);
	// int visitFrames(FrameVisitor fv);
	// void WriteFrame(Frame& fr, FILE * dst);
	
};

#endif

#ifndef FRAME_H
#define FRAME_H
//
#define MASK_EMPH 3
#define MASK_ORIG 4
#define MASK_COPY 8
#define MASK_EXT 48
#define MASK_MODE 192

#define MASK_PRIV 1
#define MASK_PAD 2
#define MASK_FREQ 12
#define MASK_BITR_IDX 240

#define MASK_PROT 1
#define MASK_LAYER 6
#define MASK_VERS 24

#define OFFSET_ORIG 2
#define OFFSET_COPY 3
#define OFFSET_EXT 4
#define OFFSET_MODE 6

#define OFFSET_PAD 1
#define OFFSET_FREQ 2
#define OFFSET_BIDX 4

#define OFFSET_LAYER 1
#define OFFSET_VERS 3

#include <sstream>
#include <fstream>
#include <vector>


using namespace std;
//
class Frame{

	unsigned long length;
	unsigned long numelems;
	
public:

	vector<unsigned char> bitmap; 

	Frame();
	unsigned long getLength(){ return length; }
	void addByte(char ch);
	void setHeader(char * head);
	void clear();
	long getFrame(fstream& file);
	int fastValidation();
	// long gettimemilis();
	int getVersion();
	int getLayer();
	int getBitrate();
	int getFrequency();
};

#endif
#include "mp3.h"
#include <iostream>
#include <fstream>

using namespace std;


int main()
{

Mp3 file("som.mp3");

}

Mp3::Mp3(const char * n)
	{
		name = new char [strlen(n)+1];
		strcpy(name,n);
		myfile.open(name,ios::in | ios::out | ios::binary);
		frames = get_frames(myfile);

	}
	
	list<Frame> Mp3::get_frames(fstream& file) {

		char * header = new char[4]; //1 4 bytes da frame...header.
		char * start = header;
		long offset;
		Frame f;
		list<Frame> lst;

					
		while(file.good()){

			file.read(header,4);	
			f.setHeader(header);

		if(this->first_validation(header)) 
		{

					offset = f.getFrame(file);//Pedao do ficheiro ate encontrar prox header.
					//Construir uma frame para meter na lista.
					if(f.fastValidation() == 0)
					{ 

					lst.push_back((f));
					offset = 0;
					f.clear();
					header = start;

					}
					else
					{
						f.clear();
						header = start;
						file.seekg(-(offset),ios::cur);
					}
			}
			else{
				f.clear();
				header = start;
				file.seekg(-3,ios::cur);
				}	
			}
	return lst;
}


bool Mp3::first_validation(char * header)
	{
		if(((header[0]) == 0xFF) && ((header[1]) >= 0xE0)) return true;
		return false;
	}


Frame::Frame()
	{
		numelems = 0;
		length = 0;
	}

void Frame::addByte(char byte)
{
		bitmap.push_back(byte);
		numelems++;
		length++;
	}	


void Frame::clear()
{
	bitmap.clear();
	numelems = 0;
	length=0;
}
long Frame::getFrame(fstream& file)
{
	long offset = 3;
	char head1;
	char head2;

	head1 = file.get();

	while(file.good())
	{
		head2 = file.get();

		if(((head1) == 0xFF) && (((head2) & 0xE0) == 0xE0))
			return offset;
		else	
			offset++;
			this->addByte(head1);
			head1 = head2;
			
	}
	file.seekg(-1,ios::cur);
	return offset;
}

void Frame::setHeader(char * buffer){

	int i = 0;

	while(i<4){

	this->addByte(buffer[i++]); //memcpy(vector,buffer)??
	
	}

}

int Frame::fastValidation()
	{
		
	if((this->getVersion() ==1) || (this->getLayer() == 0) || (this->getBitrate() == 0 || this->getBitrate() == 15) || (this->getFrequency() == 3))
	return -1;
	return 0;

	}
	
	int Frame::getVersion()
{
	return (bitmap[1] & MASK_VERS);

}

int Frame::getLayer()
{
	return ((bitmap[1] & MASK_LAYER) >> OFFSET_LAYER);
}

int Frame::getBitrate()
{

	return ((bitmap[2] & MASK_BITR_IDX) >> OFFSET_BIDX);

}

int Frame::getFrequency()
{
	return ((bitmap[2] & MASK_FREQ) >> OFFSET_FREQ);
}

I got it...seems that in my CPU's architecture, the char has 2 bytes. So header must be an unsigned char array(1 byte) Thats why the test isnt being done, when u get FF the array reads 0xFFFF.

New problem:

int bitrate_v2[4][16] = {
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160},
    {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160},
    {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256}
};

This seems correct...and i've used this array in C successfully... but in c++ it doesnt compile:

1>c:\users\bruno\desktop\isel\picc\trabalhos\trabalho2\trabalho2\Mp3.h(81) : error C2059: syntax error : '{'
1>c:\users\bruno\desktop\isel\picc\trabalhos\trabalho2\trabalho2\Mp3.h(81) : error C2334: unexpected token(s) preceding '{'; skipping apparent function body
1>Mp3.cpp
1>c:\users\bruno\desktop\isel\picc\trabalhos\trabalho2\trabalho2\Mp3.h(81) : error C2059: syntax error : '{'
1>c:\users\bruno\desktop\isel\picc\trabalhos\trabalho2\trabalho2\Mp3.h(81) : error C2334: unexpected token(s) preceding '{'; skipping apparent function body
1>mp3-tool.cpp
1>c:\users\bruno\desktop\isel\picc\trabalhos\trabalho2\trabalho2\Mp3.h(81) : error C2059: syntax error : '{'
1>c:\users\bruno\desktop\isel\picc\trabalhos\trabalho2\trabalho2\Mp3.h(81) : error C2334: unexpected token(s) preceding '{'; skipping apparent function body
1>FrameVisitor.cpp
1>c:\users\bruno\desktop\isel\picc\trabalhos\trabalho2\trabalho2\Mp3.h(81) : error C2059: syntax error : '{'
1>c:\users\bruno\desktop\isel\picc\trabalhos\trabalho2\trabalho2\Mp3.h(81) : error C2334: unexpected token(s) preceding '{'; skipping apparent function body
1>Frame.cpp
1>c:\users\bruno\desktop\isel\picc\trabalhos\trabalho2\trabalho2\Mp3.h(81) : error C2059: syntax error : '{'
1>c:\users\bruno\desktop\isel\picc\trabalhos\trabalho2\trabalho2\Mp3.h(81) : error C2334: unexpected token(s) preceding '{'; skipping apparent function body
1>.\Frame.cpp(113) : error C2065: 'bitrate_v2' : undeclared identifier

Edited 3 Years Ago by mike_2000_17: Fixed formatting

class Frame{
	
	unsigned long length;
	unsigned long numelems;
	int position;
	
public:

int bitrate_v2[4][16] = {
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160},
	{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160},
	{0,32,48,56,64,80,96,112,128,144,160,176,192,224,256}
};	//Versoes 2 e 2.5

	int bitrate_v1[4][15] = {
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,32,40,48,56,64,80,96,112,128,160,192,224,256,320},
	{0,32,48,56,64,80,96,112,128,160,192,224,256,320,384},
	{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448}
}; //Versão I. depende da Layer.

Someone please tell me what am i doing wrong here? This syntax seem correct but it wont compile...

If you are trying to initialize the array inside a class definition, that will not work. To initialize like that the array needs to be global, local to a namespace, or local to a function.

Hey again...i was able to finish a lot of work now that im more in touch with ++ language. Now the problem is about file copying. I have a source file opened with fstream and a destination file opened with FILE*...im trying to copy a chunk of the source file into the destination (the function receives as parameters the start second on the source file in which we should start "recording" and the duration of the file to generate from the copy). It seems to be copying the bytes correctly (at least it generates the file, with something in it), but when i try with several different media players the file is impossible to open.

void Mp3::writeFrame(const Frame& f, FILE * dst, long start, long dur)
	{

		fstream file(this->name, ios::in || ios::binary);

		int btr = (f.getBitrate() * 1000);
		int currpos = f.get_start();
		int start_byte = (currpos + (start * (btr/8)));
		int finish_byte = ((dur * (btr/8)) + start_byte);
		int memblock = (finish_byte - start_byte);
		 char * block = new char[memblock];

		 cout<<dec<<start_byte<<'\t'<<dec<<finish_byte<<'\n';
		 cout<<dec<<currpos<<'\t'<<dec<<memblock<<'\n';
		 cout<<dec<<start<<'\t'<<dec<<dur<<'\n';
		 cout<<dec<<btr<<'\t'<<'\n';

		file.seekg(start_byte, ios::beg);
		file.read(block,memblock);

		cout<<hex<<block[0]<<'\t'<<hex<<block[1]<<'\n';

		fwrite(block,memblock,1,dst);
	}

Can you help me here? what am i doing wrong? the FILE* is already opened in main in binary mode.

Thanks

This question has already been answered. Start a new discussion instead.