mirror of
https://github.com/raysan5/raylib.git
synced 2025-12-06 06:13:10 +00:00
REVIEWED: audio_fft_spectrum_visualizer, not working on web
This commit is contained in:
parent
e3738c1b17
commit
5fdf178969
@ -19,11 +19,19 @@
|
|||||||
********************************************************************************************/
|
********************************************************************************************/
|
||||||
|
|
||||||
#include "raylib.h"
|
#include "raylib.h"
|
||||||
|
|
||||||
#include "raymath.h"
|
#include "raymath.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#if defined(PLATFORM_DESKTOP)
|
||||||
|
#define GLSL_VERSION 330
|
||||||
|
#else // PLATFORM_ANDROID, PLATFORM_WEB
|
||||||
|
#define GLSL_VERSION 100
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MONO 1
|
#define MONO 1
|
||||||
#define SAMPLE_RATE 44100
|
#define SAMPLE_RATE 44100
|
||||||
#define SAMPLE_RATE_F 44100.0f
|
#define SAMPLE_RATE_F 44100.0f
|
||||||
@ -77,7 +85,8 @@ int main(void)
|
|||||||
RenderTexture2D bufferA = LoadRenderTexture(screenWidth, screenHeight);
|
RenderTexture2D bufferA = LoadRenderTexture(screenWidth, screenHeight);
|
||||||
Vector2 iResolution = { (float)screenWidth, (float)screenHeight };
|
Vector2 iResolution = { (float)screenWidth, (float)screenHeight };
|
||||||
|
|
||||||
Shader shader = LoadShader(NULL, "resources/fft.glsl");
|
Shader shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/fft.fs", GLSL_VERSION));
|
||||||
|
|
||||||
int iResolutionLocation = GetShaderLocation(shader, "iResolution");
|
int iResolutionLocation = GetShaderLocation(shader, "iResolution");
|
||||||
int iChannel0Location = GetShaderLocation(shader, "iChannel0");
|
int iChannel0Location = GetShaderLocation(shader, "iChannel0");
|
||||||
SetShaderValue(shader, iResolutionLocation, &iResolution, SHADER_UNIFORM_VEC2);
|
SetShaderValue(shader, iResolutionLocation, &iResolution, SHADER_UNIFORM_VEC2);
|
||||||
@ -86,6 +95,7 @@ int main(void)
|
|||||||
InitAudioDevice();
|
InitAudioDevice();
|
||||||
SetAudioStreamBufferSizeDefault(AUDIO_STREAM_RING_BUFFER_SIZE);
|
SetAudioStreamBufferSizeDefault(AUDIO_STREAM_RING_BUFFER_SIZE);
|
||||||
|
|
||||||
|
// WARNING: Memory out-of-bounds on PLATFORM_WEB
|
||||||
Wave wav = LoadWave("resources/country.mp3");
|
Wave wav = LoadWave("resources/country.mp3");
|
||||||
WaveFormat(&wav, SAMPLE_RATE, PER_SAMPLE_BIT_DEPTH, MONO);
|
WaveFormat(&wav, SAMPLE_RATE, PER_SAMPLE_BIT_DEPTH, MONO);
|
||||||
|
|
||||||
@ -95,10 +105,10 @@ int main(void)
|
|||||||
int fftHistoryLen = (int)ceilf(FFT_HISTORICAL_SMOOTHING_DUR/WINDOW_TIME) + 1;
|
int fftHistoryLen = (int)ceilf(FFT_HISTORICAL_SMOOTHING_DUR/WINDOW_TIME) + 1;
|
||||||
|
|
||||||
FFTData fft = {
|
FFTData fft = {
|
||||||
.spectrum = malloc(sizeof(FFTComplex)*FFT_WINDOW_SIZE),
|
.spectrum = RL_CALLOC(sizeof(FFTComplex), FFT_WINDOW_SIZE),
|
||||||
.workBuffer = malloc(sizeof(FFTComplex)*FFT_WINDOW_SIZE),
|
.workBuffer = RL_CALLOC(sizeof(FFTComplex), FFT_WINDOW_SIZE),
|
||||||
.prevMagnitudes = calloc(BUFFER_SIZE, sizeof(float)),
|
.prevMagnitudes = RL_CALLOC(BUFFER_SIZE, sizeof(float)),
|
||||||
.fftHistory = calloc(fftHistoryLen, sizeof(float[BUFFER_SIZE])),
|
.fftHistory = RL_CALLOC(fftHistoryLen, sizeof(float[BUFFER_SIZE])),
|
||||||
.fftHistoryLen = fftHistoryLen,
|
.fftHistoryLen = fftHistoryLen,
|
||||||
.historyPos = 0,
|
.historyPos = 0,
|
||||||
.lastFftTime = 0.0,
|
.lastFftTime = 0.0,
|
||||||
@ -127,15 +137,12 @@ int main(void)
|
|||||||
int right = (wav.channels == 2)? wavPCM16[wavCursor*2 + 1] : left;
|
int right = (wav.channels == 2)? wavPCM16[wavCursor*2 + 1] : left;
|
||||||
chunkSamples[i] = (short)((left + right)/2);
|
chunkSamples[i] = (short)((left + right)/2);
|
||||||
|
|
||||||
if (++wavCursor >= wav.frameCount)
|
if (++wavCursor >= wav.frameCount) wavCursor = 0;
|
||||||
wavCursor = 0;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateAudioStream(audioStream, chunkSamples, AUDIO_STREAM_RING_BUFFER_SIZE);
|
UpdateAudioStream(audioStream, chunkSamples, AUDIO_STREAM_RING_BUFFER_SIZE);
|
||||||
|
|
||||||
for (int i = 0; i < FFT_WINDOW_SIZE; i++)
|
for (int i = 0; i < FFT_WINDOW_SIZE; i++) audioSamples[i] = (chunkSamples[i*2] + chunkSamples[i*2 + 1])*0.5f/32767.0f;
|
||||||
audioSamples[i] = (chunkSamples[i*2] + chunkSamples[i*2 + 1])*0.5f/32767.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CaptureFrame(&fft, audioSamples);
|
CaptureFrame(&fft, audioSamples);
|
||||||
@ -146,14 +153,16 @@ int main(void)
|
|||||||
// Draw
|
// Draw
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
ClearBackground(BLACK);
|
|
||||||
|
ClearBackground(RAYWHITE);
|
||||||
|
|
||||||
BeginShaderMode(shader);
|
BeginShaderMode(shader);
|
||||||
SetShaderValueTexture(shader, iChannel0Location, fftTexture);
|
SetShaderValueTexture(shader, iChannel0Location, fftTexture);
|
||||||
DrawTextureRec(bufferA.texture,
|
DrawTextureRec(bufferA.texture,
|
||||||
(Rectangle){ 0, 0, (float)screenWidth, (float)-screenHeight },
|
(Rectangle){ 0, 0, (float)screenWidth, (float)-screenHeight },
|
||||||
(Vector2){ 0, 0 },
|
(Vector2){ 0, 0 }, WHITE);
|
||||||
WHITE);
|
|
||||||
EndShaderMode();
|
EndShaderMode();
|
||||||
|
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
}
|
}
|
||||||
@ -168,10 +177,10 @@ int main(void)
|
|||||||
UnloadWave(wav);
|
UnloadWave(wav);
|
||||||
CloseAudioDevice();
|
CloseAudioDevice();
|
||||||
|
|
||||||
free(fft.spectrum);
|
RL_FREE(fft.spectrum);
|
||||||
free(fft.workBuffer);
|
RL_FREE(fft.workBuffer);
|
||||||
free(fft.prevMagnitudes);
|
RL_FREE(fft.prevMagnitudes);
|
||||||
free(fft.fftHistory);
|
RL_FREE(fft.fftHistory);
|
||||||
|
|
||||||
CloseWindow(); // Close window and OpenGL context
|
CloseWindow(); // Close window and OpenGL context
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|||||||
@ -1,32 +0,0 @@
|
|||||||
#version 330
|
|
||||||
|
|
||||||
in vec2 fragTexCoord;
|
|
||||||
in vec4 fragColor;
|
|
||||||
|
|
||||||
out vec4 finalColor;
|
|
||||||
|
|
||||||
uniform vec2 iResolution;
|
|
||||||
uniform sampler2D iChannel0;
|
|
||||||
|
|
||||||
const vec4 BLACK = vec4(0.0, 0.0, 0.0, 1.0);
|
|
||||||
const vec4 WHITE = vec4(1.0, 1.0, 1.0, 1.0);
|
|
||||||
const float FFT_ROW = 0.0;
|
|
||||||
const float NUM_OF_BINS = 512.0;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec2 fragCoord = fragTexCoord*iResolution;
|
|
||||||
float cell_width = iResolution.x/NUM_OF_BINS;
|
|
||||||
float bin_index = floor(fragCoord.x/cell_width);
|
|
||||||
float local_x = mod(fragCoord.x, cell_width);
|
|
||||||
float bar_width = cell_width - 1.0;
|
|
||||||
vec4 color = BLACK;
|
|
||||||
if (local_x <= bar_width) {
|
|
||||||
float sample_x = (bin_index + 0.5)/NUM_OF_BINS;
|
|
||||||
vec2 sample_coord = vec2(sample_x, FFT_ROW);
|
|
||||||
float amplitude = texture(iChannel0, sample_coord).r; // only filled the red channel, all channels left open for alternative use
|
|
||||||
if (fragTexCoord.y < amplitude) {
|
|
||||||
color = WHITE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finalColor = color;
|
|
||||||
}
|
|
||||||
37
examples/audio/resources/shaders/glsl100/fft.fs
Normal file
37
examples/audio/resources/shaders/glsl100/fft.fs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#version 100
|
||||||
|
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
// Input vertex attributes (from vertex shader)
|
||||||
|
varying vec2 fragTexCoord;
|
||||||
|
varying vec4 fragColor;
|
||||||
|
|
||||||
|
// Input uniform values
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform sampler2D iChannel0;
|
||||||
|
|
||||||
|
const vec4 BLACK = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
|
const vec4 WHITE = vec4(1.0, 1.0, 1.0, 1.0);
|
||||||
|
const float FFT_ROW = 0.0;
|
||||||
|
const float NUM_OF_BINS = 512.0;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec2 fragCoord = fragTexCoord*iResolution;
|
||||||
|
float cellWidth = iResolution.x/NUM_OF_BINS;
|
||||||
|
float binIndex = floor(fragCoord.x/cellWidth);
|
||||||
|
float localX = mod(fragCoord.x, cellWidth);
|
||||||
|
float barWidth = cellWidth - 1.0;
|
||||||
|
vec4 color = WHITE;
|
||||||
|
|
||||||
|
if (localX <= barWidth)
|
||||||
|
{
|
||||||
|
float sampleX = (binIndex + 0.5)/NUM_OF_BINS;
|
||||||
|
vec2 sampleCoord = vec2(sampleX, FFT_ROW);
|
||||||
|
float amplitude = texture2D(iChannel0, sampleCoord).r; // Only filled the red channel, all channels left open for alternative use
|
||||||
|
|
||||||
|
if (fragTexCoord.y < amplitude) color = BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_FragColor = color;
|
||||||
|
}
|
||||||
35
examples/audio/resources/shaders/glsl120/fft.fs
Normal file
35
examples/audio/resources/shaders/glsl120/fft.fs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#version 120
|
||||||
|
|
||||||
|
// Input vertex attributes (from vertex shader)
|
||||||
|
varying vec2 fragTexCoord;
|
||||||
|
varying vec4 fragColor;
|
||||||
|
|
||||||
|
// Input uniform values
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform sampler2D iChannel0;
|
||||||
|
|
||||||
|
const vec4 BLACK = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
|
const vec4 WHITE = vec4(1.0, 1.0, 1.0, 1.0);
|
||||||
|
const float FFT_ROW = 0.0;
|
||||||
|
const float NUM_OF_BINS = 512.0;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec2 fragCoord = fragTexCoord*iResolution;
|
||||||
|
float cellWidth = iResolution.x/NUM_OF_BINS;
|
||||||
|
float binIndex = floor(fragCoord.x/cellWidth);
|
||||||
|
float localX = mod(fragCoord.x, cellWidth);
|
||||||
|
float barWidth = cellWidth - 1.0;
|
||||||
|
vec4 color = WHITE;
|
||||||
|
|
||||||
|
if (localX <= barWidth)
|
||||||
|
{
|
||||||
|
float sampleX = (binIndex + 0.5)/NUM_OF_BINS;
|
||||||
|
vec2 sampleCoord = vec2(sampleX, FFT_ROW);
|
||||||
|
float amplitude = texture2D(iChannel0, sampleCoord).r; // Only filled the red channel, all channels left open for alternative use
|
||||||
|
|
||||||
|
if (fragTexCoord.y < amplitude) color = BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_FragColor = color;
|
||||||
|
}
|
||||||
35
examples/audio/resources/shaders/glsl330/fft.fs
Normal file
35
examples/audio/resources/shaders/glsl330/fft.fs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#version 330
|
||||||
|
|
||||||
|
in vec2 fragTexCoord;
|
||||||
|
in vec4 fragColor;
|
||||||
|
|
||||||
|
out vec4 finalColor;
|
||||||
|
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform sampler2D iChannel0;
|
||||||
|
|
||||||
|
const vec4 BLACK = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
|
const vec4 WHITE = vec4(1.0, 1.0, 1.0, 1.0);
|
||||||
|
const float FFT_ROW = 0.0;
|
||||||
|
const float NUM_OF_BINS = 512.0;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec2 fragCoord = fragTexCoord*iResolution;
|
||||||
|
float cellWidth = iResolution.x/NUM_OF_BINS;
|
||||||
|
float binIndex = floor(fragCoord.x/cellWidth);
|
||||||
|
float localX = mod(fragCoord.x, cellWidth);
|
||||||
|
float barWidth = cellWidth - 1.0;
|
||||||
|
vec4 color = WHITE;
|
||||||
|
|
||||||
|
if (localX <= barWidth)
|
||||||
|
{
|
||||||
|
float sampleX = (binIndex + 0.5)/NUM_OF_BINS;
|
||||||
|
vec2 sampleCoord = vec2(sampleX, FFT_ROW);
|
||||||
|
float amplitude = texture(iChannel0, sampleCoord).r; // Only filled the red channel, all channels left open for alternative use
|
||||||
|
|
||||||
|
if (fragTexCoord.y < amplitude) color = BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
finalColor = color;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user