diff --git a/BUILD.BAT b/BUILD.BAT index 7a61baa..9108ed7 100644 --- a/BUILD.BAT +++ b/BUILD.BAT @@ -8,11 +8,11 @@ del softmpu.exe del *.obj del *.inc del *.map -%CLEXE% /c /W2 /BATCH /Os /Ol /Og /Oe /Oi /Gs /FoMPU401.obj MPU401.C +%CLEXE% /c /W2 /BATCH /Ox /FoMPU401.obj MPU401.C @if errorlevel 1 goto end -%CLEXE% /c /W2 /BATCH /Os /Ol /Og /Oe /Oi /Gs /FoMIDI.obj MIDI.C +%CLEXE% /c /W2 /BATCH /Ox /FoMIDI.obj MIDI.C @if errorlevel 1 goto end -%CLEXE% /c /W2 /BATCH /Os /Ol /Og /Oe /Oi /Gs /FoPIC.obj PIC.C +%CLEXE% /c /W2 /BATCH /Ox /FoPIC.obj PIC.C @if errorlevel 1 goto end %H2INC% export.h @if errorlevel 1 goto end diff --git a/README b/README index 904fc06..9052774 100644 --- a/README +++ b/README @@ -1,11 +1,11 @@ ---------------------------------------------- -SoftMPU 1.4 by bjt - Software MPU-401 Emulator +SoftMPU 1.5 by bjt - Software MPU-401 Emulator ---------------------------------------------- Copyright (C) 2013 bjt Copyright (C) 2002-2013 The DOSBox Team ---------------------------------------------- -Release Notes (26/07/13) +Release Notes (09/08/13) WHAT IS IT? @@ -40,6 +40,9 @@ Blaster, and the base I/O port address of your hardware MPU interface, e.g. The optional /DELAYSYSEX switch enables small transmission delays to prevent buffer overflow with the Rev.0 MT-32. +The optional /RA50 switch enables simulated "All Notes Off" commands for +compatibility with the Roland RA-50. + SoftMPU will remain active until the PC is restarted. It occupies approximately 7KB and can be loaded into high memory using the LH command. @@ -86,4 +89,4 @@ SPECIAL THANKS - The DOSBox Team for their intelligent mode MPU-401 emulation code. SoftMPU couldn't exist without it! -- Forum members at vogons.zetafleet.com for their encouragement and advice :) +- Forum members at www.vogons.org for their encouragement and advice :) diff --git a/SOFTMPU.EXE b/SOFTMPU.EXE index 6590256..41b3792 100644 Binary files a/SOFTMPU.EXE and b/SOFTMPU.EXE differ diff --git a/SRC/EXPORT.H b/SRC/EXPORT.H index 04db28a..a129a91 100644 --- a/SRC/EXPORT.H +++ b/SRC/EXPORT.H @@ -39,7 +39,7 @@ typedef enum EventID {MPU_EVENT,RESET_DONE,EOI_HANDLER,NUM_EVENTS} EventID; /* Interface functions */ void PIC_Update(bool blocking); -void MPU401_Init(Bitu sbport,Bitu irq,Bitu mpuport,bool delaysysex); +void MPU401_Init(Bitu sbport,Bitu irq,Bitu mpuport,bool delaysysex,bool fakeallnotesoff); void MPU401_SetEnableSBIRQ(bool enable); Bitu MPU401_ReadStatus(void); void MPU401_WriteCommand(Bitu val); diff --git a/SRC/MIDI.C b/SRC/MIDI.C index cfd2834..4db05ba 100644 --- a/SRC/MIDI.C +++ b/SRC/MIDI.C @@ -55,7 +55,13 @@ typedef int Bits; #define SYSEX_SIZE 1024 #define RAWBUF 1024 -static char* MIDI_welcome_msg="\xf0\x41\x10\x16\x12\x20\x00\x00 SoftMPU v1.4 \x29\xf7"; /* SOFTMPU */ +/* SOFTMPU: Note tracking for RA-50 */ +#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.5 \x28\xf7"; /* SOFTMPU */ + +static Bit8u MIDI_note_off[3] = { 0x80,0x00,0x00 }; /* SOFTMPU */ static Bit8u MIDI_evt_len[256] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x00 @@ -80,6 +86,15 @@ static Bit8u MIDI_evt_len[256] = { 0,2,3,2, 0,0,1,0, 1,0,1,1, 1,0,1,0 // 0xf0 }; +/* SOFTMPU: Note tracking for RA-50 */ +typedef struct { + Bit8u used; + Bit8u next; + Bit8u notes[MAX_TRACKED_NOTES]; +} channel; + +channel tracked_channels[MAX_TRACKED_CHANNELS]; + static struct { Bitu mpuport; Bitu status; @@ -93,6 +108,7 @@ static struct { Bitu delay; Bit32u start; } sysex; + bool fakeallnotesoff; bool available; /*MidiHandler * handler;*/ /* SOFTMPU */ } midi; @@ -125,7 +141,30 @@ static void PlayMsg(Bit8u* msg,Bitu len) } }; +/* SOFTMPU: Fake "All Notes Off" for Roland RA-50 */ +static void FakeAllNotesOff(Bitu chan) +{ + Bitu note; + channel* pChan; + + MIDI_note_off[0] &= 0xf0; + MIDI_note_off[0] |= (Bit8u)chan; + + pChan=&tracked_channels[chan]; + + for (note=0;noteused;note++) + { + MIDI_note_off[1]=pChan->notes[note]; + PlayMsg(MIDI_note_off,3); + } + + pChan->used=0; + pChan->next=0; +} + void MIDI_RawOutByte(Bit8u data) { + channel* pChan; /* SOFTMPU */ + if (midi.sysex.start && MIDI_sysex_delay) { _asm { @@ -206,9 +245,40 @@ void MIDI_RawOutByte(Bit8u data) { if (midi.cmd_pos >= midi.cmd_len) { /*if (CaptureState & CAPTURE_MIDI) { CAPTURE_AddMidi(false, midi.cmd_len, midi.cmd_buf); - }*/ /* SOFTMPU */ - PlayMsg(midi.cmd_buf,midi.cmd_len); - midi.cmd_pos=1; //Use Running status + }*/ /* SOFTMPU */ + + if (midi.fakeallnotesoff) + { + /* SOFTMPU: Test for "Note On" */ + if ((midi.status&0xf0)==0x90) + { + if (midi.cmd_buf[2]>0) + { + pChan=&tracked_channels[midi.status&0x0f]; + pChan->notes[pChan->next++]=midi.cmd_buf[1]; + if (pChan->next==MAX_TRACKED_NOTES) pChan->next=0; + if (pChan->usedused++; + } + + PlayMsg(midi.cmd_buf,midi.cmd_len); + } + /* SOFTMPU: Test for "All Notes Off" */ + else if (((midi.status&0xf0)==0xb0) && + (midi.cmd_buf[1]>=0x7b) && + (midi.cmd_buf[1]<=0x7f)) + { + FakeAllNotesOff(midi.status&0x0f); + } + else + { + PlayMsg(midi.cmd_buf,midi.cmd_len); + } + } + else + { + PlayMsg(midi.cmd_buf,midi.cmd_len); + } + midi.cmd_pos=1; //Use Running status } } } @@ -218,7 +288,7 @@ bool MIDI_Available(void) { } /* SOFTMPU: Initialisation */ -void MIDI_Init(Bitu mpuport,bool delaysysex) +void MIDI_Init(Bitu mpuport,bool delaysysex,bool fakeallnotesoff) { Bitu i; /* SOFTMPU */ midi.sysex.delay = 0; @@ -234,13 +304,21 @@ void MIDI_Init(Bitu mpuport,bool delaysysex) midi.status=0x00; midi.cmd_pos=0; midi.cmd_len=0; + midi.fakeallnotesoff=fakeallnotesoff; midi.available=true; /* SOFTMPU: Display welcome message on MT-32 */ - for(i=0;i<30;i++) + for (i=0;i<30;i++) { MIDI_RawOutByte(MIDI_welcome_msg[i]); } + + /* SOFTMPU: Init note tracking */ + for (i=0;ies for var access from init jmp FAR PTR EMMErr ; Fail -@@InitSoftMPU: INVOKE MPU401_Init,cs:SBPortAddr,cs:SBIRQ,cs:MPUDataPortAddr,cs:DelaySysex +@@InitSoftMPU: INVOKE MPU401_Init,cs:SBPortAddr,cs:SBIRQ,cs:MPUDataPortAddr,cs:DelaySysex,cs:FakeAllNotesOff push es mov ax,cs mov es,ax ; Copy cs->es for var access from init diff --git a/SRC/SOFTMPU.ASM b/SRC/SOFTMPU.ASM index 7e34878..5cd597e 100644 --- a/SRC/SOFTMPU.ASM +++ b/SRC/SOFTMPU.ASM @@ -54,6 +54,10 @@ ; - Fixed games with digital FX ; - Improved EMM386 detection ; +; 1.5 +; +; - Optional simulated "All Notes Off" commands for RA-50 +; ; ------------------------------------------ StackSize EQU 0400h ; 1k stack for init diff --git a/SRC/STRINGS.ASM b/SRC/STRINGS.ASM index e32a6f4..e0f1e50 100644 --- a/SRC/STRINGS.ASM +++ b/SRC/STRINGS.ASM @@ -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,0C4h,0C4h,0C4h,0C4h,0C4h,0BFh,0Dh,0Ah - DB 0B3h,'SoftMPU 1.4 by bjt ',0FEh,' Software MPU-401 Emulator',0B3h,0Dh,0Ah + DB 0B3h,'SoftMPU 1.5 by bjt ',0FEh,' Software MPU-401 Emulator',0B3h,0Dh,0Ah DB 0B3h,' ',0B3h,0Dh,0Ah DB 0B3h,'Copyright (C) 2013 bjt ',0B3h,0Dh,0Ah DB 0B3h,'Copyright (C) 2002-2013 The DOSBox Team ',0B3h,0Dh,0Ah @@ -57,14 +57,16 @@ MPUSuccessStart DB 0FBh,' MPU-401 detected at port ','$' MPUSuccessEnd DB 0Dh,0Ah,'$' MPUPortNum DB ' ','$' 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]',0Dh,0Ah +HelpText DB 'Usage: SOFTMPU /SB:nnn /IRQ:nn /MPU:nnn [/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 ' /DELAYSYSEX Prevent Rev.0 MT-32 buffer overflow',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 EMMDevice2 DB 'EMMQXXX0',00h diff --git a/SRC/TRANS.ASM b/SRC/TRANS.ASM index 8abc5ce..ed9c903 100644 --- a/SRC/TRANS.ASM +++ b/SRC/TRANS.ASM @@ -70,7 +70,13 @@ Init: ; Ensure ds=cs cmp eax,'LED/' ; Check for delay switch je @@EnableDelay cmp eax,'led/' + je @@EnableDelay + cmp eax,'5AR/' + je @@EnableFakeOff + cmp eax,'5ar/' jne @@NextParam +@@EnableFakeOff:mov es:FakeAllNotesOff,1 ; Enable simulated "All Notes Off" + jmp @@NextParam @@EnableDelay: mov es:DelaySysex,1 ; Enable sysex delays jmp @@NextParam @@ -320,7 +326,11 @@ Init: ; Ensure ds=cs je @@NoDelay mov dx,OFFSET DelaysEnabled int 021h ; Print sysex delay message -@@NoDelay: pop ds +@@NoDelay: cmp es:FakeAllNotesOff,0 + je @@NoFakeNotes + mov dx,OFFSET FakeEnabled + int 021h +@@NoFakeNotes: pop ds retf ; Return to caller EMMOK: ; Ensure ds=cs