A simple image to sound conversion python script.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

123 lines
4.3 KiB

#!/usr/bin/env python
from PIL import Image, ImageOps
import wave, math, array, argparse, sys, timeit
def parser():
parser = argparse.ArgumentParser()
# Specified command options and its helps message
parser.add_argument ("INPUT_FILE", help="Name of the image to be converted.")
parser.add_argument ("-r", "--rotate", help="Rotate image 90 degrees for more sexy spectograph looks and sound", action='store_true')
parser.add_argument ("-i", "--invert", help="Invert image colors.", action='store_true')
parser.add_argument ("-o", "--output", help="Name of the output wav file. Default value: out.wav).")
parser.add_argument ("-b", "--bottom", help="Bottom frequency range. Default value: 200.", type=int)
parser.add_argument ("-t", "--top", help="Top frequency range. Default value: 20000.", type=int)
parser.add_argument ("-p", "--pixels", help="Pixels per second. Default value: 30.", type=int)
parser.add_argument ("-s", "--sampling", help="Sample rate. Default value: 44100.", type=int)
# Create "arguments" object based on user input
arguments = parser.parse_args()
# Default values
min_freq = 200
max_freq = 20000
sample_rate = 44100
pixels = 30
output = "out.wav"
rotate = False
invert = False
# Check arguments values
if arguments.output:
output = arguments.output
if arguments.bottom:
min_freq = arguments.bottom
if arguments.top:
max_freq = arguments.top
if arguments.pixels:
pixels = arguments.pixels
if arguments.sampling:
sample_rate = arguments.sampling
if arguments.rotate:
rotate = True
if arguments.invert:
invert = True
print ("------------------------------------ Simple Image To Sound Script ------------------------------------\n")
print ('Input file: %s.' % arguments.INPUT_FILE)
print ('Frequency range: %d - %d.' % (min_freq, max_freq))
print ('Pixels per second: %d.' % pixels)
print ('Sampling rate: %d.' % sample_rate)
print ('Rotate Image: %s.' % ('Yes' if rotate else 'No'))
return (arguments.INPUT_FILE, output, min_freq, max_freq, pixels, sample_rate, rotate, invert)
def convert (INPUT_FILE, output, min_freq, max_freq, pixels, sample_rate, rotate, invert):
image = Image.open (INPUT_FILE).convert ('L')
# rotate image if requested
if rotate:
image = image.rotate (90)
# invert image if requested
if invert:
image = ImageOps.invert (image)
output = wave.open (output, 'w')
output.setparams ((1, 2, sample_rate, 0, 'NONE', 'not compressed'))
freq_range = max_freq - min_freq
interval = freq_range / image.size[1]
samples = sample_rate // pixels
data = array.array ('h')
# Converting process start
time_start = timeit.default_timer()
for x in range (image.size[0]):
row = []
for y in range (image.size[1]):
yinv = image.size[1] - y - 1
amplitude = image.getpixel ((x,y))
if (amplitude > 0):
row.append (gen_wave (yinv * interval + min_freq, amplitude, samples, sample_rate))
for i in range(samples):
for j in row:
try:
data[i + x * samples] += j[i]
except (IndexError):
data.insert (i + x * samples, j[i])
except (OverflowError):
if j[i] > 0:
data[i + x * samples] = 32767
else:
data[i + x * samples] = -32768
sys.stdout.write ("Conversion progress: %d%% \r" % (float(x) / image.size[0] * 100))
sys.stdout.flush()
output.writeframes (data.tobytes())
output.close()
# Converting process end
time_end = timeit.default_timer()
print ("Conversion progress: 100%")
print ("Success. Completed in %d seconds." % int(time_end - time_start))
def gen_wave (frequency, amplitude, samples, sample_rate):
cycles = samples * frequency / sample_rate
wave = []
for i in range(samples):
x = math.sin (float (cycles) * 2 * math.pi * i / float (samples)) * float (amplitude)
wave.append (int (math.floor (x)))
return wave
if __name__ == '__main__':
input_choice = parser()
convert (*input_choice)