Browse Source

another attempt, using svg path for rendering to audio

master
Thomas Buck 1 year ago
parent
commit
f98f6890ad
  1. 83
      render.py
  2. BIN
      toolbox.png
  3. 48
      toolbox.svg

83
render.py

@ -20,49 +20,45 @@
import sys
import wave
import pyaudio
from PIL import Image
from svgpathtools import svg2paths
samplerate = 44100 #192000
default_duration = 5.0
def read_image(image):
print("image: width={} height={} total={}".format(image.width, image.height, image.width * image.height))
# resize coordinates for conversion to amplitude values
max_len = max(image.width, image.height)
fact = 32767 / max_len
sw, sh = int(image.width * fact), int(image.height * fact)
print("amplitude: width={} height={}".format(sw, sh))
default_outfile = "out.wav"
def read_image(filename):
paths, attributes = svg2paths(filename)
path = paths[0]
if len(paths) > 1:
print("WARNING: multiple paths in file. will just draw first one.")
print("paths={} segments={}".format(len(paths), len(path)))
points = [[path[0].start.real, path[0].start.imag]]
p_min = [points[0][0], points[0][1]]
p_max = [points[0][0], points[0][1]]
for segment in path:
p = [segment.end.real, segment.end.imag]
for i in range(0, 2):
if p[i] < p_min[i]:
p_min[i] = p[i]
if p[i] > p_max[i]:
p_max[i] = p[i]
points.append(p)
print("min={} max={}".format(p_min, p_max))
data = bytearray()
for x in range(0, image.width):
for y in range(0, image.height):
if image.getpixel((x, y))[3] > 127:
xc, yc = int((x - (image.width / 2)) * fact), int((y - (image.height / 2)) * fact)
data.extend(yc.to_bytes(2, byteorder="little", signed=True))
data.extend(xc.to_bytes(2, byteorder="little", signed=True))
for n in range(0, len(points)):
for i in range(0, 2):
v = points[n][i]
v -= p_min[i]
v /= p_max[i] - p_min[i]
c = int((v * 2 - 1) * (32767 / 100 * 70))
data.extend(c.to_bytes(2, byteorder="little", signed=True))
return data
def play_waveform(data):
pa = pyaudio.PyAudio()
# int16
stream = pa.open(format=pa.get_format_from_width(2),
channels=2,
rate=samplerate,
output=True)
stream.write(data, int(len(data) / 4), True)
stream.stop_stream()
stream.close()
pa.terminate()
def write_waveform(data):
with wave.open("out.wav", "w") as f:
def write_waveform(data, filename):
with wave.open(filename, "w") as f:
f.setnchannels(2)
f.setsampwidth(2)
f.setframerate(samplerate)
@ -71,16 +67,20 @@ def write_waveform(data):
def main():
if len(sys.argv) <= 1:
print("Usage:")
print("\t" + sys.argv[0] + " image.png [seconds]")
print("\t" + sys.argv[0] + " image.png [out.wav] [seconds]")
sys.exit(1)
if len(sys.argv) >= 3:
if len(sys.argv) == 3:
duration = float(sys.argv[2])
outfile = default_outfile
if len(sys.argv) >= 4:
duration = float(sys.argv[2])
outfile = sys.argv[3]
else:
duration = default_duration
outfile = default_outfile
with Image.open(sys.argv[1]) as image:
wave = read_image(image)
wave = read_image(sys.argv[1])
samplecount = int(len(wave) / 2 / 2) # stereo, int16
drawrate = samplerate / samplecount
@ -92,8 +92,7 @@ def main():
data.extend(wave)
print("len={}".format(len(data)))
#play_waveform(bytes(data))
write_waveform(bytes(data))
write_waveform(bytes(data), outfile)
if __name__ == "__main__":
main()

BIN
toolbox.png

Before

Width: 125  |  Height: 140  |  Size: 8.3 KiB

48
toolbox.svg

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="18.108976mm"
height="21.025101mm"
viewBox="0 0 18.108976 21.025101"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
sodipodi:docname="toolbox.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="9.7401438"
inkscape:cx="34.291075"
inkscape:cy="39.732473"
inkscape:window-width="1920"
inkscape:window-height="1020"
inkscape:window-x="0"
inkscape:window-y="420"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-45.755199,-45.487921)">
<path
inkscape:connector-curvature="0"
id="path32"
style="fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.0352778;stroke-opacity:1"
d="m 54.809672,66.488838 -0.0032,-0.0019 -0.0033,0.0019 -0.0032,-0.0057 -9.011829,-5.198633 h -0.0153 l 0.0029,-10.567212 9.035378,-5.20901 9.028924,5.208587 v 4.160979 h -0.01739 l 0.01739,0.03006 -1.862843,1.074597 1.862843,1.074702 -5.64e-4,9.88e-4 5.64e-4,2.82e-4 v 4.202042 h -0.0088 l 0.0088,0.01517 -9.027266,5.207453 -0.0032,0.0057 m 0.897926,-11.088264 v 0 l 0.01475,8.37463 6.246777,-3.580133 v -2.057153 l -1.864043,-1.075267 -1.899073,1.095516 V 55.99825 l 3.763116,-2.170818 v -2.029848 l -7.160824,-4.130957 -7.164416,4.133003 v 8.395441 l 6.19276,3.569109 v -7.281566 l -1.492427,0.863212 -1.871098,-1.079429 5.594315,-3.236454 1.871909,1.079994 -2.231742,1.290637" />
</g>
</svg>
Loading…
Cancel
Save