Encoding an image to sound

The purpose of this project is to encode an image to a sound that can be viewed with a spectrogram. For some time I have known that musical artists have encoded pictures into their music. Most notable of these is artists is Aphex Twin. Luckily I had a copy of Windolicker and a great visualization program Sonic Visualiser. After looking at the images I decided it would be cool to try and encode my own images. I saw a few programs available, but decided it would be a better challenge to write my own program from scratch using Perl.


A spectrogram is a graph representing the intensity or a frequency with relation to time. Normally the frequencies are along the Y axis, with the time on the X axis. The intensity of the frequency is represented by the brightness of the color. The frequency and color can use either a linear scale or a logarithmic scale. Below is an spectrogram of a few piano chords. The audio file used can be found on Wikipedia here.

Image encoding

The idea I had to encode the image was to simply create a sine wave at a corresponding frequency to represent the Y axis, a corresponding time to represent the X axis and a corresponding amplitude to represent the pixel color intensity.

Creating Sound

The first step to encoding an image was to learn how audio formats work. At first I tried writing a script that plays a frequency to the ‘/dev/dsp’ (Which is the sound card on Linux). When writing straight to /dev/dsp you are limited by a sample rate of 8000hz and a sample size of 8bits. Below simple Perl script that plays a concert A 440hz. To execute run ‘./sin.pl > /dev/dsp’.

use Math::Trig;
use strict;
use POSIX;

my $sample = 8000;
my $frequency = 440;
my $cycles = 6;
my $period = POSIX::floor($sample / $frequency * $cycles);

while (1) {
for(my $i=1;$i<=$period;$i++)
my $x = 128 + sin($cycles * 2 * pi * $i / $period) * 128;
$x = POSIX::floor($x);
my $char = pack(C,$x);
print $char color=”#ff00ff”>”

The DSP defaults do not offer much fidelity I needed at least the fidelity of an audio CD, which is 16bits at 44.1khz. I did some of searching on CPAN to find a library that allowed me write wave files. Most of the audio libraries had a too much overhead for what I wanted to do. Instead I looked up the file format for a ‘.wav’ and coded my own library. This library is limited to only producing a 16bit 44.1khz mono wave.

#Author Evan Salazar
#Generate a .wav file for 16 bit mono PCM
use strict;
package SimpleWave;

sub genWave {

#Get the reference to the data array

my ($audioData) = @_;

#This is the default sample rate
my $samplerate = 44100;
my $bits = 16;
my $samples = $#{$audioData} + 1;

my $channels = 1;

#Do Calculations for data wave headers
my $byterate = $samplerate * $channels * $bits / 8;
my $blockalign = $channels * $bits / 8;
my $filesize = $samples * ($bits/8) * $channels + 36;

#RIFF Chunk;
my $riff = pack(a4Va4,RIFF,$filesize,WAVE);

#Format Chunk
my $format = pack(a4VvvVVvv,
fmt ,

#Data Chunk
my $dataChunk = pack(a4V,data,$blockalign * $samples);

#Read audoData array
my $data;
for(my $i=0;$i<$samples;$i++) {

$data .= pack(v,$audioData->[$i]);

#Return a byte string of the wave
return $riff . $format . $dataChunk. $data;

Reading a Bitmap

Luckily I found a simple bitmap reader on CPAN called Image::BMP. This is a nice lightweight library that dose not depend on any external libraries or compiled code. Using this library I was able to easily load and read the bitmap data.

Encoding the Image

The first pass of my program disregarded the color data and only produced a frequency for the Y axis if the color intensity was less that half the sum of all colors. Below is an example. Note: I converted the WAV to an MP3 to conserve bandwidth, at 320kbps not much data is lost.

Audio File: ohmpie.mp3

I was really shocked to fist see the image! The only tweaking I needed to do was to use a linear scale for the frequency. Also if I selected too high an amplitude for the sin wave, clipping occurred in areas with too much black. For image above I used an amplitude of about 1000 on a scale of 0 to 32768.

The next step was to add amplitude scaling to match the color intensity. For this I summed all the color channels for a given pixel and scaled it to represent the max amplitude ‘(R + G + B) / 768 * max_amplitude’. Below is a picture of me after using the scaling.

Audio File: evan.mp3

By selecting a color scheme that goes from black to white and using a linear scale for the volume I get a very good black and white image. To prevent clipping on very dark images I added an inverse option that will invert the color producing a negative image.

Audo File: evanInv.mp3

You can reverse the color scheme to go from white to black to produce the regular image

Full Program

Below you can view and/or download the full code to this program. Currently performance is not optimized. So don’t write me telling me its slow. I currently have a few idea to speed it up. Also for best results use a small image around 100px tall.

Download: imageEncode-0.7.tar.gz

Using a packet sniffer to track games/applications phoning home, and how to block them via the routing table or the hosts file

The other day I was trying to play an old game I bought some time ago on my LAN. I was just trying to enjoy a little cooperative bot killing fun with my buddy, but for some reason, the game kept telling me my ‘master key’ or something along those lines didn’t check out. Needless to say I wasn’t happy with it… I bought this game… and maybe I wasn’t supposed to play it on two machines at once… but at the very least I certainly didn’t want it phoning home for a simple LAN game, a game mode where no master server or internet should be required.

So I decided to see what my ‘game’ was up to. A quick download of Wireshark (formerly Ethereal) and an even quicker packet sniff and sure enough I could see where my ‘game’ was initiating connections and across what port.

After booting up wireshark, simply click on the “Capture” menu and select “Interfaces…” and from there it will show you a list of available ones to capture from. Select your active connection (the one with an IP thats NOT your localhost (, and click start. You should see something similar to this screenshot as Wireshark attempts to capture all the packets entering and leaving your machine.

If you’ve closed all your other connections (browsers, streaming music, etc.) you should now try to recreate the traffic you wish to sniff. In my case this involves launching the game I want to play and trying to connect to a LAN game, with which I am promptly kicked back for failing to ‘check out’ with the master server correctly. Now exit the game and pull up Wireshark to see what it caught.

In the interest of not angering anyone, I’ve obscured the specific IP and domain name that my machine is connecting to. But for these purposes, it shouldn’t matter. Notice there are numerous outbound and inbound packets originating from the IP 216.27.xx.xxx, and in the right hand column you can [almost] see that an actual domain name has also been found.

This is where the windows ‘hosts’ file comes into action. The hosts file is a pretty simple file to deal with, usually located at c:/windows/system32/drivers/etc/hosts on xp machines (On most linux distributions a similar file is located at /etc/hosts). Here is where you can redirect certain domains to other IPs for a variety of reasons. In our case we want to redirect the server xxxxx.server1.xxxxx.com to the localhost, to prevent the game from phoning home.

In the screenshot above you’ll notice I’ve added a line to my hosts file to redirect the offending domain. Now all outbound connections to xxxxx.server1.xxxxx.com will be redirected to the localhost, preventing any real connection from occurring between the two. But what if there’s no domain name listed? Then the hosts file will be fairly worthless to you, but there are a couple of possible alternatives.

First, try doing an ‘nslookup’ on the IP that looks suspect, and see if you get a domain name to return, in most cases you probably won’t. The next possible solution is to do a google search for the statistics, analytics or authentication server your program is trying to connect to. In many cases google will know the answer already for you. But if both of these methods fail, its time edit the routing table on your machine.

Bring up a [lame] windows command line, if you don’t know how simply click the ‘start’ menu, select ‘run…’ and type in ‘cmd.’ From here you can view and alter the routing table.

Type ‘route print’ at the command line and it should print out the routing table for you to like the screenshot above. If at any point you wish to learn more about route just type in ‘route’ by itself and it will print out detailed help. What we want to do now is create a route for the offensive IP to be sent to the localhost. In some cases this can be done by simply pointing the offending IP to, however in my case I had to point it to the actual local IP address of my machine ( since there was already a route in place to direct traffic heading to to the localhost at

C:\Documents and Settings\Administrator>route print

IPv4 Route Table
Interface List
0×1 ……………………… MS TCP Loopback interface
0×2 …00 01 29 d2 2c 2b …… NVIDIA nForce Networking Controller – Packet Sch
eduler Miniport
0×3 …00 01 29 d2 2c 2a …… Marvell Yukon 88E8001/8003/8010 PCI Gigabit Ethe
rnet Controller – Packet Scheduler Miniport

Active Routes:
Network Destination Netmask Gateway Interface Metric 20 1 20 20 20 20 1 2 1
Default Gateway:
Persistent Routes:

C:\Documents and Settings\Administrator>

Use the ‘add’ parameter to add a new route to your table like this (change destination and source IP accordingly)

C:\Documents and Settings\Administrator>route add 216.27.xx.xxx
C:\Documents and Settings\Administrator>

You can also use the route command to change the route for entire subnets, but for my purposes its unnecessary, all I needed to do is redirect a specific IP.

Now launch a new session of Wireshark and begin capturing. Open up the offending game or application and test that it works (no longer phones home for any reason). In my case I can see that a bunch of traffic formerly headed to that rouge IP is now heading to, which then heads to, and effectively gets nowhere.

Congratulations! You’ve now stopped your game or application from ‘checking home.’ It should be noted that on many high end firewalls/routers, its possible to do similar things from within the router itself, but I’ve found that with most consumer level firewalls this still isn’t an option. For instance, on my cheap Belkin I can restrict specific port ranges by internal IP, which would actually work fine for this particular problem, but is a less than perfect solution since it would block ALL traffic outbound on that specific port (a less than optimal solution if the application is using a standard port).

In this day and age you can really never be too careful about privacy, more and more seemingly everyday games and applications religiously phone home your personal information about everything from your private browsing habits to your choice of music. In my case, I’d like to keep them from finding that type of information out.

This entry was posted in Freedom. Bookmark the permalink.

2 Responses to Using a packet sniffer to track games/applications phoning home, and how to block them via the routing table or the hosts file

  1. Tanman YoungerMan says:

    Thanks for the great write up, I wanted to add a few notes that might help out your readers who are using other systems.

    On Vista and Win 7, in order to edit your c:/windows/system32/drivers/etc/hosts you need to right click the file and deselect the “read only” check box. If you are using UAC you will be prompted to enter an administrator password. After this you can edit the file and save your changes, otherwise you will be unable to save you changes to the c:/windows/system32/drivers/etc/hosts file. For BSD and variants thereof such as Mac OS 10.x a simple “sudo vi /etc/hosts” will do the trick. If you don’t want to leave the comfort of your terminal a simple “sudo tcpdump -i en1″ (replacing en1 for whatever you Ethernet device happens to be). en1 is the default wireless interface on a mac, en0 is the default wired port, for other *nix variants you might have eth(x) or wlan(x), ra(x), vr(x), and so on and so forth.