Outputing hex data to file to mimick original Hex input.

  • (2 Pages)
  • +
  • 1
  • 2

17 Replies - 851 Views - Last Post: 24 December 2013 - 08:12 AM Rate Topic: -----

#1 otm  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 27
  • Joined: 18-April 10

Outputing hex data to file to mimick original Hex input.

Posted 22 December 2013 - 06:08 PM

Hi,

Me again, with More questions........

I am trying to do a relatively simple task (I say simple....) of reading in a .WAV audio file, and extracting the useful information and the audio samples...

I plan on using hardware to play the audio samples back to reproduce the file audio.

Here is where I am at currently::

I have read the .WAV file header into a struct,
I have converted the relevant char arrays into strings to allow for simple if(string == "Blah") statements
I have done relevant testing of the various bits of data to make sure the file is a compatible uncompressed file


What I'm kind of struggling with is the outputting of the data into a file were the format is identical to the input file (minus superfluous data I don't need)

Here is elements of my code (The // at the moment are basic references to the source where any info was found -- I'm not trying to pass of any code that isn't mine as mine :P/> )


#include <fstream>
#include <iostream>
#include <string>

// www.youtube.com/watch?v=r0QR3HH3xDs --- Aamir Mirza -- Edited by me for .wav headers
typedef struct _wavheader{

	char chunkid_riff[4]; 
	unsigned long chunk_size;
	char format_wave[4];
	char subchunk_1_id_fmt_[4];
	unsigned long subchunk_1_size;
	short audio_format;
	short num_channels;
	unsigned long sample_rate;
	unsigned long byte_rate;
	short block_align;
	short bits_per_sample;
	char subchunk_2_id_data[4];
	unsigned long subchunk_2_size;
	} WAVEHEADER;

using namespace std;


// www.youtube.com/watch?v=r0QR3HH3xDs --- Aamir Mirza -- Edited by me for .wav headers
void main(){
	
	unsigned long num_samples;
	ifstream wave_file("test.wav", ios::binary | ios::in);
	if (!wave_file)
	{
		cout << "Fatal Error" << endl;
		EXIT_FAILURE;
	}

	WAVEHEADER wavheaddata;
	
	wave_file.read((char*)&wavheaddata, sizeof(WAVEHEADER));

	//stackoverflow.com/questions/4691608/copying-non-null-terminated-unsigned-char-array-to-stdstring

	string riff_header(wavheaddata.chunkid_riff, wavheaddata.chunkid_riff + sizeof(wavheaddata.chunkid_riff));
	string wave_header(wavheaddata.format_wave, wavheaddata.format_wave + sizeof(wavheaddata.format_wave));
	string fmt_header(wavheaddata.subchunk_1_id_fmt_, wavheaddata.subchunk_1_id_fmt_ + sizeof(wavheaddata.subchunk_1_id_fmt_));
	string data_header(wavheaddata.subchunk_2_id_data, wavheaddata.subchunk_2_id_data + sizeof(wavheaddata.subchunk_2_id_data));
	
	if (riff_header == "RIFF")
	{
		cout << "CHUNK ID: " << riff_header << " THIS IS A RIFF FILE" << endl;
		if (wave_header == "WAVE")
		{
			cout << "FILE FORMAT: " << wave_header << " THIS IS A WAVE FILE" << endl;
			if (fmt_header == "fmt ")
			{
				cout << "FORMAT SUBCHUNK FOUND, PROCESSING FORMAT DATA" << endl;
				if (wavheaddata.audio_format == 1)
				{
					cout << "AUDIO DATA IN PCM, THEREFORE NO COMPRESSION" << endl;
					if (wavheaddata.num_channels == 1)
					{
						cout << "THE FILE CONTAINS MONO AUDIO" << endl;

						if (data_header == "data")
						{
							cout << "DATA BLOCK FOUND" << endl;
							cout << "EVERYTHING SEEMS OK, NOW ATTEMPTING TO WRITE TO OUTPUT FILE" << endl;

							ofstream out_file("out.bin", ios::out | ios::binary);
							if (!out_file)
							{
								cout << "Unable to Create Ouput File" << endl;
								EXIT_FAILURE;
							}

							out_file << wavheaddata.sample_rate;
							out_file << wavheaddata.bits_per_sample;
							num_samples = (wavheaddata.subchunk_2_size / wavheaddata.block_align);
							out_file << num_samples;
							//DATA CODE HERE
						}
						else
							cout << endl << "ERROR:: CANNOT LOCATE THE DATA SUBCHUNK, INVALID FILE" << endl << endl;
					}
					else
					{
						cout << "THE FILE CONTAINS " << wavheaddata.num_channels << " CHANNELS, ONLY ONE CHANNEL WILL BE EXTRACTED" << endl;
						//extract only one channel code here.....
					}
				}
				else
					cout << endl << "ERROR:: AUDIO DATA IS NOT IN PCM, AND HAS SOME COMPRESSION APPLIED, PLEASE PROVIDE UNCOMPRESSED PCM ONLY" << endl << endl;
			}
			else
				cout << endl << "ERROR:: CANNOT LOCATE THE FORMAT SUBCHUNK, INVALID FILE" << endl << endl;
		}
		else
			cout << endl << "ERROR:: NOT A WAVE FILE, PLEASE ONLY PROVIDE A VALID .WAV FILE" << endl << endl;
	}
	else
		cout << endl << "ERROR:: NOT A RIFF FILE, PLEASE ONLY PROVIDE A VALID .WAV FILE" << endl << endl;
} 



Here's my problem, I kind of think I know where it originates, but I'm not sure how to fix it.....

If I load the original .wav file in a hex editor to see the raw data I end up with the following example:


52 49 46 46 0C 04 00 00 57 41 56 45 66 6D 74 20 10 00 00 00 01 00 01 00 44 AC 00 00 44 AC 00 00 01 00 08 00 64 61 74 61 E8 03 00 00 80 82 84 86 88 8A 8C 8E 90 92 94 96 98 9A 9C 9E A0 A2 A4 A6 A8 AA AC AE B1 B3 B5 B7 B9 BB BD BF C1 C3 C5 C7 C9 CB CD CF D1 D3 D5 D7 D9 DB DE E0 E2 E4 E6 1B 1D 1F 21 23 25 27 29 2B 2D 2F 31 33 35 38 3A 3C

looking at this you can see some of the elements... the first four bytes 0x52494646 translate to ACSII as 'RIFF'

however, when the header is read into the struct, C (or the compiler...) obviously converts them to more sensible 'numbers' and characters.... for instance If I were to insert the below code I would see the resulting output::

cout << wavheaddata.bits_per_sample << endl;

The output, (and the stored value): 8



so it stands to reason, that when I output the file, and then open up in a hex editor I see the following::

34 34 31 30 30 38 31 30 30 30

(This is just the sample frequency, the bit depth of each sample, and the number of samples)

instead of outputting the hex value for 8, it has outputted hex value for the ASCII character 8 (38) and so on and so forth...

If I change the output lines to ::

out_file << hex << num_samples;



The output in the hex editor is hex values for the ASCII characters '38E' which is the Hex number I want stored (1000)

Are you still with me?? Sorry about this!!

TL;DR Basically, my question boils down to, how do I in C++ output a data file, that when opened in a hex editor looks like this (for my example of 44100 sampling frequency, 8 bit sample depth, and 1000 samples)::

44 AC 00 00 08 00 E8 03

(Now I know this is in Little Endian form, but at this moment I want it to stay that way, If I need it in big Endian form its just a case of manipulating the data BEFORE writing it to the file, so I can work on that)

It would be akin to a hex dump I suppose.....

Any and all help is greatly appreciated!

Once I've cracked this the next step would be to read in that actual sample data, if needed strip any 'extra' audio channels out so that you are left with a mono data file, which contains only the following elements:: Sample Frequency, bit depth, number of sample, data.... that way, I can use the first word to configure any hardware, then just pump out the sample data.... but that will be my next challenge.... and no doubt, another question!!

Thank you very much,

Owen.

Is This A Good Question/Topic? 0
  • +

Replies To: Outputing hex data to file to mimick original Hex input.

#2 CTphpnwb  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2999
  • View blog
  • Posts: 10,384
  • Joined: 08-August 08

Re: Outputing hex data to file to mimick original Hex input.

Posted 22 December 2013 - 06:13 PM

This is wrong:
void main(){

I stopped reading there.
Was This Post Helpful? 1
  • +
  • -

#3 otm  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 27
  • Joined: 18-April 10

Re: Outputing hex data to file to mimick original Hex input.

Posted 22 December 2013 - 06:57 PM

Hi,

Ok, mistake 1, it should be int main(void){ ... with something like return 0 at the end...

(I think...)

Also, I may not have properly closed the files either, but its not related to my problems at this time and I will fix it once I have the code sorted....

Any help on the specific question?

Owen.

This post has been edited by otm: 22 December 2013 - 07:00 PM

Was This Post Helpful? 0
  • +
  • -

#4 jimblumberg  Icon User is online

  • member icon


Reputation: 4098
  • View blog
  • Posts: 12,679
  • Joined: 25-December 09

Re: Outputing hex data to file to mimick original Hex input.

Posted 22 December 2013 - 07:23 PM

Look at the following snippet:
                     ofstream out_file("out.bin", ios::out | ios::binary);
                     if (!out_file)
                     {
                        cout << "Unable to Create Ouput File" << endl;
                        //								EXIT_FAILURE;
                     }

                     out_file << wavheaddata.sample_rate;
                     out_file << wavheaddata.bits_per_sample;
                     num_samples = (wavheaddata.subchunk_2_size / wavheaddata.block_align);
                     out_file << num_samples;

When you write numbers using formatted output you get the ASCII representation, not the hex you seem to want. You should be using the read/write method functions instead.


Jim
Was This Post Helpful? 1
  • +
  • -

#5 CTphpnwb  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2999
  • View blog
  • Posts: 10,384
  • Joined: 08-August 08

Re: Outputing hex data to file to mimick original Hex input.

Posted 22 December 2013 - 07:45 PM

Note also that unsigned long varies depending on the system. Your code wouldn't open a wave file on my system until I changed it to unsigned int, which should be 32 bits on most systems.

View Postotm, on 22 December 2013 - 09:57 PM, said:

Also, I may not have properly closed the files either, but its not related to my problems at this time and I will fix it once I have the code sorted....

Never a good idea. Fix problems when you see them. Later they're out of sight and mind, but still problems.
Was This Post Helpful? 1
  • +
  • -

#6 jjl  Icon User is offline

  • Engineer
  • member icon

Reputation: 1074
  • View blog
  • Posts: 4,533
  • Joined: 09-June 09

Re: Outputing hex data to file to mimick original Hex input.

Posted 22 December 2013 - 07:55 PM

using type uint32_t is probably the safest move. It is a type defined in cstdint
Was This Post Helpful? 1
  • +
  • -

#7 otm  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 27
  • Joined: 18-April 10

Re: Outputing hex data to file to mimick original Hex input.

Posted 22 December 2013 - 08:13 PM

View Postjimblumberg, on 23 December 2013 - 02:23 AM, said:

Look at the following snippet:
                     ofstream out_file("out.bin", ios::out | ios::binary);
                     if (!out_file)
                     {
                        cout << "Unable to Create Ouput File" << endl;
                        //								EXIT_FAILURE;
                     }

                     out_file << wavheaddata.sample_rate;
                     out_file << wavheaddata.bits_per_sample;
                     num_samples = (wavheaddata.subchunk_2_size / wavheaddata.block_align);
                     out_file << num_samples;

When you write numbers using formatted output you get the ASCII representation, not the hex you seem to want. You should be using the read/write method functions instead.


Jim


Jim, ahhhhhhhhh..... I must admit, this is the first time I've ever dealt with binary files. And I've never used .read or .write before......

It took me some time to combine the reference materials I had to cobble this code together!!

Also, is cstdint.h a standard header? I always get confused with what is amd isn't! !

I will implement the .write function as soon as I can, if I get stuck I might need help!!

Slighty thinking about the next issue..... I'm not sure how best to tackle the actual data itself.... as you won't know the .wav file size until runtime I would assume vectors would be best, can I use .read to read in bytes to a buffer then push them into the vector? But really if (more likely when!) I get stuck thats another topic!

As for the file closing, I realised after posting that I hadn't done that, and that you may pick up on it, but as it's not related to the question I would have hoped that it wouldn't have stopped people from helping me.

Owen.
Was This Post Helpful? 0
  • +
  • -

#8 jimblumberg  Icon User is online

  • member icon


Reputation: 4098
  • View blog
  • Posts: 12,679
  • Joined: 25-December 09

Re: Outputing hex data to file to mimick original Hex input.

Posted 22 December 2013 - 08:23 PM

Quote

Also, is cstdint.h a standard header? I always get confused with what is amd isn't! !

No, you'd add the c to the front of the C standard header and leave off any extension. For example <cstdio>

Quote

I will implement the .write function as soon as I can, if I get stuck I might need help!!

What? Remember the C++ streams already have a read() and write() method function.

Quote

As for the file closing, I realised after posting that I hadn't done that, and that you may pick up on it, but as it's not related to the question I would have hoped that it wouldn't have stopped people from helping me.

Quite often it is not necessary to close C++ file streams because they will close themselves when the go out of scope. The only time you really need to worry about closing the stream is when you try to re-use the stream.

You stated that this was a possible problem and people told you not to defer fixing possible problems, that doesn't mean that it will stop them from helping. Unless you seem to be ignoring the help being given.

Quote

Slighty thinking about the next issue..... I'm not sure how best to tackle the actual data itself.... as you won't know the .wav file size until runtime I would assume vectors would be best, can I use .read to read in bytes to a buffer then push them into the vector?

Remember that you are writing fixed amounts of data to and from your files. So you can read this fixed number of bytes from file one and then write these same bytes to the file. There is no real need to read and write the complete file at one time.

Jim
Was This Post Helpful? 1
  • +
  • -

#9 otm  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 27
  • Joined: 18-April 10

Re: Outputing hex data to file to mimick original Hex input.

Posted 22 December 2013 - 08:54 PM

Hi jim,

Cheers for the reponse,

About .write I should been clearer, tomorrow afternoon, I will spend time fully getting to grips with the fstream.write function.

As for the data, my only tbought was that I am developing the hardware to play back the adulterated .wav files and it will only be mono, there is no need for stero, and adds layers of unnecessary complexity etc... if the provided audio file is stero (or for that matter any other number other than 1) I will need to read in the data, then only write out every other piece, or every 3rd piece
.. but then again, a small input buffer (array of fixed size in bytes) could read in a sample, then only write specific elements of that array to the output.

Only thing I need to consider with higher bit depths is that >16 bit wav files store the samples in 2's complement :( I need to think about hardware issues then!

Thanks for the support, no doubt I'll be back soon enough!!

Owen.
Was This Post Helpful? 0
  • +
  • -

#10 otm  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 27
  • Joined: 18-April 10

Re: Outputing hex data to file to mimick original Hex input.

Posted 23 December 2013 - 09:19 AM

Hi All,

just for completeness....

the code I have that incorporates what was talked about here::

#include <fstream>
#include <iostream>
#include <string>
#include <cstdint>




typedef struct _wavheader{

	char chunkid_riff[4]; 
	uint32_t chunk_size;
	char format_wave[4];
	char subchunk_1_id_fmt_[4];
	uint32_t subchunk_1_size;
	uint16_t audio_format;
	uint16_t num_channels;
	uint16_t sample_rate;
	uint32_t byte_rate;
	uint16_t block_align;
	uint16_t bits_per_sample;
	char subchunk_2_id_data[4];
	uint32_t subchunk_2_size;
	} WAVEHEADER;

using namespace std;


// www.youtube.com/watch?v=r0QR3HH3xDs --- Aamir Mirza -- Edited by me for .wav headers
int main(void){
	
	unsigned long num_samples;
	ifstream wave_file("test.wav", ios::binary | ios::in);
	if (!wave_file)
	{
		cout << "Fatal Error" << endl;
		EXIT_FAILURE;
	}

	WAVEHEADER wavheaddata;
	
	wave_file.read((char*)&wavheaddata, sizeof(WAVEHEADER));

	//stackoverflow.com/questions/4691608/copying-non-null-terminated-unsigned-char-array-to-stdstring

	string riff_header(wavheaddata.chunkid_riff, wavheaddata.chunkid_riff + sizeof(wavheaddata.chunkid_riff));
	string wave_header(wavheaddata.format_wave, wavheaddata.format_wave + sizeof(wavheaddata.format_wave));
	string fmt_header(wavheaddata.subchunk_1_id_fmt_, wavheaddata.subchunk_1_id_fmt_ + sizeof(wavheaddata.subchunk_1_id_fmt_));
	string data_header(wavheaddata.subchunk_2_id_data, wavheaddata.subchunk_2_id_data + sizeof(wavheaddata.subchunk_2_id_data));
	
	if (riff_header == "RIFF")
	{
		cout << "CHUNK ID: " << riff_header << " THIS IS A RIFF FILE" << endl;
		if (wave_header == "WAVE")
		{
			cout << "FILE FORMAT: " << wave_header << " THIS IS A WAVE FILE" << endl;
			if (fmt_header == "fmt ")
			{
				cout << "FORMAT SUBCHUNK FOUND, PROCESSING FORMAT DATA" << endl;
				if (wavheaddata.audio_format == 1)
				{
					cout << "AUDIO DATA IN PCM, THEREFORE NO COMPRESSION" << endl;
					if (wavheaddata.num_channels == 1)
					{
						cout << "THE FILE CONTAINS MONO AUDIO" << endl;

						if (data_header == "data")
						{
							cout << "DATA BLOCK FOUND" << endl;
							cout << "EVERYTHING SEEMS OK, NOW ATTEMPTING TO WRITE TO OUTPUT FILE" << endl;

							ofstream out_file("out.bin", ios::out | ios::binary);
							if (!out_file)
							{
								cout << "Unable to Create Ouput File" << endl;
								EXIT_FAILURE;
							}

							num_samples = (wavheaddata.subchunk_2_size / wavheaddata.block_align);
							//stackoverflow.com/questions/8329767/writing-into-binary-files
							out_file.write(reinterpret_cast<const char*>(&wavheaddata.sample_rate), sizeof &wavheaddata.sample_rate);
							out_file.write(reinterpret_cast<const char*>(&wavheaddata.bits_per_sample), sizeof &wavheaddata.bits_per_sample/2);
							out_file.write(reinterpret_cast<const char*>(&num_samples), sizeof &num_samples/2);
							//DATA CODE HERE
							out_file.close();
						}
						else
							cout << endl << "ERROR:: CANNOT LOCATE THE DATA SUBCHUNK, INVALID FILE" << endl << endl;
					}
					else
					{
						cout << "THE FILE CONTAINS " << wavheaddata.num_channels << " CHANNELS, ONLY ONE CHANNEL WILL BE EXTRACTED" << endl;
						//extract only one channel code here.....
					}
				}
				else
					cout << endl << "ERROR:: AUDIO DATA IS NOT IN PCM, AND HAS SOME COMPRESSION APPLIED, PLEASE PROVIDE UNCOMPRESSED PCM ONLY" << endl << endl;
			}
			else
				cout << endl << "ERROR:: CANNOT LOCATE THE FORMAT SUBCHUNK, INVALID FILE" << endl << endl;
		}
		else
			cout << endl << "ERROR:: NOT A WAVE FILE, PLEASE ONLY PROVIDE A VALID .WAV FILE" << endl << endl;
	}
	else
		cout << endl << "ERROR:: NOT A RIFF FILE, PLEASE ONLY PROVIDE A VALID .WAV FILE" << endl << endl;

	wave_file.close();
	return 0;
} 



File Output::

44 AC 00 00 08 00 E8 03

I will need to work on the data when I am able to next... stay tuned for new topics!! (no doubt!!)

Cheers,

Owen.
Was This Post Helpful? 0
  • +
  • -

#11 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3589
  • View blog
  • Posts: 11,159
  • Joined: 05-May 12

Re: Outputing hex data to file to mimick original Hex input.

Posted 23 December 2013 - 09:32 AM

Your lines 37 and 76 do not do what you think they are supposed to be doing. They will not exit the program.

Additionally, in a C++ program, you should not be using exit(). The prevents the destructors for classes from running.
Was This Post Helpful? 1
  • +
  • -

#12 otm  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 27
  • Joined: 18-April 10

Re: Outputing hex data to file to mimick original Hex input.

Posted 23 December 2013 - 04:30 PM

Hi,

Thanks for pointing that out... how am I best supposed to exit the program on errors?

Would the Break command work here?

I rarely write C++ (I prefer the embedded systems related code of basic C and assembly) so this would be vital knowledge for the future...

Cheers,

Owen.
Was This Post Helpful? 0
  • +
  • -

#13 jimblumberg  Icon User is online

  • member icon


Reputation: 4098
  • View blog
  • Posts: 12,679
  • Joined: 25-December 09

Re: Outputing hex data to file to mimick original Hex input.

Posted 23 December 2013 - 04:38 PM

You only have one function, main() so a simple return would be best. Return 0 for success and EXIT_FAILURE for failure.


Jim
Was This Post Helpful? 1
  • +
  • -

#14 CTphpnwb  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2999
  • View blog
  • Posts: 10,384
  • Joined: 08-August 08

Re: Outputing hex data to file to mimick original Hex input.

Posted 23 December 2013 - 04:47 PM

View PostSkydiver, on 23 December 2013 - 12:32 PM, said:

Additionally, in a C++ program, you should not be using exit(). The prevents the destructors for classes from running.

I've wondered about this for a long time. Why should we care? Unless there's data that we want to be sure is saved before exiting a program it seems like calling the destructors is just extra work since all of the memory used by the app will be freed by the OS regardless. I always wonder about this when an app takes too long (long enough for me to notice) to quit and I know I didn't intend to save anything. Maybe it's a problem with Windows memory management? Will it not free memory properly when and app terminates?
Was This Post Helpful? 1
  • +
  • -

#15 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3589
  • View blog
  • Posts: 11,159
  • Joined: 05-May 12

Re: Outputing hex data to file to mimick original Hex input.

Posted 23 December 2013 - 08:39 PM

It's not just heap memory resources that a class can hold. It can also hold file handles, file locks, database connections, mutexes, semaphores, share memory, etc. Basically things that are not automatically cleaned up when a process terminates.

Normally the slow shutdown issue you are seeing is because Windows is still trying to send messages to a program whose message pump is not running anymore, or whose window procedure now points to memory that has been deallocated or unloaded. For the dead message pump case, Windows will sit for a while before it detects that a program is not responding (because it is not pumping messages anymore). For the deallocated or unloaded windows procedure, typically an exception is thrown, and Windows will try to walk up the exception stack to see if somebody can handle it, and if nobody can handle it, it looks to see if this crash is common. To see if it is common, it needs to package up the call stack as well as a memory dump and try to send it back to MSFT's Watson crash database.
Was This Post Helpful? 1
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2