From eb84c93b7ba5cd31e2526581f48250532f4f75b7 Mon Sep 17 00:00:00 2001 From: homeburger Date: Sat, 26 Sep 2026 19:04:32 -0500 Subject: [PATCH] add wavetables --- .gitignore | 4 +- config/wavetables/saw.wt | Bin 0 -> 8192 bytes config/wavetables/shark_fin.wt | Bin 0 -> 8192 bytes config/wavetables/sigmoid.wt | Bin 0 -> 8192 bytes config/wavetables/sine.wt | Bin 0 -> 8192 bytes config/wavetables/square.wt | Bin 0 -> 8192 bytes config/wavetables/triangle.wt | Bin 0 -> 8192 bytes scripts/wavetables/example_wavetable.py | 52 ++++++++++++++++++ scripts/wavetables/generate_wavetable.py | 67 +++++++++++++++++++++++ 9 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 config/wavetables/saw.wt create mode 100644 config/wavetables/shark_fin.wt create mode 100644 config/wavetables/sigmoid.wt create mode 100644 config/wavetables/sine.wt create mode 100644 config/wavetables/square.wt create mode 100644 config/wavetables/triangle.wt create mode 100644 scripts/wavetables/example_wavetable.py create mode 100644 scripts/wavetables/generate_wavetable.py diff --git a/.gitignore b/.gitignore index a9bea9b..ddcf4f1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ -build/* \ No newline at end of file +build/* + +*/__pycache__/* \ No newline at end of file diff --git a/config/wavetables/saw.wt b/config/wavetables/saw.wt new file mode 100644 index 0000000000000000000000000000000000000000..16eb6cecb5525b7ed55a929a386749e141265572 GIT binary patch literal 8192 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 G{q;Z0kSx3a literal 0 HcmV?d00001 diff --git a/config/wavetables/shark_fin.wt b/config/wavetables/shark_fin.wt new file mode 100644 index 0000000000000000000000000000000000000000..733864b53223e13324e17b4835a9ef9726825c50 GIT binary patch literal 8192 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 zh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>B zh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>B zh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>B zh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>B zh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>B zh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>B zh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>B zh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>B zh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>B zh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>B zh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>B zh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>B zh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>B zh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>Bh5v>B zh5v>Bx&A$b|AqgB|AqgB|AqgB|AqgB|AqgB|AqgB|AqgB|AqgB|AqgB|AqgB|AqgB z|AqgB|AqgB|AqgB|AqgB|AqgB|AqgB|AqgB|AqgB|AqgB|AqgB|AqgB|AqgB|Aqfq z^Txve!vDhm!vDhm!vDhm!vDhm!vDhm!vDhm!vDhm!vDhm!vDhm!vDhm!vDhm!vDhm z!vDhm!vDhm!vDhm!vDhm!vDhm!vDhm!vDhm!v6vO5Ac70{{#FV;Qs*s2lzk0{{j9F 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 Wa6gdWYcVYOho$^n2IT!(4*w62hW9uC literal 0 HcmV?d00001 diff --git a/config/wavetables/sine.wt b/config/wavetables/sine.wt new file mode 100644 index 0000000000000000000000000000000000000000..c37a42bfb9f10881bad9169936d268aa39cdcf1d GIT binary patch literal 8192 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 Wzw^#opXaP<{hl@ZcRK&|_5TmQ8!;>Z literal 0 HcmV?d00001 diff --git a/scripts/wavetables/example_wavetable.py b/scripts/wavetables/example_wavetable.py new file mode 100644 index 0000000..066086c --- /dev/null +++ b/scripts/wavetables/example_wavetable.py @@ -0,0 +1,52 @@ + +import math +from generate_wavetable import generateWavetable + +WAVETABLE_FILE_NAME = "config/wavetables/shark_fin.wt" + +# process expects a waveform from x=[0, 2pi) centered around f(x)=0 +# normalization is handled by the wavetable generator + +def sine(phase): + return math.sin(phase) + +def square(phase): + sample = 1.0 + if(phase <= math.pi): + sample = -1 + return sample + +def saw(phase): + return (phase / math.pi) - 1.0 + +def triangle(phase): + sample = 0.0 + if(phase <= math.pi/2.0): + sample = phase * 2.0/math.pi + elif(phase <= 3.0*math.pi/2.0): + sample = phase * (-2.0/math.pi) + 2.0 + else: + sample = phase * 2.0/math.pi - 4.0 + return sample + +def sharkFin(phase): + k = 10.0 + sample = 0.0 + if(phase <= math.pi): + sample = 2.0 * (phase/math.pi) ** k - 1.0 + else: + sample = -2.0 * (phase/math.pi - 1) ** k + 1.0 + return sample + +def sigmoid(phase): + k = 4.0 + a = -k * (phase - math.pi) + sample = 2.0 / (1.0 + math.exp(a)) - 1.0 + return sample + +# pass in the name of your wavetable file and the process function +def main(): + generateWavetable(WAVETABLE_FILE_NAME, sharkFin) + +if __name__ == "__main__": + main() diff --git a/scripts/wavetables/generate_wavetable.py b/scripts/wavetables/generate_wavetable.py new file mode 100644 index 0000000..d918578 --- /dev/null +++ b/scripts/wavetables/generate_wavetable.py @@ -0,0 +1,67 @@ + +# this is a script for generating a wavetable file +# a wavetable file consists of a one-dimensional array of samples representing one period of a waveform +# metadata includes: +# - file version (for program compatibilty) +# - binary format (float, double, int32, etc.) +# - domain (eg phase is represented from [0, 2pi) ) +# - range (determined by datatype, e.g. float=[-1,1], int32=[-2^15, 2^15-1]) +# - waveform RMS (for loudness normalization) +# - sample count +# the synth program uses the filename, not any metadata + +# this script uses the input function to calculate samples +# if you want a custom wavetable, copt/edit/modify the example function (i used desmos for brainstorming) +# import this script and call generateWavetable(processFunction) to generate a custom wavetable + +from array import array +import math + +wavetableLength = 2048 + +def createFile(name): + filename = name + print("Creating file " + filename) + file = open(filename, "wb") + return file + +def writeMetadata(file): + print(">> im writing metadata") + +def writeData(file, processFunction): + print(">> im generating the wavetable") + + # init variables + data_list = [None] * wavetableLength + phaseInc = 2*math.pi / wavetableLength + x = 0 + accumulator = 0 + + # generate each discrete sample + for i in range(wavetableLength): + sample = processFunction(x) + accumulator += sample * sample + x += phaseInc + data_list[i] = sample + + # normalize by rms + rms = math.sqrt(accumulator/wavetableLength) + print(">> wavetable RMS: ", rms) + for i in range(wavetableLength): + data_list[i] /= rms + + # write to file + binary_data = array("f", data_list) + file.write(binary_data) + +def closeFile(file): + print(">> finishing up") + file.close() + +def generateWavetable(name, processFunction): + print("Hello main") + file = createFile(name) + writeMetadata(file) + writeData(file, processFunction) + closeFile(file) + print("Done")