started backporting the eradicate code
[dosdemo] / src / dos / audos.c
diff --git a/src/dos/audos.c b/src/dos/audos.c
new file mode 100644 (file)
index 0000000..513bf89
--- /dev/null
@@ -0,0 +1,211 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "audio.h"
+#include "midasdll.h"
+
+#define SET_MUS_VOL(vol) \
+       do { \
+               int mv = (vol) * vol_master >> 10; \
+               MIDASsetMusicVolume(modplay, mv ? mv + 1 : 0); \
+       } while(0)
+
+extern int force_snd_config;
+
+static MIDASmodulePlayHandle modplay;
+static struct au_module *curmod;
+
+static int vol_master, vol_mus, vol_sfx;
+
+int au_init(void)
+{
+       modplay = 0;
+       curmod = 0;
+       vol_master = vol_mus = vol_sfx = 255;
+
+       MIDASstartup();
+
+       if(force_snd_config || (!MIDASloadConfig("sound.cfg") && !MIDASdetectSoundCard())) {
+               if(MIDASconfig()) {
+                       if(!MIDASsaveConfig("sound.cfg")) {
+                               fprintf(stderr, "failed to save sound card configuration\n");
+                       }
+               }
+       }
+
+       MIDASinit();
+
+       MIDASstartBackgroundPlay(0);
+       return 0;
+}
+
+void au_shutdown(void)
+{
+       if(curmod) {
+               au_stop_module(curmod);
+       }
+       MIDASstopBackgroundPlay();
+       MIDASclose();
+}
+
+struct au_module *au_load_module(const char *fname)
+{
+       static MIDASmoduleInfo info;
+       struct au_module *mod;
+       char *name, *end;
+
+       if(!(mod = malloc(sizeof *mod))) {
+               fprintf(stderr, "au_load_module: failed to allocate module\n");
+               return 0;
+       }
+
+       if(!(mod->impl = MIDASloadModule((char*)fname))) {
+               fprintf(stderr, "au_load_module: failed to load module: %s\n", fname);
+               free(mod);
+               return 0;
+       }
+
+       name = 0;
+       if(MIDASgetModuleInfo(mod->impl, &info)) {
+               name = info.songName;
+               end = name + strlen(name) - 1;
+               while(end >= name && isspace(*end)) {
+                       *end-- = 0;
+               }
+               if(!*name) name = 0;
+       }
+
+       if(!name) {
+               /* fallback to using the filename */
+               if((name = strrchr(fname, '/')) || (name = strrchr(fname, '\\'))) {
+                       name++;
+               } else {
+                       name = (char*)fname;
+               }
+       }
+
+       if(!(mod->name = malloc(strlen(name) + 1))) {
+               fprintf(stderr, "au_load_module: mod->name malloc failed\n");
+               MIDASfreeModule(mod->impl);
+               return 0;
+       }
+       strcpy(mod->name, name);
+
+       printf("loaded module \"%s\" (%s)\n", name, fname);
+       return mod;
+}
+
+void au_free_module(struct au_module *mod)
+{
+       if(!mod) return;
+
+       if(mod == curmod) {
+               au_stop_module(curmod);
+       }
+       MIDASfreeModule(mod->impl);
+       free(mod->name);
+       free(mod);
+}
+
+int au_play_module(struct au_module *mod)
+{
+       if(curmod) {
+               if(curmod == mod) return 0;
+               au_stop_module(curmod);
+       }
+
+       if(!(modplay = MIDASplayModule(mod->impl, 1))) {
+               fprintf(stderr, "au_play_module: failed to play module: %s\n", mod->name);
+               return -1;
+       }
+       SET_MUS_VOL(vol_mus);
+       curmod = mod;
+       return 0;
+}
+
+void au_update(void)
+{
+}
+
+int au_stop_module(struct au_module *mod)
+{
+       if(mod && curmod != mod) return -1;
+       if(!curmod) return -1;
+
+       MIDASstopModule(modplay);
+       curmod = 0;
+       return 0;
+}
+
+int au_module_state(struct au_module *mod)
+{
+       if(mod) {
+               return curmod == mod ? AU_PLAYING : AU_STOPPED;
+       }
+       return curmod ? AU_PLAYING : AU_STOPPED;
+}
+
+int au_volume(int vol)
+{
+       AU_VOLADJ(vol_master, vol);
+       if(vol != vol_master) {
+               vol_master = vol;
+
+               au_sfx_volume(vol_sfx);
+               au_music_volume(vol_mus);
+       }
+       return vol_master;
+}
+
+int au_sfx_volume(int vol)
+{
+       AU_VOLADJ(vol_sfx, vol);
+       vol_sfx = vol;
+
+       /* TODO set sfx volume */
+       return vol_sfx;
+}
+
+
+int au_music_volume(int vol)
+{
+       AU_VOLADJ(vol_mus, vol);
+       vol_mus = vol;
+
+       if(curmod) {
+               SET_MUS_VOL(vol);
+       }
+       return vol_mus;
+}
+
+/* when using MIDAS, we can't access the PIT directly, so we don't build timer.c
+ * and implement all the timer functions here, using MIDAS callbacks
+ */
+static volatile unsigned long ticks;
+static unsigned long tick_interval;
+
+static void MIDAS_CALL midas_timer(void)
+{
+       ticks++;
+}
+
+/* macro to divide and round to the nearest integer */
+#define DIV_ROUND(a, b) \
+       ((a) / (b) + ((a) % (b)) / ((b) / 2))
+
+void init_timer(int res_hz)
+{
+       MIDASsetTimerCallbacks(res_hz * 1000, 0, midas_timer, 0, 0);
+       tick_interval = DIV_ROUND(1000, res_hz);
+}
+
+void reset_timer(void)
+{
+       ticks = 0;
+}
+
+unsigned long get_msec(void)
+{
+       return ticks * tick_interval;
+}