Difference between revisions of "ImageEncode-0.7"
From SoundDB
(Created page with "<pre> #!/usr/bin/perl #Author: Evan Salazar #------------------------------------------ # #Convert bitmap image into audo file that #can be seen in a spectrogram # #-------------...") |
|||
| Line 1: | Line 1: | ||
| + | http://www.ohmpie.com/imageencode/ | ||
<pre> | <pre> | ||
#!/usr/bin/perl | #!/usr/bin/perl | ||
Latest revision as of 11:01, 8 February 2011
http://www.ohmpie.com/imageencode/
#!/usr/bin/perl
#Author: Evan Salazar
#------------------------------------------
#
#Convert bitmap image into audo file that
#can be seen in a spectrogram
#
#------------------------------------------
use SimpleWave;
use POSIX;
use Math::Trig;
use Image::BMP;
use Getopt::Std;
use strict;
################
#Constants used
################
#Version
my $version = 0.7;
#low frequency
my $lowfreq = 200;
#high frequency:
my $highfreq = 20000;
#Sample rate for CD quality
#(The only frequency supported as of now)
my $samplerate = 44100;
#Parse commadn line arguments
my ($input,$output,$pixelsecond,$highamp,$inverse) = parseArgs();
print "Input: $input \nOutput: $output \n";
print "Pixel per second: $pixelsecond \nMax amplitude per sample: $highamp \n";
print "Image color inverted\n" if ($inverse);
#Open BMP
my $img = new Image::BMP(file=> $input);
#Create file to write to
open(WAVEFILE, ">$output");
#Get width and height
my $width = $img->{Width};
my $height = $img->{Height};
print "Image Width: $width Height: $height \n";
#scale frequency per height;
my $freqrange = $highfreq-$lowfreq;
my $interval = $freqrange / $height;
print "Frequency Interval: $interval\n";
#Calculate samples per width pixel;
my $samplespixel = POSIX::floor($samplerate / $pixelsecond);
print "Samples per Pixel: $samplespixel \n";
#This is the main algorithm
my @audioOut;
for (my $x=0;$x<$width;$x++) {
#Calculate rows;
my @audiorow;
my $pos=0;
for (my $y=0;$y<$height;$y++) {
my $yinv = $height - $y - 1;
#Get the amplitude
my $amp = color($img->xy_rgb($x,$y));
if($amp > 0) {
#Generate a sine wave
@audiorow[$pos++] = genSine( $yinv * $interval + $lowfreq ,$amp,$samplespixel,$samplerate);
}
}
#Add all the samples for the column
for(my $i=0;$i<$samplespixel;$i++) {
for(my $j=0;$j<@audiorow;$j++) {
@audioOut[$i + $x * $samplespixel] += $audiorow[$j]->[$i];
}
}
#My attempt to print the progress
#my $done = POSIX::floor($x / ($width - 1) * 100);
#print "$done " if (($done % 10) == 0);
}
print "\nGenerating wave file \n";
#Write samples to wave file
print WAVEFILE SimpleWave::genWave(\@audioOut);
#-----------------------------------------
#
#Generate a sine wave for the given
#frequency and amplitude
#
#(This functions could be faster by using
#a lookup table instead of calculating the
#wave every time)
#
#-----------------------------------------
sub genSine {
my ($frequency,$amplitude,$samples,$samplerate) = @_;
my $cycles = $samples * $frequency / $samplerate;
my @audioArray;
for(my $i=0;$i<$samples;$i++)
{
my $x = sin($cycles * 2 * pi * $i / $samples) * $amplitude;
$audioArray[$i] = POSIX::floor($x);
}
return \@audioArray;
}
#-----------------------------------------
#
#Convert the RGB value to a amplitude
#
#-----------------------------------------
sub color {
my ($r,$g,$b) = @_;
my $total = $r + $g + $b;
#Invert the color if -I is set
$total = 765 - $total if($inverse);
my $amp = $total / 765 * $highamp;
#Ignore all intensitys under 50
if($amp > 50) {
return $amp;
}
return 0;
}
#-----------------------------------------
#
#Read arguments from the command line;
#
#-----------------------------------------
sub parseArgs {
#Default arguments
my $pixelsecond = 15;
my $highamp = 300;
my $inverse = 0;
#Set options for reading
my %args = ();
getopts("i:o:p:a:hI",\%args);
help() if($args{h});
help("Need input filename") if(!$args{i});
help("Need output filename") if(!$args{o});
$pixelsecond = $args{p} if($args{p});
$highamp = $args{a} if($args{a});
$inverse = 1 if($args{I});
return ($args{i},$args{o},$pixelsecond,$highamp,$inverse);
}
#-----------------------------------------
#
#Display help message for program
#
#-----------------------------------------
sub help {
my ($message) = @_;
print <<EOF;
Image Encode Ver $version by Evan Salazar
Encode an bitmat to a wave that can be viewed
with a spectrogram
-----------------------------------------------------------------
Usage: imageEncode -i input.bmp -o output.wav
-i [File] Input bitmap (Best use small BMP arround 100x150)
-o [File] Output wave (44.1khz 16bit mono)
-p [int] Pixels per Second (default: 10)
-a [int] Max amplitude per sample (default: 200) Max: 32000
-I Invert image color (Best for dark images)
-h Display this help message
-------------------------------------------------------------------
EOF
print "Error: $message \n" if($message ne '');
exit(1);
}
SimpleWave.pm
#!/usr/bin/perl
#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 ',
16,1,
$channels,
$samplerate,
$byterate,
$blockalign,
$bits);
#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;
}
1;