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.

122 lines
4.3 KiB

  1. #!/usr/bin/env python
  2. from PIL import Image, ImageOps
  3. import wave, math, array, argparse, sys, timeit
  4. def parser():
  5. parser = argparse.ArgumentParser()
  6. # Specified command options and its helps message
  7. parser.add_argument ("INPUT_FILE", help="Name of the image to be converted.")
  8. parser.add_argument ("-r", "--rotate", help="Rotate image 90 degrees for more sexy spectograph looks and sound", action='store_true')
  9. parser.add_argument ("-i", "--invert", help="Invert image colors.", action='store_true')
  10. parser.add_argument ("-o", "--output", help="Name of the output wav file. Default value: out.wav).")
  11. parser.add_argument ("-b", "--bottom", help="Bottom frequency range. Default value: 200.", type=int)
  12. parser.add_argument ("-t", "--top", help="Top frequency range. Default value: 20000.", type=int)
  13. parser.add_argument ("-p", "--pixels", help="Pixels per second. Default value: 30.", type=int)
  14. parser.add_argument ("-s", "--sampling", help="Sample rate. Default value: 44100.", type=int)
  15. # Create "arguments" object based on user input
  16. arguments = parser.parse_args()
  17. # Default values
  18. min_freq = 200
  19. max_freq = 20000
  20. sample_rate = 44100
  21. pixels = 30
  22. output = "out.wav"
  23. rotate = False
  24. invert = False
  25. # Check arguments values
  26. if arguments.output:
  27. output = arguments.output
  28. if arguments.bottom:
  29. min_freq = arguments.bottom
  30. if arguments.top:
  31. max_freq = arguments.top
  32. if arguments.pixels:
  33. pixels = arguments.pixels
  34. if arguments.sampling:
  35. sample_rate = arguments.sampling
  36. if arguments.rotate:
  37. rotate = True
  38. if arguments.invert:
  39. invert = True
  40. print ("------------------------------------ Simple Image To Sound Script ------------------------------------\n")
  41. print ('Input file: %s.' % arguments.INPUT_FILE)
  42. print ('Frequency range: %d - %d.' % (min_freq, max_freq))
  43. print ('Pixels per second: %d.' % pixels)
  44. print ('Sampling rate: %d.' % sample_rate)
  45. print ('Rotate Image: %s.' % ('Yes' if rotate else 'No'))
  46. return (arguments.INPUT_FILE, output, min_freq, max_freq, pixels, sample_rate, rotate, invert)
  47. def convert (INPUT_FILE, output, min_freq, max_freq, pixels, sample_rate, rotate, invert):
  48. image = Image.open (INPUT_FILE).convert ('L')
  49. # rotate image if requested
  50. if rotate:
  51. image = image.rotate (90)
  52. # invert image if requested
  53. if invert:
  54. image = ImageOps.invert (image)
  55. output = wave.open (output, 'w')
  56. output.setparams ((1, 2, sample_rate, 0, 'NONE', 'not compressed'))
  57. freq_range = max_freq - min_freq
  58. interval = freq_range / image.size[1]
  59. samples = sample_rate // pixels
  60. data = array.array ('h')
  61. # Converting process start
  62. time_start = timeit.default_timer()
  63. for x in range (image.size[0]):
  64. row = []
  65. for y in range (image.size[1]):
  66. yinv = image.size[1] - y - 1
  67. amplitude = image.getpixel ((x,y))
  68. if (amplitude > 0):
  69. row.append (gen_wave (yinv * interval + min_freq, amplitude, samples, sample_rate))
  70. for i in range(samples):
  71. for j in row:
  72. try:
  73. data[i + x * samples] += j[i]
  74. except (IndexError):
  75. data.insert (i + x * samples, j[i])
  76. except (OverflowError):
  77. if j[i] > 0:
  78. data[i + x * samples] = 32767
  79. else:
  80. data[i + x * samples] = -32768
  81. sys.stdout.write ("Conversion progress: %d%% \r" % (float(x) / image.size[0] * 100))
  82. sys.stdout.flush()
  83. output.writeframes (data.tobytes())
  84. output.close()
  85. # Converting process end
  86. time_end = timeit.default_timer()
  87. print ("Conversion progress: 100%")
  88. print ("Success. Completed in %d seconds." % int(time_end - time_start))
  89. def gen_wave (frequency, amplitude, samples, sample_rate):
  90. cycles = samples * frequency / sample_rate
  91. wave = []
  92. for i in range(samples):
  93. x = math.sin (float (cycles) * 2 * math.pi * i / float (samples)) * float (amplitude)
  94. wave.append (int (math.floor (x)))
  95. return wave
  96. if __name__ == '__main__':
  97. input_choice = parser()
  98. convert (*input_choice)