Browse Source

add argparse to render script, add makefile.

master
Thomas Buck 1 year ago
parent
commit
31bd021985
  1. 28
      Makefile
  2. 3
      README.md
  3. 73
      render.py

28
Makefile

@ -0,0 +1,28 @@
inputs = $(wildcard *.svg)
outputs = $(inputs:%.svg=output/%_44100.wav)
outputs += $(inputs:%.svg=output/%_48000.wav)
outputs += $(inputs:%.svg=output/%_96000.wav)
outputs += $(inputs:%.svg=output/%_192000.wav)
.PHONY: all
all: output ${outputs}
output:
mkdir output
output/%_44100.wav: %.svg
./render.py -s 44100 -o $(@:%.svg=%_44100.wav) $<
output/%_48000.wav: %.svg
./render.py -s 48000 -o $(@:%.svg=%_48000.wav) $<
output/%_96000.wav: %.svg
./render.py -s 96000 -o $(@:%.svg=%_96000.wav) $<
output/%_192000.wav: %.svg
./render.py -s 192000 -o $(@:%.svg=%_192000.wav) $<
.PHONY: clean
clean:
rm -rf output

3
README.md

@ -5,3 +5,6 @@ Please see [my blog post for more details](https://www.xythobuz.de/osci_music_pl
Quick start instructions can be found in the top comment of the Python script in this repo.
ssh osci-music "sudo systemctl disable --now osci.service" && scp osci-pi.py osci-music:~ && ssh osci-music "sudo systemctl enable --now osci.service"
Also include a simple script to convert single SVG paths to audio.
Run the included makefile to convert the SVG files in this directory.

73
render.py

@ -23,15 +23,10 @@
import sys
import wave
import argparse
from svgpathtools import svg2paths
samplerate = 44100 #192000
volume_percent = 70
path_steps = 10
default_duration = 5.0
default_outfile = "out.wav"
def read_image(filename):
def read_image(filename, path_steps, volume_percent):
paths, attributes = svg2paths(filename)
path = paths[0]
if len(paths) > 1:
@ -72,16 +67,25 @@ def read_image(filename):
p.append(v)
return p
def add_segment(p1, p2, f):
p = interpolate(p1, p2, f)
add_point(p)
for n in range(0, len(points) - 1):
p1 = points[n]
p2 = points[n + 1]
for step in range(0, path_steps):
p = interpolate(p1, p2, step / path_steps)
add_point(p)
add_point(points[len(points) - 1])
add_segment(points[n], points[n + 1], step / path_steps)
#add_point(points[len(points) - 1])
for n in range(len(points) - 2, -1, -1):
for step in range(0, path_steps):
add_segment(points[n + 1], points[n], step / path_steps)
add_point(points[0])
return data
def write_waveform(data, filename):
def write_waveform(data, filename, samplerate):
with wave.open(filename, "w") as f:
f.setnchannels(2)
f.setsampwidth(2)
@ -89,26 +93,31 @@ def write_waveform(data, filename):
f.writeframes(data)
def main():
if len(sys.argv) <= 1:
print("Usage:")
print("\t" + sys.argv[0] + " image.png [out.wav] [seconds]")
sys.exit(1)
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
wave = read_image(sys.argv[1])
parser = argparse.ArgumentParser(
prog=sys.argv[0],
description='Render SVG path to vector XY audio file',
epilog='Made by Thomas Buck <thomas@xythobuz.de>. Licensed as GPLv3.')
parser.add_argument("input", help="Input SVG image file path.")
parser.add_argument("-o", "--output", dest="output", default="out.wav",
help="Output wav sound file path. Defaults to 'out.wav'.")
parser.add_argument("-t", "--time", dest="time", default=5.0, type=float,
help="Length of sound file in seconds. Defaults to 5s.")
parser.add_argument("-s", "--samplerate", dest="samplerate", default=44100, type=int,
help="Samplerate of output file in Hz. Defaults to 44.1kHz.")
parser.add_argument("-v", "--volume", dest="volume", default=100.0, type=float,
help="Volume of output file in percent. Defaults to 100%%.")
parser.add_argument("-i", "--interpolate", dest="interpolate", default=10, type=int,
help="Steps on interpolated paths. Defaults to 10.")
args = parser.parse_args()
print(args)
wave = read_image(args.input, args.interpolate, args.volume)
samplecount = int(len(wave) / 2 / 2) # stereo, int16
drawrate = samplerate / samplecount
drawcount = drawrate * duration
drawrate = args.samplerate / samplecount
drawcount = drawrate * args.time
print("len={} samples={} drawrate={:.2f} count={:.2f}".format(len(wave), samplecount, drawrate, drawcount))
data = bytearray()
@ -116,7 +125,7 @@ def main():
data.extend(wave)
print("len={}".format(len(data)))
write_waveform(bytes(data), outfile)
write_waveform(bytes(data), args.output, args.samplerate)
if __name__ == "__main__":
main()
Loading…
Cancel
Save