J'ai expérimenté avec le shader musical, mais il est de plus en plus difficile de le développer avec webGL car cela ne fonctionne pas. J'ai donc créé un script pour créer un fichier wav à partir du shader GLSL en utilisant python. Je pense qu'il sera plus facile d'ajuster les paramètres détaillés si python est impliqué.
Veuillez installer pyopengl et pyaudio avec pip. Si ça ne marche pas http://www.lfd.uci.edu/~gohlke/pythonlibs/ Le téléchargement du package à partir d'ici fonctionne généralement.
L'explication ici est difficile, veuillez donc l'utiliser comme bibliothèque. Le taux d'échantillonnage est réglé sur 48000. Si vous aimez la différence, veuillez la corriger de manière appropriée.
from OpenGL.GL import *
from OpenGL.WGL import *
from ctypes import *
import numpy
import pyaudio
import wave
import array
def shader2data(duration, src): #Temps de sortie, source de musique de shader
sampleRate = 48000
numSamples = duration*sampleRate
numSamplesC = numSamples*2
samples = (c_float * numSamplesC)()
hWnd = windll.user32.CreateWindowExA(0,0xC018,0,0,0,0,0,0,0,0,0,0)
hDC = windll.user32.GetDC(hWnd)
pfd = PIXELFORMATDESCRIPTOR(0,1,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0)
SetPixelFormat(hDC,ChoosePixelFormat(hDC, pfd), pfd)
hGLrc = wglCreateContext(hDC)
wglMakeCurrent(hDC, hGLrc)
program = glCreateProgram()
shader = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(shader, src)
glCompileShader(shader)
if glGetShaderiv(shader, GL_COMPILE_STATUS) != GL_TRUE:
raise RuntimeError(glGetShaderInfoLog(shader).decode())
glAttachShader(program, shader)
outs = cast((c_char_p*1)(b"gain"), POINTER(POINTER(c_char)))
glTransformFeedbackVaryings(program, 1, outs, GL_INTERLEAVED_ATTRIBS)
glLinkProgram(program)
glUseProgram(program)
vbo = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glBufferData(GL_ARRAY_BUFFER, sizeof(samples), None, GL_STATIC_DRAW)
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vbo)
glUniform1f(glGetUniformLocation(program, "sampleRate"), sampleRate)
glEnable(GL_RASTERIZER_DISCARD)
glBeginTransformFeedback(GL_POINTS)
glDrawArrays(GL_POINTS, 0, numSamples)
glEndTransformFeedback()
glDisable(GL_RASTERIZER_DISCARD)
glGetBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(samples), byref(samples))
wglMakeCurrent(0, 0);
wglDeleteContext(hGLrc);
windll.user32.ReleaseDC(hWnd, hDC);
windll.user32.PostQuitMessage(0);
return numpy.frombuffer(samples, dtype=numpy.float32)
def writeWav(filename, data):
sampleRate = 48000
w = wave.Wave_write(filename)
w.setnchannels(2)
w.setsampwidth(2)
w.setframerate(sampleRate)
w.writeframes(array.array('h', data*32767).tobytes())
w.close()
def readWav(filename):
w = wave.open(filename, 'rb')
print("params :", w.getparams())
print("duration:", w.getnframes() / w.getframerate(), "sec")
p = pyaudio.PyAudio()
stream = p.open(format=p.get_format_from_width(w.getsampwidth()),
channels=w.getnchannels(),
rate=w.getframerate(),
output=True)
stream.write(w.readframes(w.getnframes()))
stream.close()
p.terminate()
def playSound(data):
sampleRate = 48000
p = pyaudio.PyAudio()
stream = p.open(rate=sampleRate, channels=2, format=pyaudio.paFloat32, output=True)
stream.write(array.array('f', data).tobytes())
stream.close()
p.terminate()
Il utilise le même nom de fonction et le même nom d'argument que mainSound (), qui est la fonction principale du shader musical de shadertoy. Ainsi, vous pouvez copier et coller le shader de musique shadertoy pour cette partie. Ne changez pas d'autre uniforme, hors, principal (), etc.
src = """
#version 300 es
out vec2 gain;
uniform float sampleRate;
vec2 mainSound( float time )
{
return vec2(sin(6.2831*440.0*time)); ;
}
void main() {
float time = float(gl_VertexID) / sampleRate;
gain =mainSound(time);
}
"""
C'est la source du shader. Si vous mettez this et shader2data (duration, src) avec l'heure de sortie comme argument, des exemples de données seront générés. Entrez ces exemples de données et le nom de fichier dans writeWav (nom de fichier, données) pour créer un fichier wav. Vous pouvez entendre le son avec readWav (nom de fichier). Si vous souhaitez produire le son tel quel sans créer de fichier, utilisez playSound (data).
data = shader2data(2,src)
filename = "output.wav"
writeWav(filename, data)
readWav(filename)
playSound(data)
Je l'utilise comme ça.
Je ne pense pas qu'il y ait de demande, mais j'ai écrit un article qui se double d'un mémorandum. J'ai mis le fichier ipython ici. https://gist.github.com/gaziya/e5d40b0df1a65510af81b124c4ecf4cc
Recommended Posts