From 997d2ee86ef77422ce7ddd08859bd5a4aef66145 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Wed, 4 Mar 2009 22:07:27 +0000 Subject: Add initial stub for OPL backend. Subversion-branch: /branches/opl-branch Subversion-revision: 1447 --- src/Makefile.am | 2 + src/i_oplmusic.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/i_sdlmusic.c | 2 - src/s_sound.c | 2 + 4 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 src/i_oplmusic.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 63ddc98f..66909dd1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -155,6 +155,7 @@ FEATURE_SOUND_SOURCE_FILES = \ i_pcsound.c \ i_sdlsound.c \ i_sdlmusic.c \ +i_oplmusic.c \ mus2mid.c mus2mid.h SOURCE_FILES = $(MAIN_SOURCE_FILES) \ @@ -172,6 +173,7 @@ endif chocolate_doom_LDADD = \ ../textscreen/libtextscreen.a \ ../pcsound/libpcsound.a \ + ../opl/libopl.a \ @LDFLAGS@ \ @SDLMIXER_LIBS@ \ @SDLNET_LIBS@ diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c new file mode 100644 index 00000000..ee909193 --- /dev/null +++ b/src/i_oplmusic.c @@ -0,0 +1,214 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +// DESCRIPTION: +// System interface for music. +// +//----------------------------------------------------------------------------- + + +#include +#include + +#include "doomdef.h" +#include "memio.h" +#include "mus2mid.h" + +#include "deh_main.h" +#include "m_misc.h" +#include "s_sound.h" +#include "w_wad.h" +#include "z_zone.h" + +#define MAXMIDLENGTH (96 * 1024) + +static boolean music_initialised = false; + +//static boolean musicpaused = false; +static int current_music_volume; + +// Shutdown music + +static void I_OPL_ShutdownMusic(void) +{ +} + +// Initialise music subsystem + +static boolean I_OPL_InitMusic(void) +{ + music_initialised = true; + + return true; +} + +// Set music volume (0 - 127) + +static void I_OPL_SetMusicVolume(int volume) +{ + // Internal state variable. + current_music_volume = volume; +} + +// Start playing a mid + +static void I_OPL_PlaySong(void *handle, int looping) +{ + if (!music_initialised) + { + return; + } +} + +static void I_OPL_PauseSong(void) +{ + if (!music_initialised) + { + return; + } +} + +static void I_OPL_ResumeSong(void) +{ + if (!music_initialised) + { + return; + } +} + +static void I_OPL_StopSong(void) +{ + if (!music_initialised) + { + return; + } +} + +static void I_OPL_UnRegisterSong(void *handle) +{ + if (!music_initialised) + { + return; + } +} + +// 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_OPL_RegisterSong(void *data, int len) +{ + char *filename; + + if (!music_initialised) + { + return NULL; + } + + // MUS files begin with "MUS" + // Reject anything which doesnt have this signature + + 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); + } + + // .... + + // remove file now + + remove(filename); + + Z_Free(filename); + + return NULL; +} + +// Is the song playing? +static boolean I_OPL_MusicIsPlaying(void) +{ + if (!music_initialised) + { + return false; + } + + return false; +} + +static snddevice_t music_opl_devices[] = +{ + SNDDEVICE_ADLIB, + SNDDEVICE_SB, +}; + +music_module_t music_opl_module = +{ + music_opl_devices, + arrlen(music_opl_devices), + I_OPL_InitMusic, + I_OPL_ShutdownMusic, + I_OPL_SetMusicVolume, + I_OPL_PauseSong, + I_OPL_ResumeSong, + I_OPL_RegisterSong, + I_OPL_UnRegisterSong, + I_OPL_PlaySong, + I_OPL_StopSong, + I_OPL_MusicIsPlaying, +}; + diff --git a/src/i_sdlmusic.c b/src/i_sdlmusic.c index 313e2a58..c1ab340b 100644 --- a/src/i_sdlmusic.c +++ b/src/i_sdlmusic.c @@ -324,8 +324,6 @@ static boolean I_SDL_MusicIsPlaying(void) static snddevice_t music_sdl_devices[] = { - SNDDEVICE_ADLIB, - SNDDEVICE_SB, SNDDEVICE_PAS, SNDDEVICE_GUS, SNDDEVICE_WAVEBLASTER, diff --git a/src/s_sound.c b/src/s_sound.c index 70fa75f3..f038e9cd 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -136,6 +136,7 @@ int snd_sfxdevice = SNDDEVICE_SB; extern sound_module_t sound_sdl_module; extern sound_module_t sound_pcsound_module; extern music_module_t music_sdl_module; +extern music_module_t music_opl_module; // Compiled-in sound modules: @@ -154,6 +155,7 @@ static music_module_t *music_modules[] = { #ifdef FEATURE_SOUND &music_sdl_module, + &music_opl_module, #endif NULL, }; -- cgit v1.2.3 From 3efee3d5e2b662df97aabc4c8fd275b60b6f08f4 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Tue, 10 Mar 2009 00:03:54 +0000 Subject: Add initial GENMIDI lump loading, OPL detection. Subversion-branch: /branches/opl-branch Subversion-revision: 1456 --- src/Makefile.am | 2 +- src/i_oplmusic.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/m_config.c | 2 +- 3 files changed, 172 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 66909dd1..406d0af8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,7 +3,7 @@ gamesdir = $(prefix)/games 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 \ diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index ee909193..98170284 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -27,6 +27,7 @@ #include #include +#include #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; diff --git a/src/m_config.c b/src/m_config.c index 4066cb3c..c54b3774 100644 --- a/src/m_config.c +++ b/src/m_config.c @@ -124,6 +124,7 @@ extern int vanilla_demo_limit; 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 @@ extern int use_libsamplerate; static int snd_sbport = 0; static int snd_sbirq = 0; static int snd_sbdma = 0; -static int snd_mport = 0; typedef enum { -- cgit v1.2.3 From ca7f823d48bb78eda9048750909cdb315836125c Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Tue, 10 Mar 2009 21:21:16 +0000 Subject: Initialise OPL registers on startup, initialise voices. Subversion-branch: /branches/opl-branch Subversion-revision: 1457 --- src/i_oplmusic.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 98170284..5b3ae041 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -77,14 +77,45 @@ typedef struct genmidi_voice_t opl3_voice; } PACKEDATTR genmidi_instr_t; +typedef struct opl_voice_s opl_voice_t; + +struct opl_voice_s +{ + // Index of this voice: + int index; + + // The operators used by this voice: + int op1, op2; + + // Currently-loaded instrument data + genmidi_instr_t *current_instr; + + // Next in freelist + opl_voice_t *next; +}; + +// Operators used by the different voices. + +static const int voice_operators[2][OPL_NUM_VOICES] = { + { 0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12 }, + { 0x03, 0x04, 0x05, 0x0b, 0x0c, 0x0d, 0x13, 0x14, 0x15 } +}; + static boolean music_initialised = false; //static boolean musicpaused = false; static int current_music_volume; +// GENMIDI lump instrument data: + static genmidi_instr_t *main_instrs; static genmidi_instr_t *percussion_instrs; +// Voices: + +static opl_voice_t voices[OPL_NUM_VOICES]; +static opl_voice_t *voice_free_list; + // Configuration file variable, containing the port number for the // adlib chip. @@ -158,6 +189,47 @@ static boolean DetectOPL(void) && (result2 & 0xe0) == 0xc0; } +// Initialise registers on startup + +static void InitRegisters(void) +{ + int r; + + // Initialise level registers + + for (r=OPL_REGS_LEVEL; r < OPL_REGS_LEVEL + OPL_NUM_OPERATORS; ++r) + { + WriteRegister(r, 0x3f); + } + + // Initialise other registers + // These two loops write to registers that actually don't exist, + // but this is what Doom does ... + + for (r=OPL_REGS_ATTACK; r < OPL_REGS_WAVEFORM + OPL_NUM_OPERATORS; ++r) + { + WriteRegister(r, 0x00); + } + + // More registers ... + + for (r=0; r < OPL_REGS_LEVEL; ++r) + { + WriteRegister(r, 0x00); + } + + // Re-initialise the low registers: + + // Reset both timers and enable interrupts: + WriteRegister(OPL_REG_TIMER_CTRL, 0x60); + WriteRegister(OPL_REG_TIMER_CTRL, 0x80); + + // "Allow FM chips to control the waveform of each operator": + WriteRegister(OPL_REG_WAVEFORM_ENABLE, 0x20); + + // Keyboard split point on (?) + WriteRegister(OPL_REG_FM_MODE, 0x40); +} // Load instrument table from GENMIDI lump: @@ -182,6 +254,109 @@ static boolean LoadInstrumentTable(void) return true; } +// Get the next available voice from the freelist. + +static opl_voice_t *GetFreeVoice(void) +{ + opl_voice_t *result; + + // None available? + + if (voice_free_list == NULL) + { + return NULL; + } + + result = voice_free_list; + voice_free_list = voice_free_list->next; + + return result; +} + +// Release a voice back to the freelist. + +static void ReleaseVoice(opl_voice_t *voice) +{ + opl_voice_t **rover; + + // Search to the end of the freelist (This is how Doom behaves!) + + rover = &voice_free_list; + + while (*rover != NULL) + { + rover = &(*rover)->next; + } + + *rover = voice; +} + +// Load data to the specified operator + +static void LoadOperatorData(int operator, genmidi_op_t *data, + boolean max_level) +{ + int level; + + // The scale and level fields must be combined for the level register. + // For the carrier wave we always set the maximum level. + + level = (data->scale & 0xc0) | (data->level & 0x3f); + + if (max_level) + { + level |= 0x3f; + } + + WriteRegister(OPL_REGS_LEVEL + operator, level); + WriteRegister(OPL_REGS_TREMOLO + operator, data->tremolo); + WriteRegister(OPL_REGS_ATTACK + operator, data->attack); + WriteRegister(OPL_REGS_SUSTAIN + operator, data->sustain); + WriteRegister(OPL_REGS_WAVEFORM + operator, data->waveform); +} + +// Set the instrument for a particular voice. + +static void SetVoiceInstrument(opl_voice_t *voice, genmidi_voice_t *data) +{ + // Doom loads the second operator first, then the first. + + LoadOperatorData(voice->op2, &data->carrier, true); + LoadOperatorData(voice->op1, &data->modulator, false); + + // Set feedback register that control the connection between the + // two operators. Turn on bits in the upper nybble; I think this + // is for OPL3, where it turns on channel A/B. + + WriteRegister(OPL_REGS_FEEDBACK + voice->index, + data->feedback | 0x30); +} + +// Initialise the voice table and freelist + +static void InitVoices(void) +{ + int i; + + // Start with an empty free list. + + voice_free_list = NULL; + + // Initialise each voice. + + for (i=0; iop2, 0x94); + + // Note on: + WriteRegister(OPL_REGS_FREQ_1 + voice->index, 0x65); + WriteRegister(OPL_REGS_FREQ_2 + voice->index, 0x2b); + } +#endif + music_initialised = true; return true; -- cgit v1.2.3 From 90fd85b32dd85884fb9a9cf0a7063c4509147d40 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 12 Mar 2009 18:50:15 +0000 Subject: Read from register port when doing register writes during startup phase; afterwards, read from the data port. Subversion-branch: /branches/opl-branch Subversion-revision: 1464 --- src/i_oplmusic.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index baf17bd6..0543be2e 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -116,6 +116,13 @@ static genmidi_instr_t *percussion_instrs; static opl_voice_t voices[OPL_NUM_VOICES]; static opl_voice_t *voice_free_list; +// In the initialisation stage, register writes are spaced by reading +// from the register port (0). After initialisation, spacing is +// peformed by reading from the data port instead. I have no idea +// why. + +static boolean init_stage_reg_writes = false; + // Configuration file variable, containing the port number for the // adlib chip. @@ -139,7 +146,18 @@ static void WriteRegister(int reg, int value) for (i=0; i<6; ++i) { - GetStatus(); + // An oddity of the Doom OPL code: at startup initialisation, + // the spacing here is performed by reading from the register + // port; after initialisation, the data port is read, instead. + + if (init_stage_reg_writes) + { + OPL_ReadPort(OPL_REGISTER_PORT); + } + else + { + OPL_ReadPort(OPL_DATA_PORT); + } } OPL_WritePort(OPL_DATA_PORT, value); @@ -393,6 +411,8 @@ static boolean I_OPL_InitMusic(void) return false; } + init_stage_reg_writes = true; + // Doom does the detection sequence twice, for some reason: if (!DetectOPL() || !DetectOPL()) @@ -413,6 +433,11 @@ static boolean I_OPL_InitMusic(void) InitRegisters(); InitVoices(); + // Now that initialisation has finished, switch the + // register writing mode: + + init_stage_reg_writes = false; + #ifdef TEST { opl_voice_t *voice; -- cgit v1.2.3 From 543b9bdc85dfeb84ed855084595407d6bf49d8f6 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 12 Mar 2009 18:52:12 +0000 Subject: Make base_note_offset a 16-bit integer rather than an 8-bit integer. Subversion-branch: /branches/opl-branch Subversion-revision: 1465 --- src/i_oplmusic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 0543be2e..f50c3322 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -64,7 +64,7 @@ typedef struct byte feedback; genmidi_op_t carrier; byte unused; - byte base_note_offset; + short base_note_offset; } PACKEDATTR genmidi_voice_t; typedef struct -- cgit v1.2.3 From b96cdbe82fa6cb51ac91072ad86e084d739fd9be Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 28 Mar 2009 00:24:50 +0000 Subject: Initial MIDI file parsing code. Subversion-branch: /branches/opl-branch Subversion-revision: 1489 --- src/Makefile.am | 1 + src/midifile.c | 287 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/midifile.h | 135 ++++++++++++++++++++++++++ 3 files changed, 423 insertions(+) create mode 100644 src/midifile.c create mode 100644 src/midifile.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 406d0af8..92095b5c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -156,6 +156,7 @@ i_pcsound.c \ i_sdlsound.c \ i_sdlmusic.c \ i_oplmusic.c \ +midifile.c midifile.h \ mus2mid.c mus2mid.h SOURCE_FILES = $(MAIN_SOURCE_FILES) \ diff --git a/src/midifile.c b/src/midifile.c new file mode 100644 index 00000000..e74cf17f --- /dev/null +++ b/src/midifile.c @@ -0,0 +1,287 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2009 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +// DESCRIPTION: +// Reading of MIDI files. +// +//----------------------------------------------------------------------------- + +#include +#include +#include + +#include "doomtype.h" +#include "i_swap.h" +#include "midifile.h" + +#define HEADER_CHUNK_ID "MThd" +#define TRACK_CHUNK_ID "MTrk" + +typedef struct +{ + byte chunk_id[4]; + unsigned int chunk_size; +} chunk_header_t; + +typedef struct +{ + chunk_header_t chunk_header; + unsigned short format_type; + unsigned short num_tracks; + unsigned int time_division; +} midi_header_t; + +struct midi_file_s +{ + FILE *stream; + midi_header_t header; + unsigned int data_len; +}; + +static boolean CheckChunkHeader(chunk_header_t *chunk, + char *expected_id) +{ + boolean result; + + result = (strcmp((char *) chunk->chunk_id, expected_id) == 0); + + if (!result) + { + fprintf(stderr, "CheckChunkHeader: Expected '%s' chunk header!\n", + expected_id); + } + + return result; +} + +// Read and check the header chunk. + +static boolean ReadHeaderChunk(midi_file_t *file) +{ + size_t bytes_read; + + bytes_read = fread(&file->header, sizeof(midi_header_t), 1, file->stream); + + if (bytes_read < sizeof(midi_header_t)) + { + return false; + } + + if (!CheckChunkHeader(&file->header.chunk_header, HEADER_CHUNK_ID) + || LONG(file->header.chunk_header.chunk_size) != 6) + { + fprintf(stderr, "ReadHeaderChunk: Invalid MIDI chunk header!\n"); + return false; + } + + if (SHORT(file->header.format_type) != 0 + || SHORT(file->header.num_tracks) != 1) + { + fprintf(stderr, "ReadHeaderChunk: Only single track, " + "type 0 MIDI files supported!\n"); + return false; + } + + return true; +} + +// Read and check the track chunk header + +static boolean ReadTrackChunk(midi_file_t *file) +{ + size_t bytes_read; + chunk_header_t chunk_header; + + bytes_read = fread(&chunk_header, sizeof(chunk_header_t), 1, file->stream); + + if (bytes_read < sizeof(chunk_header)) + { + return false; + } + + if (!CheckChunkHeader(&chunk_header, TRACK_CHUNK_ID)) + { + return false; + } + + file->data_len = LONG(chunk_header.chunk_size); + + return true; +} + +midi_file_t *MIDI_OpenFile(char *filename) +{ + midi_file_t *file; + + file = malloc(sizeof(midi_file_t)); + + if (file == NULL) + { + return NULL; + } + + // Open file + + file->stream = fopen(filename, "rb"); + + if (file->stream == NULL) + { + fprintf(stderr, "Failed to open '%s'\n", filename); + free(file); + return NULL; + } + + // Read MIDI file header + + if (!ReadHeaderChunk(file)) + { + fclose(file->stream); + free(file); + return NULL; + } + + // Read track header + + if (!ReadTrackChunk(file)) + { + fclose(file->stream); + free(file); + return NULL; + } + + return file; +} + +void MIDI_CloseFile(midi_file_t *file) +{ + fclose(file->stream); + free(file); +} + +// Read a MIDI channel event. +// two_param indicates that the event type takes two parameters +// (three byte) otherwise it is single parameter (two byte) + +static boolean ReadChannelEvent(midi_file_t *file, midi_event_t *event, + int event_type, boolean two_param) +{ + int c; + + // Set basics: + + event->event_type = event_type >> 4; + event->data.channel.channel = event_type & 0xf; + + // Read parameters: + + c = fgetc(file->stream); + + if (c == EOF) + { + return false; + } + + event->data.channel.param1 = c; + + // Second parameter: + + if (two_param) + { + c = fgetc(file->stream); + + if (c == EOF) + { + return false; + } + + event->data.channel.param2 = c; + } + + return true; +} + +// Read sysex event: + +static boolean ReadSysExEvent(midi_file_t *file, midi_event_t *event, + int event_type) +{ + // TODO + return false; +} + +// Read meta event: + +static boolean ReadMetaEvent(midi_file_t *file, midi_event_t *event) +{ + // TODO + return false; +} + +boolean MIDI_ReadEvent(midi_file_t *file, midi_event_t *event) +{ + int event_type; + + event_type = fgetc(file->stream); + + if (event_type == EOF) + { + return false; + } + + // Check event type: + + switch (event_type >> 4) + { + // Two parameter channel events: + + case MIDI_EVENT_NOTE_OFF: + case MIDI_EVENT_NOTE_ON: + case MIDI_EVENT_AFTERTOUCH: + case MIDI_EVENT_CONTROLLER: + case MIDI_EVENT_PITCH_BEND: + return ReadChannelEvent(file, event, event_type, true); + + // Single parameter channel events: + + case MIDI_EVENT_PROGRAM_CHANGE: + case MIDI_EVENT_CHAN_AFTERTOUCH: + return ReadChannelEvent(file, event, event_type, false); + + // Other event types: + + case 0xf: + if (event_type == MIDI_EVENT_SYSEX + || event_type == MIDI_EVENT_SYSEX_SPLIT) + { + return ReadSysExEvent(file, event, event_type); + } + else if (event_type == MIDI_EVENT_META) + { + return ReadMetaEvent(file, event); + } + + // Fall-through deliberate - + + default: + fprintf(stderr, "Unknown MIDI event type: 0x%x\n", event_type); + return false; + } +} + diff --git a/src/midifile.h b/src/midifile.h new file mode 100644 index 00000000..d7df8b86 --- /dev/null +++ b/src/midifile.h @@ -0,0 +1,135 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2009 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +// DESCRIPTION: +// MIDI file parsing. +// +//----------------------------------------------------------------------------- + +#ifndef MIDIFILE_H +#define MIDIFILE_H + +typedef struct midi_file_s midi_file_t; + +typedef enum +{ + MIDI_EVENT_NOTE_OFF = 0x8, + MIDI_EVENT_NOTE_ON = 0x9, + MIDI_EVENT_AFTERTOUCH = 0xa, + MIDI_EVENT_CONTROLLER = 0xb, + MIDI_EVENT_PROGRAM_CHANGE = 0xc, + MIDI_EVENT_CHAN_AFTERTOUCH = 0xd, + MIDI_EVENT_PITCH_BEND = 0xe, + + MIDI_EVENT_SYSEX = 0xf0, + MIDI_EVENT_SYSEX_SPLIT = 0xf7, + MIDI_EVENT_META = 0xff, +} midi_event_type_t; + +typedef enum +{ + MIDI_CONTROLLER_BANK_SELECT = 0x0, + MIDI_CONTROLLER_MODULATION = 0x1, + MIDI_CONTROLLER_BREATH_CONTROL = 0x2, + MIDI_CONTROLLER_FOOT_CONTROL = 0x3, + MIDI_CONTROLLER_PORTAMENTO = 0x4, + MIDI_CONTROLLER_DATA_ENTRY = 0x5, +} midi_controller_t; + +typedef enum +{ + MIDI_META_SEQUENCE_NUMBER = 0x0, + + MIDI_META_TEXT = 0x1, + MIDI_META_COPYRIGHT = 0x2, + MIDI_META_TRACK_NAME = 0x3, + MIDI_META_INSTR_NAME = 0x4, + MIDI_META_LYRICS = 0x5, + MIDI_META_MARKER = 0x6, + MIDI_META_CUE_POINT = 0x7, + + MIDI_META_CHANNEL_PREFIX = 0x8, + MIDI_META_END_OF_TRACK = 0x9, + MIDI_META_SET_TEMPO = 0xa, + MIDI_META_SMPTE_OFFSET = 0xb, + MIDI_META_TIME_SIGNATURE = 0xc, + MIDI_META_KEY_SIGNATURE = 0xd, + MIDI_META_SEQUENCER_SPECIFIC = 0xe, +} midi_meta_event_type_t; + +typedef struct +{ + // Meta event type: + + unsigned int type; + + // Length: + + unsigned int length; + + // Meta event data: + + byte *data; +} midi_meta_event_data_t; + +typedef struct +{ + // Length: + + unsigned int length; + + // Event data: + + byte *data; +} midi_sysex_event_data_t; + +typedef struct +{ + // The channel number to which this applies: + + unsigned int channel; + + // Extra parameters: + + unsigned int param1; + unsigned int param2; +} midi_channel_event_data_t; + +typedef struct +{ + // Time between the previous event and this event. + unsigned int delta_time; + + // Type of event: + midi_event_type_t event_type; + + union + { + midi_channel_event_data_t channel; + midi_meta_event_data_t meta; + midi_sysex_event_data_t sysex; + } data; +} midi_event_t; + +midi_file_t *MIDI_OpenFile(char *filename); +void MIDI_CloseFile(midi_file_t *file); + +#endif /* #ifndef MIDIFILE_H */ + -- cgit v1.2.3 From 2b64dfc84981dbbd9de1a0d9cb11995bf0ba9379 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 29 Mar 2009 22:39:25 +0000 Subject: Parse SysEx, meta events Subversion-branch: /branches/opl-branch Subversion-revision: 1490 --- src/midifile.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 180 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/midifile.c b/src/midifile.c index e74cf17f..1b8a8786 100644 --- a/src/midifile.c +++ b/src/midifile.c @@ -53,6 +53,10 @@ struct midi_file_s FILE *stream; midi_header_t header; unsigned int data_len; + + // Data buffer used to store data read for SysEx or meta events: + byte *buffer; + unsigned int buffer_size; }; static boolean CheckChunkHeader(chunk_header_t *chunk, @@ -137,6 +141,9 @@ midi_file_t *MIDI_OpenFile(char *filename) return NULL; } + file->buffer = NULL; + file->buffer_size = 0; + // Open file file->stream = fopen(filename, "rb"); @@ -172,9 +179,116 @@ midi_file_t *MIDI_OpenFile(char *filename) void MIDI_CloseFile(midi_file_t *file) { fclose(file->stream); + free(file->buffer); free(file); } +// Read a single byte. Returns false on error. + +static boolean ReadByte(midi_file_t *file, byte *result) +{ + int c; + + c = fgetc(file->stream); + + if (c == EOF) + { + return false; + } + else + { + *result = (byte) c; + + return true; + } +} + +// Read a variable-length value. + +static boolean ReadVariableLength(midi_file_t *file, unsigned int *result) +{ + int i; + byte b; + + *result = 0; + + for (i=0; i<4; ++i) + { + if (!ReadByte(file, &b)) + { + fprintf(stderr, "Error while reading variable-length value\n"); + return false; + } + + // Insert the bottom seven bits from this byte. + + *result <<= 7; + *result |= b & 0x7f; + + // If the top bit is not set, this is the end. + + if ((b & 0x80) == 0) + { + return true; + } + } + + fprintf(stderr, "Variable-length value too long: maximum of four bytes!\n");; + return false; +} + +// Expand the size of the buffer used for SysEx/Meta events: + +static boolean ExpandBuffer(midi_file_t *file, unsigned int new_size) +{ + byte *new_buffer; + + if (file->buffer_size < new_size) + { + // Reallocate to a larger size: + + new_buffer = realloc(file->buffer, new_size); + + if (new_buffer == NULL) + { + fprintf(stderr, "ExpandBuffer: Failed to expand buffer to %u " + "bytes\n", new_size); + return false; + } + + file->buffer = new_buffer; + file->buffer_size = new_size; + } + + return true; +} + +// Read a byte sequence into the data buffer. + +static boolean ReadByteSequence(midi_file_t *file, unsigned int num_bytes) +{ + unsigned int i; + + // Check that we have enough space: + + if (!ExpandBuffer(file, num_bytes)) + { + return false; + } + + for (i=0; ibuffer[i])) + { + fprintf(stderr, "ReadByteSequence: Error while reading byte %u\n", + i); + return false; + } + } + + return true; +} + // Read a MIDI channel event. // two_param indicates that the event type takes two parameters // (three byte) otherwise it is single parameter (two byte) @@ -182,7 +296,7 @@ void MIDI_CloseFile(midi_file_t *file) static boolean ReadChannelEvent(midi_file_t *file, midi_event_t *event, int event_type, boolean two_param) { - int c; + byte b; // Set basics: @@ -191,27 +305,23 @@ static boolean ReadChannelEvent(midi_file_t *file, midi_event_t *event, // Read parameters: - c = fgetc(file->stream); - - if (c == EOF) + if (!ReadByte(file, &b)) { return false; } - event->data.channel.param1 = c; + event->data.channel.param1 = b; // Second parameter: if (two_param) { - c = fgetc(file->stream); - - if (c == EOF) + if (!ReadByte(file, &b)) { return false; } - event->data.channel.param2 = c; + event->data.channel.param2 = b; } return true; @@ -222,26 +332,79 @@ static boolean ReadChannelEvent(midi_file_t *file, midi_event_t *event, static boolean ReadSysExEvent(midi_file_t *file, midi_event_t *event, int event_type) { - // TODO - return false; + event->event_type = event_type; + + if (!ReadVariableLength(file, &event->data.sysex.length)) + { + fprintf(stderr, "ReadSysExEvent: Failed to read length of " + "SysEx block\n"); + return false; + } + + // Read the byte sequence: + + if (!ReadByteSequence(file, event->data.sysex.length)) + { + fprintf(stderr, "ReadSysExEvent: Failed while reading SysEx event\n"); + return false; + } + + event->data.sysex.data = file->buffer; + + return true; } // Read meta event: static boolean ReadMetaEvent(midi_file_t *file, midi_event_t *event) { - // TODO + byte b; + + // Read meta event type: + + if (!ReadByte(file, &b)) + { + fprintf(stderr, "ReadMetaEvent: Failed to read meta event type\n"); + return false; + } + + event->data.meta.type = b; + + // Read length of meta event data: + + if (!ReadVariableLength(file, &event->data.meta.length)) + { + fprintf(stderr, "ReadSysExEvent: Failed to read length of " + "SysEx block\n"); + return false; + } + + // Read the byte sequence: + + if (!ReadByteSequence(file, event->data.meta.length)) + { + fprintf(stderr, "ReadSysExEvent: Failed while reading SysEx event\n"); + return false; + } + + event->data.meta.data = file->buffer; + return false; } boolean MIDI_ReadEvent(midi_file_t *file, midi_event_t *event) { - int event_type; + byte event_type; - event_type = fgetc(file->stream); + if (!ReadVariableLength(file, &event->delta_time)) + { + fprintf(stderr, "MIDI_ReadEvent: Failed to read event timestamp\n"); + return false; + } - if (event_type == EOF) + if (!ReadByte(file, &event_type)) { + fprintf(stderr, "MIDI_ReadEvent: Failed to read event type\n"); return false; } @@ -277,7 +440,8 @@ boolean MIDI_ReadEvent(midi_file_t *file, midi_event_t *event) return ReadMetaEvent(file, event); } - // Fall-through deliberate - + // --- Fall-through deliberate --- + // Other 0xfx event types are unknown default: fprintf(stderr, "Unknown MIDI event type: 0x%x\n", event_type); -- cgit v1.2.3 From c4f640be999e80351f1c89c893a0d5ce39c20cd9 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 29 Mar 2009 22:55:55 +0000 Subject: Clean up error messages, minor bugs etc. Subversion-branch: /branches/opl-branch Subversion-revision: 1492 --- src/midifile.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/midifile.c b/src/midifile.c index 1b8a8786..ed60958d 100644 --- a/src/midifile.c +++ b/src/midifile.c @@ -33,6 +33,7 @@ #define HEADER_CHUNK_ID "MThd" #define TRACK_CHUNK_ID "MTrk" +#define MAX_BUFFER_SIZE 0x10000 typedef struct { @@ -68,7 +69,7 @@ static boolean CheckChunkHeader(chunk_header_t *chunk, if (!result) { - fprintf(stderr, "CheckChunkHeader: Expected '%s' chunk header!\n", + fprintf(stderr, "CheckChunkHeader: Expected '%s' chunk header\n", expected_id); } @@ -150,7 +151,7 @@ midi_file_t *MIDI_OpenFile(char *filename) if (file->stream == NULL) { - fprintf(stderr, "Failed to open '%s'\n", filename); + fprintf(stderr, "MIDI_OpenFile: Failed to open '%s'\n", filename); free(file); return NULL; } @@ -193,6 +194,7 @@ static boolean ReadByte(midi_file_t *file, byte *result) if (c == EOF) { + fprintf(stderr, "ReadByte: Unexpected end of file\n"); return false; } else @@ -216,7 +218,8 @@ static boolean ReadVariableLength(midi_file_t *file, unsigned int *result) { if (!ReadByte(file, &b)) { - fprintf(stderr, "Error while reading variable-length value\n"); + fprintf(stderr, "ReadVariableLength: Error while reading " + "variable-length value\n"); return false; } @@ -233,7 +236,8 @@ static boolean ReadVariableLength(midi_file_t *file, unsigned int *result) } } - fprintf(stderr, "Variable-length value too long: maximum of four bytes!\n");; + fprintf(stderr, "ReadVariableLength: Variable-length value too " + "long: maximum of four bytes\n"); return false; } @@ -243,6 +247,13 @@ static boolean ExpandBuffer(midi_file_t *file, unsigned int new_size) { byte *new_buffer; + if (new_size > MAX_BUFFER_SIZE) + { + fprintf(stderr, "ExpandBuffer: Tried to expand buffer to %u bytes\n", + new_size); + return false; + } + if (file->buffer_size < new_size) { // Reallocate to a larger size: @@ -294,7 +305,7 @@ static boolean ReadByteSequence(midi_file_t *file, unsigned int num_bytes) // (three byte) otherwise it is single parameter (two byte) static boolean ReadChannelEvent(midi_file_t *file, midi_event_t *event, - int event_type, boolean two_param) + byte event_type, boolean two_param) { byte b; @@ -307,6 +318,8 @@ static boolean ReadChannelEvent(midi_file_t *file, midi_event_t *event, if (!ReadByte(file, &b)) { + fprintf(stderr, "ReadChannelEvent: Error while reading channel " + "event parameters\n"); return false; } @@ -318,6 +331,8 @@ static boolean ReadChannelEvent(midi_file_t *file, midi_event_t *event, { if (!ReadByte(file, &b)) { + fprintf(stderr, "ReadChannelEvent: Error while reading channel " + "event parameters\n"); return false; } @@ -389,7 +404,7 @@ static boolean ReadMetaEvent(midi_file_t *file, midi_event_t *event) event->data.meta.data = file->buffer; - return false; + return true; } boolean MIDI_ReadEvent(midi_file_t *file, midi_event_t *event) -- cgit v1.2.3 From 9b192c44f932542ccd835936d593c43ce3e9e9e3 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Fri, 3 Apr 2009 19:58:08 +0000 Subject: Fix up MIDI reading code; add test code. Subversion-branch: /branches/opl-branch Subversion-revision: 1494 --- src/Makefile.am | 3 ++ src/midifile.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++--------- src/midifile.h | 15 ++++---- 3 files changed, 98 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 92095b5c..3874c35f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -195,3 +195,6 @@ icon.c : ../data/doom.ico endif +midiread : midifile.c + $(CC) -DTEST $(CFLAGS) @LDFLAGS@ $^ -o $@ + diff --git a/src/midifile.c b/src/midifile.c index ed60958d..e4273c12 100644 --- a/src/midifile.c +++ b/src/midifile.c @@ -27,6 +27,7 @@ #include #include +#include "doomdef.h" #include "doomtype.h" #include "i_swap.h" #include "midifile.h" @@ -39,15 +40,15 @@ typedef struct { byte chunk_id[4]; unsigned int chunk_size; -} chunk_header_t; +} PACKEDATTR chunk_header_t; typedef struct { chunk_header_t chunk_header; unsigned short format_type; unsigned short num_tracks; - unsigned int time_division; -} midi_header_t; + unsigned short time_division; +} PACKEDATTR midi_header_t; struct midi_file_s { @@ -65,12 +66,15 @@ static boolean CheckChunkHeader(chunk_header_t *chunk, { boolean result; - result = (strcmp((char *) chunk->chunk_id, expected_id) == 0); + result = (memcmp((char *) chunk->chunk_id, expected_id, 4) == 0); if (!result) { - fprintf(stderr, "CheckChunkHeader: Expected '%s' chunk header\n", - expected_id); + fprintf(stderr, "CheckChunkHeader: Expected '%s' chunk header, " + "got '%c%c%c%c'\n", + expected_id, + chunk->chunk_id[0], chunk->chunk_id[1], + chunk->chunk_id[2], chunk->chunk_id[3]); } return result; @@ -80,24 +84,26 @@ static boolean CheckChunkHeader(chunk_header_t *chunk, static boolean ReadHeaderChunk(midi_file_t *file) { - size_t bytes_read; + size_t records_read; - bytes_read = fread(&file->header, sizeof(midi_header_t), 1, file->stream); + records_read = fread(&file->header, sizeof(midi_header_t), 1, file->stream); - if (bytes_read < sizeof(midi_header_t)) + if (records_read < 1) { return false; } if (!CheckChunkHeader(&file->header.chunk_header, HEADER_CHUNK_ID) - || LONG(file->header.chunk_header.chunk_size) != 6) + || SDL_SwapBE32(file->header.chunk_header.chunk_size) != 6) { - fprintf(stderr, "ReadHeaderChunk: Invalid MIDI chunk header!\n"); + fprintf(stderr, "ReadHeaderChunk: Invalid MIDI chunk header! " + "chunk_size=%i\n", + SDL_SwapBE32(file->header.chunk_header.chunk_size)); return false; } - if (SHORT(file->header.format_type) != 0 - || SHORT(file->header.num_tracks) != 1) + if (SDL_SwapBE16(file->header.format_type) != 0 + || SDL_SwapBE16(file->header.num_tracks) != 1) { fprintf(stderr, "ReadHeaderChunk: Only single track, " "type 0 MIDI files supported!\n"); @@ -111,12 +117,12 @@ static boolean ReadHeaderChunk(midi_file_t *file) static boolean ReadTrackChunk(midi_file_t *file) { - size_t bytes_read; + size_t records_read; chunk_header_t chunk_header; - bytes_read = fread(&chunk_header, sizeof(chunk_header_t), 1, file->stream); + records_read = fread(&chunk_header, sizeof(chunk_header_t), 1, file->stream); - if (bytes_read < sizeof(chunk_header)) + if (records_read < 1) { return false; } @@ -126,7 +132,7 @@ static boolean ReadTrackChunk(midi_file_t *file) return false; } - file->data_len = LONG(chunk_header.chunk_size); + file->data_len = SDL_SwapBE32(chunk_header.chunk_size); return true; } @@ -375,6 +381,8 @@ static boolean ReadMetaEvent(midi_file_t *file, midi_event_t *event) { byte b; + event->event_type = MIDI_EVENT_META; + // Read meta event type: if (!ReadByte(file, &b)) @@ -464,3 +472,65 @@ boolean MIDI_ReadEvent(midi_file_t *file, midi_event_t *event) } } +#ifdef TEST + +int main(int argc, char *argv[]) +{ + midi_file_t *file; + midi_event_t event; + + if (argc < 2) + { + printf("Usage: %s \n", argv[0]); + exit(1); + } + + file = MIDI_OpenFile(argv[1]); + + if (file == NULL) + { + fprintf(stderr, "Failed to open %s\n", argv[1]); + exit(1); + } + + while (MIDI_ReadEvent(file, &event)) + { + printf("Event type: %i\n", event.event_type); + + switch(event.event_type) + { + case MIDI_EVENT_NOTE_OFF: + case MIDI_EVENT_NOTE_ON: + case MIDI_EVENT_AFTERTOUCH: + case MIDI_EVENT_CONTROLLER: + case MIDI_EVENT_PROGRAM_CHANGE: + case MIDI_EVENT_CHAN_AFTERTOUCH: + case MIDI_EVENT_PITCH_BEND: + printf("\tChannel: %i\n", event.data.channel.channel); + printf("\tParameter 1: %i\n", event.data.channel.param1); + printf("\tParameter 2: %i\n", event.data.channel.param2); + break; + + case MIDI_EVENT_SYSEX: + case MIDI_EVENT_SYSEX_SPLIT: + printf("\tLength: %i\n", event.data.sysex.length); + break; + + case MIDI_EVENT_META: + printf("\tMeta type: %i\n", event.data.meta.type); + printf("\tLength: %i\n", event.data.meta.length); + break; + } + + if (event.event_type == MIDI_EVENT_META + && event.data.meta.type == MIDI_META_END_OF_TRACK) + { + break; + } + } + + return 0; +} + +#endif + diff --git a/src/midifile.h b/src/midifile.h index d7df8b86..7928fdda 100644 --- a/src/midifile.h +++ b/src/midifile.h @@ -65,13 +65,14 @@ typedef enum MIDI_META_MARKER = 0x6, MIDI_META_CUE_POINT = 0x7, - MIDI_META_CHANNEL_PREFIX = 0x8, - MIDI_META_END_OF_TRACK = 0x9, - MIDI_META_SET_TEMPO = 0xa, - MIDI_META_SMPTE_OFFSET = 0xb, - MIDI_META_TIME_SIGNATURE = 0xc, - MIDI_META_KEY_SIGNATURE = 0xd, - MIDI_META_SEQUENCER_SPECIFIC = 0xe, + MIDI_META_CHANNEL_PREFIX = 0x20, + MIDI_META_END_OF_TRACK = 0x2f, + + MIDI_META_SET_TEMPO = 0x51, + MIDI_META_SMPTE_OFFSET = 0x54, + MIDI_META_TIME_SIGNATURE = 0x58, + MIDI_META_KEY_SIGNATURE = 0x59, + MIDI_META_SEQUENCER_SPECIFIC = 0x7f, } midi_meta_event_type_t; typedef struct -- cgit v1.2.3 From b2d78c296a5a2f9cf37bf8bd3dafb5c8ba166812 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Fri, 3 Apr 2009 20:07:08 +0000 Subject: Show MIDI event types with string identifiers. Subversion-branch: /branches/opl-branch Subversion-revision: 1495 --- src/midifile.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/midifile.c b/src/midifile.c index e4273c12..ef2ceb88 100644 --- a/src/midifile.c +++ b/src/midifile.c @@ -474,6 +474,36 @@ boolean MIDI_ReadEvent(midi_file_t *file, midi_event_t *event) #ifdef TEST +static char *MIDI_EventTypeToString(midi_event_type_t event_type) +{ + switch (event_type) + { + case MIDI_EVENT_NOTE_OFF: + return "MIDI_EVENT_NOTE_OFF"; + case MIDI_EVENT_NOTE_ON: + return "MIDI_EVENT_NOTE_ON"; + case MIDI_EVENT_AFTERTOUCH: + return "MIDI_EVENT_AFTERTOUCH"; + case MIDI_EVENT_CONTROLLER: + return "MIDI_EVENT_CONTROLLER"; + case MIDI_EVENT_PROGRAM_CHANGE: + return "MIDI_EVENT_PROGRAM_CHANGE"; + case MIDI_EVENT_CHAN_AFTERTOUCH: + return "MIDI_EVENT_CHAN_AFTERTOUCH"; + case MIDI_EVENT_PITCH_BEND: + return "MIDI_EVENT_PITCH_BEND"; + case MIDI_EVENT_SYSEX: + return "MIDI_EVENT_SYSEX"; + case MIDI_EVENT_SYSEX_SPLIT: + return "MIDI_EVENT_SYSEX_SPLIT"; + case MIDI_EVENT_META: + return "MIDI_EVENT_META"; + + default: + return "(unknown)"; + } +} + int main(int argc, char *argv[]) { midi_file_t *file; @@ -495,7 +525,9 @@ int main(int argc, char *argv[]) while (MIDI_ReadEvent(file, &event)) { - printf("Event type: %i\n", event.event_type); + printf("Event type: %s (%i)\n", + MIDI_EventTypeToString(event.event_type), + event.event_type); switch(event.event_type) { -- cgit v1.2.3 From 3dd7e1db9bf26e1e50bc13f6b176e54d63f2da85 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 13 Apr 2009 22:23:05 +0000 Subject: Extend MIDI file code to support reading multi-track files. Subversion-branch: /branches/opl-branch Subversion-revision: 1498 --- src/midifile.c | 562 +++++++++++++++++++++++++++++++++++---------------------- src/midifile.h | 2 +- 2 files changed, 351 insertions(+), 213 deletions(-) (limited to 'src') diff --git a/src/midifile.c b/src/midifile.c index ef2ceb88..cca0189e 100644 --- a/src/midifile.c +++ b/src/midifile.c @@ -50,17 +50,33 @@ typedef struct unsigned short time_division; } PACKEDATTR midi_header_t; +typedef struct +{ + // Length in bytes: + + unsigned int data_len; + + // Events in this track: + + midi_event_t *events; + int num_events; +} PACKEDATTR midi_track_t; + struct midi_file_s { - FILE *stream; midi_header_t header; - unsigned int data_len; + + // All tracks in this file: + midi_track_t *tracks; + unsigned int num_tracks; // Data buffer used to store data read for SysEx or meta events: byte *buffer; unsigned int buffer_size; }; +// Check the header of a chunk: + static boolean CheckChunkHeader(chunk_header_t *chunk, char *expected_id) { @@ -80,123 +96,13 @@ static boolean CheckChunkHeader(chunk_header_t *chunk, return result; } -// Read and check the header chunk. - -static boolean ReadHeaderChunk(midi_file_t *file) -{ - size_t records_read; - - records_read = fread(&file->header, sizeof(midi_header_t), 1, file->stream); - - if (records_read < 1) - { - return false; - } - - if (!CheckChunkHeader(&file->header.chunk_header, HEADER_CHUNK_ID) - || SDL_SwapBE32(file->header.chunk_header.chunk_size) != 6) - { - fprintf(stderr, "ReadHeaderChunk: Invalid MIDI chunk header! " - "chunk_size=%i\n", - SDL_SwapBE32(file->header.chunk_header.chunk_size)); - return false; - } - - if (SDL_SwapBE16(file->header.format_type) != 0 - || SDL_SwapBE16(file->header.num_tracks) != 1) - { - fprintf(stderr, "ReadHeaderChunk: Only single track, " - "type 0 MIDI files supported!\n"); - return false; - } - - return true; -} - -// Read and check the track chunk header - -static boolean ReadTrackChunk(midi_file_t *file) -{ - size_t records_read; - chunk_header_t chunk_header; - - records_read = fread(&chunk_header, sizeof(chunk_header_t), 1, file->stream); - - if (records_read < 1) - { - return false; - } - - if (!CheckChunkHeader(&chunk_header, TRACK_CHUNK_ID)) - { - return false; - } - - file->data_len = SDL_SwapBE32(chunk_header.chunk_size); - - return true; -} - -midi_file_t *MIDI_OpenFile(char *filename) -{ - midi_file_t *file; - - file = malloc(sizeof(midi_file_t)); - - if (file == NULL) - { - return NULL; - } - - file->buffer = NULL; - file->buffer_size = 0; - - // Open file - - file->stream = fopen(filename, "rb"); - - if (file->stream == NULL) - { - fprintf(stderr, "MIDI_OpenFile: Failed to open '%s'\n", filename); - free(file); - return NULL; - } - - // Read MIDI file header - - if (!ReadHeaderChunk(file)) - { - fclose(file->stream); - free(file); - return NULL; - } - - // Read track header - - if (!ReadTrackChunk(file)) - { - fclose(file->stream); - free(file); - return NULL; - } - - return file; -} - -void MIDI_CloseFile(midi_file_t *file) -{ - fclose(file->stream); - free(file->buffer); - free(file); -} - // Read a single byte. Returns false on error. -static boolean ReadByte(midi_file_t *file, byte *result) +static boolean ReadByte(byte *result, FILE *stream) { int c; - c = fgetc(file->stream); + c = fgetc(stream); if (c == EOF) { @@ -213,7 +119,7 @@ static boolean ReadByte(midi_file_t *file, byte *result) // Read a variable-length value. -static boolean ReadVariableLength(midi_file_t *file, unsigned int *result) +static boolean ReadVariableLength(unsigned int *result, FILE *stream) { int i; byte b; @@ -222,7 +128,7 @@ static boolean ReadVariableLength(midi_file_t *file, unsigned int *result) for (i=0; i<4; ++i) { - if (!ReadByte(file, &b)) + if (!ReadByte(&b, stream)) { fprintf(stderr, "ReadVariableLength: Error while reading " "variable-length value\n"); @@ -247,71 +153,46 @@ static boolean ReadVariableLength(midi_file_t *file, unsigned int *result) return false; } -// Expand the size of the buffer used for SysEx/Meta events: - -static boolean ExpandBuffer(midi_file_t *file, unsigned int new_size) -{ - byte *new_buffer; - - if (new_size > MAX_BUFFER_SIZE) - { - fprintf(stderr, "ExpandBuffer: Tried to expand buffer to %u bytes\n", - new_size); - return false; - } - - if (file->buffer_size < new_size) - { - // Reallocate to a larger size: - - new_buffer = realloc(file->buffer, new_size); - - if (new_buffer == NULL) - { - fprintf(stderr, "ExpandBuffer: Failed to expand buffer to %u " - "bytes\n", new_size); - return false; - } - - file->buffer = new_buffer; - file->buffer_size = new_size; - } - - return true; -} - // Read a byte sequence into the data buffer. -static boolean ReadByteSequence(midi_file_t *file, unsigned int num_bytes) +static void *ReadByteSequence(unsigned int num_bytes, FILE *stream) { unsigned int i; + byte *result; + + // Allocate a buffer: - // Check that we have enough space: + result = malloc(num_bytes); - if (!ExpandBuffer(file, num_bytes)) + if (result == NULL) { - return false; + fprintf(stderr, "ReadByteSequence: Failed to allocate buffer\n"); + return NULL; } + // Read the data: + for (i=0; ibuffer[i])) + if (!ReadByte(&result[i], stream)) { fprintf(stderr, "ReadByteSequence: Error while reading byte %u\n", i); - return false; + free(result); + return NULL; } } - return true; + return result; } // Read a MIDI channel event. // two_param indicates that the event type takes two parameters // (three byte) otherwise it is single parameter (two byte) -static boolean ReadChannelEvent(midi_file_t *file, midi_event_t *event, - byte event_type, boolean two_param) +static boolean ReadChannelEvent(midi_event_t *event, + byte event_type, boolean two_param, + FILE *stream) { byte b; @@ -322,7 +203,7 @@ static boolean ReadChannelEvent(midi_file_t *file, midi_event_t *event, // Read parameters: - if (!ReadByte(file, &b)) + if (!ReadByte(&b, stream)) { fprintf(stderr, "ReadChannelEvent: Error while reading channel " "event parameters\n"); @@ -335,7 +216,7 @@ static boolean ReadChannelEvent(midi_file_t *file, midi_event_t *event, if (two_param) { - if (!ReadByte(file, &b)) + if (!ReadByte(&b, stream)) { fprintf(stderr, "ReadChannelEvent: Error while reading channel " "event parameters\n"); @@ -350,12 +231,12 @@ static boolean ReadChannelEvent(midi_file_t *file, midi_event_t *event, // Read sysex event: -static boolean ReadSysExEvent(midi_file_t *file, midi_event_t *event, - int event_type) +static boolean ReadSysExEvent(midi_event_t *event, int event_type, + FILE *stream) { event->event_type = event_type; - if (!ReadVariableLength(file, &event->data.sysex.length)) + if (!ReadVariableLength(&event->data.sysex.length, stream)) { fprintf(stderr, "ReadSysExEvent: Failed to read length of " "SysEx block\n"); @@ -364,20 +245,20 @@ static boolean ReadSysExEvent(midi_file_t *file, midi_event_t *event, // Read the byte sequence: - if (!ReadByteSequence(file, event->data.sysex.length)) + event->data.sysex.data = ReadByteSequence(event->data.sysex.length, stream); + + if (event->data.sysex.data == NULL) { fprintf(stderr, "ReadSysExEvent: Failed while reading SysEx event\n"); return false; } - event->data.sysex.data = file->buffer; - return true; } // Read meta event: -static boolean ReadMetaEvent(midi_file_t *file, midi_event_t *event) +static boolean ReadMetaEvent(midi_event_t *event, FILE *stream) { byte b; @@ -385,7 +266,7 @@ static boolean ReadMetaEvent(midi_file_t *file, midi_event_t *event) // Read meta event type: - if (!ReadByte(file, &b)) + if (!ReadByte(&b, stream)) { fprintf(stderr, "ReadMetaEvent: Failed to read meta event type\n"); return false; @@ -395,7 +276,7 @@ static boolean ReadMetaEvent(midi_file_t *file, midi_event_t *event) // Read length of meta event data: - if (!ReadVariableLength(file, &event->data.meta.length)) + if (!ReadVariableLength(&event->data.meta.length, stream)) { fprintf(stderr, "ReadSysExEvent: Failed to read length of " "SysEx block\n"); @@ -404,30 +285,30 @@ static boolean ReadMetaEvent(midi_file_t *file, midi_event_t *event) // Read the byte sequence: - if (!ReadByteSequence(file, event->data.meta.length)) + event->data.meta.data = ReadByteSequence(event->data.meta.length, stream); + + if (event->data.meta.data == NULL) { fprintf(stderr, "ReadSysExEvent: Failed while reading SysEx event\n"); return false; } - event->data.meta.data = file->buffer; - return true; } -boolean MIDI_ReadEvent(midi_file_t *file, midi_event_t *event) +static boolean ReadEvent(midi_event_t *event, FILE *stream) { byte event_type; - if (!ReadVariableLength(file, &event->delta_time)) + if (!ReadVariableLength(&event->delta_time, stream)) { - fprintf(stderr, "MIDI_ReadEvent: Failed to read event timestamp\n"); + fprintf(stderr, "ReadEvent: Failed to read event timestamp\n"); return false; } - if (!ReadByte(file, &event_type)) + if (!ReadByte(&event_type, stream)) { - fprintf(stderr, "MIDI_ReadEvent: Failed to read event type\n"); + fprintf(stderr, "ReadEvent: Failed to read event type\n"); return false; } @@ -442,13 +323,13 @@ boolean MIDI_ReadEvent(midi_file_t *file, midi_event_t *event) case MIDI_EVENT_AFTERTOUCH: case MIDI_EVENT_CONTROLLER: case MIDI_EVENT_PITCH_BEND: - return ReadChannelEvent(file, event, event_type, true); + return ReadChannelEvent(event, event_type, true, stream); // Single parameter channel events: case MIDI_EVENT_PROGRAM_CHANGE: case MIDI_EVENT_CHAN_AFTERTOUCH: - return ReadChannelEvent(file, event, event_type, false); + return ReadChannelEvent(event, event_type, false, stream); // Other event types: @@ -456,11 +337,11 @@ boolean MIDI_ReadEvent(midi_file_t *file, midi_event_t *event) if (event_type == MIDI_EVENT_SYSEX || event_type == MIDI_EVENT_SYSEX_SPLIT) { - return ReadSysExEvent(file, event, event_type); + return ReadSysExEvent(event, event_type, stream); } else if (event_type == MIDI_EVENT_META) { - return ReadMetaEvent(file, event); + return ReadMetaEvent(event, stream); } // --- Fall-through deliberate --- @@ -472,6 +353,254 @@ boolean MIDI_ReadEvent(midi_file_t *file, midi_event_t *event) } } +// Free an event: + +static void FreeEvent(midi_event_t *event) +{ + // Some event types have dynamically allocated buffers assigned + // to them that must be freed. + + switch (event->event_type) + { + case MIDI_EVENT_SYSEX: + case MIDI_EVENT_SYSEX_SPLIT: + free(event->data.sysex.data); + break; + + case MIDI_EVENT_META: + free(event->data.meta.data); + break; + + default: + // Nothing to do. + break; + } +} + +// Read and check the track chunk header + +static boolean ReadTrackHeader(midi_track_t *track, FILE *stream) +{ + size_t records_read; + chunk_header_t chunk_header; + + records_read = fread(&chunk_header, sizeof(chunk_header_t), 1, stream); + + if (records_read < 1) + { + return false; + } + + if (!CheckChunkHeader(&chunk_header, TRACK_CHUNK_ID)) + { + return false; + } + + track->data_len = SDL_SwapBE32(chunk_header.chunk_size); + + return true; +} + +static boolean ReadTrack(midi_track_t *track, FILE *stream) +{ + midi_event_t *new_events; + midi_event_t *event; + + track->num_events = 0; + track->events = NULL; + + // Read the header: + + if (!ReadTrackHeader(track, stream)) + { + return false; + } + + // Then the events: + + for (;;) + { + // Resize the track slightly larger to hold another event: + + new_events = realloc(track->events, + sizeof(midi_event_t) * (track->num_events + 1)); + + if (new_events == NULL) + { + return false; + } + + track->events = new_events; + + // Read the next event: + + event = &track->events[track->num_events]; + if (!ReadEvent(event, stream)) + { + return false; + } + + ++track->num_events; + + // End of track? + + if (event->event_type == MIDI_EVENT_META + && event->data.meta.type == MIDI_META_END_OF_TRACK) + { + break; + } + } + + return true; +} + +// Free a track: + +static void FreeTrack(midi_track_t *track) +{ + unsigned int i; + + for (i=0; inum_events; ++i) + { + FreeEvent(&track->events[i]); + } + + free(track->events); +} + +static boolean ReadAllTracks(midi_file_t *file, FILE *stream) +{ + unsigned int i; + + // Allocate list of tracks and read each track: + + file->tracks = malloc(sizeof(midi_track_t) * file->num_tracks); + + if (file->tracks == NULL) + { + return false; + } + + memset(file->tracks, 0, sizeof(midi_track_t) * file->num_tracks); + + // Read each track: + + for (i=0; inum_tracks; ++i) + { + if (!ReadTrack(&file->tracks[i], stream)) + { + return false; + } + } + + return true; +} + +// Read and check the header chunk. + +static boolean ReadFileHeader(midi_file_t *file, FILE *stream) +{ + size_t records_read; + unsigned int format_type; + + records_read = fread(&file->header, sizeof(midi_header_t), 1, stream); + + if (records_read < 1) + { + return false; + } + + if (!CheckChunkHeader(&file->header.chunk_header, HEADER_CHUNK_ID) + || SDL_SwapBE32(file->header.chunk_header.chunk_size) != 6) + { + fprintf(stderr, "ReadFileHeader: Invalid MIDI chunk header! " + "chunk_size=%i\n", + SDL_SwapBE32(file->header.chunk_header.chunk_size)); + return false; + } + + format_type = SDL_SwapBE16(file->header.format_type); + file->num_tracks = SDL_SwapBE16(file->header.num_tracks); + + if ((format_type != 0 && format_type != 1) + || file->num_tracks < 1) + { + fprintf(stderr, "ReadFileHeader: Only type 0/1 " + "MIDI files supported!\n"); + return false; + } + + return true; +} + +void MIDI_FreeFile(midi_file_t *file) +{ + int i; + + if (file->tracks != NULL) + { + for (i=0; inum_tracks; ++i) + { + FreeTrack(&file->tracks[i]); + } + + free(file->tracks); + } + + free(file); +} + +midi_file_t *MIDI_OpenFile(char *filename) +{ + midi_file_t *file; + FILE *stream; + + file = malloc(sizeof(midi_file_t)); + + if (file == NULL) + { + return NULL; + } + + file->tracks = NULL; + file->num_tracks = 0; + file->buffer = NULL; + file->buffer_size = 0; + + // Open file + + stream = fopen(filename, "rb"); + + if (stream == NULL) + { + fprintf(stderr, "MIDI_OpenFile: Failed to open '%s'\n", filename); + MIDI_FreeFile(file); + return NULL; + } + + // Read MIDI file header + + if (!ReadFileHeader(file, stream)) + { + fclose(stream); + MIDI_FreeFile(file); + return NULL; + } + + // Read all tracks: + + if (!ReadAllTracks(file, stream)) + { + fclose(stream); + MIDI_FreeFile(file); + return NULL; + } + + fclose(stream); + + return file; +} + #ifdef TEST static char *MIDI_EventTypeToString(midi_event_type_t event_type) @@ -504,32 +633,20 @@ static char *MIDI_EventTypeToString(midi_event_type_t event_type) } } -int main(int argc, char *argv[]) +void PrintTrack(midi_track_t *track) { - midi_file_t *file; - midi_event_t event; - - if (argc < 2) - { - printf("Usage: %s \n", argv[0]); - exit(1); - } - - file = MIDI_OpenFile(argv[1]); + midi_event_t *event; + unsigned int i; - if (file == NULL) + for (i=0; inum_events; ++i) { - fprintf(stderr, "Failed to open %s\n", argv[1]); - exit(1); - } + event = &track->events[i]; - while (MIDI_ReadEvent(file, &event)) - { printf("Event type: %s (%i)\n", - MIDI_EventTypeToString(event.event_type), - event.event_type); + MIDI_EventTypeToString(event->event_type), + event->event_type); - switch(event.event_type) + switch(event->event_type) { case MIDI_EVENT_NOTE_OFF: case MIDI_EVENT_NOTE_ON: @@ -538,27 +655,48 @@ int main(int argc, char *argv[]) case MIDI_EVENT_PROGRAM_CHANGE: case MIDI_EVENT_CHAN_AFTERTOUCH: case MIDI_EVENT_PITCH_BEND: - printf("\tChannel: %i\n", event.data.channel.channel); - printf("\tParameter 1: %i\n", event.data.channel.param1); - printf("\tParameter 2: %i\n", event.data.channel.param2); + printf("\tChannel: %i\n", event->data.channel.channel); + printf("\tParameter 1: %i\n", event->data.channel.param1); + printf("\tParameter 2: %i\n", event->data.channel.param2); break; case MIDI_EVENT_SYSEX: case MIDI_EVENT_SYSEX_SPLIT: - printf("\tLength: %i\n", event.data.sysex.length); + printf("\tLength: %i\n", event->data.sysex.length); break; case MIDI_EVENT_META: - printf("\tMeta type: %i\n", event.data.meta.type); - printf("\tLength: %i\n", event.data.meta.length); + printf("\tMeta type: %i\n", event->data.meta.type); + printf("\tLength: %i\n", event->data.meta.length); break; } + } +} - if (event.event_type == MIDI_EVENT_META - && event.data.meta.type == MIDI_META_END_OF_TRACK) - { - break; - } +int main(int argc, char *argv[]) +{ + midi_file_t *file; + unsigned int i; + + if (argc < 2) + { + printf("Usage: %s \n", argv[0]); + exit(1); + } + + file = MIDI_OpenFile(argv[1]); + + if (file == NULL) + { + fprintf(stderr, "Failed to open %s\n", argv[1]); + exit(1); + } + + for (i=0; inum_tracks; ++i) + { + printf("\n== Track %i ==\n\n", i); + + PrintTrack(&file->tracks[i]); } return 0; diff --git a/src/midifile.h b/src/midifile.h index 7928fdda..16f911e7 100644 --- a/src/midifile.h +++ b/src/midifile.h @@ -130,7 +130,7 @@ typedef struct } midi_event_t; midi_file_t *MIDI_OpenFile(char *filename); -void MIDI_CloseFile(midi_file_t *file); +void MIDI_FreeFile(midi_file_t *file); #endif /* #ifndef MIDIFILE_H */ -- cgit v1.2.3 From d8ada5c41da3eec5ef163d9efac9cb5dbdc2cb6b Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Wed, 15 Apr 2009 19:00:25 +0000 Subject: Parse MIDI events that reuse the event type from the previous event. Subversion-branch: /branches/opl-branch Subversion-revision: 1499 --- src/midifile.c | 70 +++++++++++++++++++++++++++++++++++++++++----------------- src/midifile.h | 14 ++++++------ 2 files changed, 57 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/midifile.c b/src/midifile.c index cca0189e..1be6ec75 100644 --- a/src/midifile.c +++ b/src/midifile.c @@ -198,8 +198,8 @@ static boolean ReadChannelEvent(midi_event_t *event, // Set basics: - event->event_type = event_type >> 4; - event->data.channel.channel = event_type & 0xf; + event->event_type = event_type & 0xf0; + event->data.channel.channel = event_type & 0x0f; // Read parameters: @@ -296,7 +296,8 @@ static boolean ReadMetaEvent(midi_event_t *event, FILE *stream) return true; } -static boolean ReadEvent(midi_event_t *event, FILE *stream) +static boolean ReadEvent(midi_event_t *event, unsigned int *last_event_type, + FILE *stream) { byte event_type; @@ -312,9 +313,29 @@ static boolean ReadEvent(midi_event_t *event, FILE *stream) return false; } + // All event types have their top bit set. Therefore, if + // the top bit is not set, it is because we are using the "same + // as previous event type" shortcut to save a byte. Skip back + // a byte so that we read this byte again. + + if ((event_type & 0x80) == 0) + { + event_type = *last_event_type; + + if (fseek(stream, -1, SEEK_CUR) < 0) + { + fprintf(stderr, "ReadEvent: Unable to seek in stream\n"); + return false; + } + } + else + { + *last_event_type = event_type; + } + // Check event type: - switch (event_type >> 4) + switch (event_type & 0xf0) { // Two parameter channel events: @@ -331,26 +352,27 @@ static boolean ReadEvent(midi_event_t *event, FILE *stream) case MIDI_EVENT_CHAN_AFTERTOUCH: return ReadChannelEvent(event, event_type, false, stream); - // Other event types: + default: + break; + } + + // Specific value? - case 0xf: - if (event_type == MIDI_EVENT_SYSEX - || event_type == MIDI_EVENT_SYSEX_SPLIT) - { - return ReadSysExEvent(event, event_type, stream); - } - else if (event_type == MIDI_EVENT_META) - { - return ReadMetaEvent(event, stream); - } + switch (event_type) + { + case MIDI_EVENT_SYSEX: + case MIDI_EVENT_SYSEX_SPLIT: + return ReadSysExEvent(event, event_type, stream); - // --- Fall-through deliberate --- - // Other 0xfx event types are unknown + case MIDI_EVENT_META: + return ReadMetaEvent(event, stream); default: - fprintf(stderr, "Unknown MIDI event type: 0x%x\n", event_type); - return false; + break; } + + fprintf(stderr, "ReadEvent: Unknown MIDI event type: 0x%x\n", event_type); + return false; } // Free an event: @@ -405,6 +427,7 @@ static boolean ReadTrack(midi_track_t *track, FILE *stream) { midi_event_t *new_events; midi_event_t *event; + unsigned int last_event_type; track->num_events = 0; track->events = NULL; @@ -418,6 +441,8 @@ static boolean ReadTrack(midi_track_t *track, FILE *stream) // Then the events: + last_event_type = 0; + for (;;) { // Resize the track slightly larger to hold another event: @@ -435,7 +460,7 @@ static boolean ReadTrack(midi_track_t *track, FILE *stream) // Read the next event: event = &track->events[track->num_events]; - if (!ReadEvent(event, stream)) + if (!ReadEvent(event, &last_event_type, stream)) { return false; } @@ -642,6 +667,11 @@ void PrintTrack(midi_track_t *track) { event = &track->events[i]; + if (event->delta_time > 0) + { + printf("Delay: %i ticks\n", event->delta_time); + } + printf("Event type: %s (%i)\n", MIDI_EventTypeToString(event->event_type), event->event_type); diff --git a/src/midifile.h b/src/midifile.h index 16f911e7..490b0171 100644 --- a/src/midifile.h +++ b/src/midifile.h @@ -30,13 +30,13 @@ typedef struct midi_file_s midi_file_t; typedef enum { - MIDI_EVENT_NOTE_OFF = 0x8, - MIDI_EVENT_NOTE_ON = 0x9, - MIDI_EVENT_AFTERTOUCH = 0xa, - MIDI_EVENT_CONTROLLER = 0xb, - MIDI_EVENT_PROGRAM_CHANGE = 0xc, - MIDI_EVENT_CHAN_AFTERTOUCH = 0xd, - MIDI_EVENT_PITCH_BEND = 0xe, + MIDI_EVENT_NOTE_OFF = 0x80, + MIDI_EVENT_NOTE_ON = 0x90, + MIDI_EVENT_AFTERTOUCH = 0xa0, + MIDI_EVENT_CONTROLLER = 0xb0, + MIDI_EVENT_PROGRAM_CHANGE = 0xc0, + MIDI_EVENT_CHAN_AFTERTOUCH = 0xd0, + MIDI_EVENT_PITCH_BEND = 0xe0, MIDI_EVENT_SYSEX = 0xf0, MIDI_EVENT_SYSEX_SPLIT = 0xf7, -- cgit v1.2.3 From 324c1d8776054394d30ea987f84c1ba2f1b1ff6f Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 29 Aug 2009 21:05:36 +0000 Subject: Rename MIDI_OpenFile to MIDI_LoadFile, remove unneeded structure packing. Subversion-branch: /branches/opl-branch Subversion-revision: 1636 --- src/midifile.c | 4 ++-- src/midifile.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/midifile.c b/src/midifile.c index 1be6ec75..6eb9e7db 100644 --- a/src/midifile.c +++ b/src/midifile.c @@ -60,7 +60,7 @@ typedef struct midi_event_t *events; int num_events; -} PACKEDATTR midi_track_t; +} midi_track_t; struct midi_file_s { @@ -575,7 +575,7 @@ void MIDI_FreeFile(midi_file_t *file) free(file); } -midi_file_t *MIDI_OpenFile(char *filename) +midi_file_t *MIDI_LoadFile(char *filename) { midi_file_t *file; FILE *stream; diff --git a/src/midifile.h b/src/midifile.h index 490b0171..f9acea35 100644 --- a/src/midifile.h +++ b/src/midifile.h @@ -129,7 +129,7 @@ typedef struct } data; } midi_event_t; -midi_file_t *MIDI_OpenFile(char *filename); +midi_file_t *MIDI_LoadFile(char *filename); void MIDI_FreeFile(midi_file_t *file); #endif /* #ifndef MIDIFILE_H */ -- cgit v1.2.3 From 9cc843c60027cb9365f3eaae3028343769d17a26 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 29 Aug 2009 21:22:32 +0000 Subject: Load MIDI file. Subversion-branch: /branches/opl-branch Subversion-revision: 1637 --- src/i_oplmusic.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index f50c3322..c444dfd8 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -40,6 +40,7 @@ #include "z_zone.h" #include "opl.h" +#include "midifile.h" #define MAXMIDLENGTH (96 * 1024) #define GENMIDI_NUM_INSTRS 128 @@ -507,6 +508,11 @@ static void I_OPL_UnRegisterSong(void *handle) { return; } + + if (handle != NULL) + { + MIDI_FreeFile(handle); + } } // Determine whether memory block is a .mid file @@ -544,6 +550,7 @@ static boolean ConvertMus(byte *musdata, int len, char *filename) static void *I_OPL_RegisterSong(void *data, int len) { + midi_file_t *result; char *filename; if (!music_initialised) @@ -567,7 +574,12 @@ static void *I_OPL_RegisterSong(void *data, int len) ConvertMus(data, len, filename); } - // .... + result = MIDI_LoadFile(filename); + + if (result == NULL) + { + fprintf(stderr, "I_OPL_RegisterSong: Failed to load MID.\n"); + } // remove file now @@ -575,7 +587,7 @@ static void *I_OPL_RegisterSong(void *data, int len) Z_Free(filename); - return NULL; + return result; } // Is the song playing? -- cgit v1.2.3 From a10180a460f6425cd308719584aa58ab4fcb63fb Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 29 Aug 2009 21:26:43 +0000 Subject: Use OPL_Delay to wait 1ms for timer to expire when doing OPL detect. Subversion-branch: /branches/opl-branch Subversion-revision: 1638 --- src/i_oplmusic.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index c444dfd8..0e1b69a3 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -202,6 +202,8 @@ static boolean DetectOPL(void) GetStatus(); } + OPL_Delay(1); + // Read status result2 = GetStatus(); -- cgit v1.2.3 From f2f36117c889c19b643058a0af33070baf4b48be Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 29 Aug 2009 21:30:26 +0000 Subject: MIDI_OpenFile -> MIDI_LoadFile. Subversion-branch: /branches/opl-branch Subversion-revision: 1639 --- src/midifile.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/midifile.c b/src/midifile.c index 6eb9e7db..61e06463 100644 --- a/src/midifile.c +++ b/src/midifile.c @@ -598,7 +598,7 @@ midi_file_t *MIDI_LoadFile(char *filename) if (stream == NULL) { - fprintf(stderr, "MIDI_OpenFile: Failed to open '%s'\n", filename); + fprintf(stderr, "MIDI_LoadFile: Failed to open '%s'\n", filename); MIDI_FreeFile(file); return NULL; } @@ -714,7 +714,7 @@ int main(int argc, char *argv[]) exit(1); } - file = MIDI_OpenFile(argv[1]); + file = MIDI_LoadFile(argv[1]); if (file == NULL) { -- cgit v1.2.3 From f6ce7dfea99cf32beb2afc8e7b02fb5f19f7544f Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 30 Aug 2009 01:56:33 +0000 Subject: Make some noise. Subversion-branch: /branches/opl-branch Subversion-revision: 1640 --- src/i_oplmusic.c | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 0e1b69a3..2c0efa92 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -42,6 +42,8 @@ #include "opl.h" #include "midifile.h" +#define TEST + #define MAXMIDLENGTH (96 * 1024) #define GENMIDI_NUM_INSTRS 128 @@ -405,6 +407,30 @@ static void I_OPL_ShutdownMusic(void) } } +#ifdef TEST +static void TestCallback(void *arg) +{ + opl_voice_t *voice = arg; + int note; + int wait_time; + + // Set level: + WriteRegister(OPL_REGS_LEVEL + voice->op2, 0); + + // Note off: + + WriteRegister(OPL_REGS_FREQ_2 + voice->index, 0x00); + // Note on: + + note = (rand() % (0x2ae - 0x16b)) + 0x16b; + WriteRegister(OPL_REGS_FREQ_1 + voice->index, note & 0xff); + WriteRegister(OPL_REGS_FREQ_2 + voice->index, 0x30 + (note >> 8)); + + wait_time = (rand() % 700) + 50; + OPL_SetCallback(wait_time, TestCallback, arg); +} +#endif + // Initialise music subsystem static boolean I_OPL_InitMusic(void) @@ -443,17 +469,19 @@ static boolean I_OPL_InitMusic(void) #ifdef TEST { + int i; opl_voice_t *voice; + int instr_num; - voice = GetFreeVoice(); - SetVoiceInstrument(voice, &main_instrs[34].opl2_voice); + for (i=0; i<3; ++i) + { + voice = GetFreeVoice(); + instr_num = rand() % 100; - // Set level: - WriteRegister(OPL_REGS_LEVEL + voice->op2, 0x94); + SetVoiceInstrument(voice, &main_instrs[instr_num].opl2_voice); - // Note on: - WriteRegister(OPL_REGS_FREQ_1 + voice->index, 0x65); - WriteRegister(OPL_REGS_FREQ_2 + voice->index, 0x2b); + OPL_SetCallback(0, TestCallback, voice); + } } #endif -- cgit v1.2.3 From ca23c95db8053b82fb817241e5de83a881f931e5 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 30 Aug 2009 21:34:12 +0000 Subject: Initial/basic MIDI track playback. Subversion-branch: /branches/opl-branch Subversion-revision: 1643 --- src/i_oplmusic.c | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/midifile.c | 69 ++++++++++++ src/midifile.h | 28 +++++ 3 files changed, 423 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 2c0efa92..3d9a2649 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -42,7 +42,7 @@ #include "opl.h" #include "midifile.h" -#define TEST +//#define TEST #define MAXMIDLENGTH (96 * 1024) #define GENMIDI_NUM_INSTRS 128 @@ -80,6 +80,37 @@ typedef struct genmidi_voice_t opl3_voice; } PACKEDATTR genmidi_instr_t; +// Data associated with a channel of a track that is currently playing. + +typedef struct +{ + // The instrument currently used for this track. + + genmidi_instr_t *instrument; + + // Volume level + + int volume; +} opl_channel_data_t; + +// Data associated with a track that is currently playing. + +typedef struct +{ + // Data for each channel. + + opl_channel_data_t channels[MIDI_CHANNELS_PER_TRACK]; + + // Track iterator used to read new events. + + midi_track_iter_t *iter; + + // Tempo control variables + + unsigned int ticks_per_beat; + unsigned int us_per_beat; +} opl_track_data_t; + typedef struct opl_voice_s opl_voice_t; struct opl_voice_s @@ -93,6 +124,15 @@ struct opl_voice_s // Currently-loaded instrument data genmidi_instr_t *current_instr; + // The channel currently using this voice. + opl_channel_data_t *channel; + + // The note that this voice is playing. + unsigned int note; + + // The frequency value being used. + unsigned int freq; + // Next in freelist opl_voice_t *next; }; @@ -104,6 +144,22 @@ static const int voice_operators[2][OPL_NUM_VOICES] = { { 0x03, 0x04, 0x05, 0x0b, 0x0c, 0x0d, 0x13, 0x14, 0x15 } }; +// Frequency values to use for each note. + +static const unsigned int note_frequencies[] = { + + // These frequencies are only used for the first seven + // MIDI note values: + + 0x158, 0x16d, 0x183, 0x19a, 0x1b2, 0x1cc, 0x1e7, + + // These frequencies are used repeatedly, cycling around + // for each octave: + + 0x204, 0x223, 0x244, 0x266, 0x28b, 0x2b1, + 0x2da, 0x306, 0x334, 0x365, 0x398, 0x3cf, +}; + static boolean music_initialised = false; //static boolean musicpaused = false; @@ -119,6 +175,10 @@ static genmidi_instr_t *percussion_instrs; static opl_voice_t voices[OPL_NUM_VOICES]; static opl_voice_t *voice_free_list; +// Track data for playing tracks: + +static opl_track_data_t *tracks; + // In the initialisation stage, register writes are spaced by reading // from the register port (0). After initialisation, spacing is // peformed by reading from the data port instead. I have no idea @@ -310,6 +370,9 @@ static void ReleaseVoice(opl_voice_t *voice) { opl_voice_t **rover; + voice->channel = NULL; + voice->note = 0; + // Search to the end of the freelist (This is how Doom behaves!) rover = &voice_free_list; @@ -320,6 +383,7 @@ static void ReleaseVoice(opl_voice_t *voice) } *rover = voice; + voice->next = NULL; } // Load data to the specified operator @@ -498,14 +562,274 @@ static void I_OPL_SetMusicVolume(int volume) current_music_volume = volume; } +static opl_voice_t *FindVoiceForNote(opl_channel_data_t *channel, int note) +{ + unsigned int i; + + for (i=0; idata.channel.channel, + event->data.channel.param1, + event->data.channel.param2); + + channel = &track->channels[event->data.channel.channel]; + + // Find the voice being used to play the note. + + voice = FindVoiceForNote(channel, event->data.channel.param1); + + if (voice == NULL) + { + return; + } + + // Note off. + + WriteRegister(OPL_REGS_FREQ_2 + voice->index, voice->freq >> 8); + + // Finished with this voice now. + + ReleaseVoice(voice); +} + +// Given a MIDI note number, get the corresponding OPL +// frequency value to use. + +static unsigned int FrequencyForNote(unsigned int note) +{ + unsigned int octave; + unsigned int key_num; + + // The first seven frequencies in the frequencies array are used + // only for the first seven MIDI notes. After this, the frequency + // value loops around the same twelve notes, increasing the + // octave. + + if (note < 7) + { + return note_frequencies[note]; + } + else + { + octave = (note - 7) / 12; + key_num = (note - 7) % 12; + + return note_frequencies[key_num + 7] | (octave << 10); + } +} + +static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) +{ + opl_voice_t *voice; + opl_channel_data_t *channel; + + printf("note on: channel %i, %i, %i\n", + event->data.channel.channel, + event->data.channel.param1, + event->data.channel.param2); + + // The channel. + + channel = &track->channels[event->data.channel.channel]; + + // Find a voice to use for this new note. + + voice = GetFreeVoice(); + + if (voice == NULL) + { + return; + } + + // Program the voice with the instrument data: + + SetVoiceInstrument(voice, &channel->instrument->opl2_voice); + + // TODO: Set the volume level. + + WriteRegister(OPL_REGS_LEVEL + voice->op2, 0); + + // Play the note. + + voice->channel = channel; + voice->note = event->data.channel.param1; + + // Write the frequency value to turn the note on. + + voice->freq = FrequencyForNote(voice->note); + + WriteRegister(OPL_REGS_FREQ_1 + voice->index, voice->freq & 0xff); + WriteRegister(OPL_REGS_FREQ_2 + voice->index, (voice->freq >> 8) | 0x20); +} + +static void ProgramChangeEvent(opl_track_data_t *track, midi_event_t *event) +{ + int channel; + int instrument; + + // Set the instrument used on this channel. + + channel = event->data.channel.channel; + instrument = event->data.channel.param1; + track->channels[channel].instrument = &main_instrs[instrument]; + + // TODO: Look through existing voices that are turned on on this + // channel, and change the instrument. +} + +static void ControllerEvent(opl_track_data_t *track, midi_event_t *event) +{ + printf("change controller: channel %i, %i, %i\n", + event->data.channel.channel, + event->data.channel.param1, + event->data.channel.param2); + + // TODO: Volume, pan. +} + +// Process a MIDI event from a track. + +static void ProcessEvent(opl_track_data_t *track, midi_event_t *event) +{ + switch (event->event_type) + { + case MIDI_EVENT_NOTE_OFF: + NoteOffEvent(track, event); + break; + + case MIDI_EVENT_NOTE_ON: + NoteOnEvent(track, event); + break; + + case MIDI_EVENT_CONTROLLER: + ControllerEvent(track, event); + break; + + case MIDI_EVENT_PROGRAM_CHANGE: + ProgramChangeEvent(track, event); + break; + + default: + fprintf(stderr, "Unknown MIDI event type %i\n", event->event_type); + break; + } +} + +static void ScheduleTrack(opl_track_data_t *track); + +// Callback function invoked when another event needs to be read from +// a track. + +static void TrackTimerCallback(void *arg) +{ + opl_track_data_t *track = arg; + midi_event_t *event; + + // Get the next event and process it. + + if (!MIDI_GetNextEvent(track->iter, &event)) + { + return; + } + + ProcessEvent(track, event); + + // Reschedule the callback for the next event in the track. + + ScheduleTrack(track); +} + +static void ScheduleTrack(opl_track_data_t *track) +{ + unsigned int nticks; + unsigned int us; + static int total = 0; + + // Get the number of microseconds until the next event. + + nticks = MIDI_GetDeltaTime(track->iter); + us = (nticks * track->us_per_beat) / track->ticks_per_beat; + total += us; + + // Set a timer to be invoked when the next event is + // ready to play. + + OPL_SetCallback(us / 1000, TrackTimerCallback, track); +} + +// Initialise a channel. + +static void InitChannel(opl_track_data_t *track, opl_channel_data_t *channel) +{ + // TODO: Work out sensible defaults? + + channel->instrument = &main_instrs[0]; + channel->volume = 127; +} + +// Start a MIDI track playing: + +static void StartTrack(midi_file_t *file, unsigned int track_num) +{ + opl_track_data_t *track; + unsigned int i; + + track = &tracks[track_num]; + track->iter = MIDI_IterateTrack(file, track_num); + track->ticks_per_beat = MIDI_GetFileTimeDivision(file); + + // Default is 120 bpm. + // TODO: this is wrong + + track->us_per_beat = 500 * 1000 * 200; + + for (i=0; ichannels[i]); + } + + // Schedule the first event. + + ScheduleTrack(track); +} + // Start playing a mid static void I_OPL_PlaySong(void *handle, int looping) { - if (!music_initialised) + midi_file_t *file; + unsigned int i; + + if (!music_initialised || handle == NULL) { return; } + + file = handle; + + // Allocate track data. + + tracks = malloc(MIDI_NumTracks(file) * sizeof(opl_track_data_t)); + + for (i=0; i #include #include +#include #include "doomdef.h" #include "doomtype.h" @@ -62,6 +63,12 @@ typedef struct int num_events; } midi_track_t; +struct midi_track_iter_s +{ + midi_track_t *track; + unsigned int position; +}; + struct midi_file_s { midi_header_t header; @@ -626,6 +633,68 @@ midi_file_t *MIDI_LoadFile(char *filename) return file; } +// Get the number of tracks in a MIDI file. + +unsigned int MIDI_NumTracks(midi_file_t *file) +{ + return file->num_tracks; +} + +// Start iterating over the events in a track. + +midi_track_iter_t *MIDI_IterateTrack(midi_file_t *file, unsigned int track) +{ + midi_track_iter_t *iter; + + assert(track < file->num_tracks); + + iter = malloc(sizeof(*iter)); + iter->track = &file->tracks[track]; + iter->position = 0; + + return iter; +} + +// Get the time until the next MIDI event in a track. + +unsigned int MIDI_GetDeltaTime(midi_track_iter_t *iter) +{ + if (iter->position < iter->track->num_events) + { + midi_event_t *next_event; + + next_event = &iter->track->events[iter->position]; + + return next_event->delta_time; + } + else + { + return 0; + } +} + +// Get a pointer to the next MIDI event. + +int MIDI_GetNextEvent(midi_track_iter_t *iter, midi_event_t **event) +{ + if (iter->position < iter->track->num_events) + { + *event = &iter->track->events[iter->position]; + ++iter->position; + + return 1; + } + else + { + return 0; + } +} + +unsigned int MIDI_GetFileTimeDivision(midi_file_t *file) +{ + return file->header.time_division; +} + #ifdef TEST static char *MIDI_EventTypeToString(midi_event_type_t event_type) diff --git a/src/midifile.h b/src/midifile.h index f9acea35..a1ab4976 100644 --- a/src/midifile.h +++ b/src/midifile.h @@ -27,6 +27,9 @@ #define MIDIFILE_H typedef struct midi_file_s midi_file_t; +typedef struct midi_track_iter_s midi_track_iter_t; + +#define MIDI_CHANNELS_PER_TRACK 16 typedef enum { @@ -129,8 +132,33 @@ typedef struct } data; } midi_event_t; +// Load a MIDI file. + midi_file_t *MIDI_LoadFile(char *filename); + +// Free a MIDI file. + void MIDI_FreeFile(midi_file_t *file); +// Get the time division value from the MIDI header. + +unsigned int MIDI_GetFileTimeDivision(midi_file_t *file); + +// Get the number of tracks in a MIDI file. + +unsigned int MIDI_NumTracks(midi_file_t *file); + +// Start iterating over the events in a track. + +midi_track_iter_t *MIDI_IterateTrack(midi_file_t *file, unsigned int track_num); + +// Get the time until the next MIDI event in a track. + +unsigned int MIDI_GetDeltaTime(midi_track_iter_t *iter); + +// Get a pointer to the next MIDI event. + +int MIDI_GetNextEvent(midi_track_iter_t *iter, midi_event_t **event); + #endif /* #ifndef MIDIFILE_H */ -- cgit v1.2.3 From 1d045ed19c58abff063ac69db24a2e73d62ef530 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 30 Aug 2009 22:03:20 +0000 Subject: Initial, broken, volume level setting. Subversion-branch: /branches/opl-branch Subversion-revision: 1644 --- src/i_oplmusic.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- src/midifile.h | 3 +++ 2 files changed, 49 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 3d9a2649..7a619c5d 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -160,6 +160,27 @@ static const unsigned int note_frequencies[] = { 0x2da, 0x306, 0x334, 0x365, 0x398, 0x3cf, }; +// Mapping from MIDI volume level to OPL level value. + +static const unsigned int volume_mapping_table[] = { + 0x3f, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x3a, + 0x39, 0x38, 0x37, 0x37, 0x36, 0x35, 0x34, 0x34, + 0x33, 0x32, 0x32, 0x31, 0x30, 0x2f, 0x2f, 0x2e, + 0x2d, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, + 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x22, 0x21, + 0x20, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1c, + 0x1b, 0x1b, 0x1a, 0x1a, 0x19, 0x18, 0x18, 0x17, + 0x17, 0x16, 0x16, 0x16, 0x16, 0x15, 0x15, 0x14, + 0x14, 0x13, 0x13, 0x12, 0x12, 0x12, 0x11, 0x11, + 0x10, 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, + 0x0e, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0b, + 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, + 0x08, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, + 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x04, + 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, +}; + static boolean music_initialised = false; //static boolean musicpaused = false; @@ -662,7 +683,10 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) // TODO: Set the volume level. - WriteRegister(OPL_REGS_LEVEL + voice->op2, 0); + WriteRegister(OPL_REGS_LEVEL + voice->op2, + volume_mapping_table[channel->volume]); + + printf("volume = %i\n", channel->volume); // Play the note. @@ -694,12 +718,32 @@ static void ProgramChangeEvent(opl_track_data_t *track, midi_event_t *event) static void ControllerEvent(opl_track_data_t *track, midi_event_t *event) { + unsigned int controller; + unsigned int param; + opl_channel_data_t *channel; + printf("change controller: channel %i, %i, %i\n", event->data.channel.channel, event->data.channel.param1, event->data.channel.param2); - // TODO: Volume, pan. + channel = &track->channels[event->data.channel.channel]; + controller = event->data.channel.param1; + param = event->data.channel.param2; + + switch (controller) + { + case MIDI_CONTROLLER_MAIN_VOLUME: + channel->volume = param; + break; + + case MIDI_CONTROLLER_PAN: + break; + + default: + fprintf(stderr, "Unknown MIDI controller type: %i\n", controller); + break; + } } // Process a MIDI event from a track. diff --git a/src/midifile.h b/src/midifile.h index a1ab4976..faef549c 100644 --- a/src/midifile.h +++ b/src/midifile.h @@ -54,6 +54,9 @@ typedef enum MIDI_CONTROLLER_FOOT_CONTROL = 0x3, MIDI_CONTROLLER_PORTAMENTO = 0x4, MIDI_CONTROLLER_DATA_ENTRY = 0x5, + + MIDI_CONTROLLER_MAIN_VOLUME = 0x7, + MIDI_CONTROLLER_PAN = 0xa } midi_controller_t; typedef enum -- cgit v1.2.3 From 61b2e3d2b8b6b2b6ddf8b92842ac4bcf47945160 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 30 Aug 2009 22:26:30 +0000 Subject: Set the right instrument for percussion notes. Subversion-branch: /branches/opl-branch Subversion-revision: 1645 --- src/i_oplmusic.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 7a619c5d..d844fd7b 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -656,8 +656,10 @@ static unsigned int FrequencyForNote(unsigned int note) static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) { + genmidi_instr_t *instrument; opl_voice_t *voice; opl_channel_data_t *channel; + unsigned int note; printf("note on: channel %i, %i, %i\n", event->data.channel.channel, @@ -667,6 +669,23 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) // The channel. channel = &track->channels[event->data.channel.channel]; + note = event->data.channel.param1; + + // Percussion channel (10) is treated differently to normal notes. + + if (event->data.channel.channel == 9) + { + if (note < 35 || note > 81) + { + return; + } + + instrument = &percussion_instrs[note - 35]; + } + else + { + instrument = channel->instrument; + } // Find a voice to use for this new note. @@ -679,19 +698,17 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) // Program the voice with the instrument data: - SetVoiceInstrument(voice, &channel->instrument->opl2_voice); + SetVoiceInstrument(voice, &instrument->opl2_voice); // TODO: Set the volume level. WriteRegister(OPL_REGS_LEVEL + voice->op2, volume_mapping_table[channel->volume]); - printf("volume = %i\n", channel->volume); - // Play the note. voice->channel = channel; - voice->note = event->data.channel.param1; + voice->note = note; // Write the frequency value to turn the note on. @@ -840,7 +857,7 @@ static void StartTrack(midi_file_t *file, unsigned int track_num) // Default is 120 bpm. // TODO: this is wrong - track->us_per_beat = 500 * 1000 * 200; + track->us_per_beat = 500 * 1000 * 260; for (i=0; idata.channel.channel, @@ -670,6 +671,7 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) channel = &track->channels[event->data.channel.channel]; note = event->data.channel.param1; + volume = event->data.channel.param2; // Percussion channel (10) is treated differently to normal notes. @@ -703,7 +705,7 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) // TODO: Set the volume level. WriteRegister(OPL_REGS_LEVEL + voice->op2, - volume_mapping_table[channel->volume]); + volume_mapping_table[volume]); // Play the note. -- cgit v1.2.3 From ab14960e3a24208709270fb11476f0bbb629b145 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 30 Aug 2009 23:04:54 +0000 Subject: Make I_OPL_StopSong work. Subversion-branch: /branches/opl-branch Subversion-revision: 1647 --- src/i_oplmusic.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index db7e0ffc..eff3f942 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -598,6 +598,11 @@ static opl_voice_t *FindVoiceForNote(opl_channel_data_t *channel, int note) return NULL; } +static void VoiceNoteOff(opl_voice_t *voice) +{ + WriteRegister(OPL_REGS_FREQ_2 + voice->index, voice->freq >> 8); +} + static void NoteOffEvent(opl_track_data_t *track, midi_event_t *event) { opl_voice_t *voice; @@ -619,9 +624,7 @@ static void NoteOffEvent(opl_track_data_t *track, midi_event_t *event) return; } - // Note off. - - WriteRegister(OPL_REGS_FREQ_2 + voice->index, voice->freq >> 8); + VoiceNoteOff(voice); // Finished with this voice now. @@ -913,10 +916,27 @@ static void I_OPL_ResumeSong(void) static void I_OPL_StopSong(void) { + unsigned int i; + if (!music_initialised) { return; } + + // Stop all playback. + + OPL_ClearCallbacks(); + + // Free all voices. + + for (i=0; iiter); - us = (nticks * track->us_per_beat) / track->ticks_per_beat; - total += us; + ms = (nticks * track->ms_per_beat) / track->ticks_per_beat; + total += ms; // Set a timer to be invoked when the next event is // ready to play. - OPL_SetCallback(us / 1000, TrackTimerCallback, track); + OPL_SetCallback(ms, TrackTimerCallback, track); } // Initialise a channel. @@ -862,7 +862,7 @@ static void StartTrack(midi_file_t *file, unsigned int track_num) // Default is 120 bpm. // TODO: this is wrong - track->us_per_beat = 500 * 1000 * 260; + track->ms_per_beat = 500 * 260; for (i=0; ichannel = channel; + voice->note = note; + // Program the voice with the instrument data: SetVoiceInstrument(voice, &instrument->opl2_voice); @@ -710,14 +713,16 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) WriteRegister(OPL_REGS_LEVEL + voice->op2, volume_mapping_table[volume]); - // Play the note. + // Fixed pitch? - voice->channel = channel; - voice->note = note; + if ((instrument->flags & GENMIDI_FLAG_FIXED) != 0) + { + note = instrument->fixed_note; + } // Write the frequency value to turn the note on. - voice->freq = FrequencyForNote(voice->note); + voice->freq = FrequencyForNote(note); WriteRegister(OPL_REGS_FREQ_1 + voice->index, voice->freq & 0xff); WriteRegister(OPL_REGS_FREQ_2 + voice->index, (voice->freq >> 8) | 0x20); -- cgit v1.2.3 From a43e60ee11f11fa8140b7b22da70f06b598fc49d Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 31 Aug 2009 17:32:22 +0000 Subject: Make channel volume work. Subversion-branch: /branches/opl-branch Subversion-revision: 1650 --- src/i_oplmusic.c | 108 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 86 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 8a416f57..1d482595 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -133,6 +133,12 @@ struct opl_voice_s // The frequency value being used. unsigned int freq; + // The volume of the note being played on this channel. + unsigned int note_volume; + + // The current volume that has been set for this channel. + unsigned int volume; + // Next in freelist opl_voice_t *next; }; @@ -163,22 +169,22 @@ static const unsigned int note_frequencies[] = { // Mapping from MIDI volume level to OPL level value. static const unsigned int volume_mapping_table[] = { - 0x3f, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x3a, - 0x39, 0x38, 0x37, 0x37, 0x36, 0x35, 0x34, 0x34, - 0x33, 0x32, 0x32, 0x31, 0x30, 0x2f, 0x2f, 0x2e, - 0x2d, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, - 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x22, 0x21, - 0x20, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1c, - 0x1b, 0x1b, 0x1a, 0x1a, 0x19, 0x18, 0x18, 0x17, - 0x17, 0x16, 0x16, 0x16, 0x16, 0x15, 0x15, 0x14, - 0x14, 0x13, 0x13, 0x12, 0x12, 0x12, 0x11, 0x11, - 0x10, 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, - 0x0e, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0b, - 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, - 0x08, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, - 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x04, - 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0, 1, 3, 5, 6, 8, 10, 11, + 13, 14, 16, 17, 19, 20, 22, 23, + 25, 26, 27, 29, 30, 32, 33, 34, + 36, 37, 39, 41, 43, 45, 47, 49, + 50, 52, 54, 55, 57, 59, 60, 61, + 63, 64, 66, 67, 68, 69, 71, 72, + 73, 74, 75, 76, 77, 79, 80, 81, + 82, 83, 84, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 92, 93, 94, 95, + 96, 96, 97, 98, 99, 99, 100, 101, + 101, 102, 103, 103, 104, 105, 105, 106, + 107, 107, 108, 109, 109, 110, 110, 111, + 112, 112, 113, 113, 114, 114, 115, 115, + 116, 117, 117, 118, 118, 119, 119, 120, + 120, 121, 121, 122, 122, 123, 123, 123, + 124, 124, 125, 125, 126, 126, 127, 127 }; static boolean music_initialised = false; @@ -433,8 +439,13 @@ static void LoadOperatorData(int operator, genmidi_op_t *data, // Set the instrument for a particular voice. -static void SetVoiceInstrument(opl_voice_t *voice, genmidi_voice_t *data) +static void SetVoiceInstrument(opl_voice_t *voice, genmidi_instr_t *instr) { + genmidi_voice_t *data; + + voice->current_instr = instr; + data = &instr->opl2_voice; + // Doom loads the second operator first, then the first. LoadOperatorData(voice->op2, &data->carrier, true); @@ -446,6 +457,42 @@ static void SetVoiceInstrument(opl_voice_t *voice, genmidi_voice_t *data) WriteRegister(OPL_REGS_FEEDBACK + voice->index, data->feedback | 0x30); + + // Hack to force a volume update. + + voice->volume = 999; +} + +static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume) +{ + unsigned int full_volume; + unsigned int instr_volume; + unsigned int reg_volume; + + voice->note_volume = volume; + + // Multiply note volume and channel volume to get the actual volume. + + full_volume = (voice->note_volume * voice->channel->volume) / 127; + + // The volume of each instrument can be controlled via GENMIDI: + + instr_volume = 0x3f - voice->current_instr->opl2_voice.carrier.level; + + // The volume value to use in the register: + + reg_volume = ((instr_volume * volume_mapping_table[full_volume]) / 128); + reg_volume = (0x3f - reg_volume) + | voice->current_instr->opl2_voice.carrier.scale; + + // Update the register, if necessary: + + if (voice->volume != reg_volume) + { + voice->volume = reg_volume; + + WriteRegister(OPL_REGS_LEVEL + voice->op2, reg_volume); + } } // Initialise the voice table and freelist @@ -698,6 +745,7 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) if (voice == NULL) { + printf("\tno free voice\n"); return; } @@ -706,12 +754,11 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) // Program the voice with the instrument data: - SetVoiceInstrument(voice, &instrument->opl2_voice); + SetVoiceInstrument(voice, instrument); - // TODO: Set the volume level. + // Set the volume level. - WriteRegister(OPL_REGS_LEVEL + voice->op2, - volume_mapping_table[volume]); + SetVoiceVolume(voice, volume); // Fixed pitch? @@ -743,6 +790,23 @@ static void ProgramChangeEvent(opl_track_data_t *track, midi_event_t *event) // channel, and change the instrument. } +static void SetChannelVolume(opl_channel_data_t *channel, unsigned int volume) +{ + unsigned int i; + + channel->volume = volume; + + // Update all voices that this channel is using. + + for (i=0; ivolume = param; + SetChannelVolume(channel, param); break; case MIDI_CONTROLLER_PAN: -- cgit v1.2.3 From a26925cf8f27eb38b3266629a3bc259f098b1e19 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 31 Aug 2009 18:18:51 +0000 Subject: Set the volume on both operators for instruments that use non-modulating voice mode. Subversion-branch: /branches/opl-branch Subversion-revision: 1651 --- src/i_oplmusic.c | 70 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 1d482595..51a609d9 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -137,7 +137,8 @@ struct opl_voice_s unsigned int note_volume; // The current volume that has been set for this channel. - unsigned int volume; + unsigned int carrier_volume; + unsigned int modulator_volume; // Next in freelist opl_voice_t *next; @@ -442,14 +443,22 @@ static void LoadOperatorData(int operator, genmidi_op_t *data, static void SetVoiceInstrument(opl_voice_t *voice, genmidi_instr_t *instr) { genmidi_voice_t *data; + unsigned int modulating; voice->current_instr = instr; data = &instr->opl2_voice; + // Are we usind modulated feedback mode? + + modulating = (data->feedback & 0x01) == 0; + // Doom loads the second operator first, then the first. + // The carrier is set to minimum volume until the voice volume + // is set in SetVoiceVolume (below). If we are not using + // modulating mode, we must set both to minimum volume. LoadOperatorData(voice->op2, &data->carrier, true); - LoadOperatorData(voice->op1, &data->modulator, false); + LoadOperatorData(voice->op1, &data->modulator, !modulating); // Set feedback register that control the connection between the // two operators. Turn on bits in the upper nybble; I think this @@ -460,38 +469,61 @@ static void SetVoiceInstrument(opl_voice_t *voice, genmidi_instr_t *instr) // Hack to force a volume update. - voice->volume = 999; + voice->carrier_volume = 999; + voice->modulator_volume = 999; } -static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume) +// Calculate the volume level to use for a given operator. + +static void SetOperatorVolume(genmidi_op_t *op, unsigned int volume, + unsigned int opnum, + unsigned int *current_volume) { - unsigned int full_volume; - unsigned int instr_volume; + unsigned int op_volume; unsigned int reg_volume; - voice->note_volume = volume; - - // Multiply note volume and channel volume to get the actual volume. - - full_volume = (voice->note_volume * voice->channel->volume) / 127; - // The volume of each instrument can be controlled via GENMIDI: - instr_volume = 0x3f - voice->current_instr->opl2_voice.carrier.level; + op_volume = 0x3f - op->level; // The volume value to use in the register: - reg_volume = ((instr_volume * volume_mapping_table[full_volume]) / 128); - reg_volume = (0x3f - reg_volume) - | voice->current_instr->opl2_voice.carrier.scale; + reg_volume = ((op_volume * volume_mapping_table[volume]) / 128); + reg_volume = (0x3f - reg_volume) | op->scale; // Update the register, if necessary: - if (voice->volume != reg_volume) + if (*current_volume != reg_volume) { - voice->volume = reg_volume; + *current_volume = reg_volume; + + WriteRegister(OPL_REGS_LEVEL + opnum, reg_volume); + } +} - WriteRegister(OPL_REGS_LEVEL + voice->op2, reg_volume); +static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume) +{ + genmidi_voice_t *opl_voice; + unsigned int full_volume; + + voice->note_volume = volume; + + opl_voice = &voice->current_instr->opl2_voice; + + // Multiply note volume and channel volume to get the actual volume. + + full_volume = (voice->note_volume * voice->channel->volume) / 127; + + SetOperatorVolume(&opl_voice->carrier, full_volume, + voice->op2, &voice->carrier_volume); + + // If we are using non-modulated feedback mode, we must set the + // volume for both voices. + + if ((opl_voice->feedback & 0x01) != 0) + { + SetOperatorVolume(&opl_voice->modulator, full_volume, + voice->op1, &voice->modulator_volume); } } -- cgit v1.2.3 From fe96ae292d2b0e67020d77493ae366360cd93ec8 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 31 Aug 2009 18:33:36 +0000 Subject: Dont program an instrument if it is already set. Subversion-branch: /branches/opl-branch Subversion-revision: 1652 --- src/i_oplmusic.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 51a609d9..ab64505c 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -445,6 +445,13 @@ static void SetVoiceInstrument(opl_voice_t *voice, genmidi_instr_t *instr) genmidi_voice_t *data; unsigned int modulating; + // Instrument already set for this channel? + + if (voice->current_instr == instr) + { + return; + } + voice->current_instr = instr; data = &instr->opl2_voice; -- cgit v1.2.3 From eb2291030ae0f1e005a6014193fdfeaa796a913a Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 31 Aug 2009 22:50:28 +0000 Subject: Perform volume mapping on note and channel volumes before multiplying them. This gives voice volume values that are almost identical to Doom's. Subversion-branch: /branches/opl-branch Subversion-revision: 1653 --- src/i_oplmusic.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index ab64505c..74a76b00 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -495,7 +495,7 @@ static void SetOperatorVolume(genmidi_op_t *op, unsigned int volume, // The volume value to use in the register: - reg_volume = ((op_volume * volume_mapping_table[volume]) / 128); + reg_volume = (op_volume * volume) / 128; reg_volume = (0x3f - reg_volume) | op->scale; // Update the register, if necessary: @@ -519,7 +519,8 @@ static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume) // Multiply note volume and channel volume to get the actual volume. - full_volume = (voice->note_volume * voice->channel->volume) / 127; + full_volume = (volume_mapping_table[voice->note_volume] + * volume_mapping_table[voice->channel->volume]) / 127; SetOperatorVolume(&opl_voice->carrier, full_volume, voice->op2, &voice->carrier_volume); -- cgit v1.2.3 From 556f7291ea0199144794166af2757aa7ad832a7a Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Tue, 1 Sep 2009 18:17:11 +0000 Subject: Loop songs (when appropriate) Subversion-branch: /branches/opl-branch Subversion-revision: 1654 --- src/i_oplmusic.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/midifile.c | 10 ++++++ src/midifile.h | 8 +++++ 3 files changed, 108 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 74a76b00..1ac502f5 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -206,6 +206,9 @@ static opl_voice_t *voice_free_list; // Track data for playing tracks: static opl_track_data_t *tracks; +static unsigned int num_tracks; +static unsigned int running_tracks = 0; +static boolean song_looping; // In the initialisation stage, register writes are spaced by reading // from the register port (0). After initialisation, spacing is @@ -868,11 +871,40 @@ static void ControllerEvent(opl_track_data_t *track, midi_event_t *event) SetChannelVolume(channel, param); break; - case MIDI_CONTROLLER_PAN: + default: + fprintf(stderr, "Unknown MIDI controller type: %i\n", controller); + break; + } +} + +// Process a meta event. + +static void MetaEvent(opl_track_data_t *track, midi_event_t *event) +{ + switch (event->data.meta.type) + { + // Things we can just ignore. + + case MIDI_META_SEQUENCE_NUMBER: + case MIDI_META_TEXT: + case MIDI_META_COPYRIGHT: + case MIDI_META_TRACK_NAME: + case MIDI_META_INSTR_NAME: + case MIDI_META_LYRICS: + case MIDI_META_MARKER: + case MIDI_META_CUE_POINT: + case MIDI_META_SEQUENCER_SPECIFIC: + break; + + // End of track - actually handled when we run out of events + // in the track, see below. + + case MIDI_META_END_OF_TRACK: break; default: - fprintf(stderr, "Unknown MIDI controller type: %i\n", controller); + fprintf(stderr, "Unknown MIDI meta event type: %i\n", + event->data.meta.type); break; } } @@ -899,6 +931,16 @@ static void ProcessEvent(opl_track_data_t *track, midi_event_t *event) ProgramChangeEvent(track, event); break; + case MIDI_EVENT_META: + MetaEvent(track, event); + break; + + // SysEx events can be ignored. + + case MIDI_EVENT_SYSEX: + case MIDI_EVENT_SYSEX_SPLIT: + break; + default: fprintf(stderr, "Unknown MIDI event type %i\n", event->event_type); break; @@ -907,6 +949,21 @@ static void ProcessEvent(opl_track_data_t *track, midi_event_t *event) static void ScheduleTrack(opl_track_data_t *track); +// Restart a song from the beginning. + +static void RestartSong(void) +{ + unsigned int i; + + running_tracks = num_tracks; + + for (i=0; ievent_type == MIDI_EVENT_META + && event->data.meta.type == MIDI_META_END_OF_TRACK) + { + --running_tracks; + + // When all tracks have finished, restart the song. + + if (running_tracks <= 0 && song_looping) + { + RestartSong(); + } + + return; + } + // Reschedule the callback for the next event in the track. ScheduleTrack(track); @@ -1001,7 +1075,11 @@ static void I_OPL_PlaySong(void *handle, int looping) tracks = malloc(MIDI_NumTracks(file) * sizeof(opl_track_data_t)); - for (i=0; iheader.time_division; } +void MIDI_RestartIterator(midi_track_iter_t *iter) +{ + iter->position = 0; +} + #ifdef TEST static char *MIDI_EventTypeToString(midi_event_type_t event_type) diff --git a/src/midifile.h b/src/midifile.h index faef549c..4ee0ddb2 100644 --- a/src/midifile.h +++ b/src/midifile.h @@ -155,6 +155,10 @@ unsigned int MIDI_NumTracks(midi_file_t *file); midi_track_iter_t *MIDI_IterateTrack(midi_file_t *file, unsigned int track_num); +// Free an iterator. + +void MIDI_FreeIterator(midi_track_iter_t *iter); + // Get the time until the next MIDI event in a track. unsigned int MIDI_GetDeltaTime(midi_track_iter_t *iter); @@ -163,5 +167,9 @@ unsigned int MIDI_GetDeltaTime(midi_track_iter_t *iter); int MIDI_GetNextEvent(midi_track_iter_t *iter, midi_event_t **event); +// Reset an iterator to the beginning of a track. + +void MIDI_RestartIterator(midi_track_iter_t *iter); + #endif /* #ifndef MIDIFILE_H */ -- cgit v1.2.3 From d372d65b3de579fe40207a308c3f7c4bf3076c0a Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 7 Sep 2009 18:11:25 +0000 Subject: Implement pitch bend. Subversion-branch: /branches/opl-branch Subversion-revision: 1658 --- src/i_oplmusic.c | 262 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 213 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 1ac502f5..e9fdb395 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -91,6 +91,11 @@ typedef struct // Volume level int volume; + + // Pitch bend value: + + int bend; + } opl_channel_data_t; // Data associated with a track that is currently playing. @@ -127,7 +132,12 @@ struct opl_voice_s // The channel currently using this voice. opl_channel_data_t *channel; - // The note that this voice is playing. + // The midi key that this voice is playing. + unsigned int key; + + // The note being played. This is normally the same as + // the key, but if the instrument is a fixed pitch + // instrument, it is different. unsigned int note; // The frequency value being used. @@ -153,18 +163,120 @@ static const int voice_operators[2][OPL_NUM_VOICES] = { // Frequency values to use for each note. -static const unsigned int note_frequencies[] = { - - // These frequencies are only used for the first seven - // MIDI note values: - - 0x158, 0x16d, 0x183, 0x19a, 0x1b2, 0x1cc, 0x1e7, - - // These frequencies are used repeatedly, cycling around - // for each octave: - - 0x204, 0x223, 0x244, 0x266, 0x28b, 0x2b1, - 0x2da, 0x306, 0x334, 0x365, 0x398, 0x3cf, +static const unsigned short frequency_curve[] = { + + 0x133, 0x133, 0x134, 0x134, 0x135, 0x136, 0x136, 0x137, // -1 + 0x137, 0x138, 0x138, 0x139, 0x139, 0x13a, 0x13b, 0x13b, + 0x13c, 0x13c, 0x13d, 0x13d, 0x13e, 0x13f, 0x13f, 0x140, + 0x140, 0x141, 0x142, 0x142, 0x143, 0x143, 0x144, 0x144, + + 0x145, 0x146, 0x146, 0x147, 0x147, 0x148, 0x149, 0x149, // -2 + 0x14a, 0x14a, 0x14b, 0x14c, 0x14c, 0x14d, 0x14d, 0x14e, + 0x14f, 0x14f, 0x150, 0x150, 0x151, 0x152, 0x152, 0x153, + 0x153, 0x154, 0x155, 0x155, 0x156, 0x157, 0x157, 0x158, + + // These are used for the first seven MIDI note values: + + 0x158, 0x159, 0x15a, 0x15a, 0x15b, 0x15b, 0x15c, 0x15d, // 0 + 0x15d, 0x15e, 0x15f, 0x15f, 0x160, 0x161, 0x161, 0x162, + 0x162, 0x163, 0x164, 0x164, 0x165, 0x166, 0x166, 0x167, + 0x168, 0x168, 0x169, 0x16a, 0x16a, 0x16b, 0x16c, 0x16c, + + 0x16d, 0x16e, 0x16e, 0x16f, 0x170, 0x170, 0x171, 0x172, // 1 + 0x172, 0x173, 0x174, 0x174, 0x175, 0x176, 0x176, 0x177, + 0x178, 0x178, 0x179, 0x17a, 0x17a, 0x17b, 0x17c, 0x17c, + 0x17d, 0x17e, 0x17e, 0x17f, 0x180, 0x181, 0x181, 0x182, + + 0x183, 0x183, 0x184, 0x185, 0x185, 0x186, 0x187, 0x188, // 2 + 0x188, 0x189, 0x18a, 0x18a, 0x18b, 0x18c, 0x18d, 0x18d, + 0x18e, 0x18f, 0x18f, 0x190, 0x191, 0x192, 0x192, 0x193, + 0x194, 0x194, 0x195, 0x196, 0x197, 0x197, 0x198, 0x199, + + 0x19a, 0x19a, 0x19b, 0x19c, 0x19d, 0x19d, 0x19e, 0x19f, // 3 + 0x1a0, 0x1a0, 0x1a1, 0x1a2, 0x1a3, 0x1a3, 0x1a4, 0x1a5, + 0x1a6, 0x1a6, 0x1a7, 0x1a8, 0x1a9, 0x1a9, 0x1aa, 0x1ab, + 0x1ac, 0x1ad, 0x1ad, 0x1ae, 0x1af, 0x1b0, 0x1b0, 0x1b1, + + 0x1b2, 0x1b3, 0x1b4, 0x1b4, 0x1b5, 0x1b6, 0x1b7, 0x1b8, // 4 + 0x1b8, 0x1b9, 0x1ba, 0x1bb, 0x1bc, 0x1bc, 0x1bd, 0x1be, + 0x1bf, 0x1c0, 0x1c0, 0x1c1, 0x1c2, 0x1c3, 0x1c4, 0x1c4, + 0x1c5, 0x1c6, 0x1c7, 0x1c8, 0x1c9, 0x1c9, 0x1ca, 0x1cb, + + 0x1cc, 0x1cd, 0x1ce, 0x1ce, 0x1cf, 0x1d0, 0x1d1, 0x1d2, // 5 + 0x1d3, 0x1d3, 0x1d4, 0x1d5, 0x1d6, 0x1d7, 0x1d8, 0x1d8, + 0x1d9, 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, 0x1de, 0x1df, + 0x1e0, 0x1e1, 0x1e2, 0x1e3, 0x1e4, 0x1e5, 0x1e5, 0x1e6, + + 0x1e7, 0x1e8, 0x1e9, 0x1ea, 0x1eb, 0x1ec, 0x1ed, 0x1ed, // 6 + 0x1ee, 0x1ef, 0x1f0, 0x1f1, 0x1f2, 0x1f3, 0x1f4, 0x1f5, + 0x1f6, 0x1f6, 0x1f7, 0x1f8, 0x1f9, 0x1fa, 0x1fb, 0x1fc, + 0x1fd, 0x1fe, 0x1ff, 0x200, 0x201, 0x201, 0x202, 0x203, + + // First note of looped range used for all octaves: + + 0x204, 0x205, 0x206, 0x207, 0x208, 0x209, 0x20a, 0x20b, // 7 + 0x20c, 0x20d, 0x20e, 0x20f, 0x210, 0x210, 0x211, 0x212, + 0x213, 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21a, + 0x21b, 0x21c, 0x21d, 0x21e, 0x21f, 0x220, 0x221, 0x222, + + 0x223, 0x224, 0x225, 0x226, 0x227, 0x228, 0x229, 0x22a, // 8 + 0x22b, 0x22c, 0x22d, 0x22e, 0x22f, 0x230, 0x231, 0x232, + 0x233, 0x234, 0x235, 0x236, 0x237, 0x238, 0x239, 0x23a, + 0x23b, 0x23c, 0x23d, 0x23e, 0x23f, 0x240, 0x241, 0x242, + + 0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24a, 0x24b, // 9 + 0x24c, 0x24d, 0x24e, 0x24f, 0x250, 0x251, 0x252, 0x253, + 0x254, 0x256, 0x257, 0x258, 0x259, 0x25a, 0x25b, 0x25c, + 0x25d, 0x25e, 0x25f, 0x260, 0x262, 0x263, 0x264, 0x265, + + 0x266, 0x267, 0x268, 0x269, 0x26a, 0x26c, 0x26d, 0x26e, // 10 + 0x26f, 0x270, 0x271, 0x272, 0x273, 0x275, 0x276, 0x277, + 0x278, 0x279, 0x27a, 0x27b, 0x27d, 0x27e, 0x27f, 0x280, + 0x281, 0x282, 0x284, 0x285, 0x286, 0x287, 0x288, 0x289, + + 0x28b, 0x28c, 0x28d, 0x28e, 0x28f, 0x290, 0x292, 0x293, // 11 + 0x294, 0x295, 0x296, 0x298, 0x299, 0x29a, 0x29b, 0x29c, + 0x29e, 0x29f, 0x2a0, 0x2a1, 0x2a2, 0x2a4, 0x2a5, 0x2a6, + 0x2a7, 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ae, 0x2af, 0x2b0, + + 0x2b1, 0x2b2, 0x2b4, 0x2b5, 0x2b6, 0x2b7, 0x2b9, 0x2ba, // 12 + 0x2bb, 0x2bd, 0x2be, 0x2bf, 0x2c0, 0x2c2, 0x2c3, 0x2c4, + 0x2c5, 0x2c7, 0x2c8, 0x2c9, 0x2cb, 0x2cc, 0x2cd, 0x2ce, + 0x2d0, 0x2d1, 0x2d2, 0x2d4, 0x2d5, 0x2d6, 0x2d8, 0x2d9, + + 0x2da, 0x2dc, 0x2dd, 0x2de, 0x2e0, 0x2e1, 0x2e2, 0x2e4, // 13 + 0x2e5, 0x2e6, 0x2e8, 0x2e9, 0x2ea, 0x2ec, 0x2ed, 0x2ee, + 0x2f0, 0x2f1, 0x2f2, 0x2f4, 0x2f5, 0x2f6, 0x2f8, 0x2f9, + 0x2fb, 0x2fc, 0x2fd, 0x2ff, 0x300, 0x302, 0x303, 0x304, + + 0x306, 0x307, 0x309, 0x30a, 0x30b, 0x30d, 0x30e, 0x310, // 14 + 0x311, 0x312, 0x314, 0x315, 0x317, 0x318, 0x31a, 0x31b, + 0x31c, 0x31e, 0x31f, 0x321, 0x322, 0x324, 0x325, 0x327, + 0x328, 0x329, 0x32b, 0x32c, 0x32e, 0x32f, 0x331, 0x332, + + 0x334, 0x335, 0x337, 0x338, 0x33a, 0x33b, 0x33d, 0x33e, // 15 + 0x340, 0x341, 0x343, 0x344, 0x346, 0x347, 0x349, 0x34a, + 0x34c, 0x34d, 0x34f, 0x350, 0x352, 0x353, 0x355, 0x357, + 0x358, 0x35a, 0x35b, 0x35d, 0x35e, 0x360, 0x361, 0x363, + + 0x365, 0x366, 0x368, 0x369, 0x36b, 0x36c, 0x36e, 0x370, // 16 + 0x371, 0x373, 0x374, 0x376, 0x378, 0x379, 0x37b, 0x37c, + 0x37e, 0x380, 0x381, 0x383, 0x384, 0x386, 0x388, 0x389, + 0x38b, 0x38d, 0x38e, 0x390, 0x392, 0x393, 0x395, 0x397, + + 0x398, 0x39a, 0x39c, 0x39d, 0x39f, 0x3a1, 0x3a2, 0x3a4, // 17 + 0x3a6, 0x3a7, 0x3a9, 0x3ab, 0x3ac, 0x3ae, 0x3b0, 0x3b1, + 0x3b3, 0x3b5, 0x3b7, 0x3b8, 0x3ba, 0x3bc, 0x3bd, 0x3bf, + 0x3c1, 0x3c3, 0x3c4, 0x3c6, 0x3c8, 0x3ca, 0x3cb, 0x3cd, + + // The last note has an incomplete range, and loops round back to + // the start. Note that the last value is actually a buffer overrun + // and does not fit with the other values. + + 0x3cf, 0x3d1, 0x3d2, 0x3d4, 0x3d6, 0x3d8, 0x3da, 0x3db, // 18 + 0x3dd, 0x3df, 0x3e1, 0x3e3, 0x3e4, 0x3e6, 0x3e8, 0x3ea, + 0x3ec, 0x3ed, 0x3ef, 0x3f1, 0x3f3, 0x3f5, 0x3f6, 0x3f8, + 0x3fa, 0x3fc, 0x3fe, 0x36c, }; // Mapping from MIDI volume level to OPL level value. @@ -501,7 +613,7 @@ static void SetOperatorVolume(genmidi_op_t *op, unsigned int volume, reg_volume = (op_volume * volume) / 128; reg_volume = (0x3f - reg_volume) | op->scale; - // Update the register, if necessary: + // Update the register, if neccessary: if (*current_volume != reg_volume) { @@ -673,13 +785,13 @@ static void I_OPL_SetMusicVolume(int volume) current_music_volume = volume; } -static opl_voice_t *FindVoiceForNote(opl_channel_data_t *channel, int note) +static opl_voice_t *FindVoiceForKey(opl_channel_data_t *channel, int key) { unsigned int i; for (i=0; iindex, voice->freq >> 8); } +// Get the frequency that we should be using for a voice. + static void NoteOffEvent(opl_track_data_t *track, midi_event_t *event) { opl_voice_t *voice; @@ -707,7 +821,7 @@ static void NoteOffEvent(opl_track_data_t *track, midi_event_t *event) // Find the voice being used to play the note. - voice = FindVoiceForNote(channel, event->data.channel.param1); + voice = FindVoiceForKey(channel, event->data.channel.param1); if (voice == NULL) { @@ -721,29 +835,47 @@ static void NoteOffEvent(opl_track_data_t *track, midi_event_t *event) ReleaseVoice(voice); } -// Given a MIDI note number, get the corresponding OPL -// frequency value to use. - -static unsigned int FrequencyForNote(unsigned int note) +static unsigned int FrequencyForVoice(opl_voice_t *voice) { + unsigned int freq_index; unsigned int octave; - unsigned int key_num; + unsigned int sub_index; - // The first seven frequencies in the frequencies array are used - // only for the first seven MIDI notes. After this, the frequency - // value loops around the same twelve notes, increasing the - // octave. + freq_index = 64 + 32 * voice->note + voice->channel->bend; - if (note < 7) + // The first 7 notes use the start of the table, while + // consecutive notes loop around the latter part. + + if (freq_index < 284) { - return note_frequencies[note]; + return frequency_curve[freq_index]; } - else + + sub_index = (freq_index - 284) % (12 * 32); + octave = (freq_index - 284) / (12 * 32); + + // Calculate the resulting register value to use for the frequency. + + return frequency_curve[sub_index + 284] | (octave << 10); +} + +// Update the frequency that a voice is programmed to use. + +static void UpdateVoiceFrequency(opl_voice_t *voice) +{ + unsigned int freq; + + // Calculate the frequency to use for this voice and update it + // if neccessary. + + freq = FrequencyForVoice(voice); + + if (voice->freq != freq) { - octave = (note - 7) / 12; - key_num = (note - 7) % 12; + WriteRegister(OPL_REGS_FREQ_1 + voice->index, freq & 0xff); + WriteRegister(OPL_REGS_FREQ_2 + voice->index, (freq >> 8) | 0x20); - return note_frequencies[key_num + 7] | (octave << 10); + voice->freq = freq; } } @@ -752,7 +884,7 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) genmidi_instr_t *instrument; opl_voice_t *voice; opl_channel_data_t *channel; - unsigned int note; + unsigned int key; unsigned int volume; printf("note on: channel %i, %i, %i\n", @@ -763,19 +895,19 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) // The channel. channel = &track->channels[event->data.channel.channel]; - note = event->data.channel.param1; + key = event->data.channel.param1; volume = event->data.channel.param2; - // Percussion channel (10) is treated differently to normal notes. + // Percussion channel (10) is treated differently. if (event->data.channel.channel == 9) { - if (note < 35 || note > 81) + if (key < 35 || key > 81) { return; } - instrument = &percussion_instrs[note - 35]; + instrument = &percussion_instrs[key - 35]; } else { @@ -793,7 +925,19 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) } voice->channel = channel; - voice->note = note; + voice->key = key; + + // Work out the note to use. This is normally the same as + // the key, unless it is a fixed pitch instrument. + + if ((instrument->flags & GENMIDI_FLAG_FIXED) != 0) + { + voice->note = instrument->fixed_note; + } + else + { + voice->note = key; + } // Program the voice with the instrument data: @@ -803,19 +947,10 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) SetVoiceVolume(voice, volume); - // Fixed pitch? - - if ((instrument->flags & GENMIDI_FLAG_FIXED) != 0) - { - note = instrument->fixed_note; - } - // Write the frequency value to turn the note on. - voice->freq = FrequencyForNote(note); - - WriteRegister(OPL_REGS_FREQ_1 + voice->index, voice->freq & 0xff); - WriteRegister(OPL_REGS_FREQ_2 + voice->index, (voice->freq >> 8) | 0x20); + voice->freq = 0; + UpdateVoiceFrequency(voice); } static void ProgramChangeEvent(opl_track_data_t *track, midi_event_t *event) @@ -877,6 +1012,30 @@ static void ControllerEvent(opl_track_data_t *track, midi_event_t *event) } } +// Process a pitch bend event. + +static void PitchBendEvent(opl_track_data_t *track, midi_event_t *event) +{ + opl_channel_data_t *channel; + unsigned int i; + + // Update the channel bend value. Only the MSB of the pitch bend + // value is considered: this is what Doom does. + + channel = &track->channels[event->data.channel.channel]; + channel->bend = event->data.channel.param2 - 64; + + // Update all voices for this channel. + + for (i=0; iinstrument = &main_instrs[0]; channel->volume = 127; + channel->bend = 0; } // Start a MIDI track playing: -- cgit v1.2.3 From e97bc5db814b844ef2e4ee92f8a683031853dadb Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Tue, 8 Sep 2009 17:56:21 +0000 Subject: Program two voices for double voice instruments. Subversion-branch: /branches/opl-branch Subversion-revision: 1660 --- src/i_oplmusic.c | 164 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 91 insertions(+), 73 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index e9fdb395..8ec47b80 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -49,7 +49,7 @@ #define GENMIDI_HEADER "#OPL_II#" #define GENMIDI_FLAG_FIXED 0x0001 /* fixed pitch */ -#define GENMIDI_FLAG_2VOICE 0x0002 /* double voice (OPL3) */ +#define GENMIDI_FLAG_2VOICE 0x0004 /* double voice (OPL3) */ typedef struct { @@ -76,8 +76,7 @@ typedef struct byte fine_tuning; byte fixed_note; - genmidi_voice_t opl2_voice; - genmidi_voice_t opl3_voice; + genmidi_voice_t voices[2]; } PACKEDATTR genmidi_instr_t; // Data associated with a channel of a track that is currently playing. @@ -129,6 +128,11 @@ struct opl_voice_s // Currently-loaded instrument data genmidi_instr_t *current_instr; + // The voice number in the instrument to use. + // This is normally set to zero; if this is a double voice + // instrument, it may be one. + unsigned int current_instr_voice; + // The channel currently using this voice. opl_channel_data_t *channel; @@ -555,20 +559,25 @@ static void LoadOperatorData(int operator, genmidi_op_t *data, // Set the instrument for a particular voice. -static void SetVoiceInstrument(opl_voice_t *voice, genmidi_instr_t *instr) +static void SetVoiceInstrument(opl_voice_t *voice, + genmidi_instr_t *instr, + unsigned int instr_voice) { genmidi_voice_t *data; unsigned int modulating; // Instrument already set for this channel? - if (voice->current_instr == instr) + if (voice->current_instr == instr + && voice->current_instr_voice == instr_voice) { return; } voice->current_instr = instr; - data = &instr->opl2_voice; + voice->current_instr_voice = instr_voice; + + data = &instr->voices[instr_voice]; // Are we usind modulated feedback mode? @@ -630,7 +639,7 @@ static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume) voice->note_volume = volume; - opl_voice = &voice->current_instr->opl2_voice; + opl_voice = &voice->current_instr->voices[voice->current_instr_voice]; // Multiply note volume and channel volume to get the actual volume. @@ -765,7 +774,7 @@ static boolean I_OPL_InitMusic(void) voice = GetFreeVoice(); instr_num = rand() % 100; - SetVoiceInstrument(voice, &main_instrs[instr_num].opl2_voice); + SetVoiceInstrument(voice, &main_instrs[instr_num], 0); OPL_SetCallback(0, TestCallback, voice); } @@ -785,32 +794,18 @@ static void I_OPL_SetMusicVolume(int volume) current_music_volume = volume; } -static opl_voice_t *FindVoiceForKey(opl_channel_data_t *channel, int key) -{ - unsigned int i; - - for (i=0; iindex, voice->freq >> 8); } // Get the frequency that we should be using for a voice. -static void NoteOffEvent(opl_track_data_t *track, midi_event_t *event) +static void KeyOffEvent(opl_track_data_t *track, midi_event_t *event) { - opl_voice_t *voice; opl_channel_data_t *channel; + unsigned int key; + unsigned int i; printf("note off: channel %i, %i, %i\n", event->data.channel.channel, @@ -818,21 +813,22 @@ static void NoteOffEvent(opl_track_data_t *track, midi_event_t *event) event->data.channel.param2); channel = &track->channels[event->data.channel.channel]; + key = event->data.channel.param1; - // Find the voice being used to play the note. - - voice = FindVoiceForKey(channel, event->data.channel.param1); + // Turn off voices being used to play this key. + // If it is a double voice instrument there will be two. - if (voice == NULL) + for (i=0; idata.channel.channel, - event->data.channel.param1, - event->data.channel.param2); - - // The channel. - - channel = &track->channels[event->data.channel.channel]; - key = event->data.channel.param1; - volume = event->data.channel.param2; - - // Percussion channel (10) is treated differently. - - if (event->data.channel.channel == 9) - { - if (key < 35 || key > 81) - { - return; - } - - instrument = &percussion_instrs[key - 35]; - } - else - { - instrument = channel->instrument; - } // Find a voice to use for this new note. @@ -920,7 +893,7 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) if (voice == NULL) { - printf("\tno free voice\n"); + printf("\tno free voice for voice %i of instrument\n", instrument_voice); return; } @@ -941,7 +914,7 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) // Program the voice with the instrument data: - SetVoiceInstrument(voice, instrument); + SetVoiceInstrument(voice, instrument, 0); // Set the volume level. @@ -953,6 +926,51 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) UpdateVoiceFrequency(voice); } +static void KeyOnEvent(opl_track_data_t *track, midi_event_t *event) +{ + genmidi_instr_t *instrument; + opl_channel_data_t *channel; + unsigned int key; + unsigned int volume; + + printf("note on: channel %i, %i, %i\n", + event->data.channel.channel, + event->data.channel.param1, + event->data.channel.param2); + + // The channel. + + channel = &track->channels[event->data.channel.channel]; + key = event->data.channel.param1; + volume = event->data.channel.param2; + + // Percussion channel (10) is treated differently. + + if (event->data.channel.channel == 9) + { + if (key < 35 || key > 81) + { + return; + } + + instrument = &percussion_instrs[key - 35]; + } + else + { + instrument = channel->instrument; + } + + // Find and program a voice for this instrument. If this + // is a double voice instrument, we must do this twice. + + VoiceKeyOn(channel, instrument, 0, key, volume); + + if ((instrument->flags & GENMIDI_FLAG_2VOICE) != 0) + { + VoiceKeyOn(channel, instrument, 1, key, volume); + } +} + static void ProgramChangeEvent(opl_track_data_t *track, midi_event_t *event) { int channel; @@ -1075,11 +1093,11 @@ static void ProcessEvent(opl_track_data_t *track, midi_event_t *event) switch (event->event_type) { case MIDI_EVENT_NOTE_OFF: - NoteOffEvent(track, event); + KeyOffEvent(track, event); break; case MIDI_EVENT_NOTE_ON: - NoteOnEvent(track, event); + KeyOnEvent(track, event); break; case MIDI_EVENT_CONTROLLER: @@ -1284,7 +1302,7 @@ static void I_OPL_StopSong(void) { if (voices[i].channel != NULL) { - VoiceNoteOff(&voices[i]); + VoiceKeyOff(&voices[i]); ReleaseVoice(&voices[i]); } } -- cgit v1.2.3 From ba1accec2394c6ee70c5c79a42827099ef20e638 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Tue, 8 Sep 2009 18:12:10 +0000 Subject: Set the correct instrument voice, instead of using the first voice for both. Subversion-branch: /branches/opl-branch Subversion-revision: 1661 --- src/i_oplmusic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 8ec47b80..643f67c5 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -914,7 +914,7 @@ static void VoiceKeyOn(opl_channel_data_t *channel, // Program the voice with the instrument data: - SetVoiceInstrument(voice, instrument, 0); + SetVoiceInstrument(voice, instrument, instrument_voice); // Set the volume level. -- cgit v1.2.3 From cc0cc9fb0c806f6533dca794b1e829a626323d8b Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Fri, 11 Sep 2009 16:54:06 +0000 Subject: Implement the fine tuning field, based on research. Subversion-branch: /branches/opl-branch Subversion-revision: 1664 --- src/i_oplmusic.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 643f67c5..8cb833a2 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -839,6 +839,14 @@ static unsigned int FrequencyForVoice(opl_voice_t *voice) freq_index = 64 + 32 * voice->note + voice->channel->bend; + // If this is the second voice of a double voice instrument, the + // frequency index can be adjusted by the fine tuning field. + + if (voice->current_instr_voice != 0) + { + freq_index += (voice->current_instr->fine_tuning / 2) - 64; + } + // The first 7 notes use the start of the table, while // consecutive notes loop around the latter part. -- cgit v1.2.3 From a6a747e0ab96c45abe1a563f278f3ebc05fdec55 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 12 Sep 2009 17:22:58 +0000 Subject: Discard an existing voice when no voices are available (based on research with Vanilla). Subversion-branch: /branches/opl-branch Subversion-revision: 1668 --- src/i_oplmusic.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 110 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 8cb833a2..bed81109 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -154,7 +154,8 @@ struct opl_voice_s unsigned int carrier_volume; unsigned int modulator_volume; - // Next in freelist + // Next in linked list; a voice is always either in the + // free list or the allocated list. opl_voice_t *next; }; @@ -318,6 +319,7 @@ static genmidi_instr_t *percussion_instrs; static opl_voice_t voices[OPL_NUM_VOICES]; static opl_voice_t *voice_free_list; +static opl_voice_t *voice_alloced_list; // Track data for playing tracks: @@ -505,12 +507,42 @@ static opl_voice_t *GetFreeVoice(void) return NULL; } + // Remove from free list + result = voice_free_list; voice_free_list = voice_free_list->next; + // Add to allocated list + + result->next = voice_alloced_list; + voice_alloced_list = result; + return result; } +// Remove a voice from the allocated voices list. + +static void RemoveVoiceFromAllocedList(opl_voice_t *voice) +{ + opl_voice_t **rover; + + rover = &voice_alloced_list; + + // Search the list until we find the voice, then remove it. + + while (*rover != NULL) + { + if (*rover == voice) + { + *rover = voice->next; + voice->next = NULL; + break; + } + + rover = &(*rover)->next; + } +} + // Release a voice back to the freelist. static void ReleaseVoice(opl_voice_t *voice) @@ -520,6 +552,10 @@ static void ReleaseVoice(opl_voice_t *voice) voice->channel = NULL; voice->note = 0; + // Remove from alloced list. + + RemoveVoiceFromAllocedList(voice); + // Search to the end of the freelist (This is how Doom behaves!) rover = &voice_free_list; @@ -831,6 +867,66 @@ static void KeyOffEvent(opl_track_data_t *track, midi_event_t *event) } } +// When all voices are in use, we must discard an existing voice to +// play a new note. Find and free an existing voice. The channel +// passed to the function is the channel for the new note to be +// played. + +static opl_voice_t *ReplaceExistingVoice(opl_channel_data_t *channel) +{ + opl_voice_t *rover; + opl_voice_t *result; + + // Check the allocated voices, if we find an instrument that is + // of a lower priority to the new instrument, discard it. + // Priority is determined by MIDI instrument number; old + + result = NULL; + + for (rover = voice_alloced_list; rover != NULL; rover = rover->next) + { + if (rover->current_instr > channel->instrument) + { + result = rover; + break; + } + } + + // If we didn't find a voice, find an existing voice being used to + // play a note on the same channel, and use that. + + if (result == NULL) + { + for (rover = voice_alloced_list; rover != NULL; rover = rover->next) + { + if (rover->channel == channel) + { + result = rover; + break; + } + } + } + + // Still nothing found? Give up and just use the first voice in + // the list. + + if (result == NULL) + { + result = voice_alloced_list; + } + + // Stop playing this voice playing and release it back to the free + // list. + + VoiceKeyOff(result); + ReleaseVoice(result); + + // Re-allocate the voice again and return it. + + return GetFreeVoice(); +} + + static unsigned int FrequencyForVoice(opl_voice_t *voice) { unsigned int freq_index; @@ -899,10 +995,21 @@ static void VoiceKeyOn(opl_channel_data_t *channel, voice = GetFreeVoice(); + // If there are no more voices left, we must decide what to do. + // If this is the first voice of the instrument, free an existing + // voice and use that. Otherwise, if this is the second voice, + // it isn't as important; just discard it. + if (voice == NULL) { - printf("\tno free voice for voice %i of instrument\n", instrument_voice); - return; + if (instrument_voice == 0) + { + voice = ReplaceExistingVoice(channel); + } + else + { + return; + } } voice->channel = channel; -- cgit v1.2.3 From 6132a2a3e365ca36b7a1a7d721289763bac971dd Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 12 Sep 2009 21:13:08 +0000 Subject: Vanilla Doom plays d_introa, not d_intro. Subversion-branch: /branches/opl-branch Subversion-revision: 1670 --- src/d_main.c | 2 +- src/i_oplmusic.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/d_main.c b/src/d_main.c index c59a8fb7..46dd19ac 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -521,7 +521,7 @@ void D_DoAdvanceDemo (void) if ( gamemode == commercial ) S_StartMusic(mus_dm2ttl); else - S_StartMusic (mus_intro); + S_StartMusic (mus_introa); break; case 1: G_DeferedPlayDemo(DEH_String("demo1")); diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index bed81109..a6c03f6f 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -1513,7 +1513,7 @@ static void *I_OPL_RegisterSong(void *data, int len) // remove file now - remove(filename); +// remove(filename); Z_Free(filename); -- cgit v1.2.3 From 2b40842eeca7386f6bfe9b1b39760c8a4d69ca71 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 12 Sep 2009 23:04:57 +0000 Subject: Remove separate volume calculations for non-feedback (separate operator) voices. Doom writes the same value to both operators. Subversion-branch: /branches/opl-branch Subversion-revision: 1671 --- src/i_oplmusic.c | 69 ++++++++++++++++++++++++-------------------------------- 1 file changed, 29 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index a6c03f6f..ce255ff7 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -150,9 +150,8 @@ struct opl_voice_s // The volume of the note being played on this channel. unsigned int note_volume; - // The current volume that has been set for this channel. - unsigned int carrier_volume; - unsigned int modulator_volume; + // The current volume (register value) that has been set for this channel. + unsigned int reg_volume; // Next in linked list; a voice is always either in the // free list or the allocated list. @@ -636,42 +635,15 @@ static void SetVoiceInstrument(opl_voice_t *voice, // Hack to force a volume update. - voice->carrier_volume = 999; - voice->modulator_volume = 999; -} - -// Calculate the volume level to use for a given operator. - -static void SetOperatorVolume(genmidi_op_t *op, unsigned int volume, - unsigned int opnum, - unsigned int *current_volume) -{ - unsigned int op_volume; - unsigned int reg_volume; - - // The volume of each instrument can be controlled via GENMIDI: - - op_volume = 0x3f - op->level; - - // The volume value to use in the register: - - reg_volume = (op_volume * volume) / 128; - reg_volume = (0x3f - reg_volume) | op->scale; - - // Update the register, if neccessary: - - if (*current_volume != reg_volume) - { - *current_volume = reg_volume; - - WriteRegister(OPL_REGS_LEVEL + opnum, reg_volume); - } + voice->reg_volume = 999; } static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume) { genmidi_voice_t *opl_voice; unsigned int full_volume; + unsigned int op_volume; + unsigned int reg_volume; voice->note_volume = volume; @@ -682,16 +654,33 @@ static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume) full_volume = (volume_mapping_table[voice->note_volume] * volume_mapping_table[voice->channel->volume]) / 127; - SetOperatorVolume(&opl_voice->carrier, full_volume, - voice->op2, &voice->carrier_volume); + // The volume of each instrument can be controlled via GENMIDI: + + op_volume = 0x3f - opl_voice->carrier.level; - // If we are using non-modulated feedback mode, we must set the - // volume for both voices. + // The volume value to use in the register: - if ((opl_voice->feedback & 0x01) != 0) + reg_volume = (op_volume * full_volume) / 128; + reg_volume = (0x3f - reg_volume) | opl_voice->carrier.scale; + + // Update the volume register(s) if necessary. + + if (reg_volume != voice->reg_volume) { - SetOperatorVolume(&opl_voice->modulator, full_volume, - voice->op1, &voice->modulator_volume); + voice->reg_volume = reg_volume; + + WriteRegister(OPL_REGS_LEVEL + voice->op2, reg_volume); + + // If we are using non-modulated feedback mode, we must set the + // volume for both voices. + // Note that the same register volume value is written for + // both voices, always calculated from the carrier's level + // value. + + if ((opl_voice->feedback & 0x01) != 0) + { + WriteRegister(OPL_REGS_LEVEL + voice->op1, reg_volume); + } } } -- cgit v1.2.3 From 7e2eaa105e270586e81c04fdf61bcafd7c96a34c Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 13 Sep 2009 00:15:24 +0000 Subject: Change intro/introa fix to be more accurate: Doom uses d_intro, but transforms this to d_introa when using OPL playback (thanks entryway) Subversion-branch: /branches/opl-branch Subversion-revision: 1672 --- src/d_main.c | 2 +- src/s_sound.c | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/d_main.c b/src/d_main.c index 46dd19ac..c59a8fb7 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -521,7 +521,7 @@ void D_DoAdvanceDemo (void) if ( gamemode == commercial ) S_StartMusic(mus_dm2ttl); else - S_StartMusic (mus_introa); + S_StartMusic (mus_intro); break; case 1: G_DeferedPlayDemo(DEH_String("demo1")); diff --git a/src/s_sound.c b/src/s_sound.c index f038e9cd..9e70ec73 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -804,6 +804,15 @@ void S_ChangeMusic(int musicnum, int looping) char namebuf[9]; void *handle; + // The Doom IWAD file has two versions of the intro music: d_intro + // and d_introa. The latter is used for OPL playback. + + if (musicnum == mus_intro && (snd_musicdevice == SNDDEVICE_ADLIB + || snd_musicdevice == SNDDEVICE_SB)) + { + musicnum = mus_introa; + } + if (musicnum <= mus_None || musicnum >= NUMMUSIC) { I_Error("Bad music number %d", musicnum); -- cgit v1.2.3 From 13314576f8d5d8eec8bf413ca4b49255b9e1a6a2 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 19 Sep 2009 20:42:45 +0000 Subject: Add octave offset table, offset notes on specific instruments down by one octave, as per research. Subversion-branch: /branches/opl-branch Subversion-revision: 1678 --- src/i_oplmusic.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index ce255ff7..09d2ae42 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -304,6 +304,31 @@ static const unsigned int volume_mapping_table[] = { 124, 124, 125, 125, 126, 126, 127, 127 }; +// For octave offset table: + +static const unsigned int octave_offset_table[2][128] = { + { + 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, // 0-15 + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31 + 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, // 32-47 + 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, // 48-63 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, // 64-79 + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // 80-95 + 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // 96-111 + 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, // 112-127 + }, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0-15 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31 + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, // 32-47 + 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, // 48-63 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 64-79 + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80-95 + 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 96-111 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 112-127 + } +}; + static boolean music_initialised = false; //static boolean musicpaused = false; @@ -832,10 +857,12 @@ static void KeyOffEvent(opl_track_data_t *track, midi_event_t *event) unsigned int key; unsigned int i; +/* printf("note off: channel %i, %i, %i\n", event->data.channel.channel, event->data.channel.param1, event->data.channel.param2); +*/ channel = &track->channels[event->data.channel.channel]; key = event->data.channel.param1; @@ -921,8 +948,25 @@ static unsigned int FrequencyForVoice(opl_voice_t *voice) unsigned int freq_index; unsigned int octave; unsigned int sub_index; + unsigned int instr_num; + unsigned int note; + + note = voice->note; + + // What instrument number is this? + // Certain instruments have all notes offset down by one octave. + // Use the octave offset table to work out if this voice should + // be offset. + + instr_num = voice->current_instr - main_instrs; + + if (instr_num < 128 && note >= 12 + && octave_offset_table[voice->current_instr_voice][instr_num]) + { + note -= 12; + } - freq_index = 64 + 32 * voice->note + voice->channel->bend; + freq_index = 64 + 32 * note + voice->channel->bend; // If this is the second voice of a double voice instrument, the // frequency index can be adjusted by the fine tuning field. @@ -1037,10 +1081,12 @@ static void KeyOnEvent(opl_track_data_t *track, midi_event_t *event) unsigned int key; unsigned int volume; +/* printf("note on: channel %i, %i, %i\n", event->data.channel.channel, event->data.channel.param1, event->data.channel.param2); +*/ // The channel. @@ -1113,10 +1159,12 @@ static void ControllerEvent(opl_track_data_t *track, midi_event_t *event) unsigned int param; opl_channel_data_t *channel; +/* printf("change controller: channel %i, %i, %i\n", event->data.channel.channel, event->data.channel.param1, event->data.channel.param2); +*/ channel = &track->channels[event->data.channel.channel]; controller = event->data.channel.param1; -- cgit v1.2.3 From dd03cbbe2b688eac26011ac0ea0ada4047e5beb0 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 20 Sep 2009 20:47:17 +0000 Subject: Use the base note offset field to offset notes, not a fixed lookup table of instruments to offset. Subversion-branch: /branches/opl-branch Subversion-revision: 1680 --- src/i_oplmusic.c | 42 +++++------------------------------------- 1 file changed, 5 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 09d2ae42..de126c63 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -34,6 +34,7 @@ #include "mus2mid.h" #include "deh_main.h" +#include "i_swap.h" #include "m_misc.h" #include "s_sound.h" #include "w_wad.h" @@ -304,31 +305,6 @@ static const unsigned int volume_mapping_table[] = { 124, 124, 125, 125, 126, 126, 127, 127 }; -// For octave offset table: - -static const unsigned int octave_offset_table[2][128] = { - { - 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, // 0-15 - 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31 - 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, // 32-47 - 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, // 48-63 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, // 64-79 - 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // 80-95 - 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // 96-111 - 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, // 112-127 - }, - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0-15 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31 - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, // 32-47 - 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, // 48-63 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 64-79 - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80-95 - 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 96-111 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 112-127 - } -}; - static boolean music_initialised = false; //static boolean musicpaused = false; @@ -945,26 +921,18 @@ static opl_voice_t *ReplaceExistingVoice(opl_channel_data_t *channel) static unsigned int FrequencyForVoice(opl_voice_t *voice) { + genmidi_voice_t *gm_voice; unsigned int freq_index; unsigned int octave; unsigned int sub_index; - unsigned int instr_num; unsigned int note; note = voice->note; - // What instrument number is this? - // Certain instruments have all notes offset down by one octave. - // Use the octave offset table to work out if this voice should - // be offset. - - instr_num = voice->current_instr - main_instrs; + // Apply note offset: - if (instr_num < 128 && note >= 12 - && octave_offset_table[voice->current_instr_voice][instr_num]) - { - note -= 12; - } + gm_voice = &voice->current_instr->voices[voice->current_instr_voice]; + note += (signed short) SHORT(gm_voice->base_note_offset); freq_index = 64 + 32 * note + voice->channel->bend; -- cgit v1.2.3 From f894f24bcd63dc8b2a0604a9b659dd95aebbb384 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 20 Sep 2009 21:19:37 +0000 Subject: Avoid possible overflow due to base note offset. Subversion-branch: /branches/opl-branch Subversion-revision: 1683 --- src/i_oplmusic.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index de126c63..aa079614 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -934,6 +934,13 @@ static unsigned int FrequencyForVoice(opl_voice_t *voice) gm_voice = &voice->current_instr->voices[voice->current_instr_voice]; note += (signed short) SHORT(gm_voice->base_note_offset); + // Avoid possible overflow due to base note offset: + + if (note > 0x7f) + { + note = voice->note; + } + freq_index = 64 + 32 * note + voice->channel->bend; // If this is the second voice of a double voice instrument, the -- cgit v1.2.3 From fcf4a7241a742e7f3d8189c40ad852d48c674612 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 20 Sep 2009 21:21:30 +0000 Subject: Remove old test code. Subversion-branch: /branches/opl-branch Subversion-revision: 1684 --- src/i_oplmusic.c | 47 ----------------------------------------------- 1 file changed, 47 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index aa079614..b8e93534 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -43,8 +43,6 @@ #include "opl.h" #include "midifile.h" -//#define TEST - #define MAXMIDLENGTH (96 * 1024) #define GENMIDI_NUM_INSTRS 128 @@ -716,9 +714,6 @@ static void I_OPL_ShutdownMusic(void) { if (music_initialised) { -#ifdef TEST - InitRegisters(); -#endif OPL_Shutdown(); // Release GENMIDI lump @@ -729,30 +724,6 @@ static void I_OPL_ShutdownMusic(void) } } -#ifdef TEST -static void TestCallback(void *arg) -{ - opl_voice_t *voice = arg; - int note; - int wait_time; - - // Set level: - WriteRegister(OPL_REGS_LEVEL + voice->op2, 0); - - // Note off: - - WriteRegister(OPL_REGS_FREQ_2 + voice->index, 0x00); - // Note on: - - note = (rand() % (0x2ae - 0x16b)) + 0x16b; - WriteRegister(OPL_REGS_FREQ_1 + voice->index, note & 0xff); - WriteRegister(OPL_REGS_FREQ_2 + voice->index, 0x30 + (note >> 8)); - - wait_time = (rand() % 700) + 50; - OPL_SetCallback(wait_time, TestCallback, arg); -} -#endif - // Initialise music subsystem static boolean I_OPL_InitMusic(void) @@ -789,24 +760,6 @@ static boolean I_OPL_InitMusic(void) init_stage_reg_writes = false; -#ifdef TEST - { - int i; - opl_voice_t *voice; - int instr_num; - - for (i=0; i<3; ++i) - { - voice = GetFreeVoice(); - instr_num = rand() % 100; - - SetVoiceInstrument(voice, &main_instrs[instr_num], 0); - - OPL_SetCallback(0, TestCallback, voice); - } - } -#endif - music_initialised = true; return true; -- cgit v1.2.3 From 4b598f3d40e34b5d786c9236f891fbe2337c1b66 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 20 Sep 2009 21:25:59 +0000 Subject: Implement volume control. Subversion-branch: /branches/opl-branch Subversion-revision: 1685 --- src/i_oplmusic.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index b8e93534..4ac52754 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -651,7 +651,8 @@ static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume) // Multiply note volume and channel volume to get the actual volume. full_volume = (volume_mapping_table[voice->note_volume] - * volume_mapping_table[voice->channel->volume]) / 127; + * volume_mapping_table[voice->channel->volume] + * volume_mapping_table[current_music_volume]) / (127 * 127); // The volume of each instrument can be controlled via GENMIDI: @@ -769,8 +770,21 @@ static boolean I_OPL_InitMusic(void) static void I_OPL_SetMusicVolume(int volume) { + unsigned int i; + // Internal state variable. + current_music_volume = volume; + + // Update the volume of all voices. + + for (i=0; itremolo); - WriteRegister(OPL_REGS_ATTACK + operator, data->attack); - WriteRegister(OPL_REGS_SUSTAIN + operator, data->sustain); - WriteRegister(OPL_REGS_WAVEFORM + operator, data->waveform); + OPL_WriteRegister(OPL_REGS_LEVEL + operator, level); + OPL_WriteRegister(OPL_REGS_TREMOLO + operator, data->tremolo); + OPL_WriteRegister(OPL_REGS_ATTACK + operator, data->attack); + OPL_WriteRegister(OPL_REGS_SUSTAIN + operator, data->sustain); + OPL_WriteRegister(OPL_REGS_WAVEFORM + operator, data->waveform); } // Set the instrument for a particular voice. @@ -629,8 +491,8 @@ static void SetVoiceInstrument(opl_voice_t *voice, // two operators. Turn on bits in the upper nybble; I think this // is for OPL3, where it turns on channel A/B. - WriteRegister(OPL_REGS_FEEDBACK + voice->index, - data->feedback | 0x30); + OPL_WriteRegister(OPL_REGS_FEEDBACK + voice->index, + data->feedback | 0x30); // Hack to force a volume update. @@ -669,7 +531,7 @@ static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume) { voice->reg_volume = reg_volume; - WriteRegister(OPL_REGS_LEVEL + voice->op2, reg_volume); + OPL_WriteRegister(OPL_REGS_LEVEL + voice->op2, reg_volume); // If we are using non-modulated feedback mode, we must set the // volume for both voices. @@ -679,7 +541,7 @@ static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume) if ((opl_voice->feedback & 0x01) != 0) { - WriteRegister(OPL_REGS_LEVEL + voice->op1, reg_volume); + OPL_WriteRegister(OPL_REGS_LEVEL + voice->op1, reg_volume); } } } @@ -730,18 +592,8 @@ static void I_OPL_ShutdownMusic(void) static boolean I_OPL_InitMusic(void) { if (!OPL_Init(opl_io_port)) - { - return false; - } - - init_stage_reg_writes = true; - - // Doom does the detection sequence twice, for some reason: - - if (!DetectOPL() || !DetectOPL()) { printf("Dude. The Adlib isn't responding.\n"); - OPL_Shutdown(); return false; } @@ -753,14 +605,8 @@ static boolean I_OPL_InitMusic(void) return false; } - InitRegisters(); InitVoices(); - // Now that initialisation has finished, switch the - // register writing mode: - - init_stage_reg_writes = false; - music_initialised = true; return true; @@ -789,7 +635,7 @@ static void I_OPL_SetMusicVolume(int volume) static void VoiceKeyOff(opl_voice_t *voice) { - WriteRegister(OPL_REGS_FREQ_2 + voice->index, voice->freq >> 8); + OPL_WriteRegister(OPL_REGS_FREQ_2 + voice->index, voice->freq >> 8); } // Get the frequency that we should be using for a voice. @@ -947,8 +793,8 @@ static void UpdateVoiceFrequency(opl_voice_t *voice) if (voice->freq != freq) { - WriteRegister(OPL_REGS_FREQ_1 + voice->index, freq & 0xff); - WriteRegister(OPL_REGS_FREQ_2 + voice->index, (freq >> 8) | 0x20); + OPL_WriteRegister(OPL_REGS_FREQ_1 + voice->index, freq & 0xff); + OPL_WriteRegister(OPL_REGS_FREQ_2 + voice->index, (freq >> 8) | 0x20); voice->freq = freq; } -- cgit v1.2.3 From 4a70f989d2aacabffc2f02017704de042be7418a Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 1 Oct 2009 00:08:48 +0000 Subject: Convert to American English spellings. Subversion-branch: /branches/opl-branch Subversion-revision: 1700 --- src/i_oplmusic.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index e9e722e4..35ba046d 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -303,7 +303,7 @@ static const unsigned int volume_mapping_table[] = { 124, 124, 125, 125, 126, 126, 127, 127 }; -static boolean music_initialised = false; +static boolean music_initialized = false; //static boolean musicpaused = false; static int current_music_volume; @@ -546,7 +546,7 @@ static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume) } } -// Initialise the voice table and freelist +// Initialize the voice table and freelist static void InitVoices(void) { @@ -556,7 +556,7 @@ static void InitVoices(void) voice_free_list = NULL; - // Initialise each voice. + // Initialize each voice. for (i=0; i 0; +} + +// Shutdown music + +static void I_OPL_ShutdownMusic(void) +{ + if (music_initialized) + { + // Stop currently-playing track, if there is one: + + I_OPL_StopSong(); + + OPL_Shutdown(); + + // Release GENMIDI lump + + W_ReleaseLumpName("GENMIDI"); + + music_initialized = false; + } +} + +// Initialize music subsystem + +static boolean I_OPL_InitMusic(void) +{ + if (!OPL_Init(opl_io_port)) + { + printf("Dude. The Adlib isn't responding.\n"); + return false; + } + + // Load instruments from GENMIDI lump: + + if (!LoadInstrumentTable()) + { + OPL_Shutdown(); + return false; + } + + InitVoices(); + + tracks = NULL; + num_tracks = 0; + music_initialized = true; + + return true; } static snddevice_t music_opl_devices[] = -- cgit v1.2.3 From 56a6af426972ed2a334ae7001d19854aca964a75 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 11 Oct 2009 21:47:07 +0000 Subject: Don't apply base note offset if the instrument is a fixed note instrument. This should stop the ugly bleeping from the electric snare on E1M2. Subversion-branch: /branches/opl-branch Subversion-revision: 1715 --- src/i_oplmusic.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index cd331897..d32a163e 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -701,10 +701,15 @@ static unsigned int FrequencyForVoice(opl_voice_t *voice) note = voice->note; - // Apply note offset: + // Apply note offset. + // Don't apply offset if the instrument is a fixed note instrument. gm_voice = &voice->current_instr->voices[voice->current_instr_voice]; - note += (signed short) SHORT(gm_voice->base_note_offset); + + if ((voice->current_instr->flags & GENMIDI_FLAG_FIXED) == 0) + { + note += (signed short) SHORT(gm_voice->base_note_offset); + } // Avoid possible overflow due to base note offset: -- cgit v1.2.3 From e30325c40f6ea482862745db0f4555e513f2952e Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 17 Oct 2009 22:36:15 +0000 Subject: Add OPL library API function to set software emulation sample rate, and set from snd_samplerate in the configuration file. Subversion-branch: /branches/opl-branch Subversion-revision: 1723 --- src/i_oplmusic.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index d32a163e..474877d4 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -1372,6 +1372,8 @@ static void I_OPL_ShutdownMusic(void) static boolean I_OPL_InitMusic(void) { + OPL_SetSampleRate(snd_samplerate); + if (!OPL_Init(opl_io_port)) { printf("Dude. The Adlib isn't responding.\n"); -- cgit v1.2.3 From 14bcdd1008db070bc4a12be73e3f692c1990966e Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 25 Oct 2009 17:07:55 +0000 Subject: Emulate odd octave 7 behavior of Vanilla Doom. Subversion-branch: /branches/opl-branch Subversion-revision: 1725 --- src/i_oplmusic.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 474877d4..89e73f1a 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -739,6 +739,26 @@ static unsigned int FrequencyForVoice(opl_voice_t *voice) sub_index = (freq_index - 284) % (12 * 32); octave = (freq_index - 284) / (12 * 32); + // Once the seventh octave is reached, things break down. + // We can only go up to octave 7 as a maximum anyway (the OPL + // register only has three bits for octave number), but for the + // notes in octave 7, the first five bits have octave=7, the + // following notes have octave=6. This 7/6 pattern repeats in + // following octaves (which are technically impossible to + // represent anyway). + + if (octave >= 7) + { + if (sub_index < 5) + { + octave = 7; + } + else + { + octave = 6; + } + } + // Calculate the resulting register value to use for the frequency. return frequency_curve[sub_index + 284] | (octave << 10); -- cgit v1.2.3 From 299e1c5abf804e2e249c4f77b82fb7949a3f9d7b Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 31 Oct 2009 16:47:49 +0000 Subject: When replacing an existing voice, discard voices that are the second voice of a two voice instrument. Don't discard instruments from lower numbered MIDI channels for higher numbered MIDI channels. Subversion-branch: /branches/opl-branch Subversion-revision: 1727 --- src/i_oplmusic.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 89e73f1a..9501d51d 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -631,6 +631,16 @@ static void KeyOffEvent(opl_track_data_t *track, midi_event_t *event) } } +// Compare the priorities of channels, returning either -1, 0 or 1. + +static int CompareChannelPriorities(opl_channel_data_t *chan1, + opl_channel_data_t *chan2) +{ + // TODO ... + + return 1; +} + // When all voices are in use, we must discard an existing voice to // play a new note. Find and free an existing voice. The channel // passed to the function is the channel for the new note to be @@ -643,13 +653,19 @@ static opl_voice_t *ReplaceExistingVoice(opl_channel_data_t *channel) // Check the allocated voices, if we find an instrument that is // of a lower priority to the new instrument, discard it. - // Priority is determined by MIDI instrument number; old + // If a voice is being used to play the second voice of an instrument, + // use that, as second voices are non-essential. + // Lower numbered MIDI channels implicitly have a higher priority + // than higher-numbered channels, eg. MIDI channel 1 is never + // discarded for MIDI channel 2. result = NULL; for (rover = voice_alloced_list; rover != NULL; rover = rover->next) { - if (rover->current_instr > channel->instrument) + if (rover->current_instr_voice != 0 + || (rover->channel > channel + && CompareChannelPriorities(channel, rover->channel) > 0)) { result = rover; break; -- cgit v1.2.3 From c33c1fa07680ef07540fb1c48a323bdc816e3e77 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 6 Feb 2010 15:54:13 +0000 Subject: Fix Heretic/Hexen "noise" sound debug cheats. Subversion-branch: /branches/raven-branch Subversion-revision: 1850 --- src/heretic/s_sound.c | 12 ++++++++++-- src/hexen/s_sound.c | 12 ++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/heretic/s_sound.c b/src/heretic/s_sound.c index bdd24594..be4ae0e3 100644 --- a/src/heretic/s_sound.c +++ b/src/heretic/s_sound.c @@ -550,8 +550,16 @@ void S_GetChannelInfo(SoundInfo_t * s) c->priority = channel[i].priority; c->name = S_sfx[c->id].name; c->mo = channel[i].mo; - c->distance = P_AproxDistance(c->mo->x - viewx, c->mo->y - viewy) - >> FRACBITS; + + if (c->mo != NULL) + { + c->distance = P_AproxDistance(c->mo->x - viewx, c->mo->y - viewy) + >> FRACBITS; + } + else + { + c->distance = 0; + } } } diff --git a/src/hexen/s_sound.c b/src/hexen/s_sound.c index fdd01ba5..74774fb3 100644 --- a/src/hexen/s_sound.c +++ b/src/hexen/s_sound.c @@ -787,8 +787,16 @@ void S_GetChannelInfo(SoundInfo_t * s) c->priority = Channel[i].priority; c->name = S_sfx[c->id].name; c->mo = Channel[i].mo; - c->distance = P_AproxDistance(c->mo->x - viewx, c->mo->y - viewy) - >> FRACBITS; + + if (c->mo != NULL) + { + c->distance = P_AproxDistance(c->mo->x - viewx, c->mo->y - viewy) + >> FRACBITS; + } + else + { + c->distance = 0; + } } } -- cgit v1.2.3 From abb5f33199e6fe036d068b5a5f59e58e1505eb8e Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 7 Feb 2010 00:59:56 +0000 Subject: Add back unused phoenix rod object, frames, and dummy action pointer. These were in Heretic 1.0 but were later removed. Also add comments to info.h noting fire-death frames that were added Heretic 1.0. This is necessary for HHE support. Subversion-branch: /branches/raven-branch Subversion-revision: 1854 --- src/heretic/info.c | 35 +++++++++++++++++++++++++++++++++++ src/heretic/info.h | 8 ++++++-- src/heretic/p_pspr.c | 11 +++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/heretic/info.c b/src/heretic/info.c index e566222c..4848ede9 100644 --- a/src/heretic/info.c +++ b/src/heretic/info.c @@ -95,6 +95,7 @@ void A_InitPhoenixPL2(); void A_FirePhoenixPL2(); void A_ShutdownPhoenixPL2(); void A_PhoenixPuff(); +void A_RemovedPhoenixPuff(); void A_FlameEnd(); void A_FloatPuff(); void A_FireCrossbowPL1(); @@ -663,6 +664,9 @@ state_t states[NUMSTATES] = { {SPR_FX08, 32773, 4, NULL, S_PHOENIXFXI1_7, 0, 0}, // S_PHOENIXFXI1_6 {SPR_FX08, 32774, 4, NULL, S_PHOENIXFXI1_8, 0, 0}, // S_PHOENIXFXI1_7 {SPR_FX08, 32775, 4, NULL, S_NULL, 0, 0}, // S_PHOENIXFXI1_8 + {SPR_FX08, 32776, 8, NULL, S_PHOENIXFXIX_1, 0, 0 }, // S_PHOENIXFXIX_1 + {SPR_FX08, 32777, 8, A_RemovedPhoenixFunc, S_PHOENIXFXIX_2, 0, 0 }, // S_PHOENIXFXIX_2 + {SPR_FX08, 32778, 8, NULL, S_NULL, 0, 0 }, // S_PHOENIXFXIX_3 {SPR_FX04, 1, 4, NULL, S_PHOENIXPUFF2, 0, 0}, // S_PHOENIXPUFF1 {SPR_FX04, 2, 4, NULL, S_PHOENIXPUFF3, 0, 0}, // S_PHOENIXPUFF2 {SPR_FX04, 3, 4, NULL, S_PHOENIXPUFF4, 0, 0}, // S_PHOENIXPUFF3 @@ -3727,6 +3731,37 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { MF2_THRUGHOST | MF2_NOTELEPORT // flags2 }, + // The following thing is present in the mobjinfo table from Heretic 1.0, + // but not in Heretic 1.3 (ie. it was removed). It has been re-inserted + // here to support HHE patches. + + { // MT_PHOENIXFX_REMOVED + -1, // doomednum + S_PHOENIXFXIX_1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // crashstate + S_PHOENIXFXIX_3, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 2 * FRACUNIT, // radius + 4 * FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags + MF2_NOTELEPORT // flags2 + }, + { // MT_PHOENIXPUFF -1, // doomednum S_PHOENIXPUFF1, // spawnstate diff --git a/src/heretic/info.h b/src/heretic/info.h index f9581298..16b6aedc 100644 --- a/src/heretic/info.h +++ b/src/heretic/info.h @@ -653,6 +653,9 @@ typedef enum S_PHOENIXFXI1_6, S_PHOENIXFXI1_7, S_PHOENIXFXI1_8, + S_PHOENIXFXIX_1, // [ States in Heretic 1.0 that were removed + S_PHOENIXFXIX_2, + S_PHOENIXFXIX_3, // ] S_PHOENIXPUFF1, S_PHOENIXPUFF2, S_PHOENIXPUFF3, @@ -773,8 +776,8 @@ typedef enum S_PLAY_FDTH16, S_PLAY_FDTH17, S_PLAY_FDTH18, - S_PLAY_FDTH19, - S_PLAY_FDTH20, + S_PLAY_FDTH19, // < These two frames were not present in the Heretic + S_PLAY_FDTH20, // < 1.0 executable (fire death animation was extended) S_BLOODYSKULL1, S_BLOODYSKULL2, S_BLOODYSKULL3, @@ -1470,6 +1473,7 @@ typedef enum MT_GOLDWANDPUFF2, MT_WPHOENIXROD, MT_PHOENIXFX1, + MT_PHOENIXFX_REMOVED, // In Heretic 1.0, but removed. MT_PHOENIXPUFF, MT_PHOENIXFX2, MT_MISC15, diff --git a/src/heretic/p_pspr.c b/src/heretic/p_pspr.c index 7f9660ac..bd47c9a1 100644 --- a/src/heretic/p_pspr.c +++ b/src/heretic/p_pspr.c @@ -1650,6 +1650,17 @@ void A_PhoenixPuff(mobj_t * actor) puff->momz = 0; } +// +// This function was present in the Heretic 1.0 executable for the +// removed "secondary phoenix flash" object (MT_PHOENIXFX_REMOVED). +// The purpose of this object is unknown, as is this function. +// + +void A_RemovedPhoenixFunc(mobj_t *actor) +{ + I_Error("Action function invoked for removed Phoenix action!"); +} + //---------------------------------------------------------------------------- // // PROC A_InitPhoenixPL2 -- cgit v1.2.3 From b786d601aeaaa20167f408be56f7e8d13ecc2f8c Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 7 Feb 2010 02:04:12 +0000 Subject: Oops. Subversion-branch: /branches/raven-branch Subversion-revision: 1855 --- src/heretic/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/heretic/info.c b/src/heretic/info.c index 4848ede9..7149220e 100644 --- a/src/heretic/info.c +++ b/src/heretic/info.c @@ -95,7 +95,7 @@ void A_InitPhoenixPL2(); void A_FirePhoenixPL2(); void A_ShutdownPhoenixPL2(); void A_PhoenixPuff(); -void A_RemovedPhoenixPuff(); +void A_RemovedPhoenixFunc(); void A_FlameEnd(); void A_FloatPuff(); void A_FireCrossbowPL1(); -- cgit v1.2.3 From e22d6a0d26b08e2e7c69972fed1cb96f300ef523 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 7 Feb 2010 02:59:25 +0000 Subject: Refactor dehacked structure mapping code to support string fields in addition to integer fields. Subversion-branch: /branches/raven-branch Subversion-revision: 1856 --- src/deh_mapping.c | 140 +++++++++++++++++++++++++++++++++++++++++------------- src/deh_mapping.h | 22 +++++++-- 2 files changed, 124 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/deh_mapping.c b/src/deh_mapping.c index b215b128..f061c298 100644 --- a/src/deh_mapping.c +++ b/src/deh_mapping.c @@ -34,12 +34,9 @@ #include "i_system.h" #include "deh_mapping.h" -// -// Set the value of a particular field in a structure by name -// - -boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping, - void *structptr, char *name, int value) +static deh_mapping_entry_t *GetMappingEntryByName(deh_context_t *context, + deh_mapping_t *mapping, + char *name) { int i; @@ -49,44 +46,121 @@ boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping, if (!strcasecmp(entry->name, name)) { - void *location; - if (entry->location == NULL) { DEH_Warning(context, "Field '%s' is unsupported", name); - return false; + return NULL; } - location = (uint8_t *)structptr + ((uint8_t *)entry->location - (uint8_t *)mapping->base); - - // printf("Setting %p::%s to %i (%i bytes)\n", - // structptr, name, value, entry->size); - - switch (entry->size) - { - case 1: - * ((uint8_t *) location) = value; - break; - case 2: - * ((uint16_t *) location) = value; - break; - case 4: - * ((uint32_t *) location) = value; - break; - default: - DEH_Error(context, "Unknown field type for '%s' (BUG)", name); - return false; - } - - return true; + return entry; } } - // field with this name not found + // Not found. DEH_Warning(context, "Field named '%s' not found", name); - return false; + return NULL; +} + +// +// Get the location of the specified field in the specified structure. +// + +static void *GetStructField(void *structptr, + deh_mapping_t *mapping, + deh_mapping_entry_t *entry) +{ + unsigned int offset; + + offset = (uint8_t *)entry->location - (uint8_t *)mapping->base; + + return (uint8_t *)structptr + offset; +} + +// +// Set the value of a particular field in a structure by name +// + +boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping, + void *structptr, char *name, int value) +{ + deh_mapping_entry_t *entry; + void *location; + + entry = GetMappingEntryByName(context, mapping, name); + + if (entry == NULL) + { + return false; + } + + // Sanity check: + + if (entry->is_string) + { + DEH_Error(context, "Tried to set '%s' as integer (BUG)", name); + return false; + } + + location = GetStructField(structptr, mapping, entry); + + // printf("Setting %p::%s to %i (%i bytes)\n", + // structptr, name, value, entry->size); + + // Set field content based on its type: + + switch (entry->size) + { + case 1: + * ((uint8_t *) location) = value; + break; + case 2: + * ((uint16_t *) location) = value; + break; + case 4: + * ((uint32_t *) location) = value; + break; + default: + DEH_Error(context, "Unknown field type for '%s' (BUG)", name); + return false; + } + + return true; +} + +// +// Set the value of a string field in a structure by name +// + +boolean DEH_SetStringMapping(deh_context_t *context, deh_mapping_t *mapping, + void *structptr, char *name, char *value) +{ + deh_mapping_entry_t *entry; + void *location; + + entry = GetMappingEntryByName(context, mapping, name); + + if (entry == NULL) + { + return false; + } + + // Sanity check: + + if (!entry->is_string) + { + DEH_Error(context, "Tried to set '%s' as string (BUG)", name); + return false; + } + + location = GetStructField(structptr, mapping, entry); + + // Copy value into field: + + strncpy(location, value, entry->size); + + return true; } void DEH_StructMD5Sum(md5_context_t *context, deh_mapping_t *mapping, diff --git a/src/deh_mapping.h b/src/deh_mapping.h index 4862dec9..129ddcfd 100644 --- a/src/deh_mapping.h +++ b/src/deh_mapping.h @@ -42,17 +42,23 @@ #define DEH_MAPPING(deh_name, fieldname) \ {deh_name, &deh_mapping_base.fieldname, \ - sizeof(deh_mapping_base.fieldname)}, + sizeof(deh_mapping_base.fieldname), \ + false}, + +#define DEH_MAPPING_STRING(deh_name, fieldname) \ + {deh_name, &deh_mapping_base.fieldname, \ + sizeof(deh_mapping_base.fieldname), \ + true}, #define DEH_UNSUPPORTED_MAPPING(deh_name) \ - {deh_name, NULL, -1}, - + {deh_name, NULL, -1, false}, + #define DEH_END_MAPPING \ {NULL, NULL, -1} \ } \ }; - + #define MAX_MAPPING_ENTRIES 32 @@ -73,6 +79,10 @@ struct deh_mapping_entry_s // field size int size; + + // if true, this is a string value. + + boolean is_string; }; struct deh_mapping_s @@ -81,8 +91,10 @@ struct deh_mapping_s deh_mapping_entry_t entries[MAX_MAPPING_ENTRIES]; }; -boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping, +boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping, void *structptr, char *name, int value); +boolean DEH_SetStringMapping(deh_context_t *context, deh_mapping_t *mapping, + void *structptr, char *name, char *value); void DEH_StructMD5Sum(md5_context_t *context, deh_mapping_t *mapping, void *structptr); -- cgit v1.2.3 From f04325260a5a95ca4c60c3b57762e48beedc381e Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 7 Feb 2010 03:02:01 +0000 Subject: Move sound structure and ammo definitions into headers. Add #ifndef guards around info.h. Subversion-branch: /branches/raven-branch Subversion-revision: 1857 --- src/heretic/doomdef.h | 1 + src/heretic/info.h | 7 ++++++- src/heretic/p_inter.c | 2 +- src/heretic/s_sound.c | 5 ++--- src/heretic/sounds.h | 5 +++++ 5 files changed, 15 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/heretic/doomdef.h b/src/heretic/doomdef.h index 3f976c3d..aa1d0c0d 100644 --- a/src/heretic/doomdef.h +++ b/src/heretic/doomdef.h @@ -581,6 +581,7 @@ extern boolean singletics; // debug flag to cancel adaptiveness extern boolean DebugSound; // debug flag for displaying sound info extern int maxammo[NUMAMMO]; +extern int GetWeaponAmmo[NUMWEAPONS]; extern boolean demoplayback; extern int skytexture; diff --git a/src/heretic/info.h b/src/heretic/info.h index 16b6aedc..236826cb 100644 --- a/src/heretic/info.h +++ b/src/heretic/info.h @@ -21,7 +21,9 @@ // 02111-1307, USA. // //----------------------------------------------------------------------------- -// generated by multigen + +#ifndef HERETIC_INFO_H +#define HERETIC_INFO_H typedef enum { @@ -1579,3 +1581,6 @@ typedef struct } mobjinfo_t; extern mobjinfo_t mobjinfo[NUMMOBJTYPES]; + +#endif /* #ifndef HERETIC_INFO_H */ + diff --git a/src/heretic/p_inter.c b/src/heretic/p_inter.c index fba6d215..3587a95d 100644 --- a/src/heretic/p_inter.c +++ b/src/heretic/p_inter.c @@ -54,7 +54,7 @@ int maxammo[NUMAMMO] = { 150 // mace }; -static int GetWeaponAmmo[NUMWEAPONS] = { +int GetWeaponAmmo[NUMWEAPONS] = { 0, // staff 25, // gold wand 10, // crossbow diff --git a/src/heretic/s_sound.c b/src/heretic/s_sound.c index be4ae0e3..8e0be9f1 100644 --- a/src/heretic/s_sound.c +++ b/src/heretic/s_sound.c @@ -33,6 +33,8 @@ #include "r_local.h" #include "p_local.h" +#include "sounds.h" + #include "w_wad.h" #include "z_zone.h" @@ -55,9 +57,6 @@ int mus_lumpnum; void *mus_sndptr; byte *soundCurve; -extern sfxinfo_t S_sfx[]; -extern musicinfo_t S_music[]; - int snd_MaxVolume = 10; int snd_MusicVolume = 10; int snd_Channels = 16; diff --git a/src/heretic/sounds.h b/src/heretic/sounds.h index 707185c0..e50a6ad6 100644 --- a/src/heretic/sounds.h +++ b/src/heretic/sounds.h @@ -27,6 +27,8 @@ #ifndef __SOUNDSH__ #define __SOUNDSH__ +#include "i_sound.h" + #define MAX_SND_DIST 1600 #define MAX_CHANNELS 16 @@ -291,4 +293,7 @@ typedef enum NUMSFX } sfxenum_t; +extern sfxinfo_t S_sfx[]; +extern musicinfo_t S_music[]; + #endif -- cgit v1.2.3 From 6a92bc54be4081c8821ca110947133b5f1f8516b Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 7 Feb 2010 03:04:29 +0000 Subject: Initial code for HHE patch support. Subversion-branch: /branches/raven-branch Subversion-revision: 1858 --- src/Makefile.am | 4 +- src/heretic/Makefile.am | 11 +++- src/heretic/deh_ammo.c | 122 ++++++++++++++++++++++++++++++++++++++ src/heretic/deh_frame.c | 131 +++++++++++++++++++++++++++++++++++++++++ src/heretic/deh_htic.c | 85 +++++++++++++++++++++++++++ src/heretic/deh_htic.h | 45 ++++++++++++++ src/heretic/deh_sound.c | 118 +++++++++++++++++++++++++++++++++++++ src/heretic/deh_thing.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++ src/heretic/deh_weapon.c | 130 +++++++++++++++++++++++++++++++++++++++++ 9 files changed, 792 insertions(+), 3 deletions(-) create mode 100644 src/heretic/deh_ammo.c create mode 100644 src/heretic/deh_frame.c create mode 100644 src/heretic/deh_htic.c create mode 100644 src/heretic/deh_htic.h create mode 100644 src/heretic/deh_sound.c create mode 100644 src/heretic/deh_thing.c create mode 100644 src/heretic/deh_weapon.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 9e550e15..eeabeb5b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -144,9 +144,9 @@ endif @PROGRAM_PREFIX@doom_LDADD = doom/libdoom.a $(EXTRA_LIBS) if HAVE_WINDRES -@PROGRAM_PREFIX@heretic_SOURCES=$(SOURCE_FILES) resource.rc +@PROGRAM_PREFIX@heretic_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc else -@PROGRAM_PREFIX@heretic_SOURCES=$(SOURCE_FILES) +@PROGRAM_PREFIX@heretic_SOURCES=$(SOURCE_FILES_WITH_DEH) endif @PROGRAM_PREFIX@heretic_LDADD = heretic/libheretic.a $(EXTRA_LIBS) diff --git a/src/heretic/Makefile.am b/src/heretic/Makefile.am index 2a2f8245..3fdd3ff7 100644 --- a/src/heretic/Makefile.am +++ b/src/heretic/Makefile.am @@ -55,5 +55,14 @@ EXTRA_DIST= \ i_sound.c \ i_ibm.c -libheretic_a_SOURCES=$(SOURCE_FILES) +FEATURE_DEHACKED_SOURCE_FILES = \ +deh_ammo.c \ +deh_frame.c \ +deh_htic.c \ +deh_sound.c \ +deh_thing.c \ +deh_weapon.c + +libheretic_a_SOURCES=$(SOURCE_FILES) \ + $(FEATURE_DEHACKED_SOURCE_FILES) diff --git a/src/heretic/deh_ammo.c b/src/heretic/deh_ammo.c new file mode 100644 index 00000000..fe86c757 --- /dev/null +++ b/src/heretic/deh_ammo.c @@ -0,0 +1,122 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2005 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +//----------------------------------------------------------------------------- +// +// Parses "Ammo" sections in dehacked files +// +//----------------------------------------------------------------------------- + +#include +#include +#include + +#include "doomdef.h" +#include "doomtype.h" +#include "deh_defs.h" +#include "deh_io.h" +#include "deh_main.h" +#include "p_local.h" + +static void *DEH_AmmoStart(deh_context_t *context, char *line) +{ + int ammo_number = 0; + + if (sscanf(line, "Ammo %i", &ammo_number) != 1) + { + DEH_Warning(context, "Parse error on section start"); + return NULL; + } + + if (ammo_number < 0 || ammo_number >= NUMAMMO) + { + DEH_Warning(context, "Invalid ammo number: %i", ammo_number); + return NULL; + } + + return &maxammo[ammo_number]; +} + +static void DEH_AmmoParseLine(deh_context_t *context, char *line, void *tag) +{ + char *variable_name, *value; + int ivalue; + int ammo_number; + + if (tag == NULL) + return; + + ammo_number = ((int *) tag) - maxammo; + + // Parse the assignment + + if (!DEH_ParseAssignment(line, &variable_name, &value)) + { + // Failed to parse + + DEH_Warning(context, "Failed to parse assignment"); + return; + } + + ivalue = atoi(value); + + if (!strcasecmp(variable_name, "Per ammo")) + { + // Heretic doesn't have a "per clip" ammo array, instead + // it is per weapon. However, the weapon number lines + // up with the ammo number if we add one. + + GetWeaponAmmo[ammo_number + 1] = ivalue; + } + else if (!strcasecmp(variable_name, "Max ammo")) + { + maxammo[ammo_number] = ivalue; + } + else + { + DEH_Warning(context, "Field named '%s' not found", variable_name); + } +} + +static void DEH_AmmoMD5Hash(md5_context_t *context) +{ + int i; + + for (i=0; i +#include + +#include "doomtype.h" +#include "info.h" + +#include "deh_defs.h" +#include "deh_io.h" +#include "deh_main.h" +#include "deh_mapping.h" +#include "deh_htic.h" + +DEH_BEGIN_MAPPING(state_mapping, state_t) + DEH_MAPPING("Sprite number", sprite) + DEH_MAPPING("Sprite subnumber", frame) + DEH_MAPPING("Duration", tics) + DEH_MAPPING("Next frame", nextstate) + DEH_MAPPING("Unknown 1", misc1) + DEH_MAPPING("Unknown 2", misc2) + DEH_UNSUPPORTED_MAPPING("Action pointer") +DEH_END_MAPPING + +static void *DEH_FrameStart(deh_context_t *context, char *line) +{ + int frame_number = 0; + int mapped_frame_number; + state_t *state; + + if (sscanf(line, "Frame %i", &frame_number) != 1) + { + DEH_Warning(context, "Parse error on section start"); + return NULL; + } + + // Map the HHE frame number (which assumes a Heretic 1.0 state table) + // to the internal frame number (which is is the Heretic 1.3 state table): + + mapped_frame_number = DEH_MapHereticFrameNumber(frame_number); + + if (mapped_frame_number < 0 || mapped_frame_number >= DEH_HERETIC_NUMSTATES) + { + DEH_Warning(context, "Invalid frame number: %i", frame_number); + return NULL; + } + + state = &states[mapped_frame_number]; + + return state; +} + +static void DEH_FrameParseLine(deh_context_t *context, char *line, void *tag) +{ + state_t *state; + char *variable_name, *value; + int ivalue; + + if (tag == NULL) + return; + + state = (state_t *) tag; + + // Parse the assignment + + if (!DEH_ParseAssignment(line, &variable_name, &value)) + { + // Failed to parse + + DEH_Warning(context, "Failed to parse assignment"); + return; + } + + // all values are integers + + ivalue = atoi(value); + + // "Next frame" numbers need to undergo mapping. + + if (!strcasecmp(variable_name, "Next frame")) + { + ivalue = DEH_MapHereticFrameNumber(ivalue); + } + + DEH_SetMapping(context, &state_mapping, state, variable_name, ivalue); +} + +static void DEH_FrameMD5Sum(md5_context_t *context) +{ + int i; + + for (i=0; i +#include "deh_defs.h" +#include "deh_main.h" +#include "info.h" + +char *deh_signatures[] = +{ + "Patch File for HHE v1.1", + NULL +}; + +// deh_ammo.c: +extern deh_section_t deh_section_ammo; +// deh_frame.c: +extern deh_section_t deh_section_frame; +// deh_ptr.c: +extern deh_section_t deh_section_pointer; +// deh_sound.c +extern deh_section_t deh_section_sound; +// deh_text.c: +extern deh_section_t deh_section_text; +// deh_thing.c: +extern deh_section_t deh_section_thing; +// deh_weapon.c: +extern deh_section_t deh_section_weapon; + +// +// List of section types: +// + +deh_section_t *deh_section_types[] = +{ + &deh_section_ammo, + &deh_section_frame, +// &deh_section_pointer, TODO + &deh_section_sound, +// &deh_section_text, TODO + &deh_section_thing, + &deh_section_weapon, + NULL +}; + +// HHE only worked with Heretic 1.0 and unfortunately was never updated +// to support Heretic 1.3. Between Heretic 1.0 and 1.3, two new frames +// were added to the "states" table, to extend the "flame death" +// animation displayed when the player is killed by fire. Therefore, +// we must map the HHE frame numbers (which assume a Heretic 1.0 frame +// table) to corresponding indexes for the Heretic 1.3 frame table. + +int DEH_MapHereticFrameNumber(int frame) +{ + if (frame >= S_PLAY_FDTH19) + { + frame = (frame - S_PLAY_FDTH19) + S_BLOODYSKULL1; + } + + return frame; +} + diff --git a/src/heretic/deh_htic.h b/src/heretic/deh_htic.h new file mode 100644 index 00000000..fefcf818 --- /dev/null +++ b/src/heretic/deh_htic.h @@ -0,0 +1,45 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2010 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +//----------------------------------------------------------------------------- +// +// Common header for Heretic dehacked (HHE) support. +// +//----------------------------------------------------------------------------- + +#ifndef DEH_HTIC_H +#define DEH_HTIC_H + +#include "info.h" + +// HHE doesn't know about the last two states in the state table, so +// these are considered invalid. + +#define DEH_HERETIC_NUMSTATES (NUMSTATES - 2) + +// It also doesn't know about the last two things in the mobjinfo table +// (which correspond to the states above) + +#define DEH_HERETIC_NUMMOBJTYPES (NUMMOBJTYPES - 2) + +int DEH_MapHereticFrameNumber(int frame); + +#endif /* #ifndef DEH_HTIC_H */ + diff --git a/src/heretic/deh_sound.c b/src/heretic/deh_sound.c new file mode 100644 index 00000000..d1f266dd --- /dev/null +++ b/src/heretic/deh_sound.c @@ -0,0 +1,118 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2005 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +//----------------------------------------------------------------------------- +// +// Parses "Sound" sections in dehacked files +// +//----------------------------------------------------------------------------- + +#include +#include + +#include "doomfeatures.h" +#include "doomtype.h" +#include "deh_defs.h" +#include "deh_main.h" +#include "deh_mapping.h" + +#include "doomdef.h" +#include "i_sound.h" + +#include "sounds.h" + +DEH_BEGIN_MAPPING(sound_mapping, sfxinfo_t) + DEH_MAPPING_STRING("Name", name) + DEH_UNSUPPORTED_MAPPING("Special") + DEH_MAPPING("Value", priority) + DEH_MAPPING("Unknown 1", usefulness) + DEH_UNSUPPORTED_MAPPING("Unknown 2") + DEH_UNSUPPORTED_MAPPING("Unknown 3") + DEH_MAPPING("One/Two", numchannels) +DEH_END_MAPPING + +static void *DEH_SoundStart(deh_context_t *context, char *line) +{ + int sound_number = 0; + + if (sscanf(line, "Sound %i", &sound_number) != 1) + { + DEH_Warning(context, "Parse error on section start"); + return NULL; + } + + if (sound_number < 0 || sound_number >= NUMSFX) + { + DEH_Warning(context, "Invalid sound number: %i", sound_number); + return NULL; + } + + if (sound_number >= DEH_VANILLA_NUMSFX) + { + DEH_Warning(context, "Attempt to modify SFX %i. This will cause " + "problems in Vanilla dehacked.", sound_number); + } + + return &S_sfx[sound_number]; +} + +static void DEH_SoundParseLine(deh_context_t *context, char *line, void *tag) +{ + sfxinfo_t *sfx; + char *variable_name, *value; + + if (tag == NULL) + return; + + sfx = (sfxinfo_t *) tag; + + // Parse the assignment + + if (!DEH_ParseAssignment(line, &variable_name, &value)) + { + // Failed to parse + DEH_Warning(context, "Failed to parse assignment"); + return; + } + + // Set the field value: + + if (!strcasecmp(variable_name, "Name")) + { + DEH_SetStringMapping(context, &sound_mapping, sfx, + variable_name, value); + } + else + { + DEH_SetMapping(context, &sound_mapping, sfx, + variable_name, atoi(value)); + } +} + +deh_section_t deh_section_sound = +{ + "Sound", + NULL, + DEH_SoundStart, + DEH_SoundParseLine, + NULL, + NULL, +}; + diff --git a/src/heretic/deh_thing.c b/src/heretic/deh_thing.c new file mode 100644 index 00000000..fe94f3b8 --- /dev/null +++ b/src/heretic/deh_thing.c @@ -0,0 +1,149 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2005 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +//----------------------------------------------------------------------------- +// +// Parses "Thing" sections in dehacked files +// +//----------------------------------------------------------------------------- + +#include +#include + +#include "doomtype.h" + +#include "deh_defs.h" +#include "deh_main.h" +#include "deh_mapping.h" +#include "deh_htic.h" + +#include "info.h" + +DEH_BEGIN_MAPPING(thing_mapping, mobjinfo_t) + DEH_MAPPING("ID #", doomednum) + DEH_MAPPING("Initial frame", spawnstate) + DEH_MAPPING("Hit points", spawnhealth) + DEH_MAPPING("First moving frame", seestate) + DEH_MAPPING("Alert sound", seesound) + DEH_MAPPING("Reaction time", reactiontime) + DEH_MAPPING("Attack sound", attacksound) + DEH_MAPPING("Injury frame", painstate) + DEH_MAPPING("Pain chance", painchance) + DEH_MAPPING("Pain sound", painsound) + DEH_MAPPING("Close attack frame", meleestate) + DEH_MAPPING("Far attack frame", missilestate) + DEH_MAPPING("Burning frame", crashstate) + DEH_MAPPING("Death frame", deathstate) + DEH_MAPPING("Exploding frame", xdeathstate) + DEH_MAPPING("Death sound", deathsound) + DEH_MAPPING("Speed", speed) + DEH_MAPPING("Width", radius) + DEH_MAPPING("Height", height) + DEH_MAPPING("Mass", mass) + DEH_MAPPING("Missile damage", damage) + DEH_MAPPING("Action sound", activesound) + DEH_MAPPING("Bits 1", flags) + DEH_MAPPING("Bits 2", flags2) +DEH_END_MAPPING + +static void *DEH_ThingStart(deh_context_t *context, char *line) +{ + int thing_number = 0; + mobjinfo_t *mobj; + + if (sscanf(line, "Thing %i", &thing_number) != 1) + { + DEH_Warning(context, "Parse error on section start"); + return NULL; + } + + // HHE thing numbers are indexed from 1 + --thing_number; + + if (thing_number < 0 || thing_number >= DEH_HERETIC_NUMMOBJTYPES) + { + DEH_Warning(context, "Invalid thing number: %i", thing_number); + return NULL; + } + + mobj = &mobjinfo[thing_number]; + + return mobj; +} + +static void DEH_ThingParseLine(deh_context_t *context, char *line, void *tag) +{ + mobjinfo_t *mobj; + char *variable_name, *value; + int ivalue; + + if (tag == NULL) + return; + + mobj = (mobjinfo_t *) tag; + + // Parse the assignment + + if (!DEH_ParseAssignment(line, &variable_name, &value)) + { + // Failed to parse + + DEH_Warning(context, "Failed to parse assignment"); + return; + } + + // all values are integers + + ivalue = atoi(value); + + // If the value to be set is a frame, the frame number must + // undergo transformation from a Heretic 1.0 index to a + // Heretic 1.3 index. + + if (strstr(variable_name, "frame") != NULL) + { + ivalue = DEH_MapHereticFrameNumber(ivalue); + } + + // Set the field value + + DEH_SetMapping(context, &thing_mapping, mobj, variable_name, ivalue); +} + +static void DEH_ThingMD5Sum(md5_context_t *context) +{ + int i; + + for (i=0; i +#include +#include + +#include "doomtype.h" + +#include "doomdef.h" + +#include "deh_defs.h" +#include "deh_main.h" +#include "deh_mapping.h" +#include "deh_htic.h" + +DEH_BEGIN_MAPPING(weapon_mapping, weaponinfo_t) + DEH_MAPPING("Ammo type", ammo) + DEH_MAPPING("Deselect frame", upstate) + DEH_MAPPING("Select frame", downstate) + DEH_MAPPING("Bobbing frame", readystate) + DEH_MAPPING("Shooting frame", atkstate) + DEH_MAPPING("Firing frame", holdatkstate) + DEH_MAPPING("Unknown frame", flashstate) +DEH_END_MAPPING + +static void *DEH_WeaponStart(deh_context_t *context, char *line) +{ + int weapon_number = 0; + + if (sscanf(line, "Weapon %i", &weapon_number) != 1) + { + DEH_Warning(context, "Parse error on section start"); + return NULL; + } + + if (weapon_number < 0 || weapon_number >= NUMWEAPONS * 2) + { + DEH_Warning(context, "Invalid weapon number: %i", weapon_number); + return NULL; + } + + // Because of the tome of power, we have two levels of weapons: + + if (weapon_number < NUMWEAPONS) + { + return &wpnlev1info[weapon_number]; + } + else + { + return &wpnlev2info[weapon_number - NUMWEAPONS]; + } +} + +static void DEH_WeaponParseLine(deh_context_t *context, char *line, void *tag) +{ + char *variable_name, *value; + weaponinfo_t *weapon; + int ivalue; + + if (tag == NULL) + return; + + weapon = (weaponinfo_t *) tag; + + if (!DEH_ParseAssignment(line, &variable_name, &value)) + { + // Failed to parse + + DEH_Warning(context, "Failed to parse assignment"); + return; + } + + ivalue = atoi(value); + + // If this is a frame field, we need to map from Heretic 1.0 frame + // numbers to Heretic 1.3 frame numbers. + + if (strstr(variable_name, "frame") != NULL) + { + ivalue = DEH_MapHereticFrameNumber(ivalue); + } + + DEH_SetMapping(context, &weapon_mapping, weapon, variable_name, ivalue); +} + +static void DEH_WeaponMD5Sum(md5_context_t *context) +{ + int i; + + for (i=0; i #include "doomtype.h" +#include "m_misc.h" #include "deh_defs.h" #include "deh_main.h" @@ -117,7 +118,7 @@ static void DEH_ThingParseLine(deh_context_t *context, char *line, void *tag) // undergo transformation from a Heretic 1.0 index to a // Heretic 1.3 index. - if (strstr(variable_name, "frame") != NULL) + if (M_StrCaseStr(variable_name, "frame") != NULL) { ivalue = DEH_MapHereticFrameNumber(ivalue); } diff --git a/src/heretic/deh_weapon.c b/src/heretic/deh_weapon.c index 1daae766..28a90c68 100644 --- a/src/heretic/deh_weapon.c +++ b/src/heretic/deh_weapon.c @@ -29,6 +29,7 @@ #include #include "doomtype.h" +#include "m_misc.h" #include "doomdef.h" @@ -99,7 +100,7 @@ static void DEH_WeaponParseLine(deh_context_t *context, char *line, void *tag) // If this is a frame field, we need to map from Heretic 1.0 frame // numbers to Heretic 1.3 frame numbers. - if (strstr(variable_name, "frame") != NULL) + if (M_StrCaseStr(variable_name, "frame") != NULL) { ivalue = DEH_MapHereticFrameNumber(ivalue); } diff --git a/src/m_misc.c b/src/m_misc.c index 5847f1a2..9d3144b2 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -255,3 +255,29 @@ void M_ForceUppercase(char *text) } } +// +// M_StrCaseStr +// +// Case-insensitive version of strstr() +// + +char *M_StrCaseStr(char *haystack, char *needle) +{ + unsigned int needle_len; + unsigned int len; + unsigned int i; + + needle_len = strlen(needle); + len = strlen(haystack) - needle_len; + + for (i = 0; i <= len; ++i) + { + if (!strncasecmp(haystack + i, needle, needle_len)) + { + return haystack + i; + } + } + + return NULL; +} + diff --git a/src/m_misc.h b/src/m_misc.h index c92ddde8..c6be6ccb 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -42,7 +42,7 @@ long M_FileLength(FILE *handle); boolean M_StrToInt(const char *str, int *result); void M_ExtractFileBase(char *path, char *dest); void M_ForceUppercase(char *text); - +char *M_StrCaseStr(char *haystack, char *needle); #endif -- cgit v1.2.3 From b83a1ed02c6f22ebbced208b02bb59ff94bed941 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 8 Feb 2010 19:13:34 +0000 Subject: Add HHE 1.0 header signature to list of accepted signatures. Subversion-branch: /branches/raven-branch Subversion-revision: 1862 --- src/heretic/deh_htic.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/heretic/deh_htic.c b/src/heretic/deh_htic.c index 11e73075..ca1c6d5c 100644 --- a/src/heretic/deh_htic.c +++ b/src/heretic/deh_htic.c @@ -31,6 +31,7 @@ char *deh_signatures[] = { + "Patch File for HHE v1.0", "Patch File for HHE v1.1", NULL }; -- cgit v1.2.3 From c09b386e1f3cb3518b22c440d6fb7c081ff3aa0b Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 8 Feb 2010 19:15:32 +0000 Subject: Only call InitializeSections() when a dehacked patch is actually loaded. Subversion-branch: /branches/raven-branch Subversion-revision: 1863 --- src/deh_main.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/deh_main.c b/src/deh_main.c index 3f0a6f29..75934087 100644 --- a/src/deh_main.c +++ b/src/deh_main.c @@ -39,6 +39,8 @@ extern deh_section_t *deh_section_types[]; extern char *deh_signatures[]; +static boolean deh_initialized = false; + // If true, we can do long string replacements. boolean deh_allow_long_strings = false; @@ -322,6 +324,12 @@ int DEH_LoadFile(char *filename) { deh_context_t *context; + if (!deh_initialized) + { + InitializeSections(); + deh_initialized = true; + } + printf(" loading %s\n", filename); context = DEH_OpenFile(filename); @@ -346,8 +354,6 @@ void DEH_Init(void) char *filename; int p; - InitializeSections(); - //! // @category mod // -- cgit v1.2.3 From 9769464ecf7ae3c92c628deed8164b61f567923a Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 8 Feb 2010 19:16:27 +0000 Subject: Call DEH_Init on Heretic startup so that patches will be loaded. Subversion-branch: /branches/raven-branch Subversion-revision: 1864 --- src/heretic/d_main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/heretic/d_main.c b/src/heretic/d_main.c index 10f5fd3e..ddcbca20 100644 --- a/src/heretic/d_main.c +++ b/src/heretic/d_main.c @@ -33,6 +33,7 @@ #include "config.h" #include "ct_chat.h" #include "doomdef.h" +#include "deh_main.h" #include "d_iwad.h" #include "i_endoom.h" #include "i_joystick.h" @@ -890,6 +891,11 @@ void D_DoomMain(void) printf("Z_Init: Init zone memory allocation daemon.\n"); Z_Init(); +#ifdef FEATURE_DEHACKED + printf("DEH_Init: Init Dehacked support.\n"); + DEH_Init(); +#endif + printf("W_Init: Init WADfiles.\n"); iwadfile = D_FindIWAD(IWAD_MASK_HERETIC, &gamemission); -- cgit v1.2.3 From 08e0b1471b357ae22a632d1752919d973db8983e Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 8 Feb 2010 19:18:48 +0000 Subject: Move action function prototypes in info.c into separate p_action.h header. Add table of action functions along with their location in the Heretic 1.0 executable, so that the "Action pointer" frame property can be set. Subversion-branch: /branches/raven-branch Subversion-revision: 1865 --- src/heretic/Makefile.am | 1 + src/heretic/deh_frame.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++-- src/heretic/info.c | 129 +--------------------------------- src/heretic/p_action.h | 160 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 338 insertions(+), 133 deletions(-) create mode 100644 src/heretic/p_action.h (limited to 'src') diff --git a/src/heretic/Makefile.am b/src/heretic/Makefile.am index 3fdd3ff7..081ca989 100644 --- a/src/heretic/Makefile.am +++ b/src/heretic/Makefile.am @@ -20,6 +20,7 @@ info.c info.h \ in_lude.c \ m_random.c m_random.h \ mn_menu.c \ + p_action.h \ p_ceilng.c \ p_doors.c \ p_enemy.c \ diff --git a/src/heretic/deh_frame.c b/src/heretic/deh_frame.c index 7dfb5aab..6ec62ae7 100644 --- a/src/heretic/deh_frame.c +++ b/src/heretic/deh_frame.c @@ -36,6 +36,145 @@ #include "deh_mapping.h" #include "deh_htic.h" +#include "p_action.h" + +// Offsets of action pointers within the Heretic 1.0 executable. +// (Seriously Greg, was this really necessary? What was wrong with the +// "copying action pointer from another frame" technique used in dehacked?) + +static const struct +{ + int offset; + void (*func)(); +} action_ptrs[] = { + { 0, NULL }, + { 69200, A_Look }, + { 69328, A_Chase }, + { 69872, A_FaceTarget }, + { 69984, A_Pain }, + { 70016, A_DripBlood }, + { 70160, A_KnightAttack }, + { 70304, A_ImpExplode }, + { 70480, A_BeastPuff }, + { 70592, A_ImpMeAttack }, + { 70672, A_ImpMsAttack }, + { 70880, A_ImpMsAttack2 }, + { 70976, A_ImpDeath }, + { 71024, A_ImpXDeath1 }, + { 71072, A_ImpXDeath2 }, + { 71376, A_ChicAttack }, + { 71456, A_ChicLook }, + { 71488, A_ChicChase }, + { 71520, A_ChicPain }, + { 71568, A_Feathers }, + { 71808, A_MummyAttack }, + { 71920, A_MummyAttack2 }, + { 72016, A_MummyFX1Seek }, + { 72048, A_MummySoul }, + { 72096, A_Sor1Pain }, + { 72144, A_Sor1Chase }, + { 72192, A_Srcr1Attack }, + { 72480, A_SorcererRise }, + { 72816, A_Srcr2Decide }, + { 72896, A_Srcr2Attack }, + { 73120, A_BlueSpark }, + { 73232, A_GenWizard }, + { 73392, A_Sor2DthInit }, + { 73424, A_Sor2DthLoop }, + { 73456, A_SorZap }, + { 73488, A_SorRise }, + { 73520, A_SorDSph }, + { 73552, A_SorDExp }, + { 73584, A_SorDBon }, + { 73616, A_SorSightSnd }, + { 73648, A_MinotaurAtk1 }, + { 73760, A_MinotaurDecide }, + { 74032, A_MinotaurCharge }, + { 74112, A_MinotaurAtk2 }, + { 74352, A_MinotaurAtk3 }, + { 74528, A_MntrFloorFire }, + { 74640, A_BeastAttack }, + { 74752, A_HeadAttack }, + { 75168, A_WhirlwindSeek }, + { 75328, A_HeadIceImpact }, + { 75488, A_HeadFireGrow }, + { 75632, A_SnakeAttack }, + { 75712, A_SnakeAttack2 }, + { 75792, A_ClinkAttack }, + { 75872, A_GhostOff }, + { 75888, A_WizAtk1 }, + { 75920, A_WizAtk2 }, + { 75952, A_WizAtk3 }, + { 76144, A_Scream }, + { 76400, A_NoBlocking }, + { 76784, A_Explode }, + { 76896, A_PodPain }, + { 77056, A_RemovePod }, + { 77104, A_MakePod }, + { 77344, A_BossDeath }, + { 77472, A_ESound }, + { 77520, A_SpawnTeleGlitter }, + { 77600, A_SpawnTeleGlitter2 }, + { 77680, A_AccTeleGlitter }, + { 77728, A_InitKeyGizmo }, + { 77824, A_VolcanoSet }, + { 77856, A_VolcanoBlast }, + { 78080, A_VolcBallImpact }, + { 78288, A_SkullPop }, + { 78448, A_CheckSkullFloor }, + { 78480, A_CheckSkullDone }, + { 78512, A_FreeTargMobj }, + { 78608, A_AddPlayerCorpse }, + { 78704, A_FlameSnd }, + { 78736, A_HideThing }, + { 78752, A_UnHideThing }, + { 81952, A_RestoreArtifact }, + { 82048, A_RestoreSpecialThing1 }, + { 82128, A_RestoreSpecialThing2 }, + { 108432, A_ContMobjSound }, + { 111168, A_WeaponReady }, + { 111568, A_BeakReady }, + { 111696, A_ReFire }, + { 111760, A_Lower }, + { 111856, A_BeakRaise }, + { 111920, A_Raise }, + { 112272, A_BeakAttackPL1 }, + { 112448, A_BeakAttackPL2 }, + { 112640, A_StaffAttackPL1 }, + { 112784, A_StaffAttackPL2 }, + { 112928, A_FireBlasterPL1 }, + { 113072, A_FireBlasterPL2 }, + { 113152, A_FireGoldWandPL1 }, + { 113296, A_FireGoldWandPL2 }, + { 113760, A_FireMacePL1 }, + { 113904, A_MacePL1Check }, + { 114032, A_MaceBallImpact }, + { 114192, A_MaceBallImpact2 }, + { 114624, A_FireMacePL2 }, + { 114752, A_DeathBallImpact }, + { 115088, A_SpawnRippers }, + { 115232, A_FireCrossbowPL1 }, + { 115312, A_FireCrossbowPL2 }, + { 115456, A_BoltSpark }, + { 115568, A_FireSkullRodPL1 }, + { 115648, A_FireSkullRodPL2 }, + { 115776, A_SkullRodPL2Seek }, + { 115808, A_AddPlayerRain }, + { 115984, A_SkullRodStorm }, + { 116272, A_RainImpact }, + { 116336, A_HideInCeiling }, + { 116368, A_FirePhoenixPL1 }, + { 116480, A_RemovedPhoenixFunc }, + { 116496, A_PhoenixPuff }, + { 116720, A_InitPhoenixPL2 }, + { 116736, A_FirePhoenixPL2 }, + { 117104, A_ShutdownPhoenixPL2 }, + { 117120, A_FlameEnd }, + { 117152, A_FloatPuff }, + { 117184, A_GauntletAttack }, + { 117648, A_Light0 } +}; + DEH_BEGIN_MAPPING(state_mapping, state_t) DEH_MAPPING("Sprite number", sprite) DEH_MAPPING("Sprite subnumber", frame) @@ -43,7 +182,6 @@ DEH_BEGIN_MAPPING(state_mapping, state_t) DEH_MAPPING("Next frame", nextstate) DEH_MAPPING("Unknown 1", misc1) DEH_MAPPING("Unknown 2", misc2) - DEH_UNSUPPORTED_MAPPING("Action pointer") DEH_END_MAPPING // When a HHE patch is first loaded, we must apply a small change @@ -87,6 +225,22 @@ static void *DEH_FrameStart(deh_context_t *context, char *line) return state; } +static boolean GetActionPointerForOffset(int offset, void **result) +{ + int i; + + for (i=0; iaction = func; } + else + { + // "Next frame" numbers need to undergo mapping. - DEH_SetMapping(context, &state_mapping, state, variable_name, ivalue); + if (!strcasecmp(variable_name, "Next frame")) + { + ivalue = DEH_MapHereticFrameNumber(ivalue); + } + + DEH_SetMapping(context, &state_mapping, state, variable_name, ivalue); + } } static void DEH_FrameMD5Sum(md5_context_t *context) diff --git a/src/heretic/info.c b/src/heretic/info.c index 7149220e..b6dd921f 100644 --- a/src/heretic/info.c +++ b/src/heretic/info.c @@ -22,7 +22,7 @@ // //----------------------------------------------------------------------------- #include "doomdef.h" -// generated by multigen +#include "p_action.h" char *sprnames[] = { "IMPX","ACLO","PTN1","SHLD","SHD2","BAGH","SPMP","INVS","PTN2","SOAR", @@ -41,133 +41,6 @@ char *sprnames[] = { NULL }; -void A_FreeTargMobj(); -void A_RestoreSpecialThing1(); -void A_RestoreSpecialThing2(); -void A_HideThing(); -void A_UnHideThing(); -void A_RestoreArtifact(); -void A_Scream(); -void A_Explode(); -void A_PodPain(); -void A_RemovePod(); -void A_MakePod(); -void A_InitKeyGizmo(); -void A_VolcanoSet(); -void A_VolcanoBlast(); -void A_BeastPuff(); -void A_VolcBallImpact(); -void A_SpawnTeleGlitter(); -void A_SpawnTeleGlitter2(); -void A_AccTeleGlitter(); -void A_Light0(); -void A_WeaponReady(); -void A_Lower(); -void A_Raise(); -void A_StaffAttackPL1(); -void A_ReFire(); -void A_StaffAttackPL2(); -void A_BeakReady(); -void A_BeakRaise(); -void A_BeakAttackPL1(); -void A_BeakAttackPL2(); -void A_GauntletAttack(); -void A_FireBlasterPL1(); -void A_FireBlasterPL2(); -void A_SpawnRippers(); -void A_FireMacePL1(); -void A_FireMacePL2(); -void A_MacePL1Check(); -void A_MaceBallImpact(); -void A_MaceBallImpact2(); -void A_DeathBallImpact(); -void A_FireSkullRodPL1(); -void A_FireSkullRodPL2(); -void A_SkullRodPL2Seek(); -void A_AddPlayerRain(); -void A_HideInCeiling(); -void A_SkullRodStorm(); -void A_RainImpact(); -void A_FireGoldWandPL1(); -void A_FireGoldWandPL2(); -void A_FirePhoenixPL1(); -void A_InitPhoenixPL2(); -void A_FirePhoenixPL2(); -void A_ShutdownPhoenixPL2(); -void A_PhoenixPuff(); -void A_RemovedPhoenixFunc(); -void A_FlameEnd(); -void A_FloatPuff(); -void A_FireCrossbowPL1(); -void A_FireCrossbowPL2(); -void A_BoltSpark(); -void A_Pain(); -void A_NoBlocking(); -void A_AddPlayerCorpse(); -void A_SkullPop(); -void A_FlameSnd(); -void A_CheckBurnGone(); -void A_CheckSkullFloor(); -void A_CheckSkullDone(); -void A_Feathers(); -void A_ChicLook(); -void A_ChicChase(); -void A_ChicPain(); -void A_FaceTarget(); -void A_ChicAttack(); -void A_Look(); -void A_Chase(); -void A_MummyAttack(); -void A_MummyAttack2(); -void A_MummySoul(); -void A_ContMobjSound(); -void A_MummyFX1Seek(); -void A_BeastAttack(); -void A_SnakeAttack(); -void A_SnakeAttack2(); -void A_HeadAttack(); -void A_BossDeath(); -void A_HeadIceImpact(); -void A_HeadFireGrow(); -void A_WhirlwindSeek(); -void A_ClinkAttack(); -void A_WizAtk1(); -void A_WizAtk2(); -void A_WizAtk3(); -void A_GhostOff(); -void A_ImpMeAttack(); -void A_ImpMsAttack(); -void A_ImpMsAttack2(); -void A_ImpDeath(); -void A_ImpXDeath1(); -void A_ImpXDeath2(); -void A_ImpExplode(); -void A_KnightAttack(); -void A_DripBlood(); -void A_Sor1Chase(); -void A_Sor1Pain(); -void A_Srcr1Attack(); -void A_SorZap(); -void A_SorcererRise(); -void A_SorRise(); -void A_SorSightSnd(); -void A_Srcr2Decide(); -void A_Srcr2Attack(); -void A_Sor2DthInit(); -void A_SorDSph(); -void A_Sor2DthLoop(); -void A_SorDExp(); -void A_SorDBon(); -void A_BlueSpark(); -void A_GenWizard(); -void A_MinotaurAtk1(); -void A_MinotaurDecide(); -void A_MinotaurAtk2(); -void A_MinotaurAtk3(); -void A_MinotaurCharge(); -void A_MntrFloorFire(); -void A_ESound(); - state_t states[NUMSTATES] = { {SPR_IMPX, 0, -1, NULL, S_NULL, 0, 0}, // S_NULL {SPR_ACLO, 4, 1050, A_FreeTargMobj, S_NULL, 0, 0}, // S_FREETARGMOBJ diff --git a/src/heretic/p_action.h b/src/heretic/p_action.h new file mode 100644 index 00000000..8d8e383c --- /dev/null +++ b/src/heretic/p_action.h @@ -0,0 +1,160 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 1993-2008 Raven Software +// Copyright(C) 2008 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +//----------------------------------------------------------------------------- +// +// External definitions for action pointer functions. +// +//----------------------------------------------------------------------------- + +#ifndef HERETIC_P_ACTION_H +#define HERETIC_P_ACTION_H + +void A_FreeTargMobj(); +void A_RestoreSpecialThing1(); +void A_RestoreSpecialThing2(); +void A_HideThing(); +void A_UnHideThing(); +void A_RestoreArtifact(); +void A_Scream(); +void A_Explode(); +void A_PodPain(); +void A_RemovePod(); +void A_MakePod(); +void A_InitKeyGizmo(); +void A_VolcanoSet(); +void A_VolcanoBlast(); +void A_BeastPuff(); +void A_VolcBallImpact(); +void A_SpawnTeleGlitter(); +void A_SpawnTeleGlitter2(); +void A_AccTeleGlitter(); +void A_Light0(); +void A_WeaponReady(); +void A_Lower(); +void A_Raise(); +void A_StaffAttackPL1(); +void A_ReFire(); +void A_StaffAttackPL2(); +void A_BeakReady(); +void A_BeakRaise(); +void A_BeakAttackPL1(); +void A_BeakAttackPL2(); +void A_GauntletAttack(); +void A_FireBlasterPL1(); +void A_FireBlasterPL2(); +void A_SpawnRippers(); +void A_FireMacePL1(); +void A_FireMacePL2(); +void A_MacePL1Check(); +void A_MaceBallImpact(); +void A_MaceBallImpact2(); +void A_DeathBallImpact(); +void A_FireSkullRodPL1(); +void A_FireSkullRodPL2(); +void A_SkullRodPL2Seek(); +void A_AddPlayerRain(); +void A_HideInCeiling(); +void A_SkullRodStorm(); +void A_RainImpact(); +void A_FireGoldWandPL1(); +void A_FireGoldWandPL2(); +void A_FirePhoenixPL1(); +void A_InitPhoenixPL2(); +void A_FirePhoenixPL2(); +void A_ShutdownPhoenixPL2(); +void A_PhoenixPuff(); +void A_RemovedPhoenixFunc(); +void A_FlameEnd(); +void A_FloatPuff(); +void A_FireCrossbowPL1(); +void A_FireCrossbowPL2(); +void A_BoltSpark(); +void A_Pain(); +void A_NoBlocking(); +void A_AddPlayerCorpse(); +void A_SkullPop(); +void A_FlameSnd(); +void A_CheckBurnGone(); +void A_CheckSkullFloor(); +void A_CheckSkullDone(); +void A_Feathers(); +void A_ChicLook(); +void A_ChicChase(); +void A_ChicPain(); +void A_FaceTarget(); +void A_ChicAttack(); +void A_Look(); +void A_Chase(); +void A_MummyAttack(); +void A_MummyAttack2(); +void A_MummySoul(); +void A_ContMobjSound(); +void A_MummyFX1Seek(); +void A_BeastAttack(); +void A_SnakeAttack(); +void A_SnakeAttack2(); +void A_HeadAttack(); +void A_BossDeath(); +void A_HeadIceImpact(); +void A_HeadFireGrow(); +void A_WhirlwindSeek(); +void A_ClinkAttack(); +void A_WizAtk1(); +void A_WizAtk2(); +void A_WizAtk3(); +void A_GhostOff(); +void A_ImpMeAttack(); +void A_ImpMsAttack(); +void A_ImpMsAttack2(); +void A_ImpDeath(); +void A_ImpXDeath1(); +void A_ImpXDeath2(); +void A_ImpExplode(); +void A_KnightAttack(); +void A_DripBlood(); +void A_Sor1Chase(); +void A_Sor1Pain(); +void A_Srcr1Attack(); +void A_SorZap(); +void A_SorcererRise(); +void A_SorRise(); +void A_SorSightSnd(); +void A_Srcr2Decide(); +void A_Srcr2Attack(); +void A_Sor2DthInit(); +void A_SorDSph(); +void A_Sor2DthLoop(); +void A_SorDExp(); +void A_SorDBon(); +void A_BlueSpark(); +void A_GenWizard(); +void A_MinotaurAtk1(); +void A_MinotaurDecide(); +void A_MinotaurAtk2(); +void A_MinotaurAtk3(); +void A_MinotaurCharge(); +void A_MntrFloorFire(); +void A_ESound(); + +#endif /* #ifndef HERETIC_P_ACTION_H */ + -- cgit v1.2.3 From 56412813c70ba44a6f6a74cee5bf460ca6a31402 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 8 Feb 2010 21:14:30 +0000 Subject: Add Heretic implementation of HHE "Text" section, add DEH_String() around appropriate strings to allow string replacements. Subversion-branch: /branches/raven-branch Subversion-revision: 1867 --- src/heretic/Makefile.am | 1 + src/heretic/am_map.c | 7 +- src/heretic/ct_chat.c | 11 +- src/heretic/d_main.c | 72 ++-- src/heretic/deh_htext.c | 903 ++++++++++++++++++++++++++++++++++++++++++++++++ src/heretic/deh_htic.c | 6 +- src/heretic/f_finale.c | 23 +- src/heretic/g_game.c | 13 +- src/heretic/in_lude.c | 67 ++-- src/heretic/mn_menu.c | 52 +-- src/heretic/p_spec.c | 40 +-- src/heretic/p_switch.c | 5 +- src/heretic/p_user.c | 3 +- src/heretic/r_data.c | 38 +- src/heretic/r_draw.c | 49 +-- src/heretic/r_plane.c | 3 +- src/heretic/r_things.c | 14 +- src/heretic/sb_bar.c | 120 +++---- 18 files changed, 1184 insertions(+), 243 deletions(-) create mode 100644 src/heretic/deh_htext.c (limited to 'src') diff --git a/src/heretic/Makefile.am b/src/heretic/Makefile.am index 081ca989..e56ee806 100644 --- a/src/heretic/Makefile.am +++ b/src/heretic/Makefile.am @@ -59,6 +59,7 @@ i_ibm.c FEATURE_DEHACKED_SOURCE_FILES = \ deh_ammo.c \ deh_frame.c \ +deh_htext.c \ deh_htic.c \ deh_sound.c \ deh_thing.c \ diff --git a/src/heretic/am_map.c b/src/heretic/am_map.c index 99a8e206..aae30cc9 100644 --- a/src/heretic/am_map.c +++ b/src/heretic/am_map.c @@ -27,6 +27,7 @@ #include #include "doomdef.h" +#include "deh_str.h" #include "i_video.h" #include "m_controls.h" #include "p_local.h" @@ -408,7 +409,7 @@ void AM_loadPics(void) sprintf(namebuf, "AMMNUM%d", i); marknums[i] = W_CacheLumpName(namebuf, PU_STATIC); }*/ - maplump = W_CacheLumpName("AUTOPAGE", PU_STATIC); + maplump = W_CacheLumpName(DEH_String("AUTOPAGE"), PU_STATIC); } /*void AM_unloadPics(void) @@ -1473,6 +1474,7 @@ void AM_drawCrosshair(int color) void AM_Drawer(void) { + char *level_name; int numepisodes; if (!automapactive) @@ -1505,7 +1507,8 @@ void AM_Drawer(void) if (gameepisode <= numepisodes && gamemap < 10) { - MN_DrTextA(LevelNames[(gameepisode - 1) * 9 + gamemap - 1], 20, 145); + level_name = LevelNames[(gameepisode - 1) * 9 + gamemap - 1]; + MN_DrTextA(DEH_String(level_name), 20, 145); } // I_Update(); // V_MarkRect(f_x, f_y, f_w, f_h); diff --git a/src/heretic/ct_chat.c b/src/heretic/ct_chat.c index 75fa6035..958d1fff 100644 --- a/src/heretic/ct_chat.c +++ b/src/heretic/ct_chat.c @@ -29,6 +29,7 @@ #include #include "doomdef.h" #include "doomkeys.h" +#include "deh_str.h" #include "p_local.h" #include "s_sound.h" #include "v_video.h" @@ -115,7 +116,7 @@ void CT_Init(void) memset(plr_lastmsg[i], 0, MESSAGESIZE); memset(chat_msg[i], 0, MESSAGESIZE); } - FontABaseLump = W_GetNumForName("FONTA_S") + 1; + FontABaseLump = W_GetNumForName(DEH_String("FONTA_S")) + 1; return; } @@ -300,7 +301,7 @@ void CT_Ticker(void) CT_AddChar(i, 0); // set the end of message character if (numplayers > 2) { - strcpy(plr_lastmsg[i], CT_FromPlrText[i]); + strcpy(plr_lastmsg[i], DEH_String(CT_FromPlrText[i])); strcat(plr_lastmsg[i], chat_msg[i]); } else @@ -320,13 +321,13 @@ void CT_Ticker(void) if (numplayers > 1) { P_SetMessage(&players[consoleplayer], - "-MESSAGE SENT-", true); + DEH_String("-MESSAGE SENT-"), true); S_StartSound(NULL, sfx_chat); } else { P_SetMessage(&players[consoleplayer], - "THERE ARE NO OTHER PLAYERS IN THE GAME!", + DEH_String("THERE ARE NO OTHER PLAYERS IN THE GAME!"), true); S_StartSound(NULL, sfx_chat); } @@ -376,7 +377,7 @@ void CT_Drawer(void) x += patch->width; } } - V_DrawPatch(x, 10, W_CacheLumpName("FONTA59", PU_CACHE)); + V_DrawPatch(x, 10, W_CacheLumpName(DEH_String("FONTA59"), PU_CACHE)); BorderTopRefresh = true; UpdateState |= I_MESSAGES; } diff --git a/src/heretic/d_main.c b/src/heretic/d_main.c index ddcbca20..52e4239f 100644 --- a/src/heretic/d_main.c +++ b/src/heretic/d_main.c @@ -185,12 +185,12 @@ void D_Display(void) { if (!netgame) { - V_DrawPatch(160, viewwindowy + 5, W_CacheLumpName("PAUSED", + V_DrawPatch(160, viewwindowy + 5, W_CacheLumpName(DEH_String("PAUSED"), PU_CACHE)); } else { - V_DrawPatch(160, 70, W_CacheLumpName("PAUSED", PU_CACHE)); + V_DrawPatch(160, 70, W_CacheLumpName(DEH_String("PAUSED"), PU_CACHE)); } } // Handle player messages @@ -316,7 +316,7 @@ void D_PageDrawer(void) V_DrawRawScreen(W_CacheLumpName(pagename, PU_CACHE)); if (demosequence == 1) { - V_DrawPatch(4, 160, W_CacheLumpName("ADVISOR", PU_CACHE)); + V_DrawPatch(4, 160, W_CacheLumpName(DEH_String("ADVISOR"), PU_CACHE)); } UpdateState |= I_FULLSCRN; } @@ -348,45 +348,45 @@ void D_DoAdvanceDemo(void) case 0: pagetic = 210; gamestate = GS_DEMOSCREEN; - pagename = "TITLE"; + pagename = DEH_String("TITLE"); S_StartSong(mus_titl, false); break; case 1: pagetic = 140; gamestate = GS_DEMOSCREEN; - pagename = "TITLE"; + pagename = DEH_String("TITLE"); break; case 2: BorderNeedRefresh = true; UpdateState |= I_FULLSCRN; - G_DeferedPlayDemo("demo1"); + G_DeferedPlayDemo(DEH_String("demo1")); break; case 3: pagetic = 200; gamestate = GS_DEMOSCREEN; - pagename = "CREDIT"; + pagename = DEH_String("CREDIT"); break; case 4: BorderNeedRefresh = true; UpdateState |= I_FULLSCRN; - G_DeferedPlayDemo("demo2"); + G_DeferedPlayDemo(DEH_String("demo2")); break; case 5: pagetic = 200; gamestate = GS_DEMOSCREEN; if (gamemode == shareware) { - pagename = "ORDER"; + pagename = DEH_String("ORDER"); } else { - pagename = "CREDIT"; + pagename = DEH_String("CREDIT"); } break; case 6: BorderNeedRefresh = true; UpdateState |= I_FULLSCRN; - G_DeferedPlayDemo("demo3"); + G_DeferedPlayDemo(DEH_String("demo3")); break; } } @@ -639,7 +639,7 @@ void initStartup(void) // Blit main screen textScreen = TXT_GetScreenData(); - loading = W_CacheLumpName("LOADING", PU_CACHE); + loading = W_CacheLumpName(DEH_String("LOADING"), PU_CACHE); memcpy(textScreen, loading, 4000); // Print version string @@ -699,7 +699,7 @@ void tprintf(char *msg, int initflag) // haleyjd: moved up, removed WATCOMC code void CleanExit(void) { - printf("Exited from HERETIC.\n"); + printf(DEH_String("Exited from HERETIC.\n")); exit(1); } @@ -783,7 +783,7 @@ static void D_Endoom(void) return; } - endoom_data = W_CacheLumpName("ENDTEXT", PU_STATIC); + endoom_data = W_CacheLumpName(DEH_String("ENDTEXT"), PU_STATIC); I_Endoom(endoom_data); } @@ -848,7 +848,7 @@ void D_DoomMain(void) // // init subsystems // - printf("V_Init: allocate screens.\n"); + printf(DEH_String("V_Init: allocate screens.\n")); V_Init(); // Check for -CDROM @@ -873,7 +873,7 @@ void D_DoomMain(void) if (cdrom) { - M_SetConfigDir("c:\\heretic.cd\\"); + M_SetConfigDir(DEH_String("c:\\heretic.cd")); } else { @@ -881,14 +881,14 @@ void D_DoomMain(void) } // Load defaults before initing other systems - printf("M_LoadDefaults: Load system defaults.\n"); + printf(DEH_String("M_LoadDefaults: Load system defaults.\n")); D_BindVariables(); M_SetConfigFilenames("heretic.cfg", PROGRAM_PREFIX "heretic.cfg"); M_LoadDefaults(); I_AtExit(M_SaveDefaults, false); - printf("Z_Init: Init zone memory allocation daemon.\n"); + printf(DEH_String("Z_Init: Init zone memory allocation daemon.\n")); Z_Init(); #ifdef FEATURE_DEHACKED @@ -896,7 +896,7 @@ void D_DoomMain(void) DEH_Init(); #endif - printf("W_Init: Init WADfiles.\n"); + printf(DEH_String("W_Init: Init WADfiles.\n")); iwadfile = D_FindIWAD(IWAD_MASK_HERETIC, &gamemission); @@ -933,12 +933,12 @@ void D_DoomMain(void) } if (p && p < myargc - 1) { - sprintf(file, "%s.lmp", myargv[p + 1]); + sprintf(file, DEH_String("%s.lmp"), myargv[p + 1]); D_AddFile(file); - printf("Playing demo %s.lmp.\n", myargv[p + 1]); + printf(DEH_String("Playing demo %s.lmp.\n"), myargv[p + 1]); } - if (W_CheckNumForName("E2M1") == -1) + if (W_CheckNumForName(DEH_String("E2M1")) == -1) { gamemode = shareware; gamedescription = "Heretic (shareware)"; @@ -966,54 +966,54 @@ void D_DoomMain(void) // smsg[0] = 0; if (deathmatch) - status("DeathMatch..."); + status(DEH_String("DeathMatch...")); if (nomonsters) - status("No Monsters..."); + status(DEH_String("No Monsters...")); if (respawnparm) - status("Respawning..."); + status(DEH_String("Respawning...")); if (autostart) { char temp[64]; - sprintf(temp, "Warp to Episode %d, Map %d, Skill %d ", + sprintf(temp, DEH_String("Warp to Episode %d, Map %d, Skill %d "), startepisode, startmap, startskill + 1); status(temp); } wadprintf(); // print the added wadfiles - tprintf("MN_Init: Init menu system.\n", 1); + tprintf(DEH_String("MN_Init: Init menu system.\n"), 1); MN_Init(); CT_Init(); - tprintf("R_Init: Init Heretic refresh daemon.", 1); - hprintf("Loading graphics"); + tprintf(DEH_String("R_Init: Init Heretic refresh daemon."), 1); + hprintf(DEH_String("Loading graphics")); R_Init(); tprintf("\n", 0); - tprintf("P_Init: Init Playloop state.\n", 1); - hprintf("Init game engine."); + tprintf(DEH_String("P_Init: Init Playloop state.\n"), 1); + hprintf(DEH_String("Init game engine.")); P_Init(); IncThermo(); - tprintf("I_Init: Setting up machine state.\n", 1); + tprintf(DEH_String("I_Init: Setting up machine state.\n"), 1); I_CheckIsScreensaver(); I_InitTimer(); I_InitJoystick(); IncThermo(); - tprintf("S_Init: Setting up sound.\n", 1); + tprintf(DEH_String("S_Init: Setting up sound.\n"), 1); S_Init(); //IO_StartupTimer(); S_Start(); - tprintf("D_CheckNetGame: Checking network game status.\n", 1); - hprintf("Checking network game status."); + tprintf(DEH_String("D_CheckNetGame: Checking network game status.\n"), 1); + hprintf(DEH_String("Checking network game status.")); D_CheckNetGame(); IncThermo(); // haleyjd: removed WATCOMC - tprintf("SB_Init: Loading patches.\n", 1); + tprintf(DEH_String("SB_Init: Loading patches.\n"), 1); SB_Init(); IncThermo(); diff --git a/src/heretic/deh_htext.c b/src/heretic/deh_htext.c new file mode 100644 index 00000000..9075e610 --- /dev/null +++ b/src/heretic/deh_htext.c @@ -0,0 +1,903 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2005-2010 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +//----------------------------------------------------------------------------- +// +// Parses Text substitution sections in dehacked files +// +//----------------------------------------------------------------------------- + +#include +#include + +#include "doomtype.h" +#include "dstrings.h" + +#include "z_zone.h" + +#include "deh_defs.h" +#include "deh_io.h" +#include "deh_main.h" + +// +// Ok, Greg, the action pointers thing was bad enough, but this really +// takes the biscuit. Why does HHE's text replacement address strings +// by offset??!! The dehacked way was much nicer, why change it? +// +// Anyway, this is the Heretic 1.0 string table, which can be seen in +// HHE. This is the string and its offset from the start of the +// text section. Not all the strings are here; this is a redacted list +// that contains just the strings we support. +// + +static const struct +{ + unsigned int offset; + char *string; +} +string_table[] = +{ + { 0, NULL }, + { 4, NULL }, + { 64, NULL }, + { 104, NULL }, + { 160, NULL }, + { 200, NULL }, + { 220, NULL }, + { 228, "PLAYPAL" }, + { 236, NULL }, + { 244, NULL }, + { 252, NULL }, + { 272, NULL }, + { 288, NULL }, + { 296, NULL }, + { 316, NULL }, + { 332, NULL }, + { 372, NULL }, + { 436, NULL }, + { 504, NULL }, + { 536, NULL }, + { 544, NULL }, + { 560, NULL }, + { 576, NULL }, + { 584, "ENDTEXT" }, + { 592, NULL }, + { 612, NULL }, + { 640, NULL }, + { 664, NULL }, + { 712, NULL }, + { 744, NULL }, + { 764, NULL }, + { 808, NULL }, + { 820, NULL }, + { 828, NULL }, + { 840, NULL }, + { 876, NULL }, + { 884, NULL }, + { 908, NULL }, + { 952, NULL }, + { 992, NULL }, + { 1028, NULL }, + { 1036, NULL }, + { 1048, NULL }, + { 1088, NULL }, + { 1128, NULL }, + { 1160, NULL }, + { 1192, NULL }, + { 1212, NULL }, + { 1240, "E1M1: THE DOCKS" }, + { 1260, "E1M2: THE DUNGEONS" }, + { 1280, "E1M3: THE GATEHOUSE" }, + { 1304, "E1M4: THE GUARD TOWER" }, + { 1328, "E1M5: THE CITADEL" }, + { 1348, "E1M6: THE CATHEDRAL" }, + { 1372, "E1M7: THE CRYPTS" }, + { 1392, "E1M8: HELL'S MAW" }, + { 1412, "E1M9: THE GRAVEYARD" }, + { 1436, "E2M1: THE CRATER" }, + { 1456, "E2M2: THE LAVA PITS" }, + { 1480, "E2M3: THE RIVER OF FIRE" }, + { 1508, "E2M4: THE ICE GROTTO" }, + { 1532, "E2M5: THE CATACOMBS" }, + { 1556, "E2M6: THE LABYRINTH" }, + { 1580, "E2M7: THE GREAT HALL" }, + { 1604, "E2M8: THE PORTALS OF CHAOS" }, + { 1632, "E2M9: THE GLACIER" }, + { 1652, "E3M1: THE STOREHOUSE" }, + { 1676, "E3M2: THE CESSPOOL" }, + { 1696, "E3M3: THE CONFLUENCE" }, + { 1720, "E3M4: THE AZURE FORTRESS" }, + { 1748, "E3M5: THE OPHIDIAN LAIR" }, + { 1776, "E3M6: THE HALLS OF FEAR" }, + { 1804, "E3M7: THE CHASM" }, + { 1824, "E3M8: D'SPARIL'S KEEP" }, + { 1848, "E3M9: THE AQUIFER" }, + { 1868, "AUTOPAGE" }, + { 1880, "FOLLOW MODE ON" }, + { 1896, "FOLLOW MODE OFF" }, + { 1912, "GREEN: " }, + { 1936, "YELLOW: " }, + { 1948, "RED: " }, + { 1956, "BLUE: " }, + { 1964, "FONTA_S" }, + { 1972, "-MESSAGE SENT-" }, + { 1988, "THERE ARE NO OTHER PLAYERS IN THE GAME!" }, + { 2028, "FONTA59" }, + { 2036, "PAUSED" }, + { 2044, NULL }, + { 2056, NULL }, + { 2072, "ADVISOR" }, + { 2080, "TITLE" }, + { 2088, "demo1" }, + { 2096, "CREDIT" }, + { 2104, "demo2" }, + { 2112, "ORDER" }, + { 2120, "demo3" }, + { 2128, NULL }, + { 2140, NULL }, + { 2168, "hticsav%c.hsg" }, + { 2184, "heretic.wad" }, + { 2196, NULL }, + { 2212, NULL }, + { 2228, NULL }, + { 2240, "heretic.cfg" }, + { 2252, NULL }, + { 2264, NULL }, + { 2284, NULL }, + { 2304, "Exited from HERETIC.\n" }, + { 2328, NULL }, + { 2340, NULL }, + { 2352, NULL }, + { 2364, NULL }, + { 2372, NULL }, + { 2388, NULL }, + { 2404, NULL }, + { 2412, "c:\\heretic.cd" }, + { 2428, NULL }, + { 2436, NULL }, + { 2444, NULL }, + { 2464, NULL }, + { 2496, NULL }, + { 2508, NULL }, + { 2520, NULL }, + { 2528, "Playing demo %s.lmp.\n" }, + { 2552, NULL }, + { 2564, NULL }, + { 2572, NULL }, + { 2584, NULL }, + { 2592, "V_Init: allocate screens.\n" }, + { 2620, "M_LoadDefaults: Load system defaults.\n" }, + { 2660, "Z_Init: Init zone memory allocation daemon.\n" }, + { 2708, "W_Init: Init WADfiles.\n" }, + { 2732, "E2M1" }, + { 2740, "LOADING" }, + { 2748, "DeathMatch..." }, + { 2764, "No Monsters..." }, + { 2780, "Respawning..." }, + { 2796, "Warp to Episode %d, Map %d, Skill %d " }, + { 2836, "MN_Init: Init menu system.\n" }, + { 2864, "R_Init: Init Heretic refresh daemon." }, + { 2904, "Loading graphics" }, + { 2924, "P_Init: Init Playloop state." }, + { 2956, "Init game engine." }, + { 2976, "I_Init: Setting up machine state.\n" }, + { 3012, "D_CheckNetGame: Checking network game status.\n" }, + { 3060, "Checking network game status." }, + { 3092, "SB_Init: Loading patches.\n" }, + { 3120, NULL }, + { 3128, NULL }, + { 3140, NULL }, + { 3184, NULL }, + { 3220, NULL }, + { 3256, NULL }, + { 3280, NULL }, + { 3304, NULL }, + { 3320, NULL }, + { 3352, "PLAYER 1 HAS LEFT THE GAME" }, + { 3380, NULL }, + { 3432, NULL }, + { 3464, NULL }, + { 3508, NULL }, + { 3548, NULL }, + { 3600, NULL }, + { 3624, NULL }, + { 3664, NULL }, + { 3696, NULL }, + { 3736, "NET GAME" }, + { 3748, "SAVE GAME" }, + { 3760, "Only %i deathmatch spots, 4 required" }, + { 3800, "version %i" }, + { 3812, NULL }, + { 3828, NULL }, + { 3856, NULL }, + { 3872, NULL }, + { 3896, "GAME SAVED" }, + { 3908, "SKY1" }, + { 3916, "SKY2" }, + { 3924, "SKY3" }, + { 3932, NULL }, + { 3940, NULL }, + { 3976, NULL }, + { 3996, NULL }, + { 4016, E1TEXT }, + { 4536, E2TEXT }, + { 5068, E3TEXT }, + { 5632, "FLOOR25" }, + { 5640, "FLATHUH1" }, + { 5652, "FLTWAWA2" }, + { 5664, "FONTA_S" }, + { 5672, "FINAL1" }, + { 5680, "FINAL2" }, + { 5688, "E2PAL" }, + { 5696, "E2END" }, + { 5704, "PLAYPAL" }, + { 5712, "ORDER" }, + { 5720, "IMPX" }, + { 5728, "ACLO" }, + { 5736, "PTN1" }, + { 5744, "SHLD" }, + { 5752, "SHD2" }, + { 5760, "BAGH" }, + { 5768, "SPMP" }, + { 5776, "INVS" }, + { 5784, "PTN2" }, + { 5792, "SOAR" }, + { 5800, "INVU" }, + { 5808, "PWBK" }, + { 5816, "EGGC" }, + { 5824, "EGGM" }, + { 5832, "FX01" }, + { 5840, "SPHL" }, + { 5848, "TRCH" }, + { 5856, "FBMB" }, + { 5864, "XPL1" }, + { 5872, "ATLP" }, + { 5880, "PPOD" }, + { 5888, "AMG1" }, + { 5896, "SPSH" }, + { 5904, "LVAS" }, + { 5912, "SLDG" }, + { 5920, "SKH1" }, + { 5928, "SKH2" }, + { 5936, "SKH3" }, + { 5944, "SKH4" }, + { 5952, "CHDL" }, + { 5960, "SRTC" }, + { 5968, "SMPL" }, + { 5976, "STGS" }, + { 5984, "STGL" }, + { 5992, "STCS" }, + { 6000, "STCL" }, + { 6008, "KFR1" }, + { 6016, "BARL" }, + { 6024, "BRPL" }, + { 6032, "MOS1" }, + { 6040, "MOS2" }, + { 6048, "WTRH" }, + { 6056, "HCOR" }, + { 6064, "KGZ1" }, + { 6072, "KGZB" }, + { 6080, "KGZG" }, + { 6088, "KGZY" }, + { 6096, "VLCO" }, + { 6104, "VFBL" }, + { 6112, "VTFB" }, + { 6120, "SFFI" }, + { 6128, "TGLT" }, + { 6136, "TELE" }, + { 6144, "STFF" }, + { 6152, "PUF3" }, + { 6160, "PUF4" }, + { 6168, "BEAK" }, + { 6176, "WGNT" }, + { 6184, "GAUN" }, + { 6192, "PUF1" }, + { 6200, "WBLS" }, + { 6208, "BLSR" }, + { 6216, "FX18" }, + { 6224, "FX17" }, + { 6232, "WMCE" }, + { 6240, "MACE" }, + { 6248, "FX02" }, + { 6256, "WSKL" }, + { 6264, "HROD" }, + { 6272, "FX00" }, + { 6280, "FX20" }, + { 6288, "FX21" }, + { 6296, "FX22" }, + { 6304, "FX23" }, + { 6312, "GWND" }, + { 6320, "PUF2" }, + { 6328, "WPHX" }, + { 6336, "PHNX" }, + { 6344, "FX04" }, + { 6352, "FX08" }, + { 6360, "FX09" }, + { 6368, "WBOW" }, + { 6376, "CRBW" }, + { 6384, "FX03" }, + { 6392, "BLOD" }, + { 6400, "PLAY" }, + { 6408, "FDTH" }, + { 6416, "BSKL" }, + { 6424, "CHKN" }, + { 6432, "MUMM" }, + { 6440, "FX15" }, + { 6448, "BEAS" }, + { 6456, "FRB1" }, + { 6464, "SNKE" }, + { 6472, "SNFX" }, + { 6480, "HEAD" }, + { 6488, "FX05" }, + { 6496, "FX06" }, + { 6504, "FX07" }, + { 6512, "CLNK" }, + { 6520, "WZRD" }, + { 6528, "FX11" }, + { 6536, "FX10" }, + { 6544, "KNIG" }, + { 6552, "SPAX" }, + { 6560, "RAXE" }, + { 6568, "SRCR" }, + { 6576, "FX14" }, + { 6584, "SOR2" }, + { 6592, "SDTH" }, + { 6600, "FX16" }, + { 6608, "MNTR" }, + { 6616, "FX12" }, + { 6624, "FX13" }, + { 6632, "AKYY" }, + { 6640, "BKYY" }, + { 6648, "CKYY" }, + { 6656, "AMG2" }, + { 6664, "AMM1" }, + { 6672, "AMM2" }, + { 6680, "AMC1" }, + { 6688, "AMC2" }, + { 6696, "AMS1" }, + { 6704, "AMS2" }, + { 6712, "AMP1" }, + { 6720, "AMP2" }, + { 6728, "AMB1" }, + { 6736, "AMB2" }, + { 6768, "PLAYPAL" }, + { 6776, "MAPE1" }, + { 6784, "MAPE2" }, + { 6792, "MAPE3" }, + { 6800, "IN_X" }, + { 6808, "IN_YAH" }, + { 6816, "FONTB16" }, + { 6824, "FONTB_S" }, + { 6832, "FONTB13" }, + { 6840, "FONTB15" }, + { 6848, "FONTB05" }, + { 6856, "FACEA0" }, + { 6864, "FACEB0" }, + { 6872, NULL }, + { 6896, NULL }, + { 6940, "FLOOR16" }, + { 6948, "FINISHED" }, + { 6960, "NOW ENTERING:" }, + { 6976, "KILLS" }, + { 6984, "ITEMS" }, + { 6992, "SECRETS" }, + { 7000, "TIME" }, + { 7008, "BONUS" }, + { 7016, "SECRET" }, + { 7024, "TOTAL" }, + { 7032, "VICTIMS" }, + { 7044, "NEW GAME" }, + { 7056, "OPTIONS" }, + { 7064, "GAME FILES" }, + { 7076, "INFO" }, + { 7084, "QUIT GAME" }, + { 7096, "CITY OF THE DAMNED" }, + { 7116, "HELL'S MAW" }, + { 7128, "THE DOME OF D'SPARIL" }, + { 7152, "LOAD GAME" }, + { 7164, "SAVE GAME" }, + { 7176, "THOU NEEDETH A WET-NURSE" }, + { 7204, "YELLOWBELLIES-R-US" }, + { 7224, "BRINGEST THEM ONETH" }, + { 7244, "THOU ART A SMITE-MEISTER" }, + { 7272, "BLACK PLAGUE POSSESSES THEE" }, + { 7300, "END GAME" }, + { 7312, "MESSAGES : " }, + { 7324, "MOUSE SENSITIVITY" }, + { 7344, "MORE..." }, + { 7352, "SCREEN SIZE" }, + { 7364, "SFX VOLUME" }, + { 7376, "MUSIC VOLUME" }, + { 7392, "M_SKL00" }, + { 7400, "FONTA_S" }, + { 7408, "FONTB_S" }, + { 7416, "ARE YOU SURE YOU WANT TO QUIT?" }, + { 7448, "ARE YOU SURE YOU WANT TO END THE GAME?" }, + { 7488, "DO YOU WANT TO QUICKSAVE THE GAME NAMED" }, + { 7528, "DO YOU WANT TO QUICKLOAD THE GAME NAMED" }, + { 7572, "M_SLCTR1" }, + { 7584, "M_SLCTR2" }, + { 7596, "M_HTIC" }, + { 7604, NULL }, + { 7632, "hticsav%d.hsg" }, + { 7652, "M_FSLOT" }, + { 7668, "MESSAGES ON" }, + { 7680, "MESSAGES OFF" }, + { 7696, "YOU CAN'T START A NEW GAME FROM WITHIN A NETGAME!" }, + { 7748, "ONLY AVAILABLE IN THE REGISTERED VERSION" }, + { 7792, "PLAYPAL" }, + { 7800, "QUICKSAVING...." }, + { 7816, "QUICKLOADING...." }, + { 7836, "CHOOSE A QUICKSAVE SLOT" }, + { 7860, "CHOOSE A QUICKLOAD SLOT" }, + { 7884, "TITLE" }, + { 7892, "M_SLDLT" }, + { 7900, "M_SLDMD1" }, + { 7912, "M_SLDMD2" }, + { 7924, "M_SLDRT" }, + { 7932, "M_SLDKB" }, + { 7940, NULL }, + { 7968, NULL }, + { 7992, NULL }, + { 8020, NULL }, + { 8028, NULL }, + { 8056, NULL }, + { 8076, NULL }, + { 8088, NULL }, + { 8104, NULL }, + { 8116, NULL }, + { 8128, NULL }, + { 8136, NULL }, + { 8148, NULL }, + { 8164, NULL }, + { 8180, NULL }, + { 8192, NULL }, + { 8204, NULL }, + { 8220, NULL }, + { 8232, NULL }, + { 8248, NULL }, + { 8264, NULL }, + { 8276, NULL }, + { 8292, NULL }, + { 8308, NULL }, + { 8320, NULL }, + { 8328, NULL }, + { 8340, NULL }, + { 8352, NULL }, + { 8364, NULL }, + { 8376, NULL }, + { 8392, NULL }, + { 8408, NULL }, + { 8424, NULL }, + { 8436, NULL }, + { 8448, NULL }, + { 8460, NULL }, + { 8472, NULL }, + { 8488, NULL }, + { 8504, NULL }, + { 8520, NULL }, + { 8536, NULL }, + { 8548, NULL }, + { 8560, NULL }, + { 8572, NULL }, + { 8584, NULL }, + { 8596, NULL }, + { 8612, NULL }, + { 8624, NULL }, + { 8648, NULL }, + { 8660, NULL }, + { 8668, NULL }, + { 8680, NULL }, + { 8708, NULL }, + { 8720, NULL }, + { 8728, NULL }, + { 8740, NULL }, + { 8752, NULL }, + { 8764, NULL }, + { 8788, NULL }, + { 8800, NULL }, + { 8812, NULL }, + { 8824, NULL }, + { 8848, NULL }, + { 8880, NULL }, + { 8888, NULL }, + { 8896, NULL }, + { 8916, NULL }, + { 8968, "HRTIC00.pcx" }, + { 8980, NULL }, + { 9016, "SCREEN SHOT" }, + { 9028, "YOU NEED A BLUE KEY TO OPEN THIS DOOR" }, + { 9068, "YOU NEED A YELLOW KEY TO OPEN THIS DOOR" }, + { 9108, "YOU NEED A GREEN KEY TO OPEN THIS DOOR" }, + { 9148, NULL }, + { 9172, NULL }, + { 9220, NULL }, + { 9244, "CRYSTAL VIAL" }, + { 9260, "SILVER SHIELD" }, + { 9276, "ENCHANTED SHIELD" }, + { 9296, "BAG OF HOLDING" }, + { 9312, "MAP SCROLL" }, + { 9324, "BLUE KEY" }, + { 9336, "YELLOW KEY" }, + { 9348, "GREEN KEY" }, + { 9360, "QUARTZ FLASK" }, + { 9376, "WINGS OF WRATH" }, + { 9392, "RING OF INVINCIBILITY" }, + { 9416, "TOME OF POWER" }, + { 9432, "SHADOWSPHERE" }, + { 9448, "MORPH OVUM" }, + { 9460, "MYSTIC URN" }, + { 9472, "TORCH" }, + { 9480, "TIME BOMB OF THE ANCIENTS" }, + { 9508, "CHAOS DEVICE" }, + { 9524, "WAND CRYSTAL" }, + { 9540, "CRYSTAL GEODE" }, + { 9556, "MACE SPHERES" }, + { 9572, "PILE OF MACE SPHERES" }, + { 9596, "ETHEREAL ARROWS" }, + { 9612, "QUIVER OF ETHEREAL ARROWS" }, + { 9640, "CLAW ORB" }, + { 9652, "ENERGY ORB" }, + { 9664, "LESSER RUNES" }, + { 9680, "GREATER RUNES" }, + { 9696, "FLAME ORB" }, + { 9708, "INFERNO ORB" }, + { 9720, "FIREMACE" }, + { 9732, "ETHEREAL CROSSBOW" }, + { 9752, "DRAGON CLAW" }, + { 9764, "HELLSTAFF" }, + { 9776, "PHOENIX ROD" }, + { 9788, "GAUNTLETS OF THE NECROMANCER" }, + { 9820, NULL }, + { 9860, NULL }, + { 9892, NULL }, + { 9940, NULL }, + { 9972, NULL }, + { 10012, NULL }, + { 10052, NULL }, + { 10080, NULL }, + { 10088, "FLTWAWA1" }, + { 10100, "FLTFLWW1" }, + { 10112, "FLTLAVA1" }, + { 10124, "FLATHUH1" }, + { 10136, "FLTSLUD1" }, + { 10152, NULL }, + { 10192, NULL }, + { 10236, NULL }, + { 10248, NULL }, + { 10284, NULL }, + { 10320, NULL }, + { 10360, NULL }, + { 10392, NULL }, + { 10444, "PLAYPAL" }, + { 10452, NULL }, + { 10488, NULL }, + { 10508, NULL }, + { 10556, NULL }, + { 10596, "PNAMES" }, + { 10604, "TEXTURE1" }, + { 10616, "TEXTURE2" }, + { 10628, "S_END" }, + { 10636, "S_START" }, + { 10644, NULL }, + { 10684, NULL }, + { 10728, "F_START" }, + { 10736, "F_END" }, + { 10744, "COLORMAP" }, + { 10756, "\nR_InitTextures " }, + { 10776, "R_InitFlats\n" }, + { 10792, "R_InitSpriteLumps " }, + { 10812, NULL }, + { 10844, NULL }, + { 10880, NULL }, + { 10912, NULL }, + { 10948, "TINTTAB" }, + { 10956, NULL }, + { 10984, "FLOOR04" }, + { 10992, "FLAT513" }, + { 11000, "bordt" }, + { 11008, "bordb" }, + { 11016, "bordl" }, + { 11024, "bordr" }, + { 11032, "bordtl" }, + { 11040, "bordtr" }, + { 11048, "bordbr" }, + { 11056, "bordbl" }, + { 11064, "R_InitData " }, + { 11076, "R_InitPointToAngle\n" }, + { 11096, "R_InitTables " }, + { 11112, "R_InitPlanes\n" }, + { 11128, "R_InitLightTables " }, + { 11148, "R_InitSkyMap\n" }, + { 11164, "F_SKY1" }, + { 11172, NULL }, + { 11200, NULL }, + { 11232, NULL }, + { 11272, NULL }, + { 11312, NULL }, + { 11348, NULL }, + { 11380, NULL }, + { 11404, NULL }, + { 11436, NULL }, + { 11492, NULL }, + { 11548, NULL }, + { 11616, NULL }, + { 11684, NULL }, + { 11748, NULL }, + { 11792, NULL }, + { 11840, NULL }, + { 11896, NULL }, + { 11936, NULL }, + { 11980, NULL }, + { 12028, NULL }, + { 12072, NULL }, + { 12120, "LTFACE" }, + { 12128, "RTFACE" }, + { 12136, "BARBACK" }, + { 12144, "INVBAR" }, + { 12152, "CHAIN" }, + { 12160, "STATBAR" }, + { 12168, "LIFEBAR" }, + { 12176, "LIFEGEM2" }, + { 12188, "LIFEGEM0" }, + { 12200, "LTFCTOP" }, + { 12208, "RTFCTOP" }, + { 12216, "ARTIBOX" }, + { 12224, "SELECTBOX" }, + { 12236, "INVGEML1" }, + { 12248, "INVGEML2" }, + { 12260, "INVGEMR1" }, + { 12272, "INVGEMR2" }, + { 12284, "BLACKSQ" }, + { 12292, "ARMCLEAR" }, + { 12304, "CHAINBACK" }, + { 12320, "NEGNUM" }, + { 12328, "FONTB16" }, + { 12336, "SMALLIN0" }, + { 12348, "PLAYPAL" }, + { 12356, "SPINBK0" }, + { 12364, "SPFLY0" }, + { 12372, "LAME" }, + { 12408, "NAME" }, + { 12416, "MO.T" }, + { 12424, "MO.X" }, + { 12432, "MO.Y" }, + { 12448, "DIST" }, + { 12456, "------" }, + { 12472, "GOD1" }, + { 12480, "GOD2" }, + { 12488, "useartia" }, + { 12500, "ykeyicon" }, + { 12512, "gkeyicon" }, + { 12524, "bkeyicon" }, + { 12536, "GOD MODE ON" }, + { 12548, "GOD MODE OFF" }, + { 12564, "NO CLIPPING ON" }, + { 12580, "NO CLIPPING OFF" }, + { 12596, "ALL WEAPONS" }, + { 12608, "POWER OFF" }, + { 12620, "POWER ON" }, + { 12632, "FULL HEALTH" }, + { 12644, "ALL KEYS" }, + { 12656, "SOUND DEBUG ON" }, + { 12672, "SOUND DEBUG OFF" }, + { 12688, "TICKER ON" }, + { 12700, "TICKER OFF" }, + { 12712, "CHOOSE AN ARTIFACT ( A - J )" }, + { 12744, "HOW MANY ( 1 - 9 )" }, + { 12764, "YOU GOT IT" }, + { 12776, "BAD INPUT" }, + { 12788, "LEVEL WARP" }, + { 12800, "CHICKEN OFF" }, + { 12812, "CHICKEN ON" }, + { 12824, "MASSACRE" }, + { 12836, "CHEATER - YOU DON'T DESERVE WEAPONS" }, + { 12872, "TRYING TO CHEAT, EH? NOW YOU DIE!" }, + { 12908, "Bad V_DrawPatch" }, + { 12924, NULL }, + { 12960, NULL }, + { 12968, NULL }, + { 12976, NULL }, + { 13020, NULL }, + { 13048, NULL }, + { 13076, NULL }, + { 13104, NULL }, + { 13136, NULL }, + { 13168, NULL }, + { 13196, NULL }, + { 13240, NULL }, + { 13272, NULL }, + { 13296, NULL }, + { 13312, NULL }, + { 13324, NULL }, + { 13364, NULL }, + { 13408, NULL }, + { 13460, NULL }, + { 13492, NULL }, + { 13516, NULL }, + { 13560, NULL }, + { 13612, NULL }, + { 13664, NULL }, + { 13700, NULL }, + { 13744, NULL }, + { 13796, NULL }, + { 13848, NULL }, + { 13884, NULL }, + { 13940, NULL }, + { 13996, NULL }, + { 14040, NULL }, + { 14084, NULL }, + { 14140, NULL }, + { 14148, NULL }, + { 14164, NULL }, + { 14184, NULL }, + { 14192, NULL }, + { 14212, NULL }, + { 14256, NULL }, + { 14272, NULL }, + { 14284, NULL }, + { 14300, NULL }, + { 14312, NULL }, + { 14324, NULL }, + { 14348, NULL }, + { 14360, NULL }, + { 14372, NULL }, + { 14380, NULL }, + { 14392, NULL }, + { 14432, NULL }, + { 14444, NULL }, + { 14472, NULL }, + { 14496, NULL }, + { 14516, NULL }, + { 14536, NULL }, + { 14548, NULL }, + { 14560, NULL }, + { 14572, NULL }, + { 14580, NULL }, + { 14588, NULL }, + { 14596, NULL }, + { 14604, NULL }, + { 14612, NULL }, + { 14620, NULL }, + { 14636, NULL }, + { 14660, NULL }, + { 14704, NULL }, + { 14748, NULL }, + { 14760, NULL }, + { 14768, NULL }, +}; + +static boolean GetStringByOffset(unsigned int offset, char **result) +{ + int i; + + for (i=0; i MaxStringLength(strlen(orig_text))) + { + DEH_Error(context, "Replacement string is longer than the maximum " + "possible in heretic.exe"); + } + else + { + // Success. + + DEH_AddStringReplacement(orig_text, repl_text); + + return NULL; + } + + // Failure. + + Z_Free(repl_text); + + return NULL; +} + +static void DEH_TextParseLine(deh_context_t *context, char *line, void *tag) +{ + // not used +} + +deh_section_t deh_section_heretic_text = +{ + "Text", + NULL, + DEH_TextStart, + DEH_TextParseLine, + NULL, + NULL, +}; + diff --git a/src/heretic/deh_htic.c b/src/heretic/deh_htic.c index ca1c6d5c..59c426ef 100644 --- a/src/heretic/deh_htic.c +++ b/src/heretic/deh_htic.c @@ -44,8 +44,8 @@ extern deh_section_t deh_section_frame; extern deh_section_t deh_section_pointer; // deh_sound.c extern deh_section_t deh_section_sound; -// deh_text.c: -extern deh_section_t deh_section_text; +// deh_htext.c: +extern deh_section_t deh_section_heretic_text; // deh_thing.c: extern deh_section_t deh_section_thing; // deh_weapon.c: @@ -61,7 +61,7 @@ deh_section_t *deh_section_types[] = &deh_section_frame, // &deh_section_pointer, TODO &deh_section_sound, -// &deh_section_text, TODO + &deh_section_heretic_text, &deh_section_thing, &deh_section_weapon, NULL diff --git a/src/heretic/f_finale.c b/src/heretic/f_finale.c index 03806214..27b33e96 100644 --- a/src/heretic/f_finale.c +++ b/src/heretic/f_finale.c @@ -26,6 +26,7 @@ #include #include "doomdef.h" +#include "deh_str.h" #include "i_swap.h" #include "i_video.h" #include "s_sound.h" @@ -72,30 +73,30 @@ void F_StartFinale(void) switch (gameepisode) { case 1: - finaleflat = "FLOOR25"; + finaleflat = DEH_String("FLOOR25"); finaletext = e1text; break; case 2: - finaleflat = "FLATHUH1"; + finaleflat = DEH_String("FLATHUH1"); finaletext = e2text; break; case 3: - finaleflat = "FLTWAWA2"; + finaleflat = DEH_String("FLTWAWA2"); finaletext = e3text; break; case 4: - finaleflat = "FLOOR28"; + finaleflat = DEH_String("FLOOR28"); finaletext = e4text; break; case 5: - finaleflat = "FLOOR08"; + finaleflat = DEH_String("FLOOR08"); finaletext = e5text; break; } finalestage = 0; finalecount = 0; - FontABaseLump = W_GetNumForName("FONTA_S") + 1; + FontABaseLump = W_GetNumForName(DEH_String("FONTA_S")) + 1; // S_ChangeMusic(mus_victor, true); S_StartSong(mus_cptd, true); @@ -277,8 +278,8 @@ void F_DemonScroll(void) { return; } - p1 = W_CacheLumpName("FINAL1", PU_LEVEL); - p2 = W_CacheLumpName("FINAL2", PU_LEVEL); + p1 = W_CacheLumpName(DEH_String("FINAL1"), PU_LEVEL); + p2 = W_CacheLumpName(DEH_String("FINAL2"), PU_LEVEL); if (finalecount < 70) { memcpy(I_VideoBuffer, p1, SCREENHEIGHT * SCREENWIDTH); @@ -319,8 +320,8 @@ void F_DrawUnderwater(void) { underwawa = true; memset((byte *) 0xa0000, 0, SCREENWIDTH * SCREENHEIGHT); - I_SetPalette(W_CacheLumpName("E2PAL", PU_CACHE)); - V_DrawRawScreen(W_CacheLumpName("E2END", PU_CACHE)); + I_SetPalette(W_CacheLumpName(DEH_String("E2PAL"), PU_CACHE)); + V_DrawRawScreen(W_CacheLumpName(DEH_String("E2END"), PU_CACHE)); } paused = false; MenuActive = false; @@ -328,7 +329,7 @@ void F_DrawUnderwater(void) break; case 2: - V_DrawRawScreen(W_CacheLumpName("TITLE", PU_CACHE)); + V_DrawRawScreen(W_CacheLumpName(DEH_String("TITLE"), PU_CACHE)); //D_StartTitle(); // go to intro/demo mode. } } diff --git a/src/heretic/g_game.c b/src/heretic/g_game.c index a256b63b..4d1e63c3 100644 --- a/src/heretic/g_game.c +++ b/src/heretic/g_game.c @@ -28,6 +28,7 @@ #include #include "doomdef.h" #include "doomkeys.h" +#include "deh_str.h" #include "i_timer.h" #include "i_system.h" #include "m_controls.h" @@ -862,11 +863,11 @@ void G_Ticker(void) { if (netgame) { - strcpy(savedescription, "NET GAME"); + strcpy(savedescription, DEH_String("NET GAME")); } else { - strcpy(savedescription, "SAVE GAME"); + strcpy(savedescription, DEH_String("SAVE GAME")); } } savegameslot = @@ -1320,7 +1321,7 @@ void G_DoLoadGame(void) save_p = savebuffer + SAVESTRINGSIZE; // Skip the description field memset(vcheck, 0, sizeof(vcheck)); - sprintf(vcheck, "version %i", HERETIC_VERSION); + sprintf(vcheck, DEH_String("version %i"), HERETIC_VERSION); if (strcmp((char *) save_p, vcheck) != 0) { // Bad version return; @@ -1449,11 +1450,11 @@ void G_InitNew(skill_t skill, int episode, int map) // Set the sky map if (episode > 5) { - skytexture = R_TextureNumForName("SKY1"); + skytexture = R_TextureNumForName(DEH_String("SKY1")); } else { - skytexture = R_TextureNumForName(skyLumpNames[episode - 1]); + skytexture = R_TextureNumForName(DEH_String(skyLumpNames[episode - 1])); } // @@ -1694,7 +1695,7 @@ void G_DoSaveGame(void) SV_Open(name); SV_Write(description, SAVESTRINGSIZE); memset(verString, 0, sizeof(verString)); - sprintf(verString, "version %i", HERETIC_VERSION); + sprintf(verString, DEH_String("version %i"), HERETIC_VERSION); SV_Write(verString, VERSIONSIZE); SV_WriteByte(gameskill); SV_WriteByte(gameepisode); diff --git a/src/heretic/in_lude.c b/src/heretic/in_lude.c index 33b75956..084cd5c3 100644 --- a/src/heretic/in_lude.c +++ b/src/heretic/in_lude.c @@ -30,6 +30,7 @@ */ #include "doomdef.h" +#include "deh_str.h" #include "s_sound.h" #include "i_system.h" #include "i_video.h" @@ -161,7 +162,7 @@ extern void AM_Stop(void); void IN_Start(void) { - I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE)); + I_SetPalette(W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE)); IN_LoadPics(); IN_InitStats(); intermission = true; @@ -308,26 +309,26 @@ static void IN_LoadUnloadPics(void (*callback)(char *lumpname, switch (gameepisode) { case 1: - callback("MAPE1", 0, &patchINTERPIC); + callback(DEH_String("MAPE1"), 0, &patchINTERPIC); break; case 2: - callback("MAPE2", 0, &patchINTERPIC); + callback(DEH_String("MAPE2"), 0, &patchINTERPIC); break; case 3: - callback("MAPE3", 0, &patchINTERPIC); + callback(DEH_String("MAPE3"), 0, &patchINTERPIC); break; default: break; } - callback("IN_X", 0, &patchBEENTHERE); - callback("IN_YAH", 0, &patchGOINGTHERE); - callback("FONTB13", 0, &FontBNegative); + callback(DEH_String("IN_X"), 0, &patchBEENTHERE); + callback(DEH_String("IN_YAH"), 0, &patchGOINGTHERE); + callback(DEH_String("FONTB13"), 0, &FontBNegative); - callback("FONTB15", 0, &FontBSlash); - callback("FONTB05", 0, &FontBPercent); + callback(DEH_String("FONTB15"), 0, &FontBSlash); + callback(DEH_String("FONTB05"), 0, &FontBPercent); - FontBLumpBase = W_GetNumForName("FONTB16"); + FontBLumpBase = W_GetNumForName(DEH_String("FONTB16")); for (i = 0; i < 10; i++) { @@ -355,9 +356,9 @@ static void LoadLumpCallback(char *lumpname, int lumpnum, patch_t **ptr) void IN_LoadPics(void) { - FontBLump = W_GetNumForName("FONTB_S") + 1; - patchFaceOkayBase = W_GetNumForName("FACEA0"); - patchFaceDeadBase = W_GetNumForName("FACEB0"); + FontBLump = W_GetNumForName(DEH_String("FONTB_S")) + 1; + patchFaceOkayBase = W_GetNumForName(DEH_String("FACEA0")); + patchFaceDeadBase = W_GetNumForName(DEH_String("FACEB0")); IN_LoadUnloadPics(LoadLumpCallback); } @@ -580,7 +581,7 @@ void IN_DrawStatBack(void) byte *src; byte *dest; - src = W_CacheLumpName("FLOOR16", PU_CACHE); + src = W_CacheLumpName(DEH_String("FLOOR16"), PU_CACHE); dest = I_VideoBuffer; for (y = 0; y < SCREENHEIGHT; y++) @@ -612,8 +613,8 @@ void IN_DrawOldLevel(void) x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7) / 2; IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7, x, 3); - x = 160 - MN_TextAWidth("FINISHED") / 2; - MN_DrTextA("FINISHED", x, 25); + x = 160 - MN_TextAWidth(DEH_String("FINISHED")) / 2; + MN_DrTextA(DEH_String("FINISHED"), x, 25); if (prevmap == 9) { @@ -660,8 +661,8 @@ void IN_DrawYAH(void) int i; int x; - x = 160 - MN_TextAWidth("NOW ENTERING:") / 2; - MN_DrTextA("NOW ENTERING:", x, 10); + x = 160 - MN_TextAWidth(DEH_String("NOW ENTERING:")) / 2; + MN_DrTextA(DEH_String("NOW ENTERING:"), x, 10); x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + gamemap - 1] + 7) / 2; IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + gamemap - 1] + 7, x, 20); @@ -698,15 +699,15 @@ void IN_DrawSingleStats(void) int x; static int sounds; - IN_DrTextB("KILLS", 50, 65); - IN_DrTextB("ITEMS", 50, 90); - IN_DrTextB("SECRETS", 50, 115); + IN_DrTextB(DEH_String("KILLS"), 50, 65); + IN_DrTextB(DEH_String("ITEMS"), 50, 90); + IN_DrTextB(DEH_String("SECRETS"), 50, 115); x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7) / 2; IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7, x, 3); - x = 160 - MN_TextAWidth("FINISHED") / 2; - MN_DrTextA("FINISHED", x, 25); + x = 160 - MN_TextAWidth(DEH_String("FINISHED")) / 2; + MN_DrTextA(DEH_String("FINISHED"), x, 25); if (intertime < 30) { @@ -757,13 +758,13 @@ void IN_DrawSingleStats(void) if (gamemode != retail || gameepisode <= 3) { - IN_DrTextB("TIME", 85, 160); + IN_DrTextB(DEH_String("TIME"), 85, 160); IN_DrawTime(155, 160, hours, minutes, seconds); } else { - x = 160 - MN_TextAWidth("NOW ENTERING:") / 2; - MN_DrTextA("NOW ENTERING:", x, 160); + x = 160 - MN_TextAWidth(DEH_String("NOW ENTERING:")) / 2; + MN_DrTextA(DEH_String("NOW ENTERING:"), x, 160); x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + gamemap - 1] + 7) / 2; @@ -787,14 +788,14 @@ void IN_DrawCoopStats(void) static int sounds; - IN_DrTextB("KILLS", 95, 35); - IN_DrTextB("BONUS", 155, 35); - IN_DrTextB("SECRET", 232, 35); + IN_DrTextB(DEH_String("KILLS"), 95, 35); + IN_DrTextB(DEH_String("BONUS"), 155, 35); + IN_DrTextB(DEH_String("SECRET"), 232, 35); x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7) / 2; IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7, x, 3); - x = 160 - MN_TextAWidth("FINISHED") / 2; - MN_DrTextA("FINISHED", x, 25); + x = 160 - MN_TextAWidth(DEH_String("FINISHED")) / 2; + MN_DrTextA(DEH_String("FINISHED"), x, 25); ypos = 50; for (i = 0; i < MAXPLAYERS; i++) @@ -845,8 +846,8 @@ void IN_DrawDMStats(void) xpos = 90; ypos = 55; - IN_DrTextB("TOTAL", 265, 30); - MN_DrTextA("VICTIMS", 140, 8); + IN_DrTextB(DEH_String("TOTAL"), 265, 30); + MN_DrTextA(DEH_String("VICTIMS"), 140, 8); for (i = 0; i < 7; i++) { MN_DrTextA(KillersText[i], 10, 80 + 9 * i); diff --git a/src/heretic/mn_menu.c b/src/heretic/mn_menu.c index 33024a96..2b380234 100644 --- a/src/heretic/mn_menu.c +++ b/src/heretic/mn_menu.c @@ -25,6 +25,8 @@ // MN_menu.c #include + +#include "deh_str.h" #include "doomdef.h" #include "doomkeys.h" #include "i_system.h" @@ -73,7 +75,7 @@ typedef struct { ItemType_t type; char *text; - boolean(*func) (int option); + boolean(*func) (int option); int option; MenuType_t menu; } MenuItem_t; @@ -305,7 +307,7 @@ void MN_Init(void) InitFonts(); MenuActive = false; messageson = true; - SkullBaseLump = W_GetNumForName("M_SKL00"); + SkullBaseLump = W_GetNumForName(DEH_String("M_SKL00")); if (gamemode == retail) { // Add episodes 4 and 5 to the menu @@ -322,8 +324,8 @@ void MN_Init(void) static void InitFonts(void) { - FontABaseLump = W_GetNumForName("FONTA_S") + 1; - FontBBaseLump = W_GetNumForName("FONTB_S") + 1; + FontABaseLump = W_GetNumForName(DEH_String("FONTA_S")) + 1; + FontBBaseLump = W_GetNumForName(DEH_String("FONTB_S")) + 1; } //--------------------------------------------------------------------------- @@ -476,14 +478,16 @@ void MN_Drawer(void) int x; int y; MenuItem_t *item; + char *message; char *selName; if (MenuActive == false) { if (askforquit) { - MN_DrTextA(QuitEndMsg[typeofask - 1], 160 - - MN_TextAWidth(QuitEndMsg[typeofask - 1]) / 2, 80); + message = DEH_String(QuitEndMsg[typeofask - 1]); + + MN_DrTextA(message, 160 - MN_TextAWidth(message) / 2, 80); if (typeofask == 3) { MN_DrTextA(SlotText[quicksave - 1], 160 - @@ -525,13 +529,13 @@ void MN_Drawer(void) { if (item->type != ITT_EMPTY && item->text) { - MN_DrTextB(item->text, x, y); + MN_DrTextB(DEH_String(item->text), x, y); } y += ITEM_HEIGHT; item++; } y = CurrentMenu->y + (CurrentItPos * ITEM_HEIGHT) + SELECTOR_YOFFSET; - selName = MenuTime & 16 ? "M_SLCTR1" : "M_SLCTR2"; + selName = DEH_String(MenuTime & 16 ? "M_SLCTR1" : "M_SLCTR2"); V_DrawPatch(x + SELECTOR_XOFFSET, y, W_CacheLumpName(selName, PU_CACHE)); } @@ -548,7 +552,7 @@ static void DrawMainMenu(void) int frame; frame = (MenuTime / 3) % 18; - V_DrawPatch(88, 0, W_CacheLumpName("M_HTIC", PU_CACHE)); + V_DrawPatch(88, 0, W_CacheLumpName(DEH_String("M_HTIC"), PU_CACHE)); V_DrawPatch(40, 10, W_CacheLumpNum(SkullBaseLump + (17 - frame), PU_CACHE)); V_DrawPatch(232, 10, W_CacheLumpNum(SkullBaseLump + frame, PU_CACHE)); @@ -597,7 +601,11 @@ static void DrawFilesMenu(void) static void DrawLoadMenu(void) { - MN_DrTextB("LOAD GAME", 160 - MN_TextBWidth("LOAD GAME") / 2, 10); + char *title; + + title = DEH_String("LOAD GAME"); + + MN_DrTextB(title, 160 - MN_TextBWidth(title) / 2, 10); if (!slottextloaded) { MN_LoadSlotText(); @@ -613,7 +621,11 @@ static void DrawLoadMenu(void) static void DrawSaveMenu(void) { - MN_DrTextB("SAVE GAME", 160 - MN_TextBWidth("SAVE GAME") / 2, 10); + char *title; + + title = DEH_String("SAVE GAME"); + + MN_DrTextB(title, 160 - MN_TextBWidth(title) / 2, 10); if (!slottextloaded) { MN_LoadSlotText(); @@ -675,7 +687,7 @@ static void DrawFileSlots(Menu_t * menu) y = menu->y; for (i = 0; i < 6; i++) { - V_DrawPatch(x, y, W_CacheLumpName("M_FSLOT", PU_CACHE)); + V_DrawPatch(x, y, W_CacheLumpName(DEH_String("M_FSLOT"), PU_CACHE)); if (SlotStatus[i]) { MN_DrTextA(SlotText[i], x + 5, y + 5); @@ -796,11 +808,11 @@ static boolean SCMessages(int option) messageson ^= 1; if (messageson) { - P_SetMessage(&players[consoleplayer], "MESSAGES ON", true); + P_SetMessage(&players[consoleplayer], DEH_String("MESSAGES ON"), true); } else { - P_SetMessage(&players[consoleplayer], "MESSAGES OFF", true); + P_SetMessage(&players[consoleplayer], DEH_String("MESSAGES OFF"), true); } S_StartSound(NULL, sfx_chat); return true; @@ -1460,7 +1472,7 @@ boolean MN_Responder(event_t * event) if (CurrentMenu->items[i].text) { if (toupper(charTyped) - == toupper(CurrentMenu->items[i].text[0])) + == toupper(DEH_String(CurrentMenu->items[i].text)[0])) { CurrentItPos = i; return (true); @@ -1628,13 +1640,13 @@ static void DrawSlider(Menu_t * menu, int item, int width, int slot) x = menu->x + 24; y = menu->y + 2 + (item * ITEM_HEIGHT); - V_DrawPatch(x - 32, y, W_CacheLumpName("M_SLDLT", PU_CACHE)); + V_DrawPatch(x - 32, y, W_CacheLumpName(DEH_String("M_SLDLT"), PU_CACHE)); for (x2 = x, count = width; count--; x2 += 8) { - V_DrawPatch(x2, y, W_CacheLumpName(count & 1 ? "M_SLDMD1" - : "M_SLDMD2", PU_CACHE)); + V_DrawPatch(x2, y, W_CacheLumpName(DEH_String(count & 1 ? "M_SLDMD1" + : "M_SLDMD2"), PU_CACHE)); } - V_DrawPatch(x2, y, W_CacheLumpName("M_SLDRT", PU_CACHE)); + V_DrawPatch(x2, y, W_CacheLumpName(DEH_String("M_SLDRT"), PU_CACHE)); V_DrawPatch(x + 4 + slot * 8, y + 7, - W_CacheLumpName("M_SLDKB", PU_CACHE)); + W_CacheLumpName(DEH_String("M_SLDKB"), PU_CACHE)); } diff --git a/src/heretic/p_spec.c b/src/heretic/p_spec.c index 6227237b..49c067fa 100644 --- a/src/heretic/p_spec.c +++ b/src/heretic/p_spec.c @@ -25,6 +25,7 @@ // P_Spec.c #include "doomdef.h" +#include "deh_str.h" #include "i_system.h" #include "i_timer.h" #include "m_random.h" @@ -204,18 +205,12 @@ struct int type; } TerrainTypeDefs[] = { - { - "FLTWAWA1", FLOOR_WATER}, - { - "FLTFLWW1", FLOOR_WATER}, - { - "FLTLAVA1", FLOOR_LAVA}, - { - "FLATHUH1", FLOOR_LAVA}, - { - "FLTSLUD1", FLOOR_SLUDGE}, - { - "END", -1} + { "FLTWAWA1", FLOOR_WATER }, + { "FLTFLWW1", FLOOR_WATER }, + { "FLTLAVA1", FLOOR_LAVA }, + { "FLATHUH1", FLOOR_LAVA }, + { "FLTSLUD1", FLOOR_SLUDGE }, + { "END", -1 } }; mobj_t LavaInflictor; @@ -266,35 +261,40 @@ void P_InitTerrainTypes(void) void P_InitPicAnims(void) { + char *startname; + char *endname; int i; lastanim = anims; for (i = 0; animdefs[i].istexture != -1; i++) { + startname = DEH_String(animdefs[i].startname); + endname = DEH_String(animdefs[i].endname); + if (animdefs[i].istexture) { // Texture animation - if (R_CheckTextureNumForName(animdefs[i].startname) == -1) + if (R_CheckTextureNumForName(startname) == -1) { // Texture doesn't exist continue; } - lastanim->picnum = R_TextureNumForName(animdefs[i].endname); - lastanim->basepic = R_TextureNumForName(animdefs[i].startname); + lastanim->picnum = R_TextureNumForName(endname); + lastanim->basepic = R_TextureNumForName(startname); } else { // Flat animation - if (W_CheckNumForName(animdefs[i].startname) == -1) + if (W_CheckNumForName(startname) == -1) { // Flat doesn't exist continue; } - lastanim->picnum = R_FlatNumForName(animdefs[i].endname); - lastanim->basepic = R_FlatNumForName(animdefs[i].startname); + lastanim->picnum = R_FlatNumForName(endname); + lastanim->basepic = R_FlatNumForName(startname); } lastanim->istexture = animdefs[i].istexture; lastanim->numpics = lastanim->picnum - lastanim->basepic + 1; if (lastanim->numpics < 2) { I_Error("P_InitPicAnims: bad cycle from %s to %s", - animdefs[i].startname, animdefs[i].endname); + startname, endname); } lastanim->speed = animdefs[i].speed; lastanim++; @@ -1132,7 +1132,7 @@ void P_SpawnSpecials(void) int episode; episode = 1; - if (W_CheckNumForName("texture2") >= 0) + if (W_CheckNumForName(DEH_String("texture2")) >= 0) episode = 2; // diff --git a/src/heretic/p_switch.c b/src/heretic/p_switch.c index cef6a74b..2ec758b6 100644 --- a/src/heretic/p_switch.c +++ b/src/heretic/p_switch.c @@ -23,6 +23,7 @@ //----------------------------------------------------------------------------- #include "doomdef.h" +#include "deh_str.h" #include "i_system.h" #include "p_local.h" #include "s_sound.h" @@ -129,9 +130,9 @@ void P_InitSwitchList(void) if (alphSwitchList[i].episode <= episode) { switchlist[index++] = - R_TextureNumForName(alphSwitchList[i].name1); + R_TextureNumForName(DEH_String(alphSwitchList[i].name1)); switchlist[index++] = - R_TextureNumForName(alphSwitchList[i].name2); + R_TextureNumForName(DEH_String(alphSwitchList[i].name2)); } } } diff --git a/src/heretic/p_user.c b/src/heretic/p_user.c index 63368bab..16dbed49 100644 --- a/src/heretic/p_user.c +++ b/src/heretic/p_user.c @@ -27,6 +27,7 @@ #include #include "doomdef.h" +#include "deh_str.h" #include "m_random.h" #include "p_local.h" #include "s_sound.h" @@ -394,7 +395,7 @@ void P_DeathThink(player_t * player) { if (player == &players[consoleplayer]) { - I_SetPalette((byte *) W_CacheLumpName("PLAYPAL", PU_CACHE)); + I_SetPalette(W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE)); inv_ptr = 0; curpos = 0; newtorch = 0; diff --git a/src/heretic/r_data.c b/src/heretic/r_data.c index ee005248..b55e6dfc 100644 --- a/src/heretic/r_data.c +++ b/src/heretic/r_data.c @@ -316,12 +316,17 @@ void R_InitTextures(void) int offset, maxoff, maxoff2; int numtextures1, numtextures2; int *directory; + char *texture1, *texture2, *pnames; + + texture1 = DEH_String("TEXTURE1"); + texture2 = DEH_String("TEXTURE2"); + pnames = DEH_String("PNAMES"); // // load the patch names from pnames.lmp // name[8] = 0; - names = W_CacheLumpName("PNAMES", PU_STATIC); + names = W_CacheLumpName(pnames, PU_STATIC); nummappatches = LONG(*((int *) names)); name_p = names + 4; patchlookup = Z_Malloc(nummappatches * sizeof(*patchlookup), PU_STATIC, NULL); @@ -330,21 +335,21 @@ void R_InitTextures(void) strncpy(name, name_p + i * 8, 8); patchlookup[i] = W_CheckNumForName(name); } - W_ReleaseLumpName("PNAMES"); + W_ReleaseLumpName(pnames); // // load the map texture definitions from textures.lmp // - maptex = maptex1 = W_CacheLumpName("TEXTURE1", PU_STATIC); + maptex = maptex1 = W_CacheLumpName(texture1, PU_STATIC); numtextures1 = LONG(*maptex); - maxoff = W_LumpLength(W_GetNumForName("TEXTURE1")); + maxoff = W_LumpLength(W_GetNumForName(texture1)); directory = maptex + 1; - if (W_CheckNumForName("TEXTURE2") != -1) + if (W_CheckNumForName(texture2) != -1) { - maptex2 = W_CacheLumpName("TEXTURE2", PU_STATIC); + maptex2 = W_CacheLumpName(texture2, PU_STATIC); numtextures2 = LONG(*maptex2); - maxoff2 = W_LumpLength(W_GetNumForName("TEXTURE2")); + maxoff2 = W_LumpLength(W_GetNumForName(texture2)); } else { @@ -358,8 +363,11 @@ void R_InitTextures(void) // Init the startup thermometer at this point... // { + int start, end; int spramount; - spramount = W_GetNumForName("S_END") - W_GetNumForName("S_START") + 1; + start = W_GetNumForName(DEH_String("S_START")); + end = W_GetNumForName(DEH_String("S_END")); + spramount = end - start + 1; InitThermo(spramount + numtextures + 6); } @@ -427,10 +435,10 @@ void R_InitTextures(void) Z_Free(patchlookup); - W_ReleaseLumpName("TEXTURE1"); + W_ReleaseLumpName(texture1); if (maptex2) { - W_ReleaseLumpName("TEXTURE2"); + W_ReleaseLumpName(texture2); } // @@ -463,8 +471,8 @@ void R_InitFlats(void) { int i; - firstflat = W_GetNumForName("F_START") + 1; - lastflat = W_GetNumForName("F_END") - 1; + firstflat = W_GetNumForName(DEH_String("F_START")) + 1; + lastflat = W_GetNumForName(DEH_String("F_END")) - 1; numflats = lastflat - firstflat + 1; // translation table for global animation @@ -489,8 +497,8 @@ void R_InitSpriteLumps(void) int i; patch_t *patch; - firstspritelump = W_GetNumForName("S_START") + 1; - lastspritelump = W_GetNumForName("S_END") - 1; + firstspritelump = W_GetNumForName(DEH_String("S_START")) + 1; + lastspritelump = W_GetNumForName(DEH_String("S_END")) - 1; numspritelumps = lastspritelump - firstspritelump + 1; spritewidth = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0); spriteoffset = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0); @@ -527,7 +535,7 @@ void R_InitColormaps(void) // load in the light tables // 256 byte align tables // - lump = W_GetNumForName("COLORMAP"); + lump = W_GetNumForName(DEH_String("COLORMAP")); length = W_LumpLength(lump); colormaps = Z_Malloc(length, PU_STATIC, 0); W_ReadLump(lump, colormaps); diff --git a/src/heretic/r_draw.c b/src/heretic/r_draw.c index 5a20b50a..88653df1 100644 --- a/src/heretic/r_draw.c +++ b/src/heretic/r_draw.c @@ -24,6 +24,7 @@ // R_draw.c #include "doomdef.h" +#include "deh_str.h" #include "r_local.h" #include "i_video.h" #include "v_video.h" @@ -386,11 +387,11 @@ void R_DrawViewBorder(void) if (gamemode == shareware) { - src = W_CacheLumpName("FLOOR04", PU_CACHE); + src = W_CacheLumpName(DEH_String("FLOOR04"), PU_CACHE); } else { - src = W_CacheLumpName("FLAT513", PU_CACHE); + src = W_CacheLumpName(DEH_String("FLAT513"), PU_CACHE); } dest = I_VideoBuffer; @@ -409,24 +410,26 @@ void R_DrawViewBorder(void) } for (x = viewwindowx; x < viewwindowx + viewwidth; x += 16) { - V_DrawPatch(x, viewwindowy - 4, W_CacheLumpName("bordt", PU_CACHE)); - V_DrawPatch(x, viewwindowy + viewheight, W_CacheLumpName("bordb", - PU_CACHE)); + V_DrawPatch(x, viewwindowy - 4, + W_CacheLumpName(DEH_String("bordt"), PU_CACHE)); + V_DrawPatch(x, viewwindowy + viewheight, + W_CacheLumpName(DEH_String("bordb"), PU_CACHE)); } for (y = viewwindowy; y < viewwindowy + viewheight; y += 16) { - V_DrawPatch(viewwindowx - 4, y, W_CacheLumpName("bordl", PU_CACHE)); - V_DrawPatch(viewwindowx + viewwidth, y, W_CacheLumpName("bordr", - PU_CACHE)); + V_DrawPatch(viewwindowx - 4, y, + W_CacheLumpName(DEH_String("bordl"), PU_CACHE)); + V_DrawPatch(viewwindowx + viewwidth, y, + W_CacheLumpName(DEH_String("bordr"), PU_CACHE)); } - V_DrawPatch(viewwindowx - 4, viewwindowy - 4, W_CacheLumpName("bordtl", - PU_CACHE)); + V_DrawPatch(viewwindowx - 4, viewwindowy - 4, + W_CacheLumpName(DEH_String("bordtl"), PU_CACHE)); V_DrawPatch(viewwindowx + viewwidth, viewwindowy - 4, - W_CacheLumpName("bordtr", PU_CACHE)); + W_CacheLumpName(DEH_String("bordtr"), PU_CACHE)); V_DrawPatch(viewwindowx + viewwidth, viewwindowy + viewheight, - W_CacheLumpName("bordbr", PU_CACHE)); + W_CacheLumpName(DEH_String("bordbr"), PU_CACHE)); V_DrawPatch(viewwindowx - 4, viewwindowy + viewheight, - W_CacheLumpName("bordbl", PU_CACHE)); + W_CacheLumpName(DEH_String("bordbl"), PU_CACHE)); } /* @@ -450,11 +453,11 @@ void R_DrawTopBorder(void) if (gamemode == shareware) { - src = W_CacheLumpName("FLOOR04", PU_CACHE); + src = W_CacheLumpName(DEH_String("FLOOR04"), PU_CACHE); } else { - src = W_CacheLumpName("FLAT513", PU_CACHE); + src = W_CacheLumpName(DEH_String("FLAT513"), PU_CACHE); } dest = I_VideoBuffer; @@ -476,20 +479,20 @@ void R_DrawTopBorder(void) for (x = viewwindowx; x < viewwindowx + viewwidth; x += 16) { V_DrawPatch(x, viewwindowy - 4, - W_CacheLumpName("bordt", PU_CACHE)); + W_CacheLumpName(DEH_String("bordt"), PU_CACHE)); } - V_DrawPatch(viewwindowx - 4, viewwindowy, W_CacheLumpName("bordl", - PU_CACHE)); + V_DrawPatch(viewwindowx - 4, viewwindowy, + W_CacheLumpName(DEH_String("bordl"), PU_CACHE)); V_DrawPatch(viewwindowx + viewwidth, viewwindowy, - W_CacheLumpName("bordr", PU_CACHE)); + W_CacheLumpName(DEH_String("bordr"), PU_CACHE)); V_DrawPatch(viewwindowx - 4, viewwindowy + 16, - W_CacheLumpName("bordl", PU_CACHE)); + W_CacheLumpName(DEH_String("bordl"), PU_CACHE)); V_DrawPatch(viewwindowx + viewwidth, viewwindowy + 16, - W_CacheLumpName("bordr", PU_CACHE)); + W_CacheLumpName(DEH_String("bordr"), PU_CACHE)); V_DrawPatch(viewwindowx - 4, viewwindowy - 4, - W_CacheLumpName("bordtl", PU_CACHE)); + W_CacheLumpName(DEH_String("bordtl"), PU_CACHE)); V_DrawPatch(viewwindowx + viewwidth, viewwindowy - 4, - W_CacheLumpName("bordtr", PU_CACHE)); + W_CacheLumpName(DEH_String("bordtr"), PU_CACHE)); } } diff --git a/src/heretic/r_plane.c b/src/heretic/r_plane.c index e35e2931..cc86b118 100644 --- a/src/heretic/r_plane.c +++ b/src/heretic/r_plane.c @@ -25,6 +25,7 @@ #include #include "doomdef.h" +#include "deh_str.h" #include "i_system.h" #include "r_local.h" @@ -90,7 +91,7 @@ fixed_t cachedystep[SCREENHEIGHT]; void R_InitSkyMap(void) { - skyflatnum = R_FlatNumForName("F_SKY1"); + skyflatnum = R_FlatNumForName(DEH_String("F_SKY1")); skytexturemid = 200 * FRACUNIT; skyiscale = FRACUNIT; } diff --git a/src/heretic/r_things.c b/src/heretic/r_things.c index 6302303e..e5ff4b4b 100644 --- a/src/heretic/r_things.c +++ b/src/heretic/r_things.c @@ -25,6 +25,7 @@ #include #include #include "doomdef.h" +#include "deh_str.h" #include "i_swap.h" #include "i_system.h" #include "r_local.h" @@ -154,7 +155,7 @@ void R_InstallSpriteLump(int lump, unsigned frame, unsigned rotation, void R_InitSpriteDefs(char **namelist) { char **check; - int i, l, intname, frame, rotation; + int i, l, frame, rotation; int start, end; // count the number of sprite names @@ -176,17 +177,16 @@ void R_InitSpriteDefs(char **namelist) // Just compare 4 characters as ints for (i = 0; i < numsprites; i++) { - spritename = namelist[i]; + spritename = DEH_String(namelist[i]); memset(sprtemp, -1, sizeof(sprtemp)); maxframe = -1; - intname = *(int *) namelist[i]; // // scan the lumps, filling in the frames for whatever is found // for (l = start + 1; l < end; l++) - if (*(int *) lumpinfo[l].name == intname) + if (!strncasecmp(lumpinfo[l].name, spritename, 4)) { frame = lumpinfo[l].name[4] - 'A'; rotation = lumpinfo[l].name[5] - '0'; @@ -209,7 +209,7 @@ void R_InitSpriteDefs(char **namelist) if (gamemode == shareware) continue; I_Error("R_InitSprites: No lumps found for sprite %s", - namelist[i]); + spritename); } maxframe++; @@ -219,7 +219,7 @@ void R_InitSpriteDefs(char **namelist) { case -1: // no rotations were found for that frame at all I_Error("R_InitSprites: No patches found for %s frame %c", - namelist[i], frame + 'A'); + spritename, frame + 'A'); case 0: // only the first rotation is needed break; @@ -228,7 +228,7 @@ void R_InitSpriteDefs(char **namelist) if (sprtemp[frame].lump[rotation] == -1) I_Error ("R_InitSprites: Sprite %s frame %c is missing rotations", - namelist[i], frame + 'A'); + spritename, frame + 'A'); } } diff --git a/src/heretic/sb_bar.c b/src/heretic/sb_bar.c index 77bd40c2..3a90c000 100644 --- a/src/heretic/sb_bar.c +++ b/src/heretic/sb_bar.c @@ -25,6 +25,7 @@ // SB_bar.c #include "doomdef.h" +#include "deh_str.h" #include "i_video.h" #include "m_cheat.h" #include "m_misc.h" @@ -196,53 +197,53 @@ void SB_Init(void) int i; int startLump; - PatchLTFACE = W_CacheLumpName("LTFACE", PU_STATIC); - PatchRTFACE = W_CacheLumpName("RTFACE", PU_STATIC); - PatchBARBACK = W_CacheLumpName("BARBACK", PU_STATIC); - PatchINVBAR = W_CacheLumpName("INVBAR", PU_STATIC); - PatchCHAIN = W_CacheLumpName("CHAIN", PU_STATIC); + PatchLTFACE = W_CacheLumpName(DEH_String("LTFACE"), PU_STATIC); + PatchRTFACE = W_CacheLumpName(DEH_String("RTFACE"), PU_STATIC); + PatchBARBACK = W_CacheLumpName(DEH_String("BARBACK"), PU_STATIC); + PatchINVBAR = W_CacheLumpName(DEH_String("INVBAR"), PU_STATIC); + PatchCHAIN = W_CacheLumpName(DEH_String("CHAIN"), PU_STATIC); if (deathmatch) { - PatchSTATBAR = W_CacheLumpName("STATBAR", PU_STATIC); + PatchSTATBAR = W_CacheLumpName(DEH_String("STATBAR"), PU_STATIC); } else { - PatchSTATBAR = W_CacheLumpName("LIFEBAR", PU_STATIC); + PatchSTATBAR = W_CacheLumpName(DEH_String("LIFEBAR"), PU_STATIC); } if (!netgame) { // single player game uses red life gem - PatchLIFEGEM = W_CacheLumpName("LIFEGEM2", PU_STATIC); + PatchLIFEGEM = W_CacheLumpName(DEH_String("LIFEGEM2"), PU_STATIC); } else { - PatchLIFEGEM = W_CacheLumpNum(W_GetNumForName("LIFEGEM0") + PatchLIFEGEM = W_CacheLumpNum(W_GetNumForName(DEH_String("LIFEGEM0")) + consoleplayer, PU_STATIC); } - PatchLTFCTOP = W_CacheLumpName("LTFCTOP", PU_STATIC); - PatchRTFCTOP = W_CacheLumpName("RTFCTOP", PU_STATIC); - PatchSELECTBOX = W_CacheLumpName("SELECTBOX", PU_STATIC); - PatchINVLFGEM1 = W_CacheLumpName("INVGEML1", PU_STATIC); - PatchINVLFGEM2 = W_CacheLumpName("INVGEML2", PU_STATIC); - PatchINVRTGEM1 = W_CacheLumpName("INVGEMR1", PU_STATIC); - PatchINVRTGEM2 = W_CacheLumpName("INVGEMR2", PU_STATIC); - PatchBLACKSQ = W_CacheLumpName("BLACKSQ", PU_STATIC); - PatchARMCLEAR = W_CacheLumpName("ARMCLEAR", PU_STATIC); - PatchCHAINBACK = W_CacheLumpName("CHAINBACK", PU_STATIC); - startLump = W_GetNumForName("IN0"); + PatchLTFCTOP = W_CacheLumpName(DEH_String("LTFCTOP"), PU_STATIC); + PatchRTFCTOP = W_CacheLumpName(DEH_String("RTFCTOP"), PU_STATIC); + PatchSELECTBOX = W_CacheLumpName(DEH_String("SELECTBOX"), PU_STATIC); + PatchINVLFGEM1 = W_CacheLumpName(DEH_String("INVGEML1"), PU_STATIC); + PatchINVLFGEM2 = W_CacheLumpName(DEH_String("INVGEML2"), PU_STATIC); + PatchINVRTGEM1 = W_CacheLumpName(DEH_String("INVGEMR1"), PU_STATIC); + PatchINVRTGEM2 = W_CacheLumpName(DEH_String("INVGEMR2"), PU_STATIC); + PatchBLACKSQ = W_CacheLumpName(DEH_String("BLACKSQ"), PU_STATIC); + PatchARMCLEAR = W_CacheLumpName(DEH_String("ARMCLEAR"), PU_STATIC); + PatchCHAINBACK = W_CacheLumpName(DEH_String("CHAINBACK"), PU_STATIC); + startLump = W_GetNumForName(DEH_String("IN0")); for (i = 0; i < 10; i++) { PatchINumbers[i] = W_CacheLumpNum(startLump + i, PU_STATIC); } - PatchNEGATIVE = W_CacheLumpName("NEGNUM", PU_STATIC); - FontBNumBase = W_GetNumForName("FONTB16"); - startLump = W_GetNumForName("SMALLIN0"); + PatchNEGATIVE = W_CacheLumpName(DEH_String("NEGNUM"), PU_STATIC); + FontBNumBase = W_GetNumForName(DEH_String("FONTB16")); + startLump = W_GetNumForName(DEH_String("SMALLIN0")); for (i = 0; i < 10; i++) { PatchSmNumbers[i] = W_CacheLumpNum(startLump + i, PU_STATIC); } - playpalette = W_GetNumForName("PLAYPAL"); - spinbooklump = W_GetNumForName("SPINBK0"); - spinflylump = W_GetNumForName("SPFLY0"); + playpalette = W_GetNumForName(DEH_String("PLAYPAL")); + spinbooklump = W_GetNumForName(DEH_String("SPINBK0")); + spinflylump = W_GetNumForName(DEH_String("SPFLY0")); } //--------------------------------------------------------------------------- @@ -311,7 +312,7 @@ static void DrINumber(signed int val, int x, int y) { if (val < -9) { - V_DrawPatch(x + 1, y + 1, W_CacheLumpName("LAME", PU_CACHE)); + V_DrawPatch(x + 1, y + 1, W_CacheLumpName(DEH_String("LAME"), PU_CACHE)); } else { @@ -458,7 +459,7 @@ static void DrawSoundInfo(void) if (leveltime & 16) { - MN_DrTextA("*** SOUND DEBUG INFO ***", xPos[0], 20); + MN_DrTextA(DEH_String("*** SOUND DEBUG INFO ***"), xPos[0], 20); } S_GetChannelInfo(&s); if (s.channelCount == 0) @@ -466,13 +467,13 @@ static void DrawSoundInfo(void) return; } x = 0; - MN_DrTextA("NAME", xPos[x++], 30); - MN_DrTextA("MO.T", xPos[x++], 30); - MN_DrTextA("MO.X", xPos[x++], 30); - MN_DrTextA("MO.Y", xPos[x++], 30); - MN_DrTextA("ID", xPos[x++], 30); - MN_DrTextA("PRI", xPos[x++], 30); - MN_DrTextA("DIST", xPos[x++], 30); + MN_DrTextA(DEH_String("NAME"), xPos[x++], 30); + MN_DrTextA(DEH_String("MO.T"), xPos[x++], 30); + MN_DrTextA(DEH_String("MO.X"), xPos[x++], 30); + MN_DrTextA(DEH_String("MO.Y"), xPos[x++], 30); + MN_DrTextA(DEH_String("ID"), xPos[x++], 30); + MN_DrTextA(DEH_String("PRI"), xPos[x++], 30); + MN_DrTextA(DEH_String("DIST"), xPos[x++], 30); for (i = 0; i < s.channelCount; i++) { c = &s.chan[i]; @@ -480,7 +481,7 @@ static void DrawSoundInfo(void) y = 40 + i * 10; if (c->mo == NULL) { // Channel is unused - MN_DrTextA("------", xPos[0], y); + MN_DrTextA(DEH_String("------"), xPos[0], y); continue; } sprintf(text, "%s", c->name); @@ -570,8 +571,10 @@ void SB_Drawer(void) V_DrawPatch(0, 158, PatchBARBACK); if (players[consoleplayer].cheats & CF_GODMODE) { - V_DrawPatch(16, 167, W_CacheLumpName("GOD1", PU_CACHE)); - V_DrawPatch(287, 167, W_CacheLumpName("GOD2", PU_CACHE)); + V_DrawPatch(16, 167, + W_CacheLumpName(DEH_String("GOD1"), PU_CACHE)); + V_DrawPatch(287, 167, + W_CacheLumpName(DEH_String("GOD2"), PU_CACHE)); } oldhealth = -1; } @@ -776,8 +779,10 @@ void DrawMainBar(void) if (ArtifactFlash) { V_DrawPatch(180, 161, PatchBLACKSQ); - V_DrawPatch(182, 161, W_CacheLumpNum(W_GetNumForName("useartia") - + ArtifactFlash - 1, PU_CACHE)); + + temp = W_GetNumForName(DEH_String("useartia")) + ArtifactFlash - 1; + + V_DrawPatch(182, 161, W_CacheLumpNum(temp, PU_CACHE)); ArtifactFlash--; oldarti = -1; // so that the correct artifact fills in after the flash UpdateState |= I_STATBAR; @@ -789,7 +794,7 @@ void DrawMainBar(void) if (CPlayer->readyArtifact > 0) { V_DrawPatch(179, 160, - W_CacheLumpName(patcharti[CPlayer->readyArtifact], + W_CacheLumpName(DEH_String(patcharti[CPlayer->readyArtifact]), PU_CACHE)); DrSmallNumber(CPlayer->inventory[inv_ptr].count, 201, 182); } @@ -839,15 +844,15 @@ void DrawMainBar(void) { if (CPlayer->keys[key_yellow]) { - V_DrawPatch(153, 164, W_CacheLumpName("ykeyicon", PU_CACHE)); + V_DrawPatch(153, 164, W_CacheLumpName(DEH_String("ykeyicon"), PU_CACHE)); } if (CPlayer->keys[key_green]) { - V_DrawPatch(153, 172, W_CacheLumpName("gkeyicon", PU_CACHE)); + V_DrawPatch(153, 172, W_CacheLumpName(DEH_String("gkeyicon"), PU_CACHE)); } if (CPlayer->keys[key_blue]) { - V_DrawPatch(153, 180, W_CacheLumpName("bkeyicon", PU_CACHE)); + V_DrawPatch(153, 180, W_CacheLumpName(DEH_String("bkeyicon"), PU_CACHE)); } oldkeys = playerkeys; UpdateState |= I_STATBAR; @@ -861,7 +866,7 @@ void DrawMainBar(void) { DrINumber(temp, 109, 162); V_DrawPatch(111, 172, - W_CacheLumpName(ammopic[CPlayer->readyweapon - 1], + W_CacheLumpName(DEH_String(ammopic[CPlayer->readyweapon - 1]), PU_CACHE)); } oldammo = temp; @@ -887,6 +892,7 @@ void DrawMainBar(void) void DrawInventoryBar(void) { + char *patch; int i; int x; @@ -899,10 +905,9 @@ void DrawInventoryBar(void) if (CPlayer->inventorySlotNum > x + i && CPlayer->inventory[x + i].type != arti_none) { - V_DrawPatch(50 + i * 31, 160, - W_CacheLumpName(patcharti - [CPlayer->inventory[x + i].type], - PU_CACHE)); + patch = DEH_String(patcharti[CPlayer->inventory[x + i].type]); + + V_DrawPatch(50 + i * 31, 160, W_CacheLumpName(patch, PU_CACHE)); DrSmallNumber(CPlayer->inventory[x + i].count, 69 + i * 31, 182); } } @@ -921,6 +926,7 @@ void DrawInventoryBar(void) void DrawFullScreenStuff(void) { + char *patch; int i; int x; int temp; @@ -950,10 +956,9 @@ void DrawFullScreenStuff(void) { if (CPlayer->readyArtifact > 0) { - V_DrawTLPatch(286, 170, W_CacheLumpName("ARTIBOX", PU_CACHE)); - V_DrawPatch(286, 170, - W_CacheLumpName(patcharti[CPlayer->readyArtifact], - PU_CACHE)); + patch = DEH_String(patcharti[CPlayer->readyArtifact]); + V_DrawTLPatch(286, 170, W_CacheLumpName(DEH_String("ARTIBOX"), PU_CACHE)); + V_DrawPatch(286, 170, W_CacheLumpName(patch, PU_CACHE)); DrSmallNumber(CPlayer->inventory[inv_ptr].count, 307, 192); } } @@ -962,15 +967,14 @@ void DrawFullScreenStuff(void) x = inv_ptr - curpos; for (i = 0; i < 7; i++) { - V_DrawTLPatch(50 + i * 31, 168, W_CacheLumpName("ARTIBOX", - PU_CACHE)); + V_DrawTLPatch(50 + i * 31, 168, + W_CacheLumpName(DEH_String("ARTIBOX"), PU_CACHE)); if (CPlayer->inventorySlotNum > x + i && CPlayer->inventory[x + i].type != arti_none) { + patch = DEH_String(patcharti[CPlayer->inventory[x + i].type]); V_DrawPatch(50 + i * 31, 168, - W_CacheLumpName(patcharti - [CPlayer->inventory[x + i].type], - PU_CACHE)); + W_CacheLumpName(patch, PU_CACHE)); DrSmallNumber(CPlayer->inventory[x + i].count, 69 + i * 31, 190); } -- cgit v1.2.3 From 2f3b2889abdcb219ae0d27e14f233ca76bf42dec Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 8 Mar 2010 18:50:29 +0000 Subject: Use native MIDI music by default. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 1879 --- src/s_sound.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/s_sound.c b/src/s_sound.c index 6c18f65e..7ae7559a 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -120,7 +120,7 @@ static musicinfo_t *mus_playing = NULL; int numChannels = 8; -int snd_musicdevice = SNDDEVICE_SB; +int snd_musicdevice = SNDDEVICE_GENMIDI; int snd_sfxdevice = SNDDEVICE_SB; // Sound modules -- cgit v1.2.3 From d76bed743c72bfccf5cbbc18dcd9cdb1e75935b3 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 18 Apr 2010 14:30:06 +0000 Subject: Add some DEH_String() calls where appropriate. Subversion-branch: /branches/raven-branch Subversion-revision: 1894 --- src/heretic/in_lude.c | 6 +++--- src/heretic/mn_menu.c | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/heretic/in_lude.c b/src/heretic/in_lude.c index 084cd5c3..3c382814 100644 --- a/src/heretic/in_lude.c +++ b/src/heretic/in_lude.c @@ -850,7 +850,7 @@ void IN_DrawDMStats(void) MN_DrTextA(DEH_String("VICTIMS"), 140, 8); for (i = 0; i < 7; i++) { - MN_DrTextA(KillersText[i], 10, 80 + 9 * i); + MN_DrTextA(DEH_String(KillersText[i]), 10, 80 + 9 * i); } if (intertime < 20) { @@ -941,7 +941,7 @@ void IN_DrawTime(int x, int y, int h, int m, int s) if (h) { IN_DrawNumber(h, x, y, 2); - IN_DrTextB(":", x + 26, y); + IN_DrTextB(DEH_String(":"), x + 26, y); } x += 34; if (m || h) @@ -951,7 +951,7 @@ void IN_DrawTime(int x, int y, int h, int m, int s) x += 34; if (s) { - IN_DrTextB(":", x - 8, y); + IN_DrTextB(DEH_String(":"), x - 8, y); IN_DrawNumber(s, x, y, 2); } } diff --git a/src/heretic/mn_menu.c b/src/heretic/mn_menu.c index 2b380234..955e0124 100644 --- a/src/heretic/mn_menu.c +++ b/src/heretic/mn_menu.c @@ -492,14 +492,14 @@ void MN_Drawer(void) { MN_DrTextA(SlotText[quicksave - 1], 160 - MN_TextAWidth(SlotText[quicksave - 1]) / 2, 90); - MN_DrTextA("?", 160 + + MN_DrTextA(DEH_String("?"), 160 + MN_TextAWidth(SlotText[quicksave - 1]) / 2, 90); } if (typeofask == 4) { MN_DrTextA(SlotText[quickload - 1], 160 - MN_TextAWidth(SlotText[quickload - 1]) / 2, 90); - MN_DrTextA("?", 160 + + MN_DrTextA(DEH_String("?"), 160 + MN_TextAWidth(SlotText[quickload - 1]) / 2, 90); } UpdateState |= I_FULLSCRN; @@ -706,11 +706,11 @@ static void DrawOptionsMenu(void) { if (messageson) { - MN_DrTextB("ON", 196, 50); + MN_DrTextB(DEH_String("ON"), 196, 50); } else { - MN_DrTextB("OFF", 196, 50); + MN_DrTextB(DEH_String("OFF"), 196, 50); } DrawSlider(&OptionsMenu, 3, 10, mouseSensitivity); } -- cgit v1.2.3 From 53ba7baf5191bb16ccfaa2aafd81f11cb210ecca Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 18 Apr 2010 14:51:28 +0000 Subject: Add deh_hhe_version variable to specify version of executable used to generate HHE patch. Refine DEH_MapHereticFrameNumber based on patch version. Subversion-branch: /branches/raven-branch Subversion-revision: 1895 --- src/heretic/deh_htic.c | 38 +++++++++++++++++++++++++++++--------- src/heretic/deh_htic.h | 13 +++++++++++++ 2 files changed, 42 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/heretic/deh_htic.c b/src/heretic/deh_htic.c index 59c426ef..ff5d02ac 100644 --- a/src/heretic/deh_htic.c +++ b/src/heretic/deh_htic.c @@ -27,6 +27,7 @@ #include #include "deh_defs.h" #include "deh_main.h" +#include "deh_htic.h" #include "info.h" char *deh_signatures[] = @@ -36,6 +37,10 @@ char *deh_signatures[] = NULL }; +// Version number for patches. + +deh_hhe_version_t deh_hhe_version = deh_hhe_1_0; + // deh_ammo.c: extern deh_section_t deh_section_ammo; // deh_frame.c: @@ -67,18 +72,33 @@ deh_section_t *deh_section_types[] = NULL }; -// HHE only worked with Heretic 1.0 and unfortunately was never updated -// to support Heretic 1.3. Between Heretic 1.0 and 1.3, two new frames -// were added to the "states" table, to extend the "flame death" -// animation displayed when the player is killed by fire. Therefore, -// we must map the HHE frame numbers (which assume a Heretic 1.0 frame -// table) to corresponding indexes for the Heretic 1.3 frame table. - int DEH_MapHereticFrameNumber(int frame) { - if (frame >= S_PLAY_FDTH19) + if (deh_hhe_version < deh_hhe_1_0) { - frame = (frame - S_PLAY_FDTH19) + S_BLOODYSKULL1; + // Between Heretic 1.0 and 1.2, two new frames + // were added to the "states" table, to extend the "flame death" + // animation displayed when the player is killed by fire. Therefore, + // we must map Heretic 1.0 frame numbers to corresponding indexes + // for our state table. + + if (frame >= S_PLAY_FDTH19) + { + frame = (frame - S_PLAY_FDTH19) + S_BLOODYSKULL1; + } + } + else + { + // After Heretic 1.2, three unused frames were removed from the + // states table, unused phoenix rod frames. Our state table includes + // these missing states for backwards compatibility. We must therefore + // adjust frame numbers for v1.2/v1.3 to corresponding indexes for + // our state table. + + if (frame >= S_PHOENIXFXIX_1) + { + frame = (frame - S_PHOENIXFXIX_1) + S_PHOENIXPUFF1; + } } return frame; diff --git a/src/heretic/deh_htic.h b/src/heretic/deh_htic.h index fefcf818..199ad2fe 100644 --- a/src/heretic/deh_htic.h +++ b/src/heretic/deh_htic.h @@ -29,6 +29,17 @@ #include "info.h" +// HHE executable version. Loading HHE patches is (unfortunately) +// dependent on the version of the Heretic executable used to make them. + +typedef enum +{ + deh_hhe_1_0, + deh_hhe_1_2, + deh_hhe_1_3, + deh_hhe_num_versions +} deh_hhe_version_t; + // HHE doesn't know about the last two states in the state table, so // these are considered invalid. @@ -41,5 +52,7 @@ int DEH_MapHereticFrameNumber(int frame); +extern deh_hhe_version_t deh_hhe_version; + #endif /* #ifndef DEH_HTIC_H */ -- cgit v1.2.3 From bc4a39b2fe3f0883a7826fa998de6ea9825efada Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 18 Apr 2010 14:52:43 +0000 Subject: Add new action pointer lookup table, and find offset based on patch executable version. Subversion-branch: /branches/raven-branch Subversion-revision: 1897 --- src/heretic/deh_frame.c | 270 ++++++++++++++++++++++++------------------------ 1 file changed, 136 insertions(+), 134 deletions(-) (limited to 'src') diff --git a/src/heretic/deh_frame.c b/src/heretic/deh_frame.c index 6ec62ae7..8d9a8fdf 100644 --- a/src/heretic/deh_frame.c +++ b/src/heretic/deh_frame.c @@ -38,141 +38,143 @@ #include "p_action.h" +typedef struct +{ + int offsets[deh_hhe_num_versions]; + void (*func)(); +} hhe_action_pointer_t; + // Offsets of action pointers within the Heretic 1.0 executable. // (Seriously Greg, was this really necessary? What was wrong with the // "copying action pointer from another frame" technique used in dehacked?) -static const struct -{ - int offset; - void (*func)(); -} action_ptrs[] = { - { 0, NULL }, - { 69200, A_Look }, - { 69328, A_Chase }, - { 69872, A_FaceTarget }, - { 69984, A_Pain }, - { 70016, A_DripBlood }, - { 70160, A_KnightAttack }, - { 70304, A_ImpExplode }, - { 70480, A_BeastPuff }, - { 70592, A_ImpMeAttack }, - { 70672, A_ImpMsAttack }, - { 70880, A_ImpMsAttack2 }, - { 70976, A_ImpDeath }, - { 71024, A_ImpXDeath1 }, - { 71072, A_ImpXDeath2 }, - { 71376, A_ChicAttack }, - { 71456, A_ChicLook }, - { 71488, A_ChicChase }, - { 71520, A_ChicPain }, - { 71568, A_Feathers }, - { 71808, A_MummyAttack }, - { 71920, A_MummyAttack2 }, - { 72016, A_MummyFX1Seek }, - { 72048, A_MummySoul }, - { 72096, A_Sor1Pain }, - { 72144, A_Sor1Chase }, - { 72192, A_Srcr1Attack }, - { 72480, A_SorcererRise }, - { 72816, A_Srcr2Decide }, - { 72896, A_Srcr2Attack }, - { 73120, A_BlueSpark }, - { 73232, A_GenWizard }, - { 73392, A_Sor2DthInit }, - { 73424, A_Sor2DthLoop }, - { 73456, A_SorZap }, - { 73488, A_SorRise }, - { 73520, A_SorDSph }, - { 73552, A_SorDExp }, - { 73584, A_SorDBon }, - { 73616, A_SorSightSnd }, - { 73648, A_MinotaurAtk1 }, - { 73760, A_MinotaurDecide }, - { 74032, A_MinotaurCharge }, - { 74112, A_MinotaurAtk2 }, - { 74352, A_MinotaurAtk3 }, - { 74528, A_MntrFloorFire }, - { 74640, A_BeastAttack }, - { 74752, A_HeadAttack }, - { 75168, A_WhirlwindSeek }, - { 75328, A_HeadIceImpact }, - { 75488, A_HeadFireGrow }, - { 75632, A_SnakeAttack }, - { 75712, A_SnakeAttack2 }, - { 75792, A_ClinkAttack }, - { 75872, A_GhostOff }, - { 75888, A_WizAtk1 }, - { 75920, A_WizAtk2 }, - { 75952, A_WizAtk3 }, - { 76144, A_Scream }, - { 76400, A_NoBlocking }, - { 76784, A_Explode }, - { 76896, A_PodPain }, - { 77056, A_RemovePod }, - { 77104, A_MakePod }, - { 77344, A_BossDeath }, - { 77472, A_ESound }, - { 77520, A_SpawnTeleGlitter }, - { 77600, A_SpawnTeleGlitter2 }, - { 77680, A_AccTeleGlitter }, - { 77728, A_InitKeyGizmo }, - { 77824, A_VolcanoSet }, - { 77856, A_VolcanoBlast }, - { 78080, A_VolcBallImpact }, - { 78288, A_SkullPop }, - { 78448, A_CheckSkullFloor }, - { 78480, A_CheckSkullDone }, - { 78512, A_FreeTargMobj }, - { 78608, A_AddPlayerCorpse }, - { 78704, A_FlameSnd }, - { 78736, A_HideThing }, - { 78752, A_UnHideThing }, - { 81952, A_RestoreArtifact }, - { 82048, A_RestoreSpecialThing1 }, - { 82128, A_RestoreSpecialThing2 }, - { 108432, A_ContMobjSound }, - { 111168, A_WeaponReady }, - { 111568, A_BeakReady }, - { 111696, A_ReFire }, - { 111760, A_Lower }, - { 111856, A_BeakRaise }, - { 111920, A_Raise }, - { 112272, A_BeakAttackPL1 }, - { 112448, A_BeakAttackPL2 }, - { 112640, A_StaffAttackPL1 }, - { 112784, A_StaffAttackPL2 }, - { 112928, A_FireBlasterPL1 }, - { 113072, A_FireBlasterPL2 }, - { 113152, A_FireGoldWandPL1 }, - { 113296, A_FireGoldWandPL2 }, - { 113760, A_FireMacePL1 }, - { 113904, A_MacePL1Check }, - { 114032, A_MaceBallImpact }, - { 114192, A_MaceBallImpact2 }, - { 114624, A_FireMacePL2 }, - { 114752, A_DeathBallImpact }, - { 115088, A_SpawnRippers }, - { 115232, A_FireCrossbowPL1 }, - { 115312, A_FireCrossbowPL2 }, - { 115456, A_BoltSpark }, - { 115568, A_FireSkullRodPL1 }, - { 115648, A_FireSkullRodPL2 }, - { 115776, A_SkullRodPL2Seek }, - { 115808, A_AddPlayerRain }, - { 115984, A_SkullRodStorm }, - { 116272, A_RainImpact }, - { 116336, A_HideInCeiling }, - { 116368, A_FirePhoenixPL1 }, - { 116480, A_RemovedPhoenixFunc }, - { 116496, A_PhoenixPuff }, - { 116720, A_InitPhoenixPL2 }, - { 116736, A_FirePhoenixPL2 }, - { 117104, A_ShutdownPhoenixPL2 }, - { 117120, A_FlameEnd }, - { 117152, A_FloatPuff }, - { 117184, A_GauntletAttack }, - { 117648, A_Light0 } +static hhe_action_pointer_t action_pointers[] = { + { { 77680, 80144, 80208 }, A_AccTeleGlitter }, + { { 78608, 81104, 81168 }, A_AddPlayerCorpse }, + { { 115808, 118000, 118240 }, A_AddPlayerRain }, + { { 112272, 114480, 114720 }, A_BeakAttackPL1 }, + { { 112448, 114656, 114896 }, A_BeakAttackPL2 }, + { { 111856, 114176, 114416 }, A_BeakRaise }, + { { 111568, 113888, 114128 }, A_BeakReady }, + { { 74640, 77120, 77184 }, A_BeastAttack }, + { { 70480, 72992, 73056 }, A_BeastPuff }, + { { 73120, 75600, 75664 }, A_BlueSpark }, + { { 115456, 117648, 117888 }, A_BoltSpark }, + { { 77344, 79808, 79872 }, A_BossDeath }, + { { 69328, 71856, 71920 }, A_Chase }, + { { 0, 80976, 81040 }, A_CheckBurnGone }, + { { 78480, 80944, 81008 }, A_CheckSkullDone }, + { { 78448, 80912, 80976 }, A_CheckSkullFloor }, + { { 71376, 73888, 73952 }, A_ChicAttack }, + { { 71488, 74000, 74064 }, A_ChicChase }, + { { 71456, 73968, 74032 }, A_ChicLook }, + { { 71520, 74032, 74096 }, A_ChicPain }, + { { 75792, 78208, 78272 }, A_ClinkAttack }, + { { 108432, 110816, 111056 }, A_ContMobjSound }, + { { 114752, 116944, 117184 }, A_DeathBallImpact }, + { { 70016, 72528, 72592 }, A_DripBlood }, + { { 77472, 79936, 80000 }, A_ESound }, + { { 76784, 79248, 79312 }, A_Explode }, + { { 69872, 72400, 72464 }, A_FaceTarget }, + { { 71568, 74080, 74144 }, A_Feathers }, + { { 112928, 115136, 115376 }, A_FireBlasterPL1 }, + { { 113072, 115280, 115520 }, A_FireBlasterPL2 }, + { { 115232, 117424, 117664 }, A_FireCrossbowPL1 }, + { { 115312, 117504, 117744 }, A_FireCrossbowPL2 }, + { { 113152, 115360, 115600 }, A_FireGoldWandPL1 }, + { { 113296, 115504, 115744 }, A_FireGoldWandPL2 }, + { { 113760, 115968, 116208 }, A_FireMacePL1 }, + { { 114624, 116816, 117056 }, A_FireMacePL2 }, + { { 116368, 118544, 118784 }, A_FirePhoenixPL1 }, + { { 116736, 118896, 119136 }, A_FirePhoenixPL2 }, + { { 115568, 117760, 118000 }, A_FireSkullRodPL1 }, + { { 115648, 117840, 118080 }, A_FireSkullRodPL2 }, + { { 117120, 119280, 119520 }, A_FlameEnd }, + { { 78704, 81200, 81264 }, A_FlameSnd }, + { { 117152, 119312, 119552 }, A_FloatPuff }, + { { 78512, 81008, 81072 }, A_FreeTargMobj }, + { { 117184, 119344, 119584 }, A_GauntletAttack }, + { { 73232, 75712, 75776 }, A_GenWizard }, + { { 75872, 78304, 78368 }, A_GhostOff }, + { { 74752, 77232, 77296 }, A_HeadAttack }, + { { 75488, 77984, 78048 }, A_HeadFireGrow }, + { { 75328, 77824, 77888 }, A_HeadIceImpact }, + { { 116336, 118512, 118752 }, A_HideInCeiling }, + { { 78736, 81232, 81296 }, A_HideThing }, + { { 70976, 73488, 73552 }, A_ImpDeath }, + { { 70304, 72816, 72880 }, A_ImpExplode }, + { { 70592, 73104, 73168 }, A_ImpMeAttack }, + { { 70672, 73184, 73248 }, A_ImpMsAttack }, + { { 70880, 73392, 73456 }, A_ImpMsAttack2 }, + { { 71024, 73536, 73600 }, A_ImpXDeath1 }, + { { 71072, 73584, 73648 }, A_ImpXDeath2 }, + { { 77728, 80192, 80256 }, A_InitKeyGizmo }, + { { 116720, 118880, 119120 }, A_InitPhoenixPL2 }, + { { 70160, 72672, 72736 }, A_KnightAttack }, + { { 117648, 119824, 120064 }, A_Light0 }, + { { 69200, 71728, 71792 }, A_Look }, + { { 111760, 114080, 114320 }, A_Lower }, + { { 114032, 116224, 116464 }, A_MaceBallImpact }, + { { 114192, 116384, 116624 }, A_MaceBallImpact2 }, + { { 113904, 116112, 116352 }, A_MacePL1Check }, + { { 77104, 79568, 79632 }, A_MakePod }, + { { 73648, 76128, 76192 }, A_MinotaurAtk1 }, + { { 74112, 76592, 76656 }, A_MinotaurAtk2 }, + { { 74352, 76832, 76896 }, A_MinotaurAtk3 }, + { { 74032, 76512, 76576 }, A_MinotaurCharge }, + { { 73760, 76240, 76304 }, A_MinotaurDecide }, + { { 74528, 77008, 77072 }, A_MntrFloorFire }, + { { 71808, 74288, 74352 }, A_MummyAttack }, + { { 71920, 74400, 74464 }, A_MummyAttack2 }, + { { 72016, 74496, 74560 }, A_MummyFX1Seek }, + { { 72048, 74528, 74592 }, A_MummySoul }, + { { 76400, 78832, 78896 }, A_NoBlocking }, + { { 69984, 72496, 72560 }, A_Pain }, + { { 116496, 118656, 118896 }, A_PhoenixPuff }, + { { 76896, 79360, 79424 }, A_PodPain }, + { { 116272, 118448, 118688 }, A_RainImpact }, + { { 111920, 114240, 114480 }, A_Raise }, + { { 111696, 114016, 114256 }, A_ReFire }, + { { 77056, 79520, 79584 }, A_RemovePod }, + { { 116480, 0, 0 }, A_RemovedPhoenixFunc }, + { { 81952, 84464, 84528 }, A_RestoreArtifact }, + { { 82048, 84544, 84608 }, A_RestoreSpecialThing1 }, + { { 82128, 84592, 84656 }, A_RestoreSpecialThing2 }, + { { 76144, 78576, 78640 }, A_Scream }, + { { 117104, 119264, 119504 }, A_ShutdownPhoenixPL2 }, + { { 78288, 80752, 80816 }, A_SkullPop }, + { { 115776, 117968, 118208 }, A_SkullRodPL2Seek }, + { { 115984, 118176, 118416 }, A_SkullRodStorm }, + { { 75632, 78048, 78112 }, A_SnakeAttack }, + { { 75712, 78128, 78192 }, A_SnakeAttack2 }, + { { 72144, 74624, 74688 }, A_Sor1Chase }, + { { 72096, 74576, 74640 }, A_Sor1Pain }, + { { 73392, 75872, 75936 }, A_Sor2DthInit }, + { { 73424, 75904, 75968 }, A_Sor2DthLoop }, + { { 73584, 76064, 76128 }, A_SorDBon }, + { { 73552, 76032, 76096 }, A_SorDExp }, + { { 73520, 76000, 76064 }, A_SorDSph }, + { { 73488, 75968, 76032 }, A_SorRise }, + { { 73616, 76096, 76160 }, A_SorSightSnd }, + { { 73456, 75936, 76000 }, A_SorZap }, + { { 72480, 74960, 75024 }, A_SorcererRise }, + { { 115088, 117280, 117520 }, A_SpawnRippers }, + { { 77520, 79984, 80048 }, A_SpawnTeleGlitter }, + { { 77600, 80064, 80128 }, A_SpawnTeleGlitter2 }, + { { 72192, 74672, 74736 }, A_Srcr1Attack }, + { { 72896, 75376, 75440 }, A_Srcr2Attack }, + { { 72816, 75296, 75360 }, A_Srcr2Decide }, + { { 112640, 114848, 115088 }, A_StaffAttackPL1 }, + { { 112784, 114992, 115232 }, A_StaffAttackPL2 }, + { { 78752, 81248, 81312 }, A_UnHideThing }, + { { 78080, 80544, 80608 }, A_VolcBallImpact }, + { { 77856, 80320, 80384 }, A_VolcanoBlast }, + { { 77824, 80288, 80352 }, A_VolcanoSet }, + { { 111168, 113488, 113728 }, A_WeaponReady }, + { { 75168, 77664, 77728 }, A_WhirlwindSeek }, + { { 75888, 78320, 78384 }, A_WizAtk1 }, + { { 75920, 78352, 78416 }, A_WizAtk2 }, + { { 75952, 78384, 78448 }, A_WizAtk3 }, }; DEH_BEGIN_MAPPING(state_mapping, state_t) @@ -229,11 +231,11 @@ static boolean GetActionPointerForOffset(int offset, void **result) { int i; - for (i=0; i= 0; ++i) + { + if ((unsigned int) string_list[i] == offset) + { + return true; + } + } + + return false; +} + static boolean GetStringByOffset(unsigned int offset, char **result) { int i; - for (i=0; ikeys[key_blue]) { - P_SetMessage(player, TXT_NEEDBLUEKEY, false); + P_SetMessage(player, DEH_String(TXT_NEEDBLUEKEY), false); S_StartSound(NULL, sfx_plroof); return; } @@ -245,7 +246,7 @@ void EV_VerticalDoor(line_t * line, mobj_t * thing) } if (!player->keys[key_yellow]) { - P_SetMessage(player, TXT_NEEDYELLOWKEY, false); + P_SetMessage(player, DEH_String(TXT_NEEDYELLOWKEY), false); S_StartSound(NULL, sfx_plroof); return; } @@ -258,7 +259,7 @@ void EV_VerticalDoor(line_t * line, mobj_t * thing) } if (!player->keys[key_green]) { - P_SetMessage(player, TXT_NEEDGREENKEY, false); + P_SetMessage(player, DEH_String(TXT_NEEDGREENKEY), false); S_StartSound(NULL, sfx_plroof); return; } diff --git a/src/heretic/p_inter.c b/src/heretic/p_inter.c index 3587a95d..afdb37f2 100644 --- a/src/heretic/p_inter.c +++ b/src/heretic/p_inter.c @@ -25,6 +25,7 @@ // P_inter.c #include "doomdef.h" +#include "deh_str.h" #include "i_system.h" #include "i_timer.h" #include "m_random.h" @@ -580,21 +581,21 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher) { return; } - P_SetMessage(player, TXT_ITEMHEALTH, false); + P_SetMessage(player, DEH_String(TXT_ITEMHEALTH), false); break; case SPR_SHLD: // Item_Shield1 if (!P_GiveArmor(player, 1)) { return; } - P_SetMessage(player, TXT_ITEMSHIELD1, false); + P_SetMessage(player, DEH_String(TXT_ITEMSHIELD1), false); break; case SPR_SHD2: // Item_Shield2 if (!P_GiveArmor(player, 2)) { return; } - P_SetMessage(player, TXT_ITEMSHIELD2, false); + P_SetMessage(player, DEH_String(TXT_ITEMSHIELD2), false); break; case SPR_BAGH: // Item_BagOfHolding if (!player->backpack) @@ -610,21 +611,21 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher) P_GiveAmmo(player, am_crossbow, AMMO_CBOW_WIMPY); P_GiveAmmo(player, am_skullrod, AMMO_SKRD_WIMPY); P_GiveAmmo(player, am_phoenixrod, AMMO_PHRD_WIMPY); - P_SetMessage(player, TXT_ITEMBAGOFHOLDING, false); + P_SetMessage(player, DEH_String(TXT_ITEMBAGOFHOLDING), false); break; case SPR_SPMP: // Item_SuperMap if (!P_GivePower(player, pw_allmap)) { return; } - P_SetMessage(player, TXT_ITEMSUPERMAP, false); + P_SetMessage(player, DEH_String(TXT_ITEMSUPERMAP), false); break; // Keys case SPR_BKYY: // Key_Blue if (!player->keys[key_blue]) { - P_SetMessage(player, TXT_GOTBLUEKEY, false); + P_SetMessage(player, DEH_String(TXT_GOTBLUEKEY), false); } P_GiveKey(player, key_blue); sound = sfx_keyup; @@ -636,7 +637,7 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher) case SPR_CKYY: // Key_Yellow if (!player->keys[key_yellow]) { - P_SetMessage(player, TXT_GOTYELLOWKEY, false); + P_SetMessage(player, DEH_String(TXT_GOTYELLOWKEY), false); } sound = sfx_keyup; P_GiveKey(player, key_yellow); @@ -648,7 +649,7 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher) case SPR_AKYY: // Key_Green if (!player->keys[key_green]) { - P_SetMessage(player, TXT_GOTGREENKEY, false); + P_SetMessage(player, DEH_String(TXT_GOTGREENKEY), false); } sound = sfx_keyup; P_GiveKey(player, key_green); @@ -662,70 +663,70 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher) case SPR_PTN2: // Arti_HealingPotion if (P_GiveArtifact(player, arti_health, special)) { - P_SetMessage(player, TXT_ARTIHEALTH, false); + P_SetMessage(player, DEH_String(TXT_ARTIHEALTH), false); P_SetDormantArtifact(special); } return; case SPR_SOAR: // Arti_Fly if (P_GiveArtifact(player, arti_fly, special)) { - P_SetMessage(player, TXT_ARTIFLY, false); + P_SetMessage(player, DEH_String(TXT_ARTIFLY), false); P_SetDormantArtifact(special); } return; case SPR_INVU: // Arti_Invulnerability if (P_GiveArtifact(player, arti_invulnerability, special)) { - P_SetMessage(player, TXT_ARTIINVULNERABILITY, false); + P_SetMessage(player, DEH_String(TXT_ARTIINVULNERABILITY), false); P_SetDormantArtifact(special); } return; case SPR_PWBK: // Arti_TomeOfPower if (P_GiveArtifact(player, arti_tomeofpower, special)) { - P_SetMessage(player, TXT_ARTITOMEOFPOWER, false); + P_SetMessage(player, DEH_String(TXT_ARTITOMEOFPOWER), false); P_SetDormantArtifact(special); } return; case SPR_INVS: // Arti_Invisibility if (P_GiveArtifact(player, arti_invisibility, special)) { - P_SetMessage(player, TXT_ARTIINVISIBILITY, false); + P_SetMessage(player, DEH_String(TXT_ARTIINVISIBILITY), false); P_SetDormantArtifact(special); } return; case SPR_EGGC: // Arti_Egg if (P_GiveArtifact(player, arti_egg, special)) { - P_SetMessage(player, TXT_ARTIEGG, false); + P_SetMessage(player, DEH_String(TXT_ARTIEGG), false); P_SetDormantArtifact(special); } return; case SPR_SPHL: // Arti_SuperHealth if (P_GiveArtifact(player, arti_superhealth, special)) { - P_SetMessage(player, TXT_ARTISUPERHEALTH, false); + P_SetMessage(player, DEH_String(TXT_ARTISUPERHEALTH), false); P_SetDormantArtifact(special); } return; case SPR_TRCH: // Arti_Torch if (P_GiveArtifact(player, arti_torch, special)) { - P_SetMessage(player, TXT_ARTITORCH, false); + P_SetMessage(player, DEH_String(TXT_ARTITORCH), false); P_SetDormantArtifact(special); } return; case SPR_FBMB: // Arti_FireBomb if (P_GiveArtifact(player, arti_firebomb, special)) { - P_SetMessage(player, TXT_ARTIFIREBOMB, false); + P_SetMessage(player, DEH_String(TXT_ARTIFIREBOMB), false); P_SetDormantArtifact(special); } return; case SPR_ATLP: // Arti_Teleport if (P_GiveArtifact(player, arti_teleport, special)) { - P_SetMessage(player, TXT_ARTITELEPORT, false); + P_SetMessage(player, DEH_String(TXT_ARTITELEPORT), false); P_SetDormantArtifact(special); } return; @@ -736,84 +737,84 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher) { return; } - P_SetMessage(player, TXT_AMMOGOLDWAND1, false); + P_SetMessage(player, DEH_String(TXT_AMMOGOLDWAND1), false); break; case SPR_AMG2: // Ammo_GoldWandHefty if (!P_GiveAmmo(player, am_goldwand, special->health)) { return; } - P_SetMessage(player, TXT_AMMOGOLDWAND2, false); + P_SetMessage(player, DEH_String(TXT_AMMOGOLDWAND2), false); break; case SPR_AMM1: // Ammo_MaceWimpy if (!P_GiveAmmo(player, am_mace, special->health)) { return; } - P_SetMessage(player, TXT_AMMOMACE1, false); + P_SetMessage(player, DEH_String(TXT_AMMOMACE1), false); break; case SPR_AMM2: // Ammo_MaceHefty if (!P_GiveAmmo(player, am_mace, special->health)) { return; } - P_SetMessage(player, TXT_AMMOMACE2, false); + P_SetMessage(player, DEH_String(TXT_AMMOMACE2), false); break; case SPR_AMC1: // Ammo_CrossbowWimpy if (!P_GiveAmmo(player, am_crossbow, special->health)) { return; } - P_SetMessage(player, TXT_AMMOCROSSBOW1, false); + P_SetMessage(player, DEH_String(TXT_AMMOCROSSBOW1), false); break; case SPR_AMC2: // Ammo_CrossbowHefty if (!P_GiveAmmo(player, am_crossbow, special->health)) { return; } - P_SetMessage(player, TXT_AMMOCROSSBOW2, false); + P_SetMessage(player, DEH_String(TXT_AMMOCROSSBOW2), false); break; case SPR_AMB1: // Ammo_BlasterWimpy if (!P_GiveAmmo(player, am_blaster, special->health)) { return; } - P_SetMessage(player, TXT_AMMOBLASTER1, false); + P_SetMessage(player, DEH_String(TXT_AMMOBLASTER1), false); break; case SPR_AMB2: // Ammo_BlasterHefty if (!P_GiveAmmo(player, am_blaster, special->health)) { return; } - P_SetMessage(player, TXT_AMMOBLASTER2, false); + P_SetMessage(player, DEH_String(TXT_AMMOBLASTER2), false); break; case SPR_AMS1: // Ammo_SkullRodWimpy if (!P_GiveAmmo(player, am_skullrod, special->health)) { return; } - P_SetMessage(player, TXT_AMMOSKULLROD1, false); + P_SetMessage(player, DEH_String(TXT_AMMOSKULLROD1), false); break; case SPR_AMS2: // Ammo_SkullRodHefty if (!P_GiveAmmo(player, am_skullrod, special->health)) { return; } - P_SetMessage(player, TXT_AMMOSKULLROD2, false); + P_SetMessage(player, DEH_String(TXT_AMMOSKULLROD2), false); break; case SPR_AMP1: // Ammo_PhoenixRodWimpy if (!P_GiveAmmo(player, am_phoenixrod, special->health)) { return; } - P_SetMessage(player, TXT_AMMOPHOENIXROD1, false); + P_SetMessage(player, DEH_String(TXT_AMMOPHOENIXROD1), false); break; case SPR_AMP2: // Ammo_PhoenixRodHefty if (!P_GiveAmmo(player, am_phoenixrod, special->health)) { return; } - P_SetMessage(player, TXT_AMMOPHOENIXROD2, false); + P_SetMessage(player, DEH_String(TXT_AMMOPHOENIXROD2), false); break; // Weapons @@ -822,7 +823,7 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher) { return; } - P_SetMessage(player, TXT_WPNMACE, false); + P_SetMessage(player, DEH_String(TXT_WPNMACE), false); sound = sfx_wpnup; break; case SPR_WBOW: // Weapon_Crossbow @@ -830,7 +831,7 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher) { return; } - P_SetMessage(player, TXT_WPNCROSSBOW, false); + P_SetMessage(player, DEH_String(TXT_WPNCROSSBOW), false); sound = sfx_wpnup; break; case SPR_WBLS: // Weapon_Blaster @@ -838,7 +839,7 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher) { return; } - P_SetMessage(player, TXT_WPNBLASTER, false); + P_SetMessage(player, DEH_String(TXT_WPNBLASTER), false); sound = sfx_wpnup; break; case SPR_WSKL: // Weapon_SkullRod @@ -846,7 +847,7 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher) { return; } - P_SetMessage(player, TXT_WPNSKULLROD, false); + P_SetMessage(player, DEH_String(TXT_WPNSKULLROD), false); sound = sfx_wpnup; break; case SPR_WPHX: // Weapon_PhoenixRod @@ -854,7 +855,7 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher) { return; } - P_SetMessage(player, TXT_WPNPHOENIXROD, false); + P_SetMessage(player, DEH_String(TXT_WPNPHOENIXROD), false); sound = sfx_wpnup; break; case SPR_WGNT: // Weapon_Gauntlets @@ -862,7 +863,7 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher) { return; } - P_SetMessage(player, TXT_WPNGAUNTLETS, false); + P_SetMessage(player, DEH_String(TXT_WPNGAUNTLETS), false); sound = sfx_wpnup; break; default: diff --git a/src/heretic/sb_bar.c b/src/heretic/sb_bar.c index 3a90c000..51bd3b9c 100644 --- a/src/heretic/sb_bar.c +++ b/src/heretic/sb_bar.c @@ -1055,11 +1055,11 @@ static void CheatGodFunc(player_t * player, Cheat_t * cheat) player->cheats ^= CF_GODMODE; if (player->cheats & CF_GODMODE) { - P_SetMessage(player, TXT_CHEATGODON, false); + P_SetMessage(player, DEH_String(TXT_CHEATGODON), false); } else { - P_SetMessage(player, TXT_CHEATGODOFF, false); + P_SetMessage(player, DEH_String(TXT_CHEATGODOFF), false); } SB_state = -1; } @@ -1069,11 +1069,11 @@ static void CheatNoClipFunc(player_t * player, Cheat_t * cheat) player->cheats ^= CF_NOCLIP; if (player->cheats & CF_NOCLIP) { - P_SetMessage(player, TXT_CHEATNOCLIPON, false); + P_SetMessage(player, DEH_String(TXT_CHEATNOCLIPON), false); } else { - P_SetMessage(player, TXT_CHEATNOCLIPOFF, false); + P_SetMessage(player, DEH_String(TXT_CHEATNOCLIPOFF), false); } } @@ -1106,7 +1106,7 @@ static void CheatWeaponsFunc(player_t * player, Cheat_t * cheat) { player->ammo[i] = player->maxammo[i]; } - P_SetMessage(player, TXT_CHEATWEAPONS, false); + P_SetMessage(player, DEH_String(TXT_CHEATWEAPONS), false); } static void CheatPowerFunc(player_t * player, Cheat_t * cheat) @@ -1114,12 +1114,12 @@ static void CheatPowerFunc(player_t * player, Cheat_t * cheat) if (player->powers[pw_weaponlevel2]) { player->powers[pw_weaponlevel2] = 0; - P_SetMessage(player, TXT_CHEATPOWEROFF, false); + P_SetMessage(player, DEH_String(TXT_CHEATPOWEROFF), false); } else { P_UseArtifact(player, arti_tomeofpower); - P_SetMessage(player, TXT_CHEATPOWERON, false); + P_SetMessage(player, DEH_String(TXT_CHEATPOWERON), false); } } @@ -1133,7 +1133,7 @@ static void CheatHealthFunc(player_t * player, Cheat_t * cheat) { player->health = player->mo->health = MAXHEALTH; } - P_SetMessage(player, TXT_CHEATHEALTH, false); + P_SetMessage(player, DEH_String(TXT_CHEATHEALTH), false); } static void CheatKeysFunc(player_t * player, Cheat_t * cheat) @@ -1144,7 +1144,7 @@ static void CheatKeysFunc(player_t * player, Cheat_t * cheat) player->keys[key_green] = true; player->keys[key_blue] = true; playerkeys = 7; // Key refresh flags - P_SetMessage(player, TXT_CHEATKEYS, false); + P_SetMessage(player, DEH_String(TXT_CHEATKEYS), false); } static void CheatSoundFunc(player_t * player, Cheat_t * cheat) @@ -1152,11 +1152,11 @@ static void CheatSoundFunc(player_t * player, Cheat_t * cheat) DebugSound = !DebugSound; if (DebugSound) { - P_SetMessage(player, TXT_CHEATSOUNDON, false); + P_SetMessage(player, DEH_String(TXT_CHEATSOUNDON), false); } else { - P_SetMessage(player, TXT_CHEATSOUNDOFF, false); + P_SetMessage(player, DEH_String(TXT_CHEATSOUNDOFF), false); } } @@ -1165,11 +1165,11 @@ static void CheatTickerFunc(player_t * player, Cheat_t * cheat) DisplayTicker = !DisplayTicker; if (DisplayTicker) { - P_SetMessage(player, TXT_CHEATTICKERON, false); + P_SetMessage(player, DEH_String(TXT_CHEATTICKERON), false); } else { - P_SetMessage(player, TXT_CHEATTICKEROFF, false); + P_SetMessage(player, DEH_String(TXT_CHEATTICKEROFF), false); } I_DisplayFPSDots(DisplayTicker); @@ -1177,12 +1177,12 @@ static void CheatTickerFunc(player_t * player, Cheat_t * cheat) static void CheatArtifact1Func(player_t * player, Cheat_t * cheat) { - P_SetMessage(player, TXT_CHEATARTIFACTS1, false); + P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTS1), false); } static void CheatArtifact2Func(player_t * player, Cheat_t * cheat) { - P_SetMessage(player, TXT_CHEATARTIFACTS2, false); + P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTS2), false); } static void CheatArtifact3Func(player_t * player, Cheat_t * cheat) @@ -1210,7 +1210,7 @@ static void CheatArtifact3Func(player_t * player, Cheat_t * cheat) P_GiveArtifact(player, i, NULL); } } - P_SetMessage(player, TXT_CHEATARTIFACTS3, false); + P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTS3), false); } else if (type > arti_none && type < NUMARTIFACTS && count > 0 && count < 10) @@ -1218,18 +1218,18 @@ static void CheatArtifact3Func(player_t * player, Cheat_t * cheat) if (gamemode == shareware && (type == arti_superhealth || type == arti_teleport)) { - P_SetMessage(player, TXT_CHEATARTIFACTSFAIL, false); + P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTSFAIL), false); return; } for (i = 0; i < count; i++) { P_GiveArtifact(player, type, NULL); } - P_SetMessage(player, TXT_CHEATARTIFACTS3, false); + P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTS3), false); } else { // Bad input - P_SetMessage(player, TXT_CHEATARTIFACTSFAIL, false); + P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTSFAIL), false); } } @@ -1246,7 +1246,7 @@ static void CheatWarpFunc(player_t * player, Cheat_t * cheat) if (D_ValidEpisodeMap(gamemission, gamemode, episode, map)) { G_DeferedInitNew(gameskill, episode, map); - P_SetMessage(player, TXT_CHEATWARP, false); + P_SetMessage(player, DEH_String(TXT_CHEATWARP), false); } } @@ -1258,19 +1258,19 @@ static void CheatChickenFunc(player_t * player, Cheat_t * cheat) { if (P_UndoPlayerChicken(player)) { - P_SetMessage(player, TXT_CHEATCHICKENOFF, false); + P_SetMessage(player, DEH_String(TXT_CHEATCHICKENOFF), false); } } else if (P_ChickenMorphPlayer(player)) { - P_SetMessage(player, TXT_CHEATCHICKENON, false); + P_SetMessage(player, DEH_String(TXT_CHEATCHICKENON), false); } } static void CheatMassacreFunc(player_t * player, Cheat_t * cheat) { P_Massacre(); - P_SetMessage(player, TXT_CHEATMASSACRE, false); + P_SetMessage(player, DEH_String(TXT_CHEATMASSACRE), false); } static void CheatIDKFAFunc(player_t * player, Cheat_t * cheat) @@ -1285,11 +1285,11 @@ static void CheatIDKFAFunc(player_t * player, Cheat_t * cheat) player->weaponowned[i] = false; } player->pendingweapon = wp_staff; - P_SetMessage(player, TXT_CHEATIDKFA, true); + P_SetMessage(player, DEH_String(TXT_CHEATIDKFA), true); } static void CheatIDDQDFunc(player_t * player, Cheat_t * cheat) { P_DamageMobj(player->mo, NULL, player->mo, 10000); - P_SetMessage(player, TXT_CHEATIDDQD, true); + P_SetMessage(player, DEH_String(TXT_CHEATIDDQD), true); } -- cgit v1.2.3 From 8069d8a0fdf30516cb6eff6d6a9e2990061f95c1 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 18 Apr 2010 16:40:14 +0000 Subject: Add -hhever command line parameter to select patch version number. Subversion-branch: /branches/raven-branch Subversion-revision: 1902 --- src/heretic/deh_frame.c | 11 ++------ src/heretic/deh_htic.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++- src/heretic/deh_htic.h | 1 + 3 files changed, 69 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/heretic/deh_frame.c b/src/heretic/deh_frame.c index 8d9a8fdf..6d7f6c3b 100644 --- a/src/heretic/deh_frame.c +++ b/src/heretic/deh_frame.c @@ -186,17 +186,10 @@ DEH_BEGIN_MAPPING(state_mapping, state_t) DEH_MAPPING("Unknown 2", misc2) DEH_END_MAPPING -// When a HHE patch is first loaded, we must apply a small change -// to the states[] table. The table was changed between 1.0 and -// 1.3 to add two extra frames to the player "burning death" -// animation. -// If we are using an HHE patch, the table must behave like the -// Heretic 1.0 table. We must therefore change the table to cut -// these out again. - static void DEH_FrameInit(void) { - states[S_PLAY_FDTH18].nextstate = S_NULL; + // Bit of a hack here: + DEH_HereticInit(); } static void *DEH_FrameStart(deh_context_t *context, char *line) diff --git a/src/heretic/deh_htic.c b/src/heretic/deh_htic.c index ff5d02ac..40fa5765 100644 --- a/src/heretic/deh_htic.c +++ b/src/heretic/deh_htic.c @@ -24,11 +24,15 @@ // //----------------------------------------------------------------------------- +#include #include +#include + #include "deh_defs.h" #include "deh_main.h" #include "deh_htic.h" #include "info.h" +#include "m_argv.h" char *deh_signatures[] = { @@ -37,6 +41,11 @@ char *deh_signatures[] = NULL }; +static char *hhe_versions[] = +{ + "1.0", "1.2", "1.3" +}; + // Version number for patches. deh_hhe_version_t deh_hhe_version = deh_hhe_1_0; @@ -72,9 +81,65 @@ deh_section_t *deh_section_types[] = NULL }; +static void SetHHEVersionByName(char *name) +{ + int i; + + for (i=0; i + // + // Select the Heretic version number that was used to generate the + // HHE patch to be loaded. Patches for each of the Vanilla + // Heretic versions (1.0, 1.2, 1.3) can be loaded, but the correct + // version number must be specified. + + i = M_CheckParm("-hhever"); + + if (i > 0) + { + SetHHEVersionByName(myargv[i + 1]); + } + + // For v1.0 patches, we must apply a slight change to the states[] + // table. The table was changed between 1.0 and 1.3 to add two extra + // frames to the player "burning death" animation. + // + // If we are using a v1.0 patch, we must change the table to cut + // these out again. + + if (deh_hhe_version < deh_hhe_1_2) + { + states[S_PLAY_FDTH18].nextstate = S_NULL; + } +} + int DEH_MapHereticFrameNumber(int frame) { - if (deh_hhe_version < deh_hhe_1_0) + if (deh_hhe_version < deh_hhe_1_2) { // Between Heretic 1.0 and 1.2, two new frames // were added to the "states" table, to extend the "flame death" diff --git a/src/heretic/deh_htic.h b/src/heretic/deh_htic.h index 199ad2fe..f006c149 100644 --- a/src/heretic/deh_htic.h +++ b/src/heretic/deh_htic.h @@ -50,6 +50,7 @@ typedef enum #define DEH_HERETIC_NUMMOBJTYPES (NUMMOBJTYPES - 2) +void DEH_HereticInit(void); int DEH_MapHereticFrameNumber(int frame); extern deh_hhe_version_t deh_hhe_version; -- cgit v1.2.3 From 38c31575d255e1b2ff71f9de2c4d16664e8fb1e9 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 18 Apr 2010 17:15:20 +0000 Subject: Add WAD merging command line options to Heretic. Subversion-branch: /branches/raven-branch Subversion-revision: 1903 --- src/heretic/d_main.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) (limited to 'src') diff --git a/src/heretic/d_main.c b/src/heretic/d_main.c index 52e4239f..5fa2d5f9 100644 --- a/src/heretic/d_main.c +++ b/src/heretic/d_main.c @@ -46,6 +46,7 @@ #include "m_controls.h" #include "p_local.h" #include "s_sound.h" +#include "w_merge.h" #include "v_video.h" #define STARTUP_WINDOW_X 17 @@ -908,6 +909,132 @@ void D_DoomMain(void) D_AddFile(iwadfile); +#ifdef FEATURE_WAD_MERGE + + // Merged PWADs are loaded first, because they are supposed to be + // modified IWADs. + + //! + // @arg + // @category mod + // + // Simulates the behavior of deutex's -merge option, merging a PWAD + // into the main IWAD. Multiple files may be specified. + // + + p = M_CheckParm("-merge"); + + if (p > 0) + { + for (p = p + 1; p + // @category mod + // + // Simulates the behavior of NWT's -merge option. Multiple files + // may be specified. + + p = M_CheckParm("-nwtmerge"); + + if (p > 0) + { + for (p = p + 1; p + // @category mod + // + // Simulates the behavior of NWT's -af option, merging flats into + // the main IWAD directory. Multiple files may be specified. + // + + p = M_CheckParm("-af"); + + if (p > 0) + { + for (p = p + 1; p + // @category mod + // + // Simulates the behavior of NWT's -as option, merging sprites + // into the main IWAD directory. Multiple files may be specified. + // + + p = M_CheckParm("-as"); + + if (p > 0) + { + for (p = p + 1; p + // @category mod + // + // Equivalent to "-af -as ". + // + + p = M_CheckParm("-aa"); + + if (p > 0) + { + for (p = p + 1; p