• Please review our updated Terms and Rules here

NEW tool "Adlib-Host", use your opl equipped PC as an external midi module

PgrAm

Experienced Member
Joined
Sep 28, 2011
Messages
276
Location
Toronto, Canada
As I work on making new DOS games I occasionally come up with a tool that I think other people might find useful. I re-used the adlib/midi code from Chuck Jones: Space Cop of the Future to create Adlib-Host, a program that you can run on your 16-bit PC with an Adlib and MPU-401 UART card (so it works on a soundblaster 16) and turn it into a an external MIDI synthesizer. I wrote this so that I could use a modern MIDI sequencer while getting real OPL sound, with my 286 hooked up to my MIDI interface, you can even just plug a keyboard into your MPU-401 and play the OPL directly.

Supports OPL2 and OPL3 for extra voices and stereo.

Anyways, this is far from bug free and the midi implementation isn't 100% but here you go anyways:

View attachment adlhost.zip
EDIT: updated link (slight bugfix)
 
Last edited:
Nice idea! Does it just map patch numbers 1:1 to instruments in that IBK file? What strategy is used for voice allocation?

Pity it requires an MPU-401...guess I need to get that 486 of mine up and running so I can use it with one of the software emulators...
 
Yeah its just a 1:1 mapping from the .IBK file, voices are allocated using last note priority, a new note will replace the oldest note. It does not require an intelligent mode midi interface (only uart) so there are a lot of cards that will work. If you can refer me to some documentation for the original sound-blaster midi interface, I could probably add that support without too much trouble.
 
If you can refer me to some documentation for the original sound-blaster midi interface, I could probably add that support without too much trouble.

Here you go: http://pdos.csail.mit.edu/6.828/2008/readings/hardware/SoundBlaster.pdf
The MIDI stuff is very simple. If you need any help, let me know. I have some simple C code to detect the DSP, send commands etc.
I would not go for the UART MIDI mode, but the 'old' mode, since that works on the early Sound Blasters as well, not just on SB 2.0/Pro and newer.
 
Last edited:
I took a look at at the pdf and was able to reliably detect the DSP but I'm having some issues with actually receiving midi, perhaps I could take a look at that C code?

Heres basically what I'm doing now

uint8_t readSBMIDI()
{
while(in8(0x22c) & 0x80); //wait until I can send command
out8(0x22c, 0x30); //send read midi command
while(!(in8(0x22e) & 0x80)); //wait until data is available
return in8(0x22a);
}
 
Oh, thanks for bringing that up Trixter I'm probably accidentally violating a license of something, I think it was from "gmopl.ibk" that was included with OPL3BankEditor
IIRC, although many of the instruments are replaced by my own patches. I'll look into it and make sure I provide the proper attribution.

EDIT: upon further investigation It seems like the patches included with OPL3BankEditor are from various other places, I'll have to dig a little deeper.
 
I took a look at at the pdf and was able to reliably detect the DSP but I'm having some issues with actually receiving midi, perhaps I could take a look at that C code?

Turns out my 'C' code is actually mostly inline-asm which I've taken from the programming manual, but here is my code anyway: https://www.dropbox.com/s/qgnkpokyum2moak/SB.zip?dl=0

You can use it like this, to see incoming MIDI data:
Code:
	if (!ResetDSP(SB_BASE))
	{
		printf("Sound Blaster not detected!\n");
		
		return -1;
	}
	
	// Enable MIDI In polling mode
	WriteDSP(SB_BASE, 0x30);
	
	while (!kbhit())
	{
		uint8_t data = ReadDSP(SB_BASE);
		
		printf("%02X ", data);
		fflush(stdout);
	}


Heres basically what I'm doing now

Your code is more or less correct, but I think the mistake you make is that you use it to read only one MIDI byte.
The command '30h' switches the SB into MIDI in mode, so you can continue to read from the DSP until you reset the DSP with another command.
Perhaps sending the same 30h command multiple times is your problem.

The SB also has an interrupt-driven mode, perhaps that is the one you want to use.
You send 0x31 one time, instead of 0x30 (sending it again disables the mode, I think the same goes for 0x30, but it is not documented).
Then you install an IRQ handler for the appropriate IRQ (you can get that from the BLASTER variable, there's a parser in my SB code).
The IRQ handler can just read from the data port to get the incoming data. Then you need to read from the read-status port to acknowledge the IRQ, so it can fire again for the next byte. Something like:
Code:
void interrupt SBMidiHandler(void)
{
	// Receive pending data
	uint8_t data = inp(SB_BASE + SB_READ);
	
	printf("%02X ", data);
	
	// Acknowledge interrupt
	inp(SB_BASE + SB_READ_STATUS);

	outp(PIC1_COMMAND, OCW2_EOI);
}

int main(int argc, char* argv[])
{
	void interrupt (*OldHandler)(void);
	uint8_t oldPIC1Mask;
	
	if (!ResetDSP(SB_BASE))
	{
		printf("Sound Blaster not detected!\n");
		
		return -1;
	}
	
	// Enable MIDI In interrupt mode
	OldHandler = _dos_getvect(0x7 + 0x8);
	_dos_setvect(0x7 + 0x8, SBMidiHandler);
	
	oldPIC1Mask = inp(PIC1_DATA);
	
	// Enable IRQ7
	outp(PIC1_DATA, oldPIC1Mask & ~(1 << 7));
	
	WriteDSP(SB_BASE, 0x31);
	
	while (!kbhit())
	{
		fflush(stdout);
	}
	
	outp(PIC1_DATA, oldPIC1Mask);
	
	// Disable MIDI In interrupt mode
	WriteDSP(SB_BASE, 0x31);
	
	_dos_setvect(0x7 + 0x8, OldHandler);
	
	return 0;
}
 
Also, in case you're interested in supporting the OPL2LPT from Serdaco (http://www.serdashop.com/OPL2LPT), I have released a simple 'SDK' that has C headers and functions to use the OPL2LPT and the (upcoming) DreamBlaster S2P MIDI synth: https://www.dropbox.com/s/cikzxtk7z2uprzz/SerdacoSDK.zip?dl=0
If you already have working AdLib-code, it's very simple to add OPL2LPT support. Just replace writes to port 0x388 with WriteOPL2LPTAddr() and writes to port 0x389 with WriteOPL2LPTData().
The delays are already incorporated in these functions, so you don't need to take care of that yourself.
 
Oh, thanks for bringing that up Trixter I'm probably accidentally violating a license of something, I think it was from "gmopl.ibk" that was included with OPL3BankEditor
IIRC, although many of the instruments are replaced by my own patches. I'll look into it and make sure I provide the proper attribution.

The reason I ask is because George Sanger's "FAT LABS" attempted to certify instrument banks (and wavetable sets) as being acceptable for general-MIDI. You might want to do some research on that, and maybe contact George to see if he has any OPL2 or OPL3 instrument banks lying around. It would be a hoot to have your game FAT LABS APPROVED...
 
I know NovaLogic's F-22 Lightning II credited OPL2/3 patch sets from the Fat Man on its loading screen; I'll have to see if I can suss out bank files from the big-ass resource lump the demo is packed in...
 
Well I've fixed some issues and added some new features so I give you Adlib Host V1.1!

I've put a download page on my site here: https://chuckjonesdevblog.wordpress.com/adlib-host-use-you-old-pc-as-an-external-midi-module/

- added SBMIDI support (tested on SB16, hopefully somebody with a an older card can test too)
- added command line switches: -mpu401 and -sbmidi to force midi input, although sbmidi will autodetect
- added surround sound support for use with TexElec ReSound OPL3 (front/back pan on midi CC 17)
- fixed a bug which caused hanging notes when used with some sequencers
 
Man, now I really need to get an SB breakout box to test with the Sound Blaster (original? 2.0? Can't remember) in my Tandy. Wonder if the breakout box for the GUS is compatible...
 
Back
Top