Refactor: extract platform abstraction for subprocess spawning

Move all Unix-specific syscalls (fork, execvp, waitpid, strerror, /tmp)
into a platform layer so the same spectrogram.c can target Windows
(CreateProcess) and WebAssembly (stubs). Key changes:

- src/platform.h: public API with spawn handle, error codes, path helpers
- src/platform_linux.c: fork/execvp implementation, /tmp, strerror
- src/platform_win32.c: CreateProcess implementation, temp dir lookup
- src/platform_web.c: stub implementations (no subprocess support on web)
- src/spectrogram.c: consume only platform.h; replace pid_t/fork/execvp
  with Platform_SpawnChild/WaitForChild; use Platform_GetTempDir() for
  /tmp path; replace strdup with malloc/memcpy for portability
- Build: add platform_*.c to gmake, Premake, and build_web.sh
This commit is contained in:
2026-05-14 18:16:21 -07:00
parent e42554e6fd
commit b6942d8577
8 changed files with 472 additions and 28 deletions
+45 -26
View File
@@ -1,11 +1,9 @@
// spectrogram.c - Spectrogram viewer with region selection and playback
// Based on Unity Audio-Experiments project
#define _POSIX_C_SOURCE 200809L
#define _DEFAULT_SOURCE
#include "raylib.h"
#include "resource_dir.h"
#include "platform.h"
#include <stdlib.h>
#include <string.h>
@@ -418,21 +416,34 @@ static void FreeSTFT(StftResult* result)
// Convert audio file to WAV using ffmpeg (if available)
static bool ConvertToFFmpegWAV(const char* inputPath, char* outputPath, size_t outputSize)
{
// Create temp WAV path
snprintf(outputPath, outputSize, "/tmp/rspektrum_temp_converted.wav");
// Build ffmpeg command
char cmd[1024];
snprintf(cmd, sizeof(cmd), "ffmpeg -y -loglevel quiet -i \"%s\" -ar 48000 -ac 1 -f wav \"%s\" 2>&1", inputPath, outputPath);
int result = system(cmd);
if (result == 0 && FileExists(outputPath)) {
snprintf(outputPath, outputSize, "%s/rspektrum_temp_converted.wav",
Platform_GetTempDir());
/* Build argv array — no shell = no injection risk */
const char* argv[] = {
"ffmpeg", "-y", "-loglevel", "quiet",
"-i", inputPath,
"-ar", "48000", "-ac", "1", "-f", "wav",
outputPath, NULL
};
PlatformSpawnHandle handle = { 0 };
PlatformError rc = Platform_SpawnChild("ffmpeg", argv, &handle);
if (rc != PLATFORM_OK) {
TraceLog(LOG_WARNING, "Failed to spawn ffmpeg: %s", Platform_GetLastErrorMessage());
return false;
}
Platform_WaitForChild(&handle);
int exit_code = 0;
SpawnStatus status = Platform_GetExitStatus(&handle, &exit_code);
if (status == SPAWN_EXITED && exit_code == 0 && FileExists(outputPath)) {
TraceLog(LOG_INFO, "FFmpeg conversion successful: %s", outputPath);
return true;
}
TraceLog(LOG_WARNING, "FFmpeg conversion failed or not available");
TraceLog(LOG_WARNING, "FFmpeg conversion failed (exit code %d)", exit_code);
return false;
}
@@ -457,10 +468,10 @@ static bool LoadWavFile(const char* filepath, AudioSignal* signal)
}
Wave wave = LoadWave(filepath);
if (wave.data == NULL) {
TraceLog(LOG_ERROR, "Failed to open WAV file: %s", filepath);
if (isConverted) remove(convertedPath);
return false;
if (wave.data == NULL) {
TraceLog(LOG_ERROR, "Failed to open WAV file: %s", filepath);
if (isConverted) FileRemove(convertedPath);
return false;
}
signal->sampleRate = wave.sampleRate;
@@ -493,7 +504,7 @@ static bool LoadWavFile(const char* filepath, AudioSignal* signal)
// Clean up temp file if converted
if (isConverted) {
remove(convertedPath);
FileRemove(convertedPath);
TraceLog(LOG_INFO, "Cleaned up temp file: %s", convertedPath);
}
@@ -768,9 +779,13 @@ static void ScanDirectory(const char* path)
const char* name = GetFileName(files.paths[i]);
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) continue;
if (DirectoryExists(files.paths[i])) {
app.browserFiles[app.browserFileCount] = strdup(name);
app.browserIsDir[app.browserFileCount] = true;
app.browserFileCount++;
size_t len = strlen(name) + 1;
app.browserFiles[app.browserFileCount] = (char*)malloc(len);
if (app.browserFiles[app.browserFileCount]) {
memcpy(app.browserFiles[app.browserFileCount], name, len);
app.browserIsDir[app.browserFileCount] = true;
app.browserFileCount++;
}
}
}
for (int i = 0; i < files.count; i++) {
@@ -780,9 +795,13 @@ static void ScanDirectory(const char* path)
const char* ext = GetFileExtension(files.paths[i]);
if (ext && (strcmp(ext, ".wav") == 0 || strcmp(ext, ".WAV") == 0 ||
strcmp(ext, ".Wave") == 0 || strcmp(ext, ".Wav") == 0)) {
app.browserFiles[app.browserFileCount] = strdup(name);
app.browserIsDir[app.browserFileCount] = false;
app.browserFileCount++;
size_t len = strlen(name) + 1;
app.browserFiles[app.browserFileCount] = (char*)malloc(len);
if (app.browserFiles[app.browserFileCount]) {
memcpy(app.browserFiles[app.browserFileCount], name, len);
app.browserIsDir[app.browserFileCount] = false;
app.browserFileCount++;
}
}
}
}