Introduction: How to Read .aiff Files Using C
The purpose of these instructions is to show you how to read a .aiff sound file. Like any other binary files, .aiff file is also consists of different memory chunks. This tutorial will read through the common chunk of the file. After this tutorial you should be able to read the other chunks using the same logic.
Reading an .aiff file is extremely useful, mostly because it is one of the very common types of the sound files. Moreover, reading .aiff file is very similar to reading any type of binary file. In other words, as long as you know the format (the format of .aiff files can be seen at the main picture above), you can read any binary files using the same logic that is used in .aiff files.
To understand these instructions you must have at least basic understanding of C code and compiling C code. You need to know how to use arrays and strings in C as well. The most importantly, you need to be familiar with the binary-decimal conversions and the bit-wise operations in C. However, unlike most of the binary file tutorials, this tutorial does not require for you to have any knowledge about pointers. These instructions should not take more than three hours to finish but the proficient C programmers can finish this in thirty minutes.
Step 1: Get the Path to the File
1) Ask the user to enter the path to the file (see the top picture above).
2) Scan the path to the file (see the bottom picture above).
Step 2: Open the File
- Use "fopen" to open the file in "r" mode (see the top image above).
+ Caution: Use "rb" mode if you are working with windows operating system.
Note: "fopen" will return a nonzero value if the file is opened successfully. Therefore, you can use an if statement to check whether the file is actually opened or not (see the bottom image above).
Step 3: Read the Characters 'F', 'O', 'R', 'M'
- Use "fscanf: function to read the first four characters.
Note: This function works exactly the same way as "scanf" except you need to specify the target first (see the picture above).
Note: You can also use the "fread" function as well, to make this step easier. However, the usage of this function requires some knowledge of pointers and not used in this entire tutorial.
- Read one character at a time.
+ Caution: In binary files, there are no spaces therefore, trying to read a string, an integer or a float will not work and you can easily get lost in the file (assuming that you are using "fscanf" function).
As you can see from the very first picture of this tutorial, the .aiff file starts with word "FORM", which is exactly four bytes. Therefore, the first four bytes that you will read always needs to be the word "FORM".
Note: You can read all the character in the file using the logic in this step.
Step 4: Read the Number of Bytes Left in the File
According to the format of the .aiff files the next four bytes needs to be the remaining number of bytes in the entire file (as seen from the very first picture of this tutorial). The problem is that you can only read single byte at a time. Therefore, you have to mix all the bytes in the correct order.
1) Read the next four bytes in a character array.
2) Merge the four bytes to an unsigned type data.
Note: To merge the four bytes you need to use bit-wise operations. The .aiff file uses big-endian format (Most significant bit goes to the leftmost side)
- Set your unsigned variable to zero.
- Shift the first character you read 24 (3*8 (it is the the fourth byte and 1 byte= 8 bits)) to the left.
- Bit-vise or the value you gain with your unsigned variable.
- Do the same steps for the rest of the bytes, except decrease the byte number (e.g., 16 (2*8) for the second byte) (see picture above).
Note: You can read all the integer type data using the logic in this step.
Step 5: Read the ID ('A', 'I', 'F', 'F') of the File
- Read the next four bytes.
Note: Refer to the step 3.
Note: After you read these bytes you can check whether the file format is actually .aiff or not (see picture above).
Step 6: Skip Until You Found the Correct Chunk
At this point, the file consists of different chunks. Each of them is starting with a four byte identification and then four byte number, which is the remaining number of the bytes in the chunk (as seen on the format picture at the beginning of the tutorial). You have to skip until you come across the chunk that you wanted (in this case, it is the common chunk).
1) Read the identification of the chunk (see picture above).
- Refer to the step 3.
2) Read the four byte size f the chunk (see picture above).
- Refer to the step 4 (you can use integer type for this).
Note: For alignment purposes each chunk needs to consist of even number of bytes. If size is specified as an odd number, this means there is a meaningless zero byte at the end so just add one to your size.
3) Check if you are at the correct chunk or not (see picture above).
- Use a simple if statement.
4) Use a loop to skip through the rest of the chunk using your size variable (see picture above).
Step 7: Read the Channels, Samples and Bit Depth
The format picture (the very first picture of this tutorial), shows what else is in this chunk and how much bytes each of them are. Using this format you can read the numbers until sample rate (which is the next step).
1) Read the next two bytes, which is number of channels.
- Refer to the step 4.
2) Read the next four bytes, which is number of frames (samples).
- Refer to the step 4.
3) Read the next two bytes, which is the bit depth (bits used per samples).
- Refer to the step 4.
Step 8: Read the Sample Rate
Unlike other variables, sample rate is given in Extended 80-bit floating-point format (For details about this format visit http://en.wikipedia.org/wiki/Extended_precision). Therefore, you need to convert it to a float type.
1) Read next 10 bytes into a character array.
2) Read the sign bit.
- The eighth bit of your first character (1:negative, 0:positive).
3) Read the exponent bits.
- The rest of your first character and your second character.
Note: You can simply clean the sign bit and merge those two characters into an integer (refer to step 4).
4) Subtract the biased (for this format it is: 16383) from exponent.
5) Covert fraction bits to the decimal.
- These are the rest of the characters of your array.
a) Set your float variable to zero.
b) Multiply each bit with 2^(exponent).
c) Add the result to your float variable.
d) Subtract one from exponent after each bit until all the bits are done.
6) Adjust the sign using your sign bit.
Note: You can simply use an if statement.
Step 9: Calculate the Duration
1) Divide number of samples to the sample rate and store it to the seconds.
2) Divide seconds to sixty and store it to minutes.
3) Divide minutes to sixty and store it to hours.
Step 10: Close the File
- Use "fclose" to close the file.
Caution: Do not forget to close the file. If you do forget it, a memory leak may occur.