Ich habe mit Music Shader experimentiert, aber es wird schwieriger, mit WebGL zu entwickeln, weil es nicht funktioniert. Also habe ich ein Skript erstellt, um eine WAV-Datei aus dem GLSL-Shader mit Python zu erstellen. Ich denke, es wird einfacher sein, detaillierte Einstellungen anzupassen, wenn Python beteiligt ist.
Bitte installieren Sie Pyopengl und Pyaudio mit Pip. Wenn es nicht funktioniert http://www.lfd.uci.edu/~gohlke/pythonlibs/ Das Herunterladen des Pakets von hier funktioniert normalerweise.
Die Erklärung hier ist schwierig, verwenden Sie sie daher bitte als Bibliothek. Die Abtastrate ist auf 48000 eingestellt. Wenn Ihnen der Unterschied gefällt, beheben Sie ihn bitte entsprechend.
from OpenGL.GL import *
from OpenGL.WGL import *
from ctypes import *
import numpy
import pyaudio
import wave
import array
def shader2data(duration, src): #Ausgabezeit, Shader-Musikquelle
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()
Es verwendet denselben Funktionsnamen und Argumentnamen wie mainSound (), die Hauptfunktion von Shadertoys Musik-Shader. Sie können also den Shadertoy-Musik-Shader für diesen Teil kopieren und einfügen. Ändern Sie nicht andere Uniform, out, main () usw.
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);
}
"""
Dies ist die Quelle für den Shader. Wenn Sie dies und shader2data (Dauer, src) mit der Ausgabezeit als Argument eingeben, werden Beispieldaten ausgegeben. Geben Sie diese Beispieldaten und den Dateinamen in writeWav (Dateiname, Daten) ein, um eine WAV-Datei zu erstellen. Sie können den Ton mit readWav (Dateiname) hören. Wenn Sie den Sound unverändert ausgeben möchten, ohne eine Datei zu erstellen, verwenden Sie playSound (Daten).
data = shader2data(2,src)
filename = "output.wav"
writeWav(filename, data)
readWav(filename)
playSound(data)
Ich benutze es so.
Ich glaube nicht, dass es eine Nachfrage gibt, aber ich habe einen Artikel geschrieben, der gleichzeitig als Memorandum dient. Ich habe die Ipython-Datei hier abgelegt. https://gist.github.com/gaziya/e5d40b0df1a65510af81b124c4ecf4cc
Recommended Posts