From a461c2a942ae4da5bd241da41bbb15731192a091 Mon Sep 17 00:00:00 2001
From: sparky4 <sparky4@cock.li>
Date: Fri, 25 Aug 2017 14:11:36 -0500
Subject: [PATCH] imfplay works now~

---
 makefile              |   3 +
 src/i0fplay.c         | 231 ++++++++++++++++++++++++++++++++++++++++++
 src/imfplay.c         |  41 ++++----
 src/lib/16_sd.c       |  19 +++-
 src/lib/16_sd.h       |   4 +-
 src/util/shbat/sd.bat |   1 +
 6 files changed, 272 insertions(+), 27 deletions(-)
 create mode 100755 src/i0fplay.c
 create mode 100755 src/util/shbat/sd.bat

diff --git a/makefile b/makefile
index 354c451c..a655ce6c 100755
--- a/makefile
+++ b/makefile
@@ -211,6 +211,7 @@ TESTEXEC = &
 	0tesuto.exe &
 	maptest.exe &
 	imfplay.exe &
+	i0fplay.exe &
 	vrldbg.exe
 #zcroll.exe &
 TESTEXEC2 = &
@@ -290,6 +291,7 @@ fontgfx.exe:	fontgfx.$(OBJ) gfx.lib $(DOSLIB)
 inputest.exe:	 inputest.$(OBJ) $(16LIB) $(DOSLIB) gfx.lib
 sountest.exe:	sountest.$(OBJ) $(16LIB) $(DOSLIB) gfx.lib
 imfplay.exe:		imfplay.$(OBJ) $(16LIB) $(DOSLIB) gfx.lib
+i0fplay.exe:		i0fplay.$(OBJ) $(DOSLIB)
 vrldbg.exe:		vrldbg.$(OBJ) #gfx.lib $(DOSLIB)
 pcxtest.exe:	pcxtest.$(OBJ) gfx.lib $(DOSLIB) $(16LIB)
 vrstest.exe:	vrstest.$(OBJ) $(16LIB) gfx.lib $(DOSLIB)
@@ -340,6 +342,7 @@ inputest.$(OBJ):$(SRC)/inputest.c
 #inntest.$(OBJ):$(SRC)/inntest.c
 sountest.$(OBJ): $(SRC)/sountest.c
 imfplay.$(OBJ): $(SRC)/imfplay.c
+i0fplay.$(OBJ): $(SRC)/i0fplay.c
 vrldbg.$(OBJ):	$(SRC)/vrldbg.c
 #miditest.$(OBJ): $(SRC)/miditest.c
 #testemm.$(OBJ):$(SRC)/testemm.c
diff --git a/src/i0fplay.c b/src/i0fplay.c
new file mode 100755
index 00000000..0e67d2f1
--- /dev/null
+++ b/src/i0fplay.c
@@ -0,0 +1,231 @@
+/* midi.c
+ *
+ * Adlib OPL2/OPL3 FM synthesizer chipset test program.
+ * Play MIDI file using the OPLx synthesizer (well, poorly anyway)
+ * (C) 2010-2012 Jonathan Campbell.
+ * Hackipedia DOS library.
+ *
+ * This code is licensed under the LGPL.
+ * <insert LGPL legal text here>
+ *
+ * Compiles for intended target environments:
+ *   - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
+ */
+ 
+#include <stdio.h>
+#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <math.h>
+#include <dos.h>
+
+#include <hw/vga/vga.h>
+#include <hw/dos/dos.h>
+#include <hw/8254/8254.h>		/* 8254 timer */
+#include <hw/8259/8259.h>
+#include <hw/adlib/adlib.h>
+
+static void (interrupt *old_irq0)();
+static volatile unsigned long irq0_ticks=0;
+static volatile unsigned int irq0_cnt=0,irq0_add=0,irq0_max=0;
+
+#pragma pack(push,1)
+struct imf_entry {
+	uint8_t		reg,data;
+	uint16_t	delay;
+};
+#pragma pack(pop)
+
+static struct imf_entry*	imf_music=NULL;
+static struct imf_entry*	imf_play_ptr=NULL;
+static struct imf_entry*	imf_music_end=NULL;
+static uint16_t			imf_delay_countdown=0;
+
+void imf_free_music() {
+	if (imf_music) free(imf_music);
+	imf_music = imf_play_ptr = imf_music_end = NULL;
+	imf_delay_countdown = 0;
+}
+
+int imf_load_music(const char *path) {
+	unsigned char buf[8];
+	unsigned long len;
+	int fd;
+
+	imf_free_music();
+
+	fd = open(path,O_RDONLY|O_BINARY);
+	if (fd < 0) return 0;
+
+	len = lseek(fd,0,SEEK_END);
+	lseek(fd,0,SEEK_SET);
+	read(fd,buf,2);
+	if (buf[0] != 0 || buf[1] != 0) // type 1 IMF
+		len = *((uint16_t*)buf);
+	else
+		lseek(fd,0,SEEK_SET);
+
+	if (len == 0 || len > 65535UL) {
+		close(fd);
+		return 0;
+	}
+	len -= len & 3;
+
+	imf_music = malloc(len);
+	if (imf_music == NULL) {
+		close(fd);
+		return 0;
+	}
+	read(fd,imf_music,len);
+	close(fd);
+
+	imf_play_ptr = imf_music;
+	imf_music_end = imf_music + (len >> 2UL);
+	return 1;
+}
+
+/* WARNING: subroutine call in interrupt handler. make sure you compile with -zu flag for large/compact memory models */
+void interrupt irq0() {
+	irq0_ticks++;
+	if ((irq0_cnt += irq0_add) >= irq0_max) {
+		irq0_cnt -= irq0_max;
+		old_irq0();
+	}
+	else {
+		p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
+	}
+}
+
+void imf_tick() {
+	if (imf_delay_countdown == 0) {
+		do {
+			adlib_write(imf_play_ptr->reg,imf_play_ptr->data);
+			imf_delay_countdown = imf_play_ptr->delay;
+			imf_play_ptr++;
+			if (imf_play_ptr == imf_music_end)
+				imf_play_ptr = imf_music;
+		} while (imf_delay_countdown == 0);
+	}
+	else {
+		imf_delay_countdown--;
+	}
+}
+
+void adlib_shut_up() {
+	int i;
+
+	memset(adlib_fm,0,sizeof(adlib_fm));
+	memset(&adlib_reg_bd,0,sizeof(adlib_reg_bd));
+	for (i=0;i < adlib_fm_voices;i++) {
+		struct adlib_fm_operator *f;
+		f = &adlib_fm[i].mod;
+		f->ch_a = f->ch_b = f->ch_c = f->ch_d = 1;
+		f = &adlib_fm[i].car;
+		f->ch_a = f->ch_b = f->ch_c = f->ch_d = 1;
+	}
+
+	for (i=0;i < adlib_fm_voices;i++) {
+		struct adlib_fm_operator *f;
+
+		f = &adlib_fm[i].mod;
+		f->mod_multiple = 1;
+		f->total_level = 63 - 16;
+		f->attack_rate = 15;
+		f->decay_rate = 4;
+		f->sustain_level = 0;
+		f->release_rate = 8;
+		f->f_number = 400;
+		f->sustain = 1;
+		f->octave = 4;
+		f->key_on = 0;
+
+		f = &adlib_fm[i].car;
+		f->mod_multiple = 1;
+		f->total_level = 63 - 16;
+		f->attack_rate = 15;
+		f->decay_rate = 4;
+		f->sustain_level = 0;
+		f->release_rate = 8;
+		f->f_number = 0;
+		f->sustain = 1;
+		f->octave = 0;
+		f->key_on = 0;
+	}
+
+	adlib_apply_all();
+}
+
+int main(int argc,char **argv) {
+	unsigned long tickrate = 700;
+	unsigned long ptick;
+	int c;
+
+	printf("ADLIB FM test program IMFPLAY\n");
+	if (argc < 2) {
+		printf("You must specify an IMF file to play\n");
+		return 1;
+	}
+
+	if (!init_adlib()) {
+		printf("Cannot init library\n");
+		return 1;
+	}
+	if (!probe_8254()) { /* we need the timer to keep time with the music */
+		printf("8254 timer not found\n");
+		return 1;
+	}
+
+	if (!imf_load_music(argv[1])) {
+		printf("Failed to load IMF Music\n");
+		return 1;
+	}
+
+	write_8254_system_timer(T8254_REF_CLOCK_HZ / tickrate);
+	irq0_cnt = 0;
+	irq0_add = 182;
+	irq0_max = 1000; /* about 18.2Hz */
+	old_irq0 = _dos_getvect(8);/*IRQ0*/
+	_dos_setvect(8,irq0);
+
+	adlib_shut_up();
+	shutdown_adlib_opl3(); // NTS: Apparently the music won't play otherwise
+	_cli();
+	irq0_ticks = ptick = 0;
+	_sti();
+
+	while (1) {
+		unsigned long adv;
+
+		_cli();
+		adv = irq0_ticks - ptick;
+		if (adv >= 100UL) adv = 100UL;
+		ptick = irq0_ticks;
+		_sti();
+
+		while (adv != 0) {
+			imf_tick();
+			adv--;
+		}
+
+		if (kbhit()) {
+			c = getch();
+			if (c == 0) c = getch() << 8;
+
+			if (c == 27) {
+				break;
+			}
+		}
+	}
+
+	imf_free_music();
+	adlib_shut_up();
+	shutdown_adlib();
+	_dos_setvect(8,old_irq0);
+	write_8254_system_timer(0); /* back to normal 18.2Hz */
+	return 0;
+}
+
diff --git a/src/imfplay.c b/src/imfplay.c
index 697b6d36..35527524 100755
--- a/src/imfplay.c
+++ b/src/imfplay.c
@@ -34,8 +34,8 @@
 
 extern struct glob_game_vars	*ggvv;
 
-/*static void (interrupt *old_irq0)();
-static volatile unsigned long irq0_ticks=0;
+static void (interrupt *old_irq0)();
+/*static volatile unsigned long irq0_ticks=0;
 static volatile unsigned int irq0_cnt=0,irq0_add=0,irq0_max=0;
 
 #pragma pack(push,1)
@@ -65,10 +65,10 @@ static uint16_t			imf_delay_countdown=0;
 }
 
 void imf_free_music(global_game_variables_t *gvar) {
-	if (imf_music) free(imf_music);
-	MM_FreePtr(MEMPTR gvar->ca.audiosegs[0], gvar);
-	imf_music = imf_play_ptr = imf_music_end = NULL;
-	imf_delay_countdown = 0;
+	if (gvar->ca.sd.imf_music) free(gvar->ca.sd.imf_music);
+	MM_FreePtr(MEMPTRCONV gvar->ca.audiosegs[0], gvar);
+	gvar->ca.sd.imf_music = gvar->ca.sd.imf_play_ptr = gvar->ca.sd.imf_music_end = NULL;
+	gvar->ca.sd.imf_delay_countdown = 0;
 }
 
 int imf_load_music(const char *path, global_game_variables_t *gvar) {
@@ -96,20 +96,20 @@ int imf_load_music(const char *path, global_game_variables_t *gvar) {
 	len -= len & 3;
 
 //	imf_music = malloc(len);
-	MM_GetPtr(MEMPTR gvar->ca.audiosegs[0],len, gvar);
-	imf_music = (struct imf_entry *)gvar->ca.audiosegs[0];
-	if (imf_music == NULL) {
+	MM_GetPtr(MEMPTRCONV gvar->ca.audiosegs[0],len, gvar);
+	gvar->ca.sd.imf_music = (struct imf_entry *)gvar->ca.audiosegs[0];
+	if (gvar->ca.sd.imf_music == NULL) {
 		close(fd);
 		return 0;
 	}
-	read(fd,imf_music,len);
+	read(fd,gvar->ca.sd.imf_music,len);
 	close(fd);
 
-	imf_play_ptr = imf_music;
-	imf_music_end = imf_music + (len >> 2UL);
-	PRINTBB;
+	gvar->ca.sd.imf_play_ptr = gvar->ca.sd.imf_music;
+	gvar->ca.sd.imf_music_end = gvar->ca.sd.imf_music + (len >> 2UL);
+//	PRINTBB;
 	return 1;
-}
+}*/
 
 // WARNING: subroutine call in interrupt handler. make sure you compile with -zu flag for large/compact memory models
 void interrupt irq0()
@@ -124,7 +124,7 @@ void interrupt irq0()
 	}
 }
 
-void imf_tick() {
+/*void imf_tick() {
 	if (imf_delay_countdown == 0) {
 		do {
 			adlib_write(imf_play_ptr->reg,imf_play_ptr->data);
@@ -200,15 +200,15 @@ void main(int argc,char **argv) {
 	StartupCAMMPM(&gvar);
 	printf("ADLIB FM test program IMFPLAY\n");
 	if (argc < 2) {
-		printf("You must specify an IMF file to play\n");
-//		return;
+		printf("You must specify an IMF file to play\n"); ShutdownCAMMPM(&gvar);
+		return;
 	}
 
 	SD_Initimf(&gvar);
 
 	if (!SD_imf_load_music(argv[1], &gvar)) {
-		printf("Failed to load IMF Music\n");
-//		return;
+		printf("Failed to load IMF Music\n"); ShutdownCAMMPM(&gvar);
+		return;
 	}
 
 	write_8254_system_timer(T8254_REF_CLOCK_HZ / tickrate);
@@ -219,6 +219,7 @@ void main(int argc,char **argv) {
 	gvar.ca.sd.irq0_ticks = ptick = 0;
 	_sti();
 
+	printf("playing!\n");
 	while (1) {
 		unsigned long adv;
 
@@ -242,7 +243,7 @@ void main(int argc,char **argv) {
 			}
 		}
 	}
-//	printf("contents of the imf_music\n[\n%s\n]\n", imf_music);
+	printf("contents of the imf_music\n[\n%s\n]\n", gvar.ca.sd.imf_music);
 
 	SD_imf_free_music(&gvar);
 	SD_adlib_shut_up();
diff --git a/src/lib/16_sd.c b/src/lib/16_sd.c
index 610f7ed0..f42f2019 100755
--- a/src/lib/16_sd.c
+++ b/src/lib/16_sd.c
@@ -22,8 +22,10 @@
 
 #include "src/lib/16_sd.h"
 
-//static void (interrupt *old_irq0)();
-void interrupt	(*old_irq0)(void);
+//#define SD_USESCAMMPM
+
+static void (interrupt *SD_old_irq0)();
+//void interrupt	(*old_irq0)(void);
 
 void opl2out(word reg, word data)
 {
@@ -225,8 +227,11 @@ void SD_Initimf(global_game_variables_t *gvar)
 
 void SD_imf_free_music(global_game_variables_t *gvar)
 {
-//	if (gvar->ca.sd.imf_music) free(gvar->ca.sd.imf_music);
+#ifndef SD_USESCAMMPM
+	if (gvar->ca.sd.imf_music) free(gvar->ca.sd.imf_music);
+#else
 	MM_FreePtr(MEMPTRCONV gvar->ca.audiosegs[0], gvar);	//TODO make behave like id engine
+#endif
 	gvar->ca.sd.imf_music = gvar->ca.sd.imf_play_ptr = gvar->ca.sd.imf_music_end = NULL;
 	gvar->ca.sd.imf_delay_countdown = 0;
 }
@@ -256,8 +261,12 @@ int SD_imf_load_music(const char *path, global_game_variables_t *gvar)
 	}
 	len -= len & 3;
 
+#ifndef SD_USESCAMMPM
+	gvar->ca.sd.imf_music = malloc(len);
+#else
 	MM_GetPtr(MEMPTRCONV gvar->ca.audiosegs[0],len, gvar);
 	gvar->ca.sd.imf_music = (struct imf_entry *)gvar->ca.audiosegs[0];
+#endif
 	if (gvar->ca.sd.imf_music == NULL) {
 		close(fd);
 		return 0;
@@ -272,12 +281,12 @@ int SD_imf_load_music(const char *path, global_game_variables_t *gvar)
 
 struct glob_game_vars	*ggvv;
 // WARNING: subroutine call in interrupt handler. make sure you compile with -zu flag for large/compact memory models
-void interrupt irq0()
+void interrupt SD_irq0()
 {
 	ggvv->ca.sd.irq0_ticks++;
 	if ((ggvv->ca.sd.irq0_cnt += ggvv->ca.sd.irq0_add) >= ggvv->ca.sd.irq0_max) {
 		ggvv->ca.sd.irq0_cnt -= ggvv->ca.sd.irq0_max;
-		old_irq0();
+		SD_old_irq0();
 	}
 	else {
 		p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
diff --git a/src/lib/16_sd.h b/src/lib/16_sd.h
index f91ec991..7bae1648 100755
--- a/src/lib/16_sd.h
+++ b/src/lib/16_sd.h
@@ -52,7 +52,7 @@ typedef struct{
 	byte Feedback;                  /* feedback algorithm and strength  */
 } FMInstrument;
 
-extern void interrupt	(*old_irq0)(void);
+//extern void interrupt	(*old_irq0)(void);
 
 void opl2out(word reg, word data);
 void opl3out(word reg, word data);
@@ -66,7 +66,7 @@ void FMSetVoice(int voiceNum, FMInstrument *ins);
 void SD_Initimf(global_game_variables_t *gvar);
 void SD_imf_free_music(global_game_variables_t *gvar);
 int SD_imf_load_music(const char *path, global_game_variables_t *gvar);
-void interrupt irq0(void);
+void interrupt SD_irq0(void);
 void SD_imf_tick(global_game_variables_t *gvar);
 void SD_adlib_shut_up();
 
diff --git a/src/util/shbat/sd.bat b/src/util/shbat/sd.bat
new file mode 100755
index 00000000..e878d322
--- /dev/null
+++ b/src/util/shbat/sd.bat
@@ -0,0 +1 @@
+imfplay.exe data\02.imf
-- 
2.39.5