Created
January 2, 2023 23:47
-
-
Save danilw/47ca91aa6aa35860541806759bdbd9a5 to your computer and use it in GitHub Desktop.
example of generating Shadertoy audio texture and use of mmsystem.h in Windows OS
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
// this example of generating Shadertoy audio texture and use of mmsystem.h | |
// https://docs.microsoft.com/en-us/windows/win32/api/mmsystem/ | |
// code made by ttg https://github.com/therontarigo | |
// It compiles in mingw and runs in WINE | |
#define WIN32_LEAN_AND_MEAN | |
#include <windows.h> | |
#include <mmsystem.h> | |
#include <GL/gl.h> | |
#include <GL/glext.h> | |
#include <GL/glcorearb.h> | |
//#define DEBUG | |
#define PCMCHANNELS 2 | |
#define PCMSAMPLERATE 48000 | |
#define PCMBYTES 2 | |
#define PCMDEPTH (PCMBYTES*8) | |
#define WAVEBLOCKDY 100 | |
#define WAVEBLOCKDX 8 | |
#define WAVEBLOCKSIZE (PCMCHANNELS*PCMBYTES*WAVEBLOCKDX*WAVEBLOCKDY) | |
#define WAVEBLOCKS 8 | |
#define WAVEBLOCKS_AHEAD (WAVEBLOCKS-2) | |
#define BUFFERDX 1024 | |
#define BUFFERDY 1024 | |
#define _STR(x) #x | |
#define STR(x) _STR(x) | |
#define UNI_FRAMECTR 0 | |
#define UNI_WAVEBLOCK 1 | |
#define UNI_IMAGERES_X 2 | |
#define UNI_IMAGERES_Y 3 | |
char *shader = "#version 430\nprecision highp float;" | |
"layout(location=0)uniform ivec4 uniforms[2];\n" | |
"#define FRAMECTR uniforms[0].x\n" | |
"#define WAVEBLOCK uniforms[0].y\n" | |
"#define TIME float(WAVEBLOCK*"STR(WAVEBLOCKDX*WAVEBLOCKDY)")/float("STR(PCMSAMPLERATE)")\n" | |
"#define IMAGERES uniforms[0].zw\n" | |
"void mainImage( out vec4 fragColor, in vec2 fragCoord )" | |
"{" | |
"vec2 uv = fragCoord/IMAGERES;" | |
"vec3 col = 0.5 + 0.5*cos(TIME+uv.xyx+vec3(0,2,4));" | |
//"if(uv.y<.02)col=vec3(FRAMECTR%2);" | |
"fragColor = vec4(col,1.0);" | |
"}" | |
"vec2 mainSound( int samp, float time )" | |
"{" | |
"return vec2( sin(6.2831*440.0*time)*exp(-3.0*time) );" | |
"}" | |
"out vec4 O;void main(){" | |
"ivec2 I=ivec2(gl_FragCoord.xy);" | |
"if(IMAGERES.x==0){" | |
"if(I.x<"STR(WAVEBLOCKDX)"&&I.y<"STR(WAVEBLOCKDY)"){" | |
"int i=I.x+I.y*"STR(WAVEBLOCKDX)"+"STR(WAVEBLOCKDX*WAVEBLOCKDY)"*WAVEBLOCK;" | |
"O.xy=fract(.5*clamp(mainSound(i,float(i)/float("STR(PCMSAMPLERATE)")),-1.,1.));" | |
"}" | |
"else discard;" | |
"}" | |
"else " | |
"mainImage(O,gl_FragCoord.xy);" | |
"}"; | |
static void *openglsym (const char *name) { | |
void *gldll = LoadLibraryA("opengl32"); | |
void *sym; | |
return | |
(sym = wglGetProcAddress(name)) ? sym : | |
(void*)GetProcAddress(gldll, name) ; | |
} | |
static char wavebufs[WAVEBLOCKS*(WAVEBLOCKSIZE+sizeof(WAVEHDR))]; | |
static HWAVEOUT hwo; | |
static int wavectr; | |
static int waveplayctr; | |
static void *waveblocks[WAVEBLOCKS]; | |
static int uniforms[8]; | |
#ifdef DEBUG | |
static int dwstrlen (const char *s) { | |
const char *e=s; | |
while (*e) ++e; | |
return e-s; | |
} | |
static void printnt (const char *s) { | |
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); | |
WriteFile(out, s, dwstrlen(s), NULL, NULL); | |
} | |
#define glGetString _glGetString | |
#define GLFNS_DEBUG \ | |
GL(GETSTRING,GetString) \ | |
GL(GETPROGRAMINFOLOG,GetProgramInfoLog) \ | |
GL(GETPROGRAMIV,GetProgramiv) \ | |
#else | |
#define GLFNS_DEBUG | |
#endif | |
#define glRects _glRects | |
typedef void (APIENTRYP PFNGLRECTSPROC)(GLshort x1, GLshort y1, GLshort x2, GLshort y2); | |
#define GLFNS \ | |
GL(CREATESHADERPROGRAMV,CreateShaderProgramv) \ | |
GL(USEPROGRAM,UseProgram) \ | |
GL(GENFRAMEBUFFERS,GenFramebuffers) \ | |
GL(BINDFRAMEBUFFER,BindFramebuffer) \ | |
GL(FRAMEBUFFERTEXTURE2D,FramebufferTexture2D) \ | |
GL(UNIFORM4IV,Uniform4iv) \ | |
GL(RECTS,Rects) \ | |
GLFNS_DEBUG | |
#define GL(U,l) static PFNGL##U##PROC gl##l; | |
GLFNS | |
#undef GL | |
static void wavecb (HWAVEOUT hwo, UINT umsg, int *ctr, void *p1, void *p2) { | |
++*ctr; | |
} | |
void mainCRTStartup () { | |
// Initialize waveOut | |
WAVEFORMATEX wfx = { | |
.wFormatTag = WAVE_FORMAT_PCM, | |
.nChannels = PCMCHANNELS, | |
.nSamplesPerSec = PCMSAMPLERATE, | |
.nAvgBytesPerSec = PCMCHANNELS*PCMBYTES*PCMSAMPLERATE, | |
.nBlockAlign = PCMCHANNELS*PCMBYTES, | |
.wBitsPerSample = PCMDEPTH, | |
.cbSize = 0, | |
}; | |
waveOutOpen( | |
&hwo, | |
WAVE_MAPPER, | |
&wfx, | |
(DWORD_PTR)wavecb, | |
(DWORD_PTR)&waveplayctr, | |
CALLBACK_FUNCTION ); | |
void *wavebuf = wavebufs+sizeof(wavebufs); | |
for (int i=WAVEBLOCKS; i; --i) { | |
wavebuf-= WAVEBLOCKSIZE; | |
waveblocks[i-1] = wavebuf; | |
WAVEHDR *wavehdr = wavebuf-sizeof(WAVEHDR); | |
*wavehdr = (WAVEHDR){ | |
.lpData = wavebuf, | |
.dwBufferLength = WAVEBLOCKSIZE, | |
.dwBytesRecorded = 0, | |
.dwUser = 0, | |
.dwFlags = WHDR_INQUEUE, | |
.dwLoops = 0, | |
.lpNext = 0, | |
}; | |
wavebuf = wavehdr; | |
waveOutPrepareHeader( | |
hwo, | |
wavehdr, | |
sizeof(WAVEHDR) ); | |
} | |
// Create window | |
HWND hwnd = CreateWindowExA( | |
/* dwExStyle */ 0, | |
/* lpClassName */ "STATIC", | |
/* lpWindowName */ 0, | |
/* dwStyle */ | |
WS_POPUP|WS_VISIBLE | |
#ifndef DEBUG | |
|WS_MAXIMIZE | |
#endif | |
, | |
/* X, Y */ 0, 0, | |
/* nWidth, nHeight */ 512, 512, | |
/* hWndParent, hMenu, hInstance, lpParam */ | |
0, 0, 0, 0 ); | |
HDC hdc = GetDC(hwnd); | |
PIXELFORMATDESCRIPTOR pfd = { | |
.nSize = 0, | |
.nVersion = 0, | |
.dwFlags = PFD_SUPPORT_OPENGL|PFD_DRAW_TO_WINDOW|PFD_DOUBLEBUFFER, | |
}; | |
int pfi = ChoosePixelFormat(hdc, &pfd); | |
SetPixelFormat(hdc, pfi, &pfd); | |
// Create and make current OpenGL Context | |
HGLRC ctx = wglCreateContext(hdc); | |
wglMakeCurrent(hdc, ctx); | |
// Load OpenGL functions | |
#define GL(U,l) gl##l = openglsym("gl" #l); | |
GLFNS | |
#undef GL | |
#ifdef DEBUG | |
// Print OpenGL information | |
printnt( "GL vendor "); | |
printnt((char*)glGetString(GL_VENDOR)); | |
printnt("\nGL renderer "); | |
printnt((char*)glGetString(GL_RENDERER)); | |
printnt("\nGL version "); | |
printnt((char*)glGetString(GL_VERSION)); | |
printnt("\nGL shading version "); | |
printnt((char*)glGetString(GL_SHADING_LANGUAGE_VERSION)); | |
printnt("\n"); | |
#endif | |
// Create and use shader program | |
const char *shaderv = shader; | |
GLuint ghsp = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &shaderv); | |
#ifdef DEBUG | |
GLint status; | |
glGetProgramiv(ghsp, GL_LINK_STATUS, &status); | |
if (!status) { | |
char log[1024]; | |
int len; | |
glGetProgramInfoLog(ghsp, 1024, &len, log); | |
printnt(log); | |
ExitProcess(1); | |
} | |
#endif | |
glUseProgram(ghsp); | |
// Create and configure texture framebuffer render | |
GLuint fbo, tex; | |
glGenFramebuffers(1, &fbo); | |
glGenTextures(1, &tex); | |
glBindTexture(GL_TEXTURE_2D, tex); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
glTexImage2D( | |
/* target */ GL_TEXTURE_2D, | |
/* level */ 0, | |
/* internalformat */ GL_RGBA32F, | |
/* width */ BUFFERDX, | |
/* height */ BUFFERDY, | |
/* border */ 0, | |
/* format */ GL_RGBA, | |
/* type */ GL_FLOAT, | |
/* data */ 0 ); | |
glBindFramebuffer(GL_FRAMEBUFFER, fbo); | |
glFramebufferTexture2D( | |
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); | |
ShowCursor(0); | |
while(1) { | |
glBindFramebuffer(GL_FRAMEBUFFER, 0); | |
RECT rect; | |
GetClientRect(hwnd, &rect); | |
uniforms[UNI_IMAGERES_Y] = rect.bottom; | |
uniforms[UNI_IMAGERES_X] = rect.right; | |
glUniform4iv(0, 2, uniforms); | |
glRects(-1, -1, 1, 1); | |
++uniforms[UNI_FRAMECTR]; | |
while (wavectr-waveplayctr-WAVEBLOCKS_AHEAD <= 0) { | |
glBindFramebuffer(GL_FRAMEBUFFER, fbo); | |
void *waveblk = waveblocks[wavectr%WAVEBLOCKS]; | |
#if 0 | |
// test tone | |
for (int i=0;i<WAVEBLOCKDX*WAVEBLOCKDY;i++) { | |
((unsigned short*)waveblk)[i*2+0]= (i%128)*(65536/128); | |
} | |
#else | |
glReadPixels( | |
0, 0, WAVEBLOCKDX, WAVEBLOCKDY, | |
GL_RG, GL_UNSIGNED_SHORT, waveblk); | |
#endif | |
waveOutWrite(hwo, waveblk-sizeof(WAVEHDR), sizeof(WAVEHDR)); | |
uniforms[UNI_IMAGERES_X] = 0; | |
uniforms[UNI_WAVEBLOCK] = wavectr; | |
glUniform4iv(0, 2, uniforms); | |
glRects(-1, -1, 1, 1); | |
wavectr++; | |
} | |
SwapBuffers(hdc); | |
while(1) { | |
MSG msg; | |
int avail = PeekMessageA( | |
/* lpMsg */ &msg, | |
/* hWnd */ 0, | |
/* wMsgFilterMin */ WM_KEYFIRST, | |
/* wMsgFilterMax */ WM_KEYFIRST, | |
/* wRemoveMsg */ PM_REMOVE | |
); | |
if (!avail) | |
break; | |
if (msg.wParam==VK_ESCAPE) | |
goto quit; | |
} | |
} | |
quit: | |
ExitProcess(0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment