Skip to content

Instantly share code, notes, and snippets.

@danilw
Created January 2, 2023 23:47
Show Gist options
  • Save danilw/47ca91aa6aa35860541806759bdbd9a5 to your computer and use it in GitHub Desktop.
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 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