Skip to content

Instantly share code, notes, and snippets.

@fredrb
Created August 8, 2023 12:47
Show Gist options
  • Save fredrb/d2fbfe5787e4e78c4a1ab0ded46d33ef to your computer and use it in GitHub Desktop.
Save fredrb/d2fbfe5787e4e78c4a1ab0ded46d33ef to your computer and use it in GitHub Desktop.
Playing A4 with SDL
#include "SDL2/SDL_audio.h"
#include "SDL2/SDL_timer.h"
#include <SDL2/SDL.h>
#include <errno.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
const int SAMPLE_RATE = 44100;
const int BUFFER_SIZE = 4096;
const float A4_OSC = (float)SAMPLE_RATE / 440.00f;
FILE *plot_output;
typedef struct {
float current_step;
float step_size;
float volume;
} oscillator;
oscillator oscillate(float rate, float volume) {
oscillator o = {
.current_step = 0,
.volume = volume,
.step_size = (2 * M_PI) / rate,
};
return o;
}
float next(oscillator *os) {
float ret = sinf(os->current_step);
os->current_step += os->step_size;
return ret * os->volume;
}
oscillator *A4_oscillator;
void oscillator_callback(void *userdata, Uint8 *stream, int len) {
float *fstream = (float *)stream;
for (int i = 0; i < BUFFER_SIZE; i++) {
float v = next(A4_oscillator);
fstream[i] = v;
#ifdef PLOT
fprintf(plot_output, "%.5f\n", fstream[i]);
#endif
}
}
void close() {
#ifdef PLOT
fclose(plot_output);
#endif
}
int main() {
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_EVENTS) < 0) {
printf("Failed to initialize SDL: %s\n", SDL_GetError());
return 1;
}
#ifdef PLOT
plot_output = fopen("plot_output", "w");
if (plot_output == NULL) {
printf("Failed to open file: %d", errno);
return 1;
}
#endif
oscillator a4 = oscillate(A4_OSC, 0.8f);
A4_oscillator = &a4;
SDL_AudioSpec spec = {
.format = AUDIO_F32,
.channels = 1,
.freq = SAMPLE_RATE,
.samples = 4096,
.callback = oscillator_callback,
};
if (SDL_OpenAudio(&spec, NULL) < 0) {
printf("Failed to open Audio Device: %s\n", SDL_GetError());
return 1;
}
SDL_PauseAudio(0);
while (true) {
SDL_Event e;
while (SDL_PollEvent(&e)) {
switch (e.type) {
case SDL_QUIT:
close();
return 0;
}
}
}
close();
return 0;
}
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams["figure.figsize"] = [7.50, 3.50]
plt.rcParams["figure.autolayout"] = True
with open("plot_output") as f:
plt.style.use('dark_background')
fig, axs = plt.subplots(1, 1)
num_samples = 441
lines = f.readlines()[:num_samples]
y = [float(i.strip()) for i in lines]
ticks = range(len(lines))
axs.plot(ticks, y)
axs.set_xticks(np.arange(0, num_samples, num_samples//10), np.arange(0, 11, 1))
axs.set_yticks([-1, -0.5, 0, 0.5, 1])
plt.ylabel("Amplitude")
plt.xlabel("Time (ms)")
plt.show()
@fredrb
Copy link
Author

fredrb commented Aug 8, 2023

You can compile this with plot output as:

gcc -g -o run main.c -DPLOT -lSDL2 -Wall

Then run plot.py to consume plot_output and generate the sine wave graphs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment