--- /dev/null
+// doomgeneric for Allegro library
+
+#include "doomkeys.h"
+#include "i_system.h"
+#include "i_video.h"
+#include "m_argv.h"
+#include "doomgeneric.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define ALLEGRO_NO_KEY_DEFINES 1
+#include <allegro.h>
+#undef uint32_t // ugly hack because Allegro is Old and doesn't know modern GCC has stdint.h
+
+
+static bool videomode_set = false;
+
+static BITMAP *temp_bitmap = NULL;
+
+static PALETTE pal;
+
+#define KEYQUEUE_SIZE 16
+
+static volatile unsigned int s_KeyQueue[KEYQUEUE_SIZE];
+static volatile unsigned int s_KeyQueueWriteIndex = 0;
+static unsigned int s_KeyQueueReadIndex = 0;
+
+static volatile unsigned int s_ticks = 0;
+
+
+void key_callback(int scancode) {
+ // this is in interrupt context, avoid heavy processing and be careful about volatile writes
+ s_KeyQueue[s_KeyQueueWriteIndex] = scancode;
+ s_KeyQueueWriteIndex = (s_KeyQueueWriteIndex + 1) % KEYQUEUE_SIZE;
+}
+END_OF_FUNCTION(key_callback);
+
+
+void timer_callback(void) {
+ // also in interrupt context
+ s_ticks++;
+}
+END_OF_FUNCTION(timer_callback);
+
+
+void DG_Init() {
+ int result;
+
+ printf("Initializing Allegro\n");
+
+ result = allegro_init();
+ if (result != 0)
+ {
+ I_Error("Allegro init failed: %d %s\n", result, allegro_error);
+ }
+
+ I_AtExit(allegro_exit, true);
+
+ LOCK_FUNCTION(key_callback);
+ LOCK_VARIABLE(s_KeyQueue);
+ LOCK_VARIABLE(s_KeyQueueWriteIndex);
+ LOCK_VARIABLE(s_KeyQueueReadIndex);
+
+ LOCK_FUNCTION(timer_callback);
+ LOCK_VARIABLE(s_ticks);
+
+ install_keyboard();
+ keyboard_lowlevel_callback = key_callback;
+
+ install_timer();
+ result = install_int(timer_callback, 1);
+ if (result < 0) {
+ I_Error("Unable to install timer: %d %s\n", result, allegro_error);
+ }
+
+ // don't set video mode yet so initialization messages stay on screen
+}
+
+
+static void back_to_text_mode(void) {
+ set_gfx_mode(GFX_TEXT, 80, 25, 0, 0);
+}
+
+
+void DG_DrawFrame()
+{
+ if (!DG_ScreenBuffer) {
+ return;
+ }
+
+ if (!videomode_set) {
+ int y;
+ int result;
+
+#ifdef CMAP256
+ set_color_depth(8);
+#else // CMAP256
+ // does not seem to work on real DOS hardware
+ set_color_depth(32);
+#endif // CMAP256
+
+ result = set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, DOOMGENERIC_RESX, DOOMGENERIC_RESY, 0, 0);
+ if (result < 0) {
+ I_Error("Failed to set video mode: %s\n", allegro_error);
+ }
+
+ // register an exit handler to return to text mode
+ // while this is also done by allegro_exit handler registered earlier
+ // that's too late for ENDOOM screen to work correctly
+ I_AtExit(back_to_text_mode, true);
+
+ if (!screen) {
+ I_Error("screen is null\n");
+ }
+
+ temp_bitmap = create_bitmap(DOOMGENERIC_RESX, DOOMGENERIC_RESY);
+ if (!temp_bitmap) {
+ I_Error("Failed to create temp bitmap\n");
+ }
+
+ // this is an evil hack
+ // replace the internal line pointers with pointers into DG_ScreenBuffer
+ // this avoids some copying
+ // it might crash when freeing the bitmap but we never do
+ for (y = 0; y < DOOMGENERIC_RESY; y++) {
+ temp_bitmap->line[y] = (unsigned char *) &DG_ScreenBuffer[y * DOOMGENERIC_RESX];
+ }
+
+ clear_bitmap(temp_bitmap);
+
+ videomode_set = true;
+ palette_changed = true;
+ }
+
+#ifdef CMAP256
+
+ // changing palette implicitly waits for vsync
+ // TODO: should do it explicitly in case where we don't change palette
+ if (palette_changed) {
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ // allegro uses VGA range 0..63
+ pal[i].r = colors[i].r >> 2;
+ pal[i].g = colors[i].g >> 2;
+ pal[i].b = colors[i].b >> 2;
+ }
+ set_palette(pal);
+
+ palette_changed = false;
+ }
+
+#endif // CMAP256
+
+ blit(temp_bitmap, screen, 0, 0, 0, 0, DOOMGENERIC_RESX, DOOMGENERIC_RESY);
+}
+
+
+void DG_SleepMs(uint32_t ms)
+{
+ rest(ms);
+}
+
+
+uint32_t DG_GetTicksMs()
+{
+ return s_ticks;
+}
+
+
+int DG_GetKey(int *pressed, unsigned char *doomKey)
+{
+ if (s_KeyQueueReadIndex == s_KeyQueueWriteIndex){
+ //key queue is empty
+ return 0;
+ } else {
+ bool released;
+ short keyData = 0;
+ int scancode = s_KeyQueue[s_KeyQueueReadIndex];
+ s_KeyQueueReadIndex++;
+ s_KeyQueueReadIndex %= KEYQUEUE_SIZE;
+
+ released = scancode & 0x80;
+ *pressed = !released;
+
+ scancode = scancode & 0x7F;
+
+ switch (scancode) {
+ case __allegro_KEY_RIGHT:
+ keyData = KEY_RIGHTARROW;
+ break;
+
+ case __allegro_KEY_LEFT:
+ keyData = KEY_LEFTARROW;
+ break;
+
+ case __allegro_KEY_UP:
+ keyData = KEY_UPARROW;
+ break;
+
+ case __allegro_KEY_DOWN:
+ keyData = KEY_DOWNARROW;
+ break;
+
+ case __allegro_KEY_COMMA:
+ keyData = KEY_STRAFE_L;
+ break;
+
+ case __allegro_KEY_STOP:
+ keyData = KEY_STRAFE_R;
+ break;
+
+ case __allegro_KEY_SPACE:
+ keyData = KEY_USE;
+ break;
+
+ case __allegro_KEY_LCONTROL:
+ keyData = KEY_FIRE;
+ break;
+
+ case __allegro_KEY_ESC:
+ keyData = KEY_ESCAPE;
+ break;
+
+ case __allegro_KEY_ENTER:
+ keyData = KEY_ENTER;
+ break;
+
+ case __allegro_KEY_TAB:
+ keyData = KEY_TAB;
+ break;
+
+ case __allegro_KEY_F1:
+ keyData = KEY_F1;
+ break;
+
+ case __allegro_KEY_F2:
+ keyData = KEY_F2;
+ break;
+
+ case __allegro_KEY_F3:
+ keyData = KEY_F3;
+ break;
+
+ case __allegro_KEY_F4:
+ keyData = KEY_F4;
+ break;
+
+ case __allegro_KEY_F5:
+ keyData = KEY_F5;
+ break;
+
+ case __allegro_KEY_F6:
+ keyData = KEY_F6;
+ break;
+
+ case __allegro_KEY_F7:
+ keyData = KEY_F7;
+ break;
+
+ case __allegro_KEY_F8:
+ keyData = KEY_F8;
+ break;
+
+ case __allegro_KEY_F9:
+ keyData = KEY_F9;
+ break;
+
+ case __allegro_KEY_F10:
+ keyData = KEY_F10;
+ break;
+
+ case __allegro_KEY_F11:
+ keyData = KEY_F11;
+ break;
+
+ case __allegro_KEY_F12:
+ keyData = KEY_F12;
+ break;
+
+ case __allegro_KEY_BACKSPACE:
+ keyData = KEY_BACKSPACE;
+ break;
+
+ case __allegro_KEY_PAUSE:
+ keyData = KEY_PAUSE;
+ break;
+
+ case __allegro_KEY_EQUALS:
+ keyData = KEY_EQUALS;
+ break;
+
+ case __allegro_KEY_MINUS:
+ keyData = KEY_MINUS;
+ break;
+
+ case __allegro_KEY_LSHIFT:
+ case __allegro_KEY_RSHIFT:
+ keyData = KEY_RSHIFT;
+ break;
+
+ case __allegro_KEY_RCONTROL:
+ keyData = KEY_RCTRL;
+ break;
+
+ case __allegro_KEY_ALT:
+ keyData = KEY_RALT;
+ break;
+
+ case __allegro_KEY_CAPSLOCK:
+ keyData = KEY_CAPSLOCK;
+ break;
+
+ case __allegro_KEY_NUMLOCK:
+ keyData = KEY_NUMLOCK;
+ break;
+
+ case __allegro_KEY_SCRLOCK:
+ keyData = KEY_SCRLCK;
+ break;
+
+ case __allegro_KEY_PRTSCR:
+ keyData = KEY_PRTSCR;
+ break;
+
+ case __allegro_KEY_HOME:
+ keyData = KEY_HOME;
+ break;
+
+ case __allegro_KEY_END:
+ keyData = KEY_END;
+ break;
+
+ case __allegro_KEY_PGUP:
+ keyData = KEY_PGUP;
+ break;
+
+ case __allegro_KEY_PGDN:
+ keyData = KEY_PGDN;
+ break;
+
+ case __allegro_KEY_INSERT:
+ keyData = KEY_INS;
+ break;
+
+ case __allegro_KEY_DEL:
+ keyData = KEY_DEL;
+ break;
+
+ case __allegro_KEY_0_PAD:
+ keyData = KEYP_0;
+ break;
+
+ case __allegro_KEY_1_PAD:
+ keyData = KEYP_1;
+ break;
+
+ case __allegro_KEY_2_PAD:
+ keyData = KEYP_2;
+ break;
+
+ case __allegro_KEY_3_PAD:
+ keyData = KEYP_3;
+ break;
+
+ case __allegro_KEY_4_PAD:
+ keyData = KEYP_4;
+ break;
+
+ case __allegro_KEY_5_PAD:
+ keyData = KEYP_5;
+ break;
+
+ case __allegro_KEY_6_PAD:
+ keyData = KEYP_6;
+ break;
+
+ case __allegro_KEY_7_PAD:
+ keyData = KEYP_7;
+ break;
+
+ case __allegro_KEY_8_PAD:
+ keyData = KEYP_8;
+ break;
+
+ case __allegro_KEY_9_PAD:
+ keyData = KEYP_9;
+ break;
+
+ case __allegro_KEY_SLASH_PAD:
+ keyData = KEYP_DIVIDE;
+ break;
+
+ case __allegro_KEY_PLUS_PAD:
+ keyData = KEYP_PLUS;
+ break;
+
+ case __allegro_KEY_MINUS_PAD:
+ keyData = KEYP_MINUS;
+ break;
+
+ case __allegro_KEY_ASTERISK:
+ keyData = KEYP_MULTIPLY;
+ break;
+
+ case __allegro_KEY_DEL_PAD:
+ keyData = KEYP_PERIOD;
+ break;
+
+ case __allegro_KEY_EQUALS_PAD:
+ keyData = KEYP_EQUALS;
+ break;
+
+ case __allegro_KEY_ENTER_PAD:
+ keyData = KEYP_ENTER;
+ break;
+
+ default:
+ keyData = scancode_to_ascii(scancode);
+ break;
+ }
+
+ if (keyData != 0) {
+ *doomKey = keyData & 0xFF;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+void DG_SetWindowTitle(const char *title)
+{
+ set_window_title(title);
+}
+
+
+int main(int argc, char **argv)
+{
+ doomgeneric_Create(argc, argv);
+
+ while (true)
+ {
+ doomgeneric_Tick();
+ }
+
+ return 0;
+}
--- /dev/null
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// DESCRIPTION:
+// System interface for music.
+//
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "config.h"
+#include "doomtype.h"
+#include "memio.h"
+#include "mus2mid.h"
+
+#include "deh_str.h"
+#include "gusconf.h"
+#include "i_sound.h"
+#include "i_system.h"
+#include "i_swap.h"
+#include "m_argv.h"
+#include "m_config.h"
+#include "m_misc.h"
+#include "sha1.h"
+#include "w_wad.h"
+#include "z_zone.h"
+
+#include <allegro/base.h>
+#include <allegro/midi.h>
+#include <allegro/sound.h>
+#include <allegro/system.h>
+
+
+#define MAXMIDLENGTH (96 * 1024)
+#define MID_HEADER_MAGIC "MThd"
+#define MUS_HEADER_MAGIC "MUS\x1a"
+
+
+static boolean music_initialized = false;
+
+
+static boolean musicpaused = false;
+static int current_music_volume;
+
+
+// Currently playing music track.
+MIDI *current_track_music = NULL;
+
+// If true, the currently playing track is being played on loop.
+static boolean current_track_loop;
+
+
+
+// Shutdown music
+static void I_Allegro_ShutdownMusic(void)
+{
+ // nothing here
+ // TODO: stop song?
+}
+
+
+// Initialize music subsystem
+static boolean I_Allegro_InitMusic(void)
+{
+ // nothing here, it's all done by I_Allegro_InitSound
+ music_initialized = true;
+
+ return true;
+}
+
+
+// Set music volume (0 - 127)
+static void I_Allegro_SetMusicVolume(int volume)
+{
+ int digivol = -1;
+ get_volume(&digivol, NULL);
+ // allegro range 0 - 255
+ set_volume(digivol, volume * 2);
+}
+
+
+// Start playing a mid
+static void I_Allegro_PlaySong(void *handle, boolean looping)
+{
+ int retval;
+
+ if (!music_initialized)
+ {
+ return;
+ }
+
+ if (handle == NULL)
+ {
+ return;
+ }
+
+ current_track_music = (MIDI *) handle;
+ current_track_loop = looping;
+
+ retval = play_midi(current_track_music, looping);
+ if (retval < 0) {
+ fprintf(stderr, "Error playing midi: %d \"%s\"\n", retval, allegro_error);
+ }
+}
+
+
+static void I_Allegro_PauseSong(void)
+{
+ if (!music_initialized)
+ {
+ return;
+ }
+
+ musicpaused = true;
+
+ midi_pause();
+}
+
+
+static void I_Allegro_ResumeSong(void)
+{
+ if (!music_initialized)
+ {
+ return;
+ }
+
+ musicpaused = false;
+
+ midi_resume();
+}
+
+
+static void I_Allegro_StopSong(void)
+{
+ if (!music_initialized)
+ {
+ return;
+ }
+
+ stop_midi();
+
+ current_track_music = NULL;
+}
+
+
+static void I_Allegro_UnRegisterSong(void *handle)
+{
+ MIDI *midi = (MIDI *) handle;
+
+ if (!music_initialized)
+ {
+ return;
+ }
+
+ if (handle == NULL)
+ {
+ return;
+ }
+
+ destroy_midi(midi);
+}
+
+
+// Determine whether memory block is a .mid file
+static boolean IsMid(byte *mem, int len)
+{
+ return len > 4 && !memcmp(mem, "MThd", 4);
+}
+
+
+static boolean ConvertMus(byte *musdata, int len, char *filename)
+{
+ MEMFILE *instream;
+ MEMFILE *outstream;
+ void *outbuf;
+ size_t outbuf_len;
+ int result;
+
+ instream = mem_fopen_read(musdata, len);
+ outstream = mem_fopen_write();
+
+ result = mus2mid(instream, outstream);
+
+ if (result == 0)
+ {
+ mem_get_buf(outstream, &outbuf, &outbuf_len);
+
+ M_WriteFile(filename, outbuf, outbuf_len);
+ }
+
+ mem_fclose(instream);
+ mem_fclose(outstream);
+
+ return result;
+}
+
+
+static void *I_Allegro_RegisterSong(void *data, int len)
+{
+ char *filename;
+ MIDI *music;
+
+ if (!music_initialized)
+ {
+ return NULL;
+ }
+
+ filename = M_TempFile("doom.mid");
+
+ if (IsMid(data, len) && len < MAXMIDLENGTH)
+ {
+ M_WriteFile(filename, data, len);
+ }
+ else
+ {
+ // Assume a MUS file and try to convert
+ ConvertMus(data, len, filename);
+ }
+
+ // Load the MIDI. In an ideal world we'd load it directly from memory but Allegro
+ // doesn't support that so we have to generate a temporary file.
+
+ music = load_midi(filename);
+
+ if (music == NULL)
+ {
+ // Failed to load
+ fprintf(stderr, "Error loading midi: %s\n", allegro_error);
+ }
+
+ // Remove the temporary MIDI file;
+ remove(filename);
+
+ free(filename);
+
+ return music;
+}
+
+
+// Is the song playing?
+static boolean I_Allegro_MusicIsPlaying(void)
+{
+ if (!music_initialized)
+ {
+ return false;
+ }
+
+ return (current_track_music != NULL) && (midi_pos > 0);
+}
+
+
+// Get position in substitute music track, in seconds since start of track.
+static double GetMusicPosition(void)
+{
+ return midi_time;
+}
+
+
+// Poll music position; if we have passed the loop point end position
+// then we need to go back.
+static void I_Allegro_PollMusic(void)
+{
+ // nothing here, allegro takes care of it
+}
+
+
+static snddevice_t music_allegro_devices[] =
+{
+ SNDDEVICE_PAS,
+ SNDDEVICE_GUS,
+ SNDDEVICE_WAVEBLASTER,
+ SNDDEVICE_SOUNDCANVAS,
+ SNDDEVICE_GENMIDI,
+ SNDDEVICE_AWE32,
+};
+
+
+music_module_t DG_music_module =
+{
+ music_allegro_devices,
+ arrlen(music_allegro_devices),
+ I_Allegro_InitMusic,
+ I_Allegro_ShutdownMusic,
+ I_Allegro_SetMusicVolume,
+ I_Allegro_PauseSong,
+ I_Allegro_ResumeSong,
+ I_Allegro_RegisterSong,
+ I_Allegro_UnRegisterSong,
+ I_Allegro_PlaySong,
+ I_Allegro_StopSong,
+ I_Allegro_MusicIsPlaying,
+ I_Allegro_PollMusic,
+};
+
--- /dev/null
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
+// Copyright(C) 2008 David Flater
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// DESCRIPTION:
+// System interface for sound.
+//
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.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"
+
+#include <allegro/base.h>
+#include <allegro/sound.h>
+#include <allegro/system.h>
+
+
+#define NUM_CHANNELS 16
+
+#define NUM_MIDI_CHANNELS 16
+
+
+static boolean sound_initialized = false;
+
+static sfxinfo_t *channels_playing[NUM_CHANNELS];
+
+static int allegro_voices[NUM_CHANNELS];
+
+static SAMPLE *dummy_sample = NULL;
+
+static boolean use_sfx_prefix;
+
+
+// We don't support libsamplerate with Allegro but these have to be here since
+// other code requires them
+int use_libsamplerate = 0;
+
+// Scale factor used when converting libsamplerate floating point numbers
+// to integers. Too high means the sounds can clip; too low means they
+// will be too quiet. This is an amount that should avoid clipping most
+// of the time: with all the Doom IWAD sound effects, at least. If a PWAD
+// is used, clipping might occur.
+
+float libsamplerate_scale = 0.65f;
+
+
+// Load and convert a sound effect
+// Returns true if successful
+
+static boolean CacheSFX(sfxinfo_t *sfxinfo)
+{
+ int lumpnum;
+ unsigned int lumplen;
+ int samplerate;
+ unsigned int length;
+ byte *data;
+ SAMPLE *sample;
+
+ // need to load the sound
+
+ lumpnum = sfxinfo->lumpnum;
+ data = W_CacheLumpNum(lumpnum, PU_STATIC);
+ lumplen = W_LumpLength(lumpnum);
+
+ // Check the header, and ensure this is a valid sound
+
+ if (lumplen < 8
+ || data[0] != 0x03 || data[1] != 0x00)
+ {
+ // Invalid sound
+
+ return false;
+ }
+
+ // 16 bit sample rate field, 32 bit length field
+
+ samplerate = (data[3] << 8) | data[2];
+ length = (data[7] << 24) | (data[6] << 16) | (data[5] << 8) | data[4];
+
+ // If the header specifies that the length of the sound is greater than
+ // the length of the lump itself, this is an invalid sound lump
+
+ // We also discard sound lumps that are less than 49 samples long,
+ // as this is how DMX behaves - although the actual cut-off length
+ // seems to vary slightly depending on the sample rate. This needs
+ // further investigation to better understand the correct
+ // behavior.
+
+ if (length > lumplen - 8 || length <= 48)
+ {
+ return false;
+ }
+
+ // The DMX sound library seems to skip the first 16 and last 16
+ // bytes of the lump - reason unknown.
+
+ data += 16;
+ length -= 32;
+
+ sample = create_sample(8, 0, samplerate, length);
+ if (sample == NULL) {
+ return false;
+ }
+ memcpy(sample->data, data, length);
+
+ sfxinfo->driver_data = sample;
+
+ // don't need the original lump any more
+
+ W_ReleaseLumpNum(lumpnum);
+
+ return true;
+}
+
+
+static void GetSfxLumpName(sfxinfo_t *sfx, char *buf, size_t buf_len)
+{
+ // Linked sfx lumps? Get the lump number for the sound linked to.
+
+ if (sfx->link != NULL)
+ {
+ sfx = sfx->link;
+ }
+
+ // Doom adds a DS* prefix to sound lumps; Heretic and Hexen don't
+ // do this.
+
+ 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);
+ }
+}
+
+
+static void I_Allegro_PrecacheSounds(sfxinfo_t *sounds, int num_sounds)
+{
+ char namebuf[9];
+ int i;
+
+ printf("I_Allegro_PrecacheSounds: Precaching all sound effects..");
+
+ for (i=0; i<num_sounds; ++i)
+ {
+ if ((i % 6) == 0)
+ {
+ printf(".");
+ fflush(stdout);
+ }
+
+ GetSfxLumpName(&sounds[i], namebuf, sizeof(namebuf));
+
+ sounds[i].lumpnum = W_CheckNumForName(namebuf);
+
+ if (sounds[i].lumpnum != -1)
+ {
+ CacheSFX(&sounds[i]);
+ }
+ }
+
+ printf("\n");
+}
+
+
+//
+// Retrieve the raw data lump index
+// for a given SFX name.
+//
+
+static int I_Allegro_GetSfxLumpNum(sfxinfo_t *sfx)
+{
+ char namebuf[9];
+
+ GetSfxLumpName(sfx, namebuf, sizeof(namebuf));
+
+ return W_GetNumForName(namebuf);
+}
+
+static void I_Allegro_UpdateSoundParams(int handle, int vol, int sep)
+{
+ int left, right;
+
+ if (!sound_initialized || handle < 0 || handle >= NUM_CHANNELS)
+ {
+ return;
+ }
+
+ if (channels_playing[handle] == NULL) {
+ return;
+ }
+
+ voice_set_volume(allegro_voices[handle], vol);
+ voice_set_pan(allegro_voices[handle], sep);
+}
+
+//
+// Starting a sound means adding it
+// to the current list of active sounds
+// in the internal channels.
+// As the SFX info struct contains
+// e.g. a pointer to the raw data,
+// it is ignored.
+// As our sound handling does not handle
+// priority, it is ignored.
+// Pitching (that is, increased speed of playback)
+// is set, but currently not used by mixing.
+//
+
+static int I_Allegro_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep)
+{
+ if (!sound_initialized || channel < 0 || channel >= NUM_CHANNELS)
+ {
+ return -1;
+ }
+
+ // Release a sound effect if there is already one playing
+ // on this channel
+ if (channels_playing[channel]) {
+ voice_stop(allegro_voices[channel]);
+ channels_playing[channel] = NULL;
+ }
+
+ // Get the sound data
+ if (sfxinfo->driver_data == NULL)
+ {
+ if (!CacheSFX(sfxinfo))
+ {
+ return -1;
+ }
+ }
+ assert(sfxinfo->driver_data);
+
+ // play sound
+ reallocate_voice(allegro_voices[channel], sfxinfo->driver_data);
+ voice_set_volume(allegro_voices[channel], vol);
+ voice_set_pan(allegro_voices[channel], sep);
+ voice_start(allegro_voices[channel]);
+
+ channels_playing[channel] = sfxinfo;
+
+ return channel;
+}
+
+
+static void I_Allegro_StopSound(int handle)
+{
+ if (!sound_initialized || handle < 0 || handle >= NUM_CHANNELS)
+ {
+ return;
+ }
+
+ if (channels_playing[handle] == NULL) {
+ return;
+ }
+
+ voice_stop(allegro_voices[handle]);
+ channels_playing[handle] = NULL;
+}
+
+
+static boolean I_Allegro_SoundIsPlaying(int handle)
+{
+ int position;
+
+ if (!sound_initialized || handle < 0 || handle >= NUM_CHANNELS)
+ {
+ return false;
+ }
+
+ if (channels_playing[handle] == NULL) {
+ return false;
+ }
+
+ position = voice_get_position(allegro_voices[handle]);
+ if (position < 0) {
+ // finished
+ return false;
+ }
+
+ // still playing
+ return true;
+}
+
+//
+// Periodically called to update the sound system
+//
+
+static void I_Allegro_UpdateSound(void)
+{
+ int i;
+
+ // loop through all channels which have sample, check if they're finished
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ if (channels_playing[i]) {
+ int position = voice_get_position(allegro_voices[i]);
+ if (position < 0) {
+ // finished
+ channels_playing[i] = NULL;
+ }
+ }
+ }
+}
+
+
+static void I_Allegro_ShutdownSound(void)
+{
+ int i;
+
+ if (!sound_initialized)
+ {
+ return;
+ }
+
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ if (channels_playing[i] != NULL) {
+ voice_stop(allegro_voices[i]);
+ channels_playing[i] = NULL;
+ }
+ deallocate_voice(allegro_voices[i]);
+ allegro_voices[i] = -1;
+ }
+
+ destroy_sample(dummy_sample);
+ dummy_sample = NULL;
+
+ remove_sound();
+
+ sound_initialized = false;
+}
+
+
+static boolean I_Allegro_InitSound(boolean _use_sfx_prefix)
+{
+ int i;
+
+ use_sfx_prefix = _use_sfx_prefix;
+
+ // No sounds yet
+
+ for (i=0; i<NUM_CHANNELS; ++i)
+ {
+ channels_playing[i] = NULL;
+ }
+
+ reserve_voices(NUM_CHANNELS, NUM_MIDI_CHANNELS);
+
+ i = install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, "allegro.cfg");
+ if (i < 0) {
+ printf("install_sound failed: %d \"%s\"\n", i, allegro_error);
+ return false;
+ }
+
+ printf("Allegro sound initialized\n");
+
+ printf("Mixer quality %d\n", get_mixer_quality());
+ printf("Mixer freq %d\n", get_mixer_frequency());
+ printf("Mixer bits %d\n", get_mixer_bits());
+ printf("Mixer channels %d\n", get_mixer_channels());
+ printf("Mixer voices %d\n", get_mixer_voices());
+ printf("Mixer buffer length %d\n", get_mixer_buffer_length());
+
+ // create a dummy sample used to create voices
+ dummy_sample = create_sample(8, 0, 11025, 8);
+ if (dummy_sample == NULL) {
+ printf("Failed to create sound sample: %s\n", allegro_error);
+ return false;
+ }
+
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ allegro_voices[i] = allocate_voice(dummy_sample);
+ }
+
+ sound_initialized = true;
+
+ return true;
+}
+
+
+static snddevice_t sound_allegro_devices[] =
+{
+ SNDDEVICE_SB,
+ SNDDEVICE_PAS,
+ SNDDEVICE_GUS,
+ SNDDEVICE_WAVEBLASTER,
+ SNDDEVICE_SOUNDCANVAS,
+ SNDDEVICE_AWE32,
+};
+
+
+sound_module_t DG_sound_module =
+{
+ sound_allegro_devices,
+ arrlen(sound_allegro_devices),
+ I_Allegro_InitSound,
+ I_Allegro_ShutdownSound,
+ I_Allegro_GetSfxLumpNum,
+ I_Allegro_UpdateSound,
+ I_Allegro_UpdateSoundParams,
+ I_Allegro_StartSound,
+ I_Allegro_StopSound,
+ I_Allegro_SoundIsPlaying,
+ I_Allegro_PrecacheSounds,
+};
+