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. 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" 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 sys
import wave import wave
import argparse
from svgpathtools import svg2paths 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) paths, attributes = svg2paths(filename)
path = paths[0] path = paths[0]
if len(paths) > 1: if len(paths) > 1:
@ -72,16 +67,25 @@ def read_image(filename):
p.append(v) p.append(v)
return p return p
def add_segment(p1, p2, f):
p = interpolate(p1, p2, f)
add_point(p)
for n in range(0, len(points) - 1): for n in range(0, len(points) - 1):
p1 = points[n]
p2 = points[n + 1]
for step in range(0, path_steps): 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 return data
def write_waveform(data, filename):
def write_waveform(data, filename, samplerate):
with wave.open(filename, "w") as f: with wave.open(filename, "w") as f:
f.setnchannels(2) f.setnchannels(2)
f.setsampwidth(2) f.setsampwidth(2)
@ -89,26 +93,31 @@ def write_waveform(data, filename):
f.writeframes(data) f.writeframes(data)
def main(): 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 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)) print("len={} samples={} drawrate={:.2f} count={:.2f}".format(len(wave), samplecount, drawrate, drawcount))
data = bytearray() data = bytearray()
@ -116,7 +125,7 @@ def main():
data.extend(wave) data.extend(wave)
print("len={}".format(len(data))) print("len={}".format(len(data)))
write_waveform(bytes(data), outfile)
write_waveform(bytes(data), args.output, args.samplerate)
if __name__ == "__main__": if __name__ == "__main__":
main() main()
Loading…
Cancel
Save