shithub: choc

Download patch

ref: 3efee3d5e2b662df97aabc4c8fd275b60b6f08f4
parent: 9f8ab35852dfd68eb6cc92ab84b79a90995dc027
author: Simon Howard <fraggle@gmail.com>
date: Mon Mar 9 20:03:54 EDT 2009

Add initial GENMIDI lump loading, OPL detection.

Subversion-branch: /branches/opl-branch
Subversion-revision: 1456

--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,7 +3,7 @@
 
 games_PROGRAMS = chocolate-doom chocolate-server
 
-AM_CFLAGS = -I../textscreen -I../pcsound @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
+AM_CFLAGS = -I../opl -I../textscreen -I../pcsound @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
 
 DEDSERV_FILES=\
 d_dedicated.c                              \
--- a/src/i_oplmusic.c
+++ b/src/i_oplmusic.c
@@ -27,6 +27,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include "doomdef.h"
 #include "memio.h"
@@ -38,23 +39,191 @@
 #include "w_wad.h"
 #include "z_zone.h"
 
+#include "opl.h"
+
 #define MAXMIDLENGTH (96 * 1024)
+#define GENMIDI_NUM_INSTRS  128
 
+#define GENMIDI_HEADER          "#OPL_II#"
+#define GENMIDI_FLAG_FIXED      0x0000         /* fixed pitch */
+#define GENMIDI_FLAG_2VOICE     0x0002         /* double voice (OPL3) */
+
+typedef struct
+{
+    byte tremolo;
+    byte attack;
+    byte sustain;
+    byte waveform;
+    byte scale;
+    byte level;
+} PACKEDATTR genmidi_op_t;
+
+typedef struct
+{
+    genmidi_op_t modulator;
+    byte feedback;
+    genmidi_op_t carrier;
+    byte unused;
+    byte base_note_offset;
+} PACKEDATTR genmidi_voice_t;
+
+typedef struct
+{
+    unsigned short flags;
+    byte fine_tuning;
+    byte fixed_note;
+
+    genmidi_voice_t opl2_voice;
+    genmidi_voice_t opl3_voice;
+} PACKEDATTR genmidi_instr_t;
+
 static boolean music_initialised = false;
 
 //static boolean musicpaused = false;
 static int current_music_volume;
 
+static genmidi_instr_t *main_instrs;
+static genmidi_instr_t *percussion_instrs;
+
+// Configuration file variable, containing the port number for the
+// adlib chip.
+
+int snd_mport = 0x388;
+
+static unsigned int GetStatus(void)
+{
+    return OPL_ReadPort(OPL_REGISTER_PORT);
+}
+
+// Write an OPL register value
+
+static void WriteRegister(int reg, int value)
+{
+    int i;
+
+    OPL_WritePort(OPL_REGISTER_PORT, reg);
+
+    // For timing, read the register port six times after writing the
+    // register number to cause the appropriate delay
+
+    for (i=0; i<6; ++i)
+    {
+        GetStatus();
+    }
+
+    OPL_WritePort(OPL_DATA_PORT, value);
+
+    // Read the register port 25 times after writing the value to
+    // cause the appropriate delay
+
+    for (i=0; i<25; ++i)
+    {
+        GetStatus();
+    }
+}
+
+// Detect the presence of an OPL chip
+
+static boolean DetectOPL(void)
+{
+    int result1, result2;
+
+    // Reset both timers:
+    WriteRegister(OPL_REG_TIMER_CTRL, 0x60);
+
+    // Enable interrupts:
+    WriteRegister(OPL_REG_TIMER_CTRL, 0x80);
+
+    // Read status
+    result1 = GetStatus();
+
+    // Set timer:
+    WriteRegister(OPL_REG_TIMER1, 0xff);
+
+    // Start timer 1:
+    WriteRegister(OPL_REG_TIMER_CTRL, 0x21);
+
+    // Wait for 80 microseconds
+
+    // Read status
+    result2 = GetStatus();
+
+    // Reset both timers:
+    WriteRegister(OPL_REG_TIMER_CTRL, 0x60);
+
+    // Enable interrupts:
+    WriteRegister(OPL_REG_TIMER_CTRL, 0x80);
+
+    return (result1 & 0xe0) == 0x00
+        && (result2 & 0xe0) == 0xc0;
+}
+
+
+// Load instrument table from GENMIDI lump:
+
+static boolean LoadInstrumentTable(void)
+{
+    byte *lump;
+
+    lump = W_CacheLumpName("GENMIDI", PU_STATIC);
+
+    // Check header
+
+    if (strncmp((char *) lump, GENMIDI_HEADER, strlen(GENMIDI_HEADER)) != 0)
+    {
+        W_ReleaseLumpName("GENMIDI");
+
+        return false;
+    }
+
+    main_instrs = (genmidi_instr_t *) (lump + strlen(GENMIDI_HEADER));
+    percussion_instrs = main_instrs + GENMIDI_NUM_INSTRS;
+
+    return true;
+}
+
 // Shutdown music
 
 static void I_OPL_ShutdownMusic(void)
 {
+    if (music_initialised)
+    {
+        OPL_Shutdown();
+
+        // Release GENMIDI lump
+
+        W_ReleaseLumpName("GENMIDI");
+
+        music_initialised = false;
+    }
 }
 
 // Initialise music subsystem
 
 static boolean I_OPL_InitMusic(void)
-{ 
+{
+    if (!OPL_Init(snd_mport))
+    {
+        return false;
+    }
+
+    // Doom does the detection sequence twice, for some reason:
+
+    if (!DetectOPL() || !DetectOPL())
+    {
+        printf("Dude.  The Adlib isn't responding.\n");
+        OPL_Shutdown();
+        return false;
+    }
+
+    // Load instruments from GENMIDI lump:
+
+    if (!LoadInstrumentTable())
+    {
+        OPL_Shutdown();
+        return false;
+    }
+
     music_initialised = true;
 
     return true;
--- a/src/m_config.c
+++ b/src/m_config.c
@@ -124,6 +124,7 @@
 extern int snd_musicdevice;
 extern int snd_sfxdevice;
 extern int snd_samplerate;
+extern int snd_mport;
 
 // controls whether to use libsamplerate for sample rate conversions
 
@@ -136,7 +137,6 @@
 static int snd_sbport = 0;
 static int snd_sbirq = 0;
 static int snd_sbdma = 0;
-static int snd_mport = 0;
 
 typedef enum 
 {