For this project we want to take an ascii text message and hide it into the a sound file. We will also want to be able to extract the message. For this we will need to write two program: Proj4a.java and Proj4b.java. Where Proj4a.java will place the message into a sound file and Proj4b.java will extract the message from the sound file.
Recall that a text message is a collection (i.e. encoding) of multiple ascii characters and each each ascii character can be represented as a numeric value and (finally) each numeric value can be represented in a series of one's and zero's (a binary number). Thus the text message of "Hi!" is made up of the ascii characters:
Initially we will want all of the samples in the sound object to be "evened" out. This will result in every sample having an even value. The way this is to be done is if the sample value is even, leave it unchanged. If the sample is odd, subtract one from the value to make it even. It is important that we subtract one because of the range of values the sound samples could have (the largest possible value is odd, while the smallest possible value is even).
Note that changes of a sample value by a value of one will have no impact to the sound quality on the human ear. Actually it is changes of values around 10 that begin to be detected by the human ear.
Once a sound file has been "evened", we will encode one binary digit from the text message into each sound sample. Since each ASCII character is considered to have 8 binary digits, we will need 8 sound values for each ASCII character. Thus to encode a text message of 100 characters, we would need 800 sound values. At this rate, a one second sound sample can ecnode 2762 characters.
To encode a binary digit into a sound sample, we simply add the binary digit (a value of one or zero) to the "evened" value of the sound sample. The result sound sample will be even when the binary digit was zero and odd when the binary digit was one.
The following table is to help us with this. It shows the first 24 samples from the file gettysburg10.wav. Note the sample values are relatively small numbers as this is only the first 1000th of the sound and nothing has been stated yet.
Sample
NumberOriginal
Sample
Value"Evened"
Sample
ValueASCII
CharactersDecimal
ValuesBinary
DigitsBinary
Digit
PositionFinal
Sample
Values0 59 58 H 72 0 0 58 1 39 38 0 1 38 2 16 16 0 2 16 3 10 10 1 3 11 4 -1 -2 0 4 -2 5 7 6 0 5 6 6 -12 -12 1 6 -11 7 -7 -8 0 7 -8 8 10 10 i 105 1 0 11 9 25 24 0 1 24 10 61 60 0 2 60 11 57 56 1 3 57 12 46 46 0 4 46 13 41 40 1 5 41 14 43 42 1 6 43 15 73 72 0 7 72 16 76 76 ! 33 1 0 77 17 60 60 0 1 60 18 46 46 0 2 46 19 39 38 0 3 38 20 31 30 0 4 30 21 26 26 1 5 27 22 35 34 0 6 34 23 37 36 0 7 36
To determine which binary digit of which character is associated with which sample from the sound object, use the following where sampleIndex is the index of the SoundSample from the sound object:
One we know the Character Number, we can get the character from the string by using the charAt() method of the String class. This method will give use the character at that position. To get that ASCII Character code number for the character simply store the character into a variable of type integer.
To get the bit value (zero or one) for a particular Binary Digit Position from the ASCII character code number, we should write a method with the following method description:
public static int getBinaryDigit (int asciiCode, int BinaryDigitPosition) { // This method should divide the asciiCode by 2 as many times // as specified by the BinaryDigitPosition, // Then use the modulus operator % to find the remainder // of a division by 2. // This remainder value is the bit value that we want returned // by the method. }
Once the bit values are known we need to build them together into characters and then join the characters into Strings. To build the 8 bits into a ascii character code number, we start with a variable for the ascii code that initially has a value of zero. For every BinaryDigitPosition with a value of one, we take another variable which is initial set to one and multiply it by 2 the number of times as the BinaryDigitPosition. We then take the result and add it to the variable for the ascii code. We can actually ignore any bit values of zero. Once we have done this for all the 8 bit values, we can store this integer value into a character variable. Once the character value is know, we can concatenate the character to the end of a string.
For example, assume we needed to get the character i. The 8 bits and the coorsponding BinaryDigit positions would be:
ASCII
CharactersDecimal
ValuesBinary
DigitsBinary
Digit
Positioni 105 1 0 0 1 0 2 1 3 0 4 1 5 1 6 0 7 First, we intialize the asciiCode to zero.
Then, we look at BinaryDigitPosition 0 and see we have a value of 1.
We then multiple a value of 1 by two zero times for a result of 1.
We add 1 to the asciiCode value for a new value of 1.Then, we look at BinaryDigitPosition 1 and see we have a value of 0 so we ignore it (i.e. we don't change the value in asciiCode).
Then, we look at BinaryDigitPosition 2 and see we have a value of 0 so we ignore it (i.e. we don't change the value in asciiCode).
Then, we look at BinaryDigitPosition 3 and see we have a value of 1.
We then multiple a value of 1 by two three times for a result of 8.
We add 8 to the asciiCode value for a new value of 9.Then, we look at BinaryDigitPosition 4 and see we have a value of 0 so we ignore it (i.e. we don't change the value in asciiCode).
Then, we look at BinaryDigitPosition 5 and see we have a value of 1.
We then multiple a value of 1 by two five times for a result of 32.
We add 32 to the asciiCode value for a new value of 41.Then, we look at BinaryDigitPosition 6 and see we have a value of 1.
We then multiple a value of 1 by two three times for a result of 64.
We add 64 to the asciiCode value for a new value of 105.Then, we look at BinaryDigitPosition 7 and see we have a value of 0 so we ignore it (i.e. we don't change the value in asciiCode).
The final value of asciiCode is 105, which is the proper ASCII code value for the character i.
We will assume that the number of SoundSamples greatly out numbers of number bits that need to be hidden/extracted. Thus there will be a large number of SoundSamples that have only even values in them. While doing the extraction if we encounter a character that was created from 8 sound samples with even values, we would have extracted ASCII Character 0 or the NULL character. When this occurs, we will stop the extraction process and display the string that has been created.
For the extracting program, Proj4b.java, you are to prompt the user for a sound file to use. You are to display the extracted string using one of the methods from the SimpleOutput class.
For this project, I received help from the following member of CS 101.This statement should list each helping student's name in a comment in the "header comment" of your Java file that includes the main() method.
Department of Computer Science
University of Illinois at Chicago