diff --git a/CMakeLists.txt b/CMakeLists.txt index fb71553e2..aafa46b1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,6 +144,12 @@ else() option(NEW_DYNAREC "Use the PCem v15 (\"new\") dynamic recompiler" OFF) endif() +if((CMAKE_SYSTEM_NAME STREQUAL "NetBSD") OR (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")) + option(AUDIO4 "Use audio(4) as sound backend" ON) +else() + set(AUDIO4 OFF) +endif() + if(WIN32) set(QT ON) option(CPPTHREADS "C++11 threads" OFF) diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index e8c5fbac9..c58d595c5 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -20,8 +20,8 @@ #ifndef EMU_86BOX_H #define EMU_86BOX_H -#ifdef __NetBSD__ -/* Doesn't compile on NetBSD without this include */ +#if defined(__NetBSD__) || defined(__OpenBSD__) +/* Doesn't compile on NetBSD/OpenBSD without this include */ #include #endif diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index a381051ba..955e96f5a 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -53,7 +53,10 @@ add_library(snd OBJECT snd_opl_esfm.c ) -if(OPENAL) +# TODO: Should platform-specific audio driver be here? +if(AUDIO4) + target_sources(snd PRIVATE audio4.c) +elseif(OPENAL) if(VCPKG_TOOLCHAIN) find_package(OpenAL CONFIG REQUIRED) elseif(MINGW) diff --git a/src/sound/audio4.c b/src/sound/audio4.c new file mode 100644 index 000000000..32989eecf --- /dev/null +++ b/src/sound/audio4.c @@ -0,0 +1,160 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Interface to audio(4) for NetBSD/OpenBSD. + * + * + * Authors: Nishi + * + * Copyright 2025 Nishi. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include <86box/86box.h> +#include <86box/sound.h> +#include <86box/plat_unused.h> + +#if defined(OpenBSD) && OpenBSD >= 201709 +#define USE_NEW_API +#endif + +#define I_NORMAL 0 +#define I_MUSIC 1 +#define I_WT 2 +#define I_CD 3 +#define I_MIDI 4 + +static int audio[5] = {-1, -1, -1, -1, -1}; +#ifdef USE_NEW_API +static struct audio_swpar info[5]; +#else +static audio_info_t info[5]; +#endif +static int freqs[5] = {SOUND_FREQ, MUSIC_FREQ, WT_FREQ, CD_FREQ, 0}; + +void closeal(void){ + int i; + for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ + if(audio[i] != -1){ + close(audio[i]); + } + audio[i] = -1; + } +} + +void inital(void){ + int i; + for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ + audio[i] = open("/dev/audio", O_WRONLY); + if(audio[i] == -1) audio[i] = open("/dev/audio0", O_WRONLY); + if(audio[i] != -1){ +#ifdef USE_NEW_API + AUDIO_INITPAR(&info[i]); + ioctl(audio[i], AUDIO_GETPAR, &info[i]); + info[i].pchan = 2; + info[i].bits = 16; + info[i].bps = 2; + ioctl(audio[i], AUDIO_SETPAR, &info[i]); +#else + AUDIO_INITINFO(&info[i]); +#if defined(__NetBSD__) && (__NetBSD_Version__ >= 900000000) + ioctl(audio[i], AUDIO_GETFORMAT, &info[i]); +#else + ioctl(audio[i], AUDIO_GETINFO, &info[i]); +#endif + info[i].play.channels = 2; + info[i].play.precision = 16; + info[i].play.encoding = AUDIO_ENCODING_SLINEAR; + info[i].hiwat = 5; + info[i].lowat = 3; + ioctl(audio[i], AUDIO_SETINFO, &info[i]); +#endif + } + } +} + +void givealbuffer_common(const void *buf, const uint8_t src, const int size){ + const int freq = freqs[src]; + int16_t* output; + int output_size; + int16_t* conv; + int conv_size; + int i; + double gain; + int target_rate; + if(audio[src] == -1) return; + + gain = sound_muted ? 0.0 : pow(10.0, (double) sound_gain / 20.0); + + if(sound_is_float){ + float* input = (float*)buf; + conv_size = sizeof(int16_t) * size; + conv = malloc(conv_size); + for(i = 0; i < conv_size / sizeof(int16_t); i++){ + conv[i] = 32767 * input[i]; + } + }else{ + conv_size = size * sizeof(int16_t); + conv = malloc(conv_size); + memcpy(conv, buf, conv_size); + } + +#ifdef USE_NEW_API + target_rate = info[src].rate; +#else + target_rate = info[src].play.sample_rate; +#endif + + output_size = (double)conv_size * target_rate / freq; + output_size -= output_size % 4; + output = malloc(output_size); + + for(i = 0; i < output_size / sizeof(int16_t) / 2; i++){ + int ind = i * freq / target_rate * 2; + output[i * 2 + 0] = conv[ind + 0] * gain; + output[i * 2 + 1] = conv[ind + 1] * gain; + } + + write(audio[src], output, output_size); + + free(conv); + free(output); +} + +void givealbuffer(const void *buf){ + givealbuffer_common(buf, I_NORMAL, SOUNDBUFLEN << 1); +} + +void givealbuffer_music(const void *buf){ + givealbuffer_common(buf, I_MUSIC, MUSICBUFLEN << 1); +} + +void givealbuffer_wt(const void *buf){ + givealbuffer_common(buf, I_WT, WTBUFLEN << 1); +} + +void givealbuffer_cd(const void *buf){ + givealbuffer_common(buf, I_CD, CD_BUFLEN << 1); +} +void givealbuffer_midi(const void *buf, const uint32_t size){ + givealbuffer_common(buf, I_MIDI, (int) size); +} + +void al_set_midi(const int freq, UNUSED(const int buf_size)){ + freqs[I_MIDI] = freq; +}