Last active
September 14, 2019 13:13
-
-
Save ryogrid/47b81fb735fc1c0a8bc5bd9c60f9547a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding: utf-8 | |
# to execute this code, you must install 'numpy' and 'wave' pip packages | |
# translate GLSL to python code: https://www.shadertoy.com/view/4l3GD2 | |
# explanation of above shadertoy page: https://qiita.com/notargs/items/be2fa153e62e3554a773 | |
import numpy as np | |
import wave | |
import struct | |
import math | |
FREQ = 48000 | |
FREQ_FLOAT = 48000.0 | |
ALL_TIME = 60 | |
def vec2(a, b): | |
return np.array([a, b]) | |
def dot(a, b): | |
return (a.transpose() * b)[0] | |
def rand(co): | |
return fract(math.sin(math.radians(dot(co, vec2(12.9898, 78.233)))) * 43758.5453) | |
def calcHertz(scale): | |
return 440.0 * pow(2.0, scale / 12.0) | |
def bassDrum(time): | |
t = mod(time, 1.0) / 3.0 * 8.0 | |
return math.sin(math.radians(time * (440.0))) * max(0.0, 1.0 - fract(t) * 8.0) | |
def snereDrum(time): | |
t = mod(time + 0.5, 1.0) | |
return rand(vec2(time * 32.0, 0.0)) * max(0.0, 1.0 - t * 4.0) | |
def hiHat(time): | |
t = time * 16.0 | |
if mod(t, 16.0) > 3.0 and mod(t, 2.0) > 1.0: | |
return 0.0 | |
return rand(vec2(time * 32.0, 0.0)) * max(0.0, 1.0 - fract(t) * 4.0) | |
def rect(time): | |
if fract(time / math.pi / 2.0) < 0.5: | |
return 1.0 | |
else: | |
return 0.0 | |
def strings(time): | |
t = mod(time * 4.0, 1.0) | |
sound = 0.0; | |
if mod(time, 8.0) < 4.0: | |
sound += rect(time * calcHertz(24.0)) | |
sound += rect(time * calcHertz(28.0)) | |
sound += rect(time * calcHertz(31.0)) | |
sound += rect(time * calcHertz(35.0)) | |
else: | |
sound += rect(time * calcHertz(23.0)) | |
sound += rect(time * calcHertz(26.0)) | |
sound += rect(time * calcHertz(30.0)) | |
sound += rect(time * calcHertz(33.0)) | |
return sound * max(0.0, (1.0 - t * 2.0)) | |
def bass(time): | |
time = mod(time, 8.0) | |
if time < 2.0: | |
return rect(time * calcHertz(0.0)) | |
if time > 3.0 and time < 3.5: | |
return rect(time * calcHertz(0.0)) | |
if time < 4.0: | |
return rect(time * calcHertz(12.0)) | |
if time < 6.0: | |
return rect(time * calcHertz(11.0)) | |
if time < 8.0: | |
return rect(time * calcHertz(-1.0)) | |
return 0.0 | |
def mainSound(time): | |
sound = 0.0 | |
sound += bassDrum(time) * 0.5 | |
sound += snereDrum(time) * 0.5 | |
sound += hiHat(time) * 0.5 | |
sound += strings(time) * 0.2 | |
sound += bass(time) * 0.2 | |
if (abs(sound) > 1.0): | |
sound /= abs(sound) | |
return sound | |
def fract(x): | |
return float(x) - math.floor(x) | |
def mod(x, y): | |
#return (x - y) * math.floor(x / y) | |
return x - y * math.floor(x / y) | |
def create_wave(): | |
sound_arr = np.arange(FREQ * ALL_TIME, dtype = 'float64') | |
for t in range(0, FREQ * ALL_TIME): | |
tt = t / FREQ_FLOAT | |
sound_arr[t] = mainSound(tt) | |
print(sound_arr.ndim) | |
print(sound_arr.size) | |
print(sound_arr) | |
# convert to 16bit signed integer | |
sound_wave = [int(x * 32767.0) for x in sound_arr] | |
# convert to binary data | |
binwave = struct.pack("h" * len(sound_wave), *sound_wave) | |
w = wave.Wave_write("./shadertoy.wav") | |
# channel num, sample bytes .... | |
p = (1, 2, FREQ, len(binwave), 'NONE', 'not compressed') | |
w.setparams(p) | |
w.writeframes(binwave) | |
w.close() | |
create_wave() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment