Skip to content

Commit

Permalink
Merge pull request #9 from bjt42/wip
Browse files Browse the repository at this point in the history
Pull 1.7 from wip
  • Loading branch information
bjt42 committed Dec 12, 2013
2 parents 03f79f2 + 5777777 commit 50af63d
Show file tree
Hide file tree
Showing 10 changed files with 178 additions and 39 deletions.
23 changes: 15 additions & 8 deletions README
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
-----------------------------------------
SoftMPU 1.6 - Software MPU-401 Emulator
SoftMPU 1.7 - Software MPU-401 Emulator
-----------------------------------------
Copyright (C) 2013 bjt, elianda
Copyright (C) 2002-2013 The DOSBox Team
-----------------------------------------

Release Notes (30/08/13)
Release Notes (12/12/13)

WHAT IS IT?

SoftMPU is a DOS TSR that emulates an 'intelligent mode' hardware MPU-401
interface. It's designed to work in tandem with the MPU interface found on
the Sound Blaster 16 and other common sound cards.
interface. It's designed to work in tandem with the MIDI interfaces found on
Sound Blaster and other common sound cards.

WHY'S THIS USEFUL?

Expand All @@ -20,22 +20,25 @@ MT-32/CM-32L often expect to find a hardware MPU interface that supports
'intelligent mode'. These are now expensive and difficult to find.

By supporting the 'intelligent mode' features in software, these games will
work with the basic MPU interface found on sound cards.
work with the basic MIDI interfaces found on sound cards.

REQUIREMENTS

- EMM386 4.46+ (MS-DOS 6.2) or QEMM 7.03+ must be loaded
- Sound Blaster (or compatible) sound card with an MPU-401 interface
supporting UART mode (e.g. Sound Blaster 16/AWE, Yamaha YMF71x)
- Sound Blaster (or compatible) sound card
- Roland LA synth (e.g. MT-32, CM-32L) or a sound card with MT-32 emulation

USING SOFTMPU

Run SoftMPU specifying the base I/O port address and interrupt of your Sound
Blaster, and the base I/O port address of your hardware MPU interface, e.g.
Blaster, and the base I/O port address of the MPU interface, e.g.

SOFTMPU.EXE /SB:220 /IRQ:5 /MPU:330

The optional /SBMIDI switch forces Sound Blaster MIDI to be used. This mode
is intended for use with the Sound Blaster Pro 2 and other sound cards
without a hardware MPU interface. Game compatibility may be reduced.

The optional /DELAYSYSEX switch enables small transmission delays to prevent
buffer overflow with the Rev.0 MT-32.

Expand All @@ -56,6 +59,10 @@ Problem: Some games expect to find an MPU interface on IRQ 2, but my sound
Solution: Use IRQ 9 instead. This is supported by Yamaha YMF71x sound cards,
maybe others too.

Problem: SoftMPU can't find a hardware MPU interface when using a Sound
Blaster Pro 2 or older sound card.
Solution: Run SoftMPU with the /SBMIDI switch.

Problem: My Rev.0 MT-32 displays "EXC. BUFFER OVERFLOW". Music playback
sounds incorrect.
Solution: Run SoftMPU with the /DELAYSYSEX switch.
Expand Down
Binary file modified SOFTMPU.EXE
Binary file not shown.
2 changes: 1 addition & 1 deletion SRC/EXPORT.H
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ typedef struct {
/* Interface functions */
void PIC_Update(bool blocking);

void MPU401_Init(void far* qpientry,Bitu sbport,Bitu irq,Bitu mpuport,bool delaysysex,bool fakeallnotesoff);
void MPU401_Init(void far* qpientry,Bitu sbport,Bitu irq,Bitu mpuport,bool sbmidi,bool delaysysex,bool fakeallnotesoff);
void MPU401_SetEnableSBIRQ(bool enable);
Bitu MPU401_ReadStatus(void);
void MPU401_WriteCommand(Bitu val);
Expand Down
8 changes: 5 additions & 3 deletions SRC/INTHAND.ASM
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,14 @@ DOSIntHandler: ; Check for exec call (ah=04Bh,al=00h)
cli

; Default settings
push eax
mov SBEOI,1 ; Enable SB EOI
mov SBIRQGen,1 ; Enable SB IRQ generation
mov al,SBMIDI
xor al,01h
mov SBIRQGen,al ; Never generate interrupts in SB-MIDI mode

; Parse filename for app detection substrings
push si
push eax
push ebx
mov si,dx
cld ; Auto increment si
Expand Down Expand Up @@ -220,8 +222,8 @@ DOSIntHandler: ; Check for exec call (ah=04Bh,al=00h)
sub si,3 ; Only step a byte at a time
jmp @@ParseFilename ; Next char
@@ExitISR2: pop ebx
pop eax ; Finished parsing
pop si
pop eax ; Finished parsing

; Now commit our changes
pusha
Expand Down
87 changes: 85 additions & 2 deletions SRC/MIDI.C
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ typedef int Bits;
#define MAX_TRACKED_CHANNELS 16
#define MAX_TRACKED_NOTES 8

static char* MIDI_welcome_msg = "\xf0\x41\x10\x16\x12\x20\x00\x00 SoftMPU v1.6 \x27\xf7"; /* SOFTMPU */
static char* MIDI_welcome_msg = "\xf0\x41\x10\x16\x12\x20\x00\x00 SoftMPU v1.7 \x26\xf7"; /* SOFTMPU */

static Bit8u MIDI_note_off[3] = { 0x80,0x00,0x00 }; /* SOFTMPU */

Expand Down Expand Up @@ -97,6 +97,7 @@ channel tracked_channels[MAX_TRACKED_CHANNELS];

static struct {
Bitu mpuport;
Bitu sbport;
Bitu status;
Bitu cmd_len;
Bitu cmd_pos;
Expand All @@ -116,11 +117,91 @@ static struct {
/* SOFTMPU: Sysex delay is decremented from PIC_Update */
Bitu MIDI_sysex_delay;

/* SOFTMPU: Also used by MPU401_ReadStatus */
bool MIDI_sbmidi;

/* SOFTMPU: Initialised in mpu401.c */
extern QEMMInfo qemm;

static void PlayMsg_SBMIDI(Bit8u* msg,Bitu len)
{
/* Output a MIDI message to the hardware using SB-MIDI */
/* Wait for WBS clear, then output a byte */
_asm
{
mov bx,msg
mov cx,len ; Assume len < 2^16
add cx,bx ; Get end ptr
mov dx,midi.sbport
add dx,0Ch ; Select DSP write port
NextByte: cmp bx,cx
je End
WaitWBS: cmp qemm.installed,1
jne WaitWBSUntrappedIN
push bx
mov ax,01A00h ; QPI_UntrappedIORead
call qemm.qpi_entry
mov al,bl
pop bx
_emit 0A8h ; Emit test al,(next opcode byte)
; Effectively skips next instruction
WaitWBSUntrappedIN:
in al,dx
or al,al
js WaitWBS
mov al,038h ; Normal mode MIDI output
cmp qemm.installed,1
jne WaitWBSUntrappedOUT
push bx
mov bl,al ; bl = value
mov ax,01A01h ; QPI_UntrappedIOWrite
call qemm.qpi_entry
pop bx
_emit 0A8h ; Emit test al,(next opcode byte)
; Effectively skips next instruction
WaitWBSUntrappedOUT:
out dx,al
WaitWBS2: cmp qemm.installed,1
jne WaitWBS2UntrappedIN
push bx
mov ax,01A00h ; QPI_UntrappedIORead
call qemm.qpi_entry
mov al,bl
pop bx
_emit 0A8h ; Emit test al,(next opcode byte)
; Effectively skips next instruction
WaitWBS2UntrappedIN:
in al,dx
or al,al
js WaitWBS2
mov al,[bx]
cmp qemm.installed,1
jne WaitWBS2UntrappedOUT
push bx
mov bl,al ; bl = value
mov ax,01A01h ; QPI_UntrappedIOWrite
call qemm.qpi_entry
pop bx
_emit 0A8h ; Emit test al,(next opcode byte)
; Effectively skips next instruction
WaitWBS2UntrappedOUT:
out dx,al
inc bx
jmp NextByte

; Nothing more to send
End: nop
}
};

static void PlayMsg(Bit8u* msg,Bitu len)
{
/* Pass through for SB-MIDI mode */
if (MIDI_sbmidi)
{
return PlayMsg_SBMIDI(msg,len);
}

/* Output a MIDI message to the hardware */
/* Wait for DRR clear, then output a byte */
_asm
Expand Down Expand Up @@ -313,7 +394,7 @@ bool MIDI_Available(void) {
}

/* SOFTMPU: Initialisation */
void MIDI_Init(Bitu mpuport,bool delaysysex,bool fakeallnotesoff)
void MIDI_Init(Bitu mpuport,Bitu sbport,bool sbmidi,bool delaysysex,bool fakeallnotesoff)
{
Bitu i; /* SOFTMPU */
midi.sysex.delay = 0;
Expand All @@ -326,11 +407,13 @@ void MIDI_Init(Bitu mpuport,bool delaysysex,bool fakeallnotesoff)
/*LOG_MSG("MIDI:Using delayed SysEx processing");*/ /* SOFTMPU */
}
midi.mpuport=mpuport;
midi.sbport=sbport;
midi.status=0x00;
midi.cmd_pos=0;
midi.cmd_len=0;
midi.fakeallnotesoff=fakeallnotesoff;
midi.available=true;
MIDI_sbmidi=sbmidi;

/* SOFTMPU: Display welcome message on MT-32 */
for (i=0;i<30;i++)
Expand Down
64 changes: 45 additions & 19 deletions SRC/MPU401.C
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ void PIC_SetIRQMask(Bitu irq,bool masked);
void PIC_AddEvent(EventID event,Bitu delay);
void PIC_RemoveEvents(EventID event);

void MIDI_Init(Bitu mpuport,bool delaysysex,bool fakeallnotesoff);
void MIDI_Init(Bitu mpuport,Bitu sbport,bool sbmidi,bool delaysysex,bool fakeallnotesoff);
void MIDI_RawOutByte(Bit8u data);
bool MIDI_Available(void);

Expand Down Expand Up @@ -127,6 +127,9 @@ static struct {
/* SOFTMPU: Global QEMM interface parameters accessed from MIDI_PlayMsg */
QEMMInfo qemm = { false, NULL }; /* Disabled by default */

/* SOFTMPU: Sound Blaster MIDI toggle */
extern MIDI_sbmidi;

static void QueueByte(Bit8u data) {
if (mpu.state.block_ack) {mpu.state.block_ack=false;return;}
if (mpu.queue_used==0 && mpu.intelligent && mpu.generate_irqs) {
Expand All @@ -150,22 +153,45 @@ static void ClrQueue(void) {
Bitu MPU401_ReadStatus(void) { /* SOFTMPU */
Bit8u retval=0x3f; /* Bits 6 and 7 clear */

/* SOFTMPU: Reflect hardware DRR */
_asm
{
mov dx,mpu.mpuport
inc dx
cmp qemm.installed,1
jne UntrappedIn
mov ax,01A00h ; QPI_UntrappedIORead
call qemm.qpi_entry ; Result in bl
mov al,bl
_emit 0A8h ; Emit test al,(next opcode byte)
; Effectively skips next instruction
UntrappedIn: in al,dx
and al,040h
or retval,al
}
if (MIDI_sbmidi)
{
/* SOFTMPU: Reflect hardware WBS */
_asm
{
mov dx,mpu.sbport
add dx,0Ch ; Select DSP write port
cmp qemm.installed,1
jne UntrappedIn
mov ax,01A00h ; QPI_UntrappedIORead
call qemm.qpi_entry ; Result in bl
mov al,bl
_emit 0A8h ; Emit test al,(next opcode byte)

UntrappedIn: in al,dx
shr al,1
and al,040h
or retval,al
}
}
else
{
/* SOFTMPU: Reflect hardware DRR */
_asm
{
mov dx,mpu.mpuport
inc dx
cmp qemm.installed,1
jne UntrappedIn2
mov ax,01A00h ; QPI_UntrappedIORead
call qemm.qpi_entry ; Result in bl
mov al,bl
_emit 0A8h ; Emit test al,(next opcode byte)
; Effectively skips next instruction
UntrappedIn2: in al,dx
and al,040h
or retval,al
}
}
if (mpu.state.cmd_pending) retval|=0x40;
if (!mpu.queue_used) retval|=0x80;

Expand Down Expand Up @@ -694,7 +720,7 @@ void MPU401_SetEnableSBIRQ(bool enable)
}

/* SOFTMPU: Initialisation */
void MPU401_Init(void far* qpientry,Bitu sbport,Bitu irq,Bitu mpuport,bool delaysysex,bool fakeallnotesoff)
void MPU401_Init(void far* qpientry,Bitu sbport,Bitu irq,Bitu mpuport,bool sbmidi,bool delaysysex,bool fakeallnotesoff)
{
/* Store QEMM parameters */
qemm.installed=(NULL!=qpientry);
Expand All @@ -704,7 +730,7 @@ void MPU401_Init(void far* qpientry,Bitu sbport,Bitu irq,Bitu mpuport,bool delay
PIC_Init();

/* Initialise MIDI handler */
MIDI_Init(mpuport,delaysysex,fakeallnotesoff);
MIDI_Init(mpuport,sbport,sbmidi,delaysysex,fakeallnotesoff);
if (!MIDI_Available()) return;

mpu.queue_used=0;
Expand Down
3 changes: 2 additions & 1 deletion SRC/RESIDENT.ASM
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ CmdHandlerAddr DW OFFSET PortHandler

SBPortAddr DW 0
SBIRQ DB 0
SBMIDI DB 0
DelaySysex DB 0
FakeAllNotesOff DB 0

Expand Down Expand Up @@ -129,7 +130,7 @@ Start: push es
mov es,ax ; Copy cs->es for var access from init
jmp FAR PTR EMMErr ; Fail

@@InitSoftMPU: INVOKE MPU401_Init,QPIEntry,SBPortAddr,SBIRQ,MPUDataPortAddr,DelaySysex,FakeAllNotesOff
@@InitSoftMPU: INVOKE MPU401_Init,QPIEntry,SBPortAddr,SBIRQ,MPUDataPortAddr,SBMIDI,DelaySysex,FakeAllNotesOff
push es
mov ax,cs
mov es,ax ; Copy cs->es for var access from init
Expand Down
4 changes: 4 additions & 0 deletions SRC/SOFTMPU.ASM
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@
;
; - QEMM support (requires version 7.03+)
;
; 1.7
;
; - SB-MIDI support (disables interrupt generation)
;
; ------------------------------------------

StackSize EQU 0400h ; 1k stack for init
Expand Down
6 changes: 4 additions & 2 deletions SRC/STRINGS.ASM
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Header DB 0DAh
DB 0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h
DB 0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h,0C4h
DB 0C4h,0BFh,0Dh,0Ah
DB 0B3h,'SoftMPU 1.6 ',0FEh,' Software MPU-401 Emulator ',0B3h,0Dh,0Ah
DB 0B3h,'SoftMPU 1.7 ',0FEh,' Software MPU-401 Emulator ',0B3h,0Dh,0Ah
DB 0B3h,' ',0B3h,0Dh,0Ah
DB 0B3h,'Copyright (C) 2013 bjt, elianda ',0B3h,0Dh,0Ah
DB 0B3h,'Copyright (C) 2002-2013 The DOSBox Team',0B3h,0Dh,0Ah
Expand All @@ -56,16 +56,18 @@ MPUErrorEnd DB 0Dh,0Ah,'$'
MPUSuccessStart DB 0FBh,' MPU-401 detected at port ','$'
MPUSuccessEnd DB 0Dh,0Ah,'$'
MPUPortNum DB ' ','$'
SBMIDIEnabled DB 'i SB-MIDI mode enabled',0Dh,0Ah,'$'
DelaysEnabled DB 'i SYSEX delays enabled',0Dh,0Ah,'$'
FakeEnabled DB 'i Simulated "All Notes Off" enabled',0Dh,0Ah,'$'
LoadedStart DB 0Dh,0Ah,0Eh,' SoftMPU active at port ','$'
LoadedMid DB ' IRQ ','$'
LoadedEnd DB 0Dh,0Ah,'$'
HelpText DB 'Usage: SOFTMPU /SB:nnn /IRQ:nn /MPU:nnn [/DELAYSYSEX] [/RA50]',0Dh,0Ah
HelpText DB 'Usage: SOFTMPU /SB:nnn /IRQ:nn /MPU:nnn [/SBMIDI] [/DELAYSYSEX] [/RA50]',0Dh,0Ah
DB 0Dh,0Ah
DB ' /SB:nnn Sound Blaster base I/O port address (220-280)',0Dh,0Ah
DB ' /IRQ:nn Sound Blaster interrupt (2-11)',0Dh,0Ah
DB ' /MPU:nnn MPU-401 base I/O port address (220-350)',0Dh,0Ah
DB ' /SBMIDI Use Sound Blaster MIDI',0Dh,0Ah
DB ' /DELAYSYSEX Prevent Rev.0 MT-32 buffer overflow',0Dh,0Ah
DB ' /RA50 Simulate "All Notes Off" for Roland RA-50',0Dh,0Ah,'$'
EMMDevice DB 'EMMXXXX0',00h
Expand Down
Loading

0 comments on commit 50af63d

Please sign in to comment.