Skip to content

Commit

Permalink
Implemented DosBeep in doscalls and a simple audio mixer in lib2ine.
Browse files Browse the repository at this point in the history
  • Loading branch information
icculus committed Jul 10, 2018
1 parent 8c5d43f commit 490702c
Show file tree
Hide file tree
Showing 7 changed files with 324 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Expand Up @@ -96,8 +96,10 @@ target_link_libraries(viocalls ncursesw)

# !!! FIXME: clean this up/
if(LX_LEGACY)
target_link_libraries(2ine "${CMAKE_CURRENT_SOURCE_DIR}/libSDL2-2.0.so.0")
target_link_libraries(pmwin "${CMAKE_CURRENT_SOURCE_DIR}/libSDL2-2.0.so.0")
else()
target_link_libraries(2ine "SDL2")
target_link_libraries(pmwin "SDL2")
endif()

Expand Down
163 changes: 156 additions & 7 deletions lib2ine.c
Expand Up @@ -23,8 +23,10 @@
#include <pthread.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <assert.h>

#include "lib2ine.h"
#include "SDL.h"

extern char **environ;

Expand Down Expand Up @@ -640,6 +642,157 @@ static void prepOs2Drives(void)
#endif
}

typedef struct LxAudioGeneratorInfo
{
LxAudioGeneratorFn fn;
void *data;
struct LxAudioGeneratorInfo *next;
} LxAudioGeneratorInfo;

static LxAudioGeneratorInfo *audio_generators = NULL;
static SDL_AudioDeviceID sdl_audio_device = 0;
static SDL_AudioSpec sdl_audio_spec;
static Uint32 no_audio_generators_timeout = 0;

static int SDLCALL closeAudioDeviceThread(void *arg)
{
const SDL_AudioDeviceID dev = (SDL_AudioDeviceID) (size_t) arg;
//printf("2ine: Closing idle audio device %u.\n", (uint) dev);
SDL_CloseAudioDevice(dev);
return 0;
}

static void closeAudioDeviceFromAnotherThread(void)
{
FIXME("Make this atomic");
const SDL_AudioDeviceID dev = sdl_audio_device;
if (!sdl_audio_device) {
return;
}
sdl_audio_device = 0;

SDL_Thread *thread = SDL_CreateThread(closeAudioDeviceThread, "2ine_close_audio_device", (void *) (size_t) dev);
if (thread) {
SDL_DetachThread(thread);
} else {
sdl_audio_device = dev; // oh well.
}
}


static void SDLCALL audioCallback(void *userdata, Uint8 *stream, int len)
{
memset(stream, '\0', len);
LxAudioGeneratorInfo *generator = audio_generators;
if (!generator) {
if (!no_audio_generators_timeout) {
no_audio_generators_timeout = SDL_GetTicks() + 5000;
} else if (SDL_TICKS_PASSED(SDL_GetTicks(), no_audio_generators_timeout)) {
closeAudioDeviceFromAnotherThread();
}
return;
}

no_audio_generators_timeout = 0;

const int samples = len / sizeof (float);
LxAudioGeneratorInfo *prev = NULL;
while (generator) {
LxAudioGeneratorInfo *next = generator->next;
if (generator->fn(generator->data, (float *) stream, samples, sdl_audio_spec.freq)) {
prev = generator;
} else {
// remove this generator, it's done.
if (prev) {
prev->next = next;
} else {
assert(generator == audio_generators);
audio_generators = next;
}
free(generator);
}
generator = next;
}
}

static int registerAudioGenerator_lib2ine(LxAudioGeneratorFn fn, void *data, const int singleton)
{
if (!sdl_audio_device) {
SDL_Init(SDL_INIT_AUDIO);
SDL_AudioSpec spec;
SDL_zero(spec);
spec.freq = 48000;
spec.format = AUDIO_F32SYS;
spec.channels = 1;
spec.samples = 1024;
spec.callback = audioCallback;
sdl_audio_device = SDL_OpenAudioDevice(NULL, 0, &spec, &sdl_audio_spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
if (!sdl_audio_device) {
SDL_QuitSubSystem(SDL_INIT_AUDIO);
return 0;
}
no_audio_generators_timeout = 0;
SDL_PauseAudioDevice(sdl_audio_device, 0);
}

LxAudioGeneratorInfo *info = (LxAudioGeneratorInfo *) malloc(sizeof (LxAudioGeneratorInfo *));
if (!info) {
return 0;
}

info->fn = fn;
info->data = data;

SDL_LockAudioDevice(sdl_audio_device);

if (singleton) {
for (LxAudioGeneratorInfo *i = audio_generators; i != NULL; i = i->next) {
if (i->fn == fn) {
SDL_UnlockAudioDevice(sdl_audio_device);
free(info);
return 2; // already added.
}
}
}

no_audio_generators_timeout = 0;
info->next = audio_generators;
audio_generators = info;
SDL_UnlockAudioDevice(sdl_audio_device);
return 1;
} // registerAudioGenerator_lib2ine


static void lib2ine_shutdown(void)
{
if (sdl_audio_device) {
// let the audio callback run about two more times, to let any last queued things fully render.
SDL_Delay(((sdl_audio_spec.samples * 1000) / sdl_audio_spec.freq) * 2);
SDL_CloseAudioDevice(sdl_audio_device);
SDL_QuitSubSystem(SDL_INIT_AUDIO);
sdl_audio_device = 0;
}

LxAudioGeneratorInfo *generator = audio_generators;
audio_generators = NULL;
while (generator) {
LxAudioGeneratorInfo *next = generator->next;
free(generator);
generator = next;
}

for (int i = 0; i < (sizeof (GLoaderState.disks) / sizeof (GLoaderState.disks[0])); i++) {
free(GLoaderState.disks[i]);
GLoaderState.disks[i] = NULL;
}

free(GLoaderState.pib.pib_pchenv);
GLoaderState.pib.pib_pchenv = NULL;

memset(&GLoaderState, '\0', sizeof (GLoaderState));
pthread_key_delete(tlskey);
}

LX_NATIVE_CONSTRUCTOR(lib2ine)
{
if (pthread_key_create(&tlskey, NULL) != 0) {
Expand All @@ -662,6 +815,8 @@ LX_NATIVE_CONSTRUCTOR(lib2ine)
GLoaderState.loadModule = loadModule_lib2ine;
GLoaderState.makeUnixPath = makeUnixPath_lib2ine;
GLoaderState.terminate = terminate_lib2ine;
GLoaderState.registerAudioGenerator = registerAudioGenerator_lib2ine;
GLoaderState.lib2ine_shutdown = lib2ine_shutdown;

cfgLoadFiles();
prepOs2Drives();
Expand Down Expand Up @@ -689,13 +844,7 @@ LX_NATIVE_CONSTRUCTOR(lib2ine)

LX_NATIVE_DESTRUCTOR(lib2ine)
{
for (int i = 0; i < (sizeof (GLoaderState.disks) / sizeof (GLoaderState.disks[0])); i++) {
free(GLoaderState.disks[i]);
GLoaderState.disks[i] = NULL;
}
free(GLoaderState.pib.pib_pchenv);
memset(&GLoaderState, '\0', sizeof (GLoaderState));
pthread_key_delete(tlskey);
lib2ine_shutdown();
}

// end of lib2ine.c ...
Expand Down
9 changes: 9 additions & 0 deletions lib2ine.h
Expand Up @@ -273,6 +273,13 @@ typedef struct LxPostTIB
void *anchor_block;
} LxPostTIB;

// There are a few things that need access to the sound hardware:
// DosBeep(), MMOS/2, DART, basic system sounds, etc. We unify all this
// into a single SDL audio device open where possible, so that we don't
// have to deal with multiple devices, but that means it has to move into
// lib2ine so multiple libraries can access it.
typedef int (*LxAudioGeneratorFn)(void *data, float *stream, int len, int freq);

#define LXTIBSIZE (sizeof (LxTIB) + sizeof (LxTIB2) + sizeof (LxPostTIB))

#define LX_MAX_LDT_SLOTS 8192
Expand Down Expand Up @@ -318,6 +325,8 @@ typedef struct LxLoaderState
LxModule *(*loadModule)(const char *modname);
char *(*makeUnixPath)(const char *os2path, uint32 *err);
void __attribute__((noreturn)) (*terminate)(const uint32 exitcode);
int (*registerAudioGenerator)(LxAudioGeneratorFn fn, void *data, const int singleton);
void (*lib2ine_shutdown)(void);
} LxLoaderState;

typedef const LxExport *(*LxNativeModuleInitEntryPoint)(uint32 *lx_num_exports);
Expand Down
2 changes: 2 additions & 0 deletions lx_loader.c
Expand Up @@ -667,6 +667,8 @@ static void freeLxModule(LxModule *lxmod);

static __attribute__((noreturn)) void lxTerminate(const uint32 exitcode)
{
GLoaderState.lib2ine_shutdown();

// free the actual .exe
freeLxModule(GLoaderState.main_module);

Expand Down
10 changes: 10 additions & 0 deletions native/doscalls-lx.h
Expand Up @@ -72,6 +72,12 @@ static APIRET16 bridge16to32_Dos16GetMachineMode(uint8 *args) {
return Dos16GetMachineMode(pmode);
}

static APIRET16 bridge16to32_Dos16Beep(uint8 *args) {
LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, dur);
LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, freq);
return Dos16Beep(freq, dur);
}

static APIRET16 bridge16to32_Dos16ChDir(uint8 *args) {
LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(ULONG, res);
LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PSZ, pszDir);
Expand Down Expand Up @@ -264,6 +270,7 @@ LX_NATIVE_MODULE_16BIT_SUPPORT()
LX_NATIVE_MODULE_16BIT_API(Dos16FreeSeg)
LX_NATIVE_MODULE_16BIT_API(Dos16GetHugeShift)
LX_NATIVE_MODULE_16BIT_API(Dos16GetMachineMode)
LX_NATIVE_MODULE_16BIT_API(Dos16Beep)
LX_NATIVE_MODULE_16BIT_API(Dos16ChDir)
LX_NATIVE_MODULE_16BIT_API(Dos16ChgFilePtr)
LX_NATIVE_MODULE_16BIT_API(Dos16Close)
Expand Down Expand Up @@ -308,6 +315,7 @@ static int init16_doscalls(void) {
LX_NATIVE_INIT_16BIT_BRIDGE(Dos16FreeSeg, 2)
LX_NATIVE_INIT_16BIT_BRIDGE(Dos16GetHugeShift, 4)
LX_NATIVE_INIT_16BIT_BRIDGE(Dos16GetMachineMode, 4)
LX_NATIVE_INIT_16BIT_BRIDGE(Dos16Beep, 4)
LX_NATIVE_INIT_16BIT_BRIDGE(Dos16ChDir, 8)
LX_NATIVE_INIT_16BIT_BRIDGE(Dos16ChgFilePtr, 12)
LX_NATIVE_INIT_16BIT_BRIDGE(Dos16Close, 2)
Expand Down Expand Up @@ -349,6 +357,7 @@ LX_NATIVE_MODULE_INIT({ if (!init16_doscalls()) return 0; })
LX_NATIVE_EXPORT16(Dos16FreeSeg, 39),
LX_NATIVE_EXPORT16(Dos16GetHugeShift, 41),
LX_NATIVE_EXPORT16(Dos16GetMachineMode, 49),
LX_NATIVE_EXPORT16(Dos16Beep, 50),
LX_NATIVE_EXPORT16(Dos16ChDir, 57),
LX_NATIVE_EXPORT16(Dos16ChgFilePtr, 58),
LX_NATIVE_EXPORT16(Dos16Close, 59),
Expand Down Expand Up @@ -404,6 +413,7 @@ LX_NATIVE_MODULE_INIT({ if (!init16_doscalls()) return 0; })
LX_NATIVE_EXPORT(DosRead, 281),
LX_NATIVE_EXPORT(DosWrite, 282),
LX_NATIVE_EXPORT(DosExecPgm, 283),
LX_NATIVE_EXPORT(DosBeep, 286),
LX_NATIVE_EXPORT(DosSetProcessCp, 289),
LX_NATIVE_EXPORT(DosQueryCp, 291),
LX_NATIVE_EXPORT(DosExitList, 296),
Expand Down

0 comments on commit 490702c

Please sign in to comment.