#define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include "raylib.h" #include "synth.h" #include "midi.h" atomic_int gRunning = 1; static Synth gSynth = {0}; static MidiState gMidi = {0}; static void AudioOutputCallback(void *buffer, unsigned int frames) { synthFillBuffer(&gSynth, (int16_t *)buffer, (int)frames); } static void drawWaveform(Waveform w, float dutyCycle, int x, int y, int width, int height) { int steps = width; for (int i = 0; i < steps - 1; i++) { float phase0 = (float)i / steps; float phase1 = (float)(i + 1) / steps; float s0 = waveformSample(w, phase0, dutyCycle); float s1 = waveformSample(w, phase1, dutyCycle); int cx = x + i; int cy = y + (int)((1.0f - (s0 * 0.5f + 0.5f)) * height); int nx = x + i + 1; int ny = y + (int)((1.0f - (s1 * 0.5f + 0.5f)) * height); DrawLine(cx, cy, nx, ny, GREEN); } DrawRectangleLines(x, y, width, height, DARKGRAY); } int main(void) { const int sampleRate = 48000; if (!midiInit(&gMidi, &gSynth)) return 1; midiListInputs(&gMidi); int srcClient, srcPort; printf("\nEnter client and port to connect (e.g. '20 0'), or -1 -1 to skip: "); if (scanf("%d %d", &srcClient, &srcPort) == 2 && srcClient != -1) midiConnect(&gMidi, srcClient, srcPort); pthread_t midiTid; pthread_create(&midiTid, NULL, midiThread, &gMidi); synthInit(&gSynth, (float)sampleRate); InitWindow(800, 450, "SoundThing"); InitAudioDevice(); SetAudioStreamBufferSizeDefault(1024); AudioStream stream = LoadAudioStream(sampleRate, 16, 1); SetAudioStreamCallback(stream, AudioOutputCallback); PlayAudioStream(stream); SetTargetFPS(120); while (!WindowShouldClose()) { if (IsKeyPressed(KEY_UP)) gSynth.waveform = (gSynth.waveform + 1) % WAVE_COUNT; if (IsKeyPressed(KEY_DOWN)) gSynth.waveform = (gSynth.waveform + WAVE_COUNT - 1) % WAVE_COUNT; BeginDrawing(); ClearBackground(BLACK); drawWaveform(gSynth.waveform, gSynth.dutyCycle, 20, 120, 400, 150); DrawText("SoundThing", 20, 20, 24, RAYWHITE); DrawText(TextFormat("Waveform: %s (UP/DOWN to change)", waveformName(gSynth.waveform)), 20, 55, 20, RAYWHITE); DrawText(TextFormat("MIDI: client %d port %d", gMidi.client, gMidi.port), 20, 90, 20, GRAY); if (gSynth.waveform == WAVE_PULSE) DrawText(TextFormat("Duty Cycle: %.2f", gSynth.dutyCycle), 20, 280, 20, GREEN); EndDrawing(); } gRunning = 0; StopAudioStream(stream); UnloadAudioStream(stream); CloseAudioDevice(); CloseWindow(); pthread_join(midiTid, NULL); midiClose(&gMidi); return 0; }