refactor: move DOOM out to the mtkports ports tree

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018Ae69wJS7sueQMUwNxV3nX
This commit is contained in:
2026-08-07 20:10:52 +02:00
co-authored by Claude Opus 5
parent b77449faeb
commit 27c13b8dc2
10 changed files with 35 additions and 888 deletions
-211
View File
@@ -1,211 +0,0 @@
# Makefile for DOOM (doomgeneric) on MontaukOS
# Copyright (c) 2025 Daniel Hammer
MAKEFLAGS += -rR
.SUFFIXES:
# ---- Toolchain ----
TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk-
ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),)
CC = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first)
CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first)
LD = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first)
else
CC := $(TOOLCHAIN_PREFIX)gcc
CXX := $(TOOLCHAIN_PREFIX)g++
LD := $(TOOLCHAIN_PREFIX)gcc
endif
# ---- Paths ----
DOOM_SRC := ../../../doomgeneric/doomgeneric
LIBC_INC := ../../include/libc
PROG_INC := ../../include
LIBDIR := ../../lib
LOADER_LIB := ../../lib/libloader
LINK_LD := ../../link.ld
BINDIR := ../../bin
OBJDIR := obj
# ---- Compiler flags ----
CFLAGS := \
-std=gnu11 \
-g -O2 -pipe \
-Wall \
-Wno-unused-parameter \
-Wno-unused-variable \
-Wno-missing-field-initializers \
-Wno-sign-compare \
-Wno-pointer-sign \
-ffreestanding \
-fno-stack-protector \
-fno-stack-check \
-ffunction-sections \
-fdata-sections \
-msse \
-msse2 \
-DNORMALUNIX \
-DLINUX \
-DFEATURE_SOUND \
-isystem $(LIBC_INC) \
-I . \
-I $(PROG_INC) \
-I $(DOOM_SRC) \
-isystem $(shell $(CC) -print-file-name=include)
CXXFLAGS := \
-std=gnu++20 \
-g -O2 -pipe \
-Wall \
-Wno-unused-parameter \
-ffreestanding \
-fno-stack-protector \
-fno-stack-check \
-fno-rtti \
-fno-exceptions \
-ffunction-sections \
-fdata-sections \
-msse \
-msse2 \
-isystem $(LIBC_INC) \
-I . \
-I $(PROG_INC)
# ---- Linker flags ----
LDFLAGS := \
-nostdlib \
-Wl,--gc-sections \
-T $(LINK_LD)
# ---- DOOM source files (excluding platform-specific ports and sound backends) ----
DOOM_SRCS := \
am_map.c \
d_event.c \
d_items.c \
d_iwad.c \
d_loop.c \
d_main.c \
d_mode.c \
d_net.c \
doomdef.c \
doomgeneric.c \
doomstat.c \
dstrings.c \
dummy.c \
f_finale.c \
f_wipe.c \
g_game.c \
gusconf.c \
hu_lib.c \
hu_stuff.c \
i_cdmus.c \
i_endoom.c \
i_input.c \
i_joystick.c \
i_scale.c \
i_sound.c \
i_system.c \
i_timer.c \
i_video.c \
info.c \
m_argv.c \
m_bbox.c \
m_cheat.c \
m_config.c \
m_controls.c \
m_fixed.c \
m_menu.c \
m_misc.c \
m_random.c \
memio.c \
mus2mid.c \
p_ceilng.c \
p_doors.c \
p_enemy.c \
p_floor.c \
p_inter.c \
p_lights.c \
p_map.c \
p_maputl.c \
p_mobj.c \
p_plats.c \
p_pspr.c \
p_saveg.c \
p_setup.c \
p_sight.c \
p_spec.c \
p_switch.c \
p_telept.c \
p_tick.c \
p_user.c \
r_bsp.c \
r_data.c \
r_draw.c \
r_main.c \
r_plane.c \
r_segs.c \
r_sky.c \
r_things.c \
s_sound.c \
sha1.c \
sounds.c \
st_lib.c \
st_stuff.c \
statdump.c \
tables.c \
v_video.c \
w_checksum.c \
w_file.c \
w_file_stdc.c \
w_main.c \
w_wad.c \
wi_stuff.c \
z_zone.c
# Local source files
LOCAL_SRCS := doomgeneric_montauk.c i_sound_montauk.c
LOCAL_CXX_SRCS := doom_wad_check.cpp
# ---- Object files ----
DOOM_OBJS := $(addprefix $(OBJDIR)/,$(DOOM_SRCS:.c=.o))
LOCAL_OBJS := $(addprefix $(OBJDIR)/,$(LOCAL_SRCS:.c=.o))
LOCAL_CXX_OBJS := $(addprefix $(OBJDIR)/,$(LOCAL_CXX_SRCS:.cpp=.o))
ALL_OBJS := $(DOOM_OBJS) $(LOCAL_OBJS) $(LOCAL_CXX_OBJS)
# ---- Target ----
TARGET := $(BINDIR)/apps/doom/doom.elf
.PHONY: all clean
all: $(TARGET)
$(TARGET): $(ALL_OBJS) $(LINK_LD) Makefile $(LOADER_LIB)/liblibloader.a $(LIBDIR)/libc/liblibc.a
mkdir -p $(BINDIR)/apps/doom
$(LD) $(CFLAGS) $(LDFLAGS) $(ALL_OBJS) $(LOADER_LIB)/liblibloader.a $(LIBDIR)/libc/liblibc.a -o $@
# DOOM source files (from doomgeneric directory)
$(OBJDIR)/%.o: $(DOOM_SRC)/%.c Makefile
mkdir -p $(OBJDIR)
$(CC) $(CFLAGS) -MMD -MP -c $< -o $@
# Local source files
$(OBJDIR)/%.o: %.c Makefile
mkdir -p $(OBJDIR)
$(CC) $(CFLAGS) -MMD -MP -c $< -o $@
# Local C++ source files
$(OBJDIR)/%.o: %.cpp Makefile
mkdir -p $(OBJDIR)
$(CXX) $(CXXFLAGS) -MMD -MP -c $< -o $@
clean:
rm -rf $(OBJDIR) $(TARGET)
# Auto-generated header dependency tracking (-MMD -MP).
-include $(ALL_OBJS:.o=.d)
-4
View File
@@ -1,4 +0,0 @@
/* Dummy SDL_mixer.h - not needed for MontaukOS sound backend */
#ifndef SDL_MIXER_H
#define SDL_MIXER_H
#endif
-22
View File
@@ -1,22 +0,0 @@
/*
* doom_wad_check.cpp
* Warns the user and exits cleanly if no DOOM WAD is present
* Copyright (c) 2026 Daniel Hammer
*/
#include <gui/dialogs.hpp>
#include <montauk/syscall.h>
#include <stdio.h>
extern "C" [[noreturn]] void doom_warn_missing_wad(const char* path) {
char message[400];
snprintf(message, sizeof(message),
"No DOOM WAD file was found at %s.\n\n"
"MontaukOS cannot ship proprietary DOOM WADs (doom1.wad, doom.wad, "
"freedoom1.wad, etc.) on its ISO images due to copyright restrictions.\n\n"
"Copy a legally obtained WAD file to that path and relaunch DOOM.",
path);
gui::dialogs::message_box("DOOM", message, gui::dialogs::MESSAGE_BOX_OK);
montauk::exit(1);
}
-269
View File
@@ -1,269 +0,0 @@
/*
* doomgeneric_montauk.c
* DOOM platform implementation for MontaukOS (standalone window server client)
* Copyright (c) 2025 Daniel Hammer
*/
#include "doomgeneric.h"
#include "doomkeys.h"
#include <string.h>
#include <stdio.h>
/* ---- Raw syscall interface (C versions) ---- */
static inline long _zos_syscall0(long nr) {
long ret;
__asm__ volatile("syscall" : "=a"(ret) : "a"(nr)
: "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory");
return ret;
}
static inline long _zos_syscall1(long nr, long a1) {
long ret;
__asm__ volatile(
"mov %[a1], %%rdi\n\t"
"syscall"
: "=a"(ret)
: "a"(nr), [a1] "r"(a1)
: "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory");
return ret;
}
static inline long _zos_syscall2(long nr, long a1, long a2) {
long ret;
__asm__ volatile(
"mov %[a1], %%rdi\n\t"
"mov %[a2], %%rsi\n\t"
"syscall"
: "=a"(ret)
: "a"(nr), [a1] "r"(a1), [a2] "r"(a2)
: "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory");
return ret;
}
static inline long _zos_syscall4(long nr, long a1, long a2, long a3, long a4) {
long ret;
__asm__ volatile(
"mov %[a1], %%rdi\n\t"
"mov %[a2], %%rsi\n\t"
"mov %[a3], %%rdx\n\t"
"mov %[a4], %%r10\n\t"
"syscall"
: "=a"(ret)
: "a"(nr), [a1] "r"(a1), [a2] "r"(a2), [a3] "r"(a3), [a4] "r"(a4)
: "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory");
return ret;
}
/* Syscall numbers (must match kernel/src/Api/Syscall.hpp) */
#define SYS_EXIT 0
#define SYS_SLEEP_MS 2
#define SYS_PRINT 4
#define SYS_GETMILLISECONDS 14
#define SYS_WINCREATE 54
#define SYS_WINDESTROY 55
#define SYS_WINPRESENT 56
#define SYS_WINPOLL 57
/* Window server structs (must match montauk::abi::WinCreateResult and montauk::abi::WinEvent) */
struct WinCreateResult {
int id; /* -1 on failure */
unsigned _pad;
unsigned long pixelVa; /* VA of pixel buffer in caller's address space */
};
struct WinEvent {
unsigned char type; /* 0=key, 1=mouse, 2=resize, 3=close */
unsigned char _pad[3];
union {
struct {
unsigned char scancode;
char ascii;
unsigned char pressed;
unsigned char shift;
unsigned char ctrl;
unsigned char alt;
} key;
struct { int x, y, scroll; unsigned char buttons, prev_buttons; } mouse;
struct { int w, h; } resize;
};
};
/* ---- Window state ---- */
static int g_winId = -1;
static uint32_t* g_pixBuf = 0;
/* ---- Circular key queue ---- */
#define KEY_QUEUE_SIZE 64
struct KeyQueueEntry {
int pressed;
unsigned char doomkey;
};
static struct KeyQueueEntry g_keyQueue[KEY_QUEUE_SIZE];
static int g_keyQueueRead = 0;
static int g_keyQueueWrite = 0;
static void key_queue_push(int pressed, unsigned char doomkey) {
int next = (g_keyQueueWrite + 1) % KEY_QUEUE_SIZE;
if (next == g_keyQueueRead) return; /* full, drop */
g_keyQueue[g_keyQueueWrite].pressed = pressed;
g_keyQueue[g_keyQueueWrite].doomkey = doomkey;
g_keyQueueWrite = next;
}
static int key_queue_pop(int* pressed, unsigned char* doomkey) {
if (g_keyQueueRead == g_keyQueueWrite) return 0;
*pressed = g_keyQueue[g_keyQueueRead].pressed;
*doomkey = g_keyQueue[g_keyQueueRead].doomkey;
g_keyQueueRead = (g_keyQueueRead + 1) % KEY_QUEUE_SIZE;
return 1;
}
/* ---- PS/2 scancode to ASCII table (set 1, unshifted) ---- */
static const char scancode_to_ascii[128] = {
0, 27, '1','2','3','4','5','6','7','8','9','0','-','=','\b',
'\t','q','w','e','r','t','y','u','i','o','p','[',']','\n',
0, 'a','s','d','f','g','h','j','k','l',';','\'','`',
0, '\\','z','x','c','v','b','n','m',',','.','/', 0,
'*', 0, ' '
};
/* ---- PS/2 scancode to DOOM key mapping ---- */
static unsigned char scancode_to_doomkey(unsigned char scancode, char ascii) {
switch (scancode) {
case 0x48: return KEY_UPARROW;
case 0x50: return KEY_DOWNARROW;
case 0x4B: return KEY_LEFTARROW;
case 0x4D: return KEY_RIGHTARROW;
case 0x1C: return KEY_ENTER;
case 0x01: return KEY_ESCAPE;
case 0x39: return KEY_USE; /* Space = use */
case 0x1D: return KEY_FIRE; /* LCtrl = fire */
case 0x2A: return KEY_RSHIFT; /* LShift = run */
case 0x36: return KEY_RSHIFT; /* RShift = run */
case 0x38: return KEY_RALT; /* Alt = strafe */
case 0x0E: return KEY_BACKSPACE;
case 0x0F: return KEY_TAB;
/* F1-F10 */
case 0x3B: return KEY_F1;
case 0x3C: return KEY_F2;
case 0x3D: return KEY_F3;
case 0x3E: return KEY_F4;
case 0x3F: return KEY_F5;
case 0x40: return KEY_F6;
case 0x41: return KEY_F7;
case 0x42: return KEY_F8;
case 0x43: return KEY_F9;
case 0x44: return KEY_F10;
case 0x57: return KEY_F11;
case 0x58: return KEY_F12;
/* Equals and minus for screen size */
case 0x0D: return KEY_EQUALS;
case 0x0C: return KEY_MINUS;
default:
/* Pass through printable ASCII as lowercase */
if (ascii >= 'a' && ascii <= 'z') return (unsigned char)ascii;
if (ascii >= '0' && ascii <= '9') return (unsigned char)ascii;
return 0;
}
}
/* ---- Poll window events and enqueue key events ---- */
static void poll_keyboard(void) {
struct WinEvent evt;
while (_zos_syscall2(SYS_WINPOLL, (long)g_winId, (long)&evt) > 0) {
if (evt.type == 0) {
/* Key event */
unsigned char baseSc = evt.key.scancode & 0x7F;
char ascii = 0;
if (baseSc < 128)
ascii = scancode_to_ascii[baseSc];
unsigned char dk = scancode_to_doomkey(baseSc, ascii);
if (dk != 0) {
key_queue_push(evt.key.pressed ? 1 : 0, dk);
}
} else if (evt.type == 3) {
/* Close event — exit the process */
_zos_syscall1(SYS_EXIT, 0);
}
}
}
/* ---- DG platform functions ---- */
void DG_Init(void) {
struct WinCreateResult result;
_zos_syscall4(SYS_WINCREATE, (long)"DOOM", (long)DOOMGENERIC_RESX,
(long)DOOMGENERIC_RESY, (long)&result);
if (result.id < 0) {
_zos_syscall1(SYS_EXIT, 1);
}
g_winId = result.id;
g_pixBuf = (uint32_t*)result.pixelVa;
}
void DG_DrawFrame(void) {
/* Poll keyboard first */
poll_keyboard();
/* Copy DG_ScreenBuffer into the shared pixel buffer */
if (g_pixBuf == 0 || DG_ScreenBuffer == 0) return;
memcpy(g_pixBuf, DG_ScreenBuffer,
DOOMGENERIC_RESX * DOOMGENERIC_RESY * sizeof(uint32_t));
/* Mark window as dirty so the compositor picks it up */
_zos_syscall1(SYS_WINPRESENT, (long)g_winId);
}
void DG_SleepMs(uint32_t ms) {
_zos_syscall1(SYS_SLEEP_MS, (long)ms);
}
uint32_t DG_GetTicksMs(void) {
return (uint32_t)_zos_syscall0(SYS_GETMILLISECONDS);
}
int DG_GetKey(int* pressed, unsigned char* doomKey) {
return key_queue_pop(pressed, doomKey);
}
void DG_SetWindowTitle(const char* title) {
(void)title;
}
/* ---- Entry point ---- */
/* Shows a warning dialog explaining that MontaukOS cannot ship proprietary
* DOOM WADs and does not return (implemented in doom_wad_check.cpp, which
* links against the shared dialog library). */
extern void doom_warn_missing_wad(const char* path);
void _start(void) {
static const char* wadPath = "0:/apps/doom/doom1.wad";
FILE* wad = fopen(wadPath, "rb");
if (!wad) {
doom_warn_missing_wad(wadPath);
/* unreachable: doom_warn_missing_wad() exits the process */
}
fclose(wad);
char *argv[] = { "doom", "-iwad", (char*)wadPath, 0 };
doomgeneric_Create(3, argv);
for (;;) {
doomgeneric_Tick();
}
}
-362
View File
@@ -1,362 +0,0 @@
/*
* i_sound_montauk.c
* DOOM sound effects and music modules for MontaukOS
* Implements software mixing of 16 SFX channels into the HDA audio device.
* Copyright (c) 2026 Daniel Hammer
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "deh_str.h"
#include "i_sound.h"
#include "i_system.h"
#include "i_swap.h"
#include "m_argv.h"
#include "m_misc.h"
#include "w_wad.h"
#include "z_zone.h"
#include "doomtype.h"
/* ========================================================================
Raw syscall interface for audio
======================================================================== */
static inline long _snd_syscall1(long nr, long a1) {
long ret;
__asm__ volatile(
"mov %[a1], %%rdi\n\t"
"syscall"
: "=a"(ret)
: "a"(nr), [a1] "r"(a1)
: "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory");
return ret;
}
static inline long _snd_syscall3(long nr, long a1, long a2, long a3) {
long ret;
__asm__ volatile(
"mov %[a1], %%rdi\n\t"
"mov %[a2], %%rsi\n\t"
"mov %[a3], %%rdx\n\t"
"syscall"
: "=a"(ret)
: "a"(nr), [a1] "r"(a1), [a2] "r"(a2), [a3] "r"(a3)
: "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory");
return ret;
}
#define SYS_AUDIOOPEN 80
#define SYS_AUDIOCLOSE 81
#define SYS_AUDIOWRITE 82
/* ========================================================================
Audio mixing engine
======================================================================== */
/* Required by i_sound.c config binding */
int use_libsamplerate = 0;
float libsamplerate_scale = 0.65f;
#define NUM_CHANNELS 16
#define MIX_RATE 44100
#define MIX_CHANNELS 2
#define MIX_BITS 16
/* Samples per mix frame (~35 fps, slightly oversized for timing jitter) */
#define MIX_SAMPLES 1260
#define MIX_BUF_BYTES (MIX_SAMPLES * MIX_CHANNELS * (MIX_BITS / 8))
/* Channel state */
struct snd_channel {
const uint8_t *data; /* 8-bit unsigned PCM samples */
uint32_t length; /* number of samples */
uint32_t pos; /* playback position (16.16 fixed-point) */
uint32_t step; /* step per output sample (16.16 fixed-point) */
int vol_left; /* left volume (0-127) */
int vol_right; /* right volume (0-127) */
sfxinfo_t *sfxinfo; /* NULL = inactive */
};
static struct snd_channel channels[NUM_CHANNELS];
static int audio_handle = -1;
static boolean sound_initialized = false;
static boolean use_sfx_prefix;
/* Static mix buffer (stereo interleaved int16_t) */
static int16_t mix_buf[MIX_SAMPLES * MIX_CHANNELS];
/* ========================================================================
Sound effect loading (DMX format from WAD lumps)
======================================================================== */
static void GetSfxLumpName(sfxinfo_t *sfx, char *buf, size_t buf_len) {
if (sfx->link != NULL)
sfx = sfx->link;
if (use_sfx_prefix)
M_snprintf(buf, buf_len, "ds%s", DEH_String(sfx->name));
else
M_StringCopy(buf, DEH_String(sfx->name), buf_len);
}
/* Parse a DMX sound lump. Returns the raw 8-bit PCM data and fills in
samplerate and length. Returns NULL on failure. */
static const uint8_t *ParseDmxSound(int lumpnum, int *out_rate, uint32_t *out_len) {
unsigned int lumplen = W_LumpLength(lumpnum);
const uint8_t *data = W_CacheLumpNum(lumpnum, PU_STATIC);
if (lumplen < 8 || data[0] != 0x03 || data[1] != 0x00)
return NULL;
int samplerate = (data[3] << 8) | data[2];
uint32_t length = (data[7] << 24) | (data[6] << 16) | (data[5] << 8) | data[4];
if (length > lumplen - 8 || length <= 48)
return NULL;
/* DMX skips first 16 and last 16 bytes of sample data */
*out_rate = samplerate;
*out_len = length - 32;
return data + 16;
}
/* ========================================================================
Volume/separation helpers
======================================================================== */
static void SetChannelVolSep(int ch, int vol, int sep) {
/* vol: 0-127, sep: 0-254 (0=full left, 127=center, 254=full right) */
channels[ch].vol_left = ((254 - sep) * vol) / 127;
channels[ch].vol_right = (sep * vol) / 127;
}
/* ========================================================================
Software mixer - mix all active channels into mix_buf
======================================================================== */
static void MixChannels(int num_samples) {
/* Clear mix buffer */
memset(mix_buf, 0, (size_t)(num_samples * MIX_CHANNELS) * sizeof(int16_t));
for (int ch = 0; ch < NUM_CHANNELS; ch++) {
struct snd_channel *c = &channels[ch];
if (c->sfxinfo == NULL)
continue;
int16_t *out = mix_buf;
for (int i = 0; i < num_samples; i++) {
uint32_t ipos = c->pos >> 16;
if (ipos >= c->length) {
/* Sound finished */
c->sfxinfo = NULL;
break;
}
/* Convert 8-bit unsigned (0-255, 128=silence) to signed (-128..127)
then scale to 16-bit range */
int sample = ((int)c->data[ipos] - 128) << 8;
/* Apply volume and accumulate (additive mixing) */
int left = out[i * 2 + 0] + ((sample * c->vol_left) >> 7);
int right = out[i * 2 + 1] + ((sample * c->vol_right) >> 7);
/* Clamp to int16_t range */
if (left > 32767) left = 32767;
else if (left < -32768) left = -32768;
if (right > 32767) right = 32767;
else if (right < -32768) right = -32768;
out[i * 2 + 0] = (int16_t)left;
out[i * 2 + 1] = (int16_t)right;
c->pos += c->step;
}
}
}
/* ========================================================================
sound_module_t implementation
======================================================================== */
static boolean I_Montauk_InitSound(boolean _use_sfx_prefix) {
use_sfx_prefix = _use_sfx_prefix;
for (int i = 0; i < NUM_CHANNELS; i++) {
memset(&channels[i], 0, sizeof(channels[i]));
}
audio_handle = (int)_snd_syscall3(SYS_AUDIOOPEN,
(long)MIX_RATE, (long)MIX_CHANNELS, (long)MIX_BITS);
if (audio_handle < 0) {
return false;
}
sound_initialized = true;
return true;
}
static void I_Montauk_ShutdownSound(void) {
if (!sound_initialized)
return;
for (int i = 0; i < NUM_CHANNELS; i++)
channels[i].sfxinfo = NULL;
if (audio_handle >= 0) {
_snd_syscall1(SYS_AUDIOCLOSE, (long)audio_handle);
audio_handle = -1;
}
sound_initialized = false;
}
static int I_Montauk_GetSfxLumpNum(sfxinfo_t *sfx) {
char namebuf[9];
GetSfxLumpName(sfx, namebuf, sizeof(namebuf));
return W_GetNumForName(namebuf);
}
static void I_Montauk_UpdateSound(void) {
if (!sound_initialized || audio_handle < 0)
return;
/* Mix one frame of audio and submit to the device */
MixChannels(MIX_SAMPLES);
const uint8_t *ptr = (const uint8_t *)mix_buf;
int remaining = MIX_BUF_BYTES;
/* Write as much as the device accepts (non-blocking) */
while (remaining > 0) {
int written = (int)_snd_syscall3(SYS_AUDIOWRITE,
(long)audio_handle, (long)ptr, (long)remaining);
if (written <= 0)
break;
ptr += written;
remaining -= written;
}
}
static void I_Montauk_UpdateSoundParams(int channel, int vol, int sep) {
if (!sound_initialized || channel < 0 || channel >= NUM_CHANNELS)
return;
if (channels[channel].sfxinfo == NULL)
return;
SetChannelVolSep(channel, vol, sep);
}
static int I_Montauk_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep) {
if (!sound_initialized || channel < 0 || channel >= NUM_CHANNELS)
return -1;
/* Stop any sound already on this channel */
channels[channel].sfxinfo = NULL;
/* Load and parse the sound lump */
if (sfxinfo->lumpnum == -1)
return -1;
int samplerate;
uint32_t length;
const uint8_t *data = ParseDmxSound(sfxinfo->lumpnum, &samplerate, &length);
if (data == NULL)
return -1;
/* Set up the channel */
channels[channel].data = data;
channels[channel].length = length;
channels[channel].pos = 0;
/* Resampling step: source_rate / MIX_RATE in 16.16 fixed-point */
channels[channel].step = ((uint32_t)samplerate << 16) / MIX_RATE;
SetChannelVolSep(channel, vol, sep);
channels[channel].sfxinfo = sfxinfo;
return channel;
}
static void I_Montauk_StopSound(int channel) {
if (!sound_initialized || channel < 0 || channel >= NUM_CHANNELS)
return;
channels[channel].sfxinfo = NULL;
}
static boolean I_Montauk_SoundIsPlaying(int channel) {
if (!sound_initialized || channel < 0 || channel >= NUM_CHANNELS)
return false;
return channels[channel].sfxinfo != NULL;
}
static void I_Montauk_PrecacheSounds(sfxinfo_t *sounds, int num_sounds) {
/* No-op: we load on demand */
(void)sounds;
(void)num_sounds;
}
static snddevice_t sound_montauk_devices[] = {
SNDDEVICE_SB,
SNDDEVICE_PAS,
SNDDEVICE_GUS,
SNDDEVICE_WAVEBLASTER,
SNDDEVICE_SOUNDCANVAS,
SNDDEVICE_AWE32,
};
sound_module_t DG_sound_module = {
sound_montauk_devices,
arrlen(sound_montauk_devices),
I_Montauk_InitSound,
I_Montauk_ShutdownSound,
I_Montauk_GetSfxLumpNum,
I_Montauk_UpdateSound,
I_Montauk_UpdateSoundParams,
I_Montauk_StartSound,
I_Montauk_StopSound,
I_Montauk_SoundIsPlaying,
I_Montauk_PrecacheSounds,
};
/* ========================================================================
music_module_t implementation (stub - no MIDI synthesis)
======================================================================== */
static boolean I_Montauk_InitMusic(void) { return true; }
static void I_Montauk_ShutdownMusic(void) {}
static void I_Montauk_SetMusicVolume(int vol) { (void)vol; }
static void I_Montauk_PauseMusic(void) {}
static void I_Montauk_ResumeMusic(void) {}
static void *I_Montauk_RegisterSong(void *data, int len) { (void)data; (void)len; return (void *)1; }
static void I_Montauk_UnRegisterSong(void *h) { (void)h; }
static void I_Montauk_PlaySong(void *h, boolean loop) { (void)h; (void)loop; }
static void I_Montauk_StopSong(void) {}
static boolean I_Montauk_MusicIsPlaying(void) { return false; }
static void I_Montauk_PollMusic(void) {}
static snddevice_t music_montauk_devices[] = {
SNDDEVICE_SB,
SNDDEVICE_ADLIB,
SNDDEVICE_GUS,
};
music_module_t DG_music_module = {
music_montauk_devices,
arrlen(music_montauk_devices),
I_Montauk_InitMusic,
I_Montauk_ShutdownMusic,
I_Montauk_SetMusicVolume,
I_Montauk_PauseMusic,
I_Montauk_ResumeMusic,
I_Montauk_RegisterSong,
I_Montauk_UnRegisterSong,
I_Montauk_PlaySong,
I_Montauk_StopSong,
I_Montauk_MusicIsPlaying,
I_Montauk_PollMusic,
};
-8
View File
@@ -1,8 +0,0 @@
[app]
name = "DOOM"
binary = "doom.elf"
icon = "doom.svg"
[menu]
category = "Games"
visible = true